Skip to content

Commit

Permalink
Allow deposit ID reuse
Browse files Browse the repository at this point in the history
  • Loading branch information
Theodus committed Jul 20, 2023
1 parent f58cf61 commit f621d5d
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 28 deletions.
19 changes: 13 additions & 6 deletions src/Collateralization.sol
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,23 @@ contract Collateralization {
}

/// Create a new deposit, returning its associated ID.
/// @param _id _id ID of the deposit ID to reuse. This should be set to zero to receive a new ID. IDs may only be
/// reused by its prior depositor when the deposit is withdrawn.
/// @param _value Token value of the new deposit.
/// @param _expiration Expiration timestamp of the new deposit, in seconds.
/// @param _arbiter Arbiter of the new deposit.
/// @return id Unique ID associated with the new deposit.
function deposit(uint256 _value, uint128 _expiration, address _arbiter) public returns (uint128) {
// TODO: reuse state when given `(_id != 0) && (msg.sender == getDeposit(_id).depositor)`
/// @return id ID associated with the new deposit.
function deposit(uint128 _id, uint256 _value, uint128 _expiration, address _arbiter) public returns (uint128) {
if (_value == 0) revert ZeroValue();
if (block.timestamp >= _expiration) revert Expired(true);
lastID += 1;
uint128 _id = lastID;
if (_id == 0) {
if (block.timestamp >= _expiration) revert Expired(true);
lastID += 1;
_id = lastID;
} else {
Deposit memory _deposit = getDeposit(_id);
if (msg.sender != _deposit.depositor) revert NotDepositor();
if (_deposit.state != DepositState.Withdrawn) revert UnexpectedState(_deposit.state);
}
deposits[_id] = Deposit({
depositor: msg.sender,
arbiter: _arbiter,
Expand Down
2 changes: 1 addition & 1 deletion src/examples/LoanAggregator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ contract LoanAggregator {
_index += 1;
}
collateralization.token().approve(address(collateralization), _value);
uint128 _deposit = collateralization.deposit(_value, _expiration, address(_arbiter));
uint128 _deposit = collateralization.deposit(0, _value, _expiration, address(_arbiter));
_index = 0;
while (_index < _loanCommitments.length) {
loans[_deposit].push(_loanCommitments[_index].loan);
Expand Down
53 changes: 32 additions & 21 deletions test/Collateralization.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {StdUtils} from "forge-std/StdUtils.sol";
import {Test} from "forge-std/Test.sol";
import {ERC20Burnable} from "openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
import {Collateralization, Deposit, DepositState} from "../src/Collateralization.sol";
import {Collateralization, Deposit, DepositState, UnexpectedState} from "../src/Collateralization.sol";

contract TestToken is ERC20Burnable {
constructor(uint256 _initialSupply) ERC20("MockCoin", "MOCK") {
Expand Down Expand Up @@ -44,7 +44,7 @@ contract CollateralizationHandler is CommonBase, StdUtils {
uint256 _value = bound(__value, 1, collateralization.token().balanceOf(_depositor));
vm.startPrank(_depositor);
collateralization.token().approve(address(collateralization), _value);
uint128 _id = collateralization.deposit(_value, _genExpiration(__expiration), _genActor(__arbiter));
uint128 _id = collateralization.deposit(0, _value, _genExpiration(__expiration), _genActor(__arbiter));
vm.stopPrank();
depositIDs.push(_id);
return _id;
Expand Down Expand Up @@ -137,7 +137,7 @@ contract CollateralizationUnitTests is Test {
uint128 _expiration = uint128(block.timestamp) + 1;
uint256 _initialBalance = token.balanceOf(address(this));
token.approve(address(collateralization), 1);
uint128 _id = collateralization.deposit(1, _expiration, address(0));
uint128 _id = collateralization.deposit(0, 1, _expiration, address(0));
assertEq(token.balanceOf(address(this)), _initialBalance - 1);
assertEq(token.balanceOf(address(collateralization)), 1);
assertEq(collateralization.getDeposit(_id).depositor, address(this));
Expand All @@ -148,27 +148,38 @@ contract CollateralizationUnitTests is Test {
function test_DepositUniqueID() public {
uint128 _expiration = uint128(block.timestamp) + 1;
token.approve(address(collateralization), 2);
uint128 _id1 = collateralization.deposit(1, _expiration, address(0));
uint128 _id2 = collateralization.deposit(1, _expiration, address(0));
uint128 _id1 = collateralization.deposit(0, 1, _expiration, address(0));
uint128 _id2 = collateralization.deposit(0, 1, _expiration, address(0));
assertNotEq(_id1, _id2);
}

function test_DepositReusedID() public {
uint128 _expiration = uint128(block.timestamp) + 1;
token.approve(address(collateralization), 2);
uint128 _id1 = collateralization.deposit(0, 1, _expiration, address(0));
vm.expectRevert(abi.encodeWithSelector(UnexpectedState.selector, DepositState.Unlocked));
collateralization.deposit(_id1, 1, _expiration, address(0));
collateralization.withdraw(_id1);
uint128 _id2 = collateralization.deposit(_id1, 1, _expiration, address(0));
assertEq(_id1, _id2);
}

function testFail_DepositExpirationAtBlock() public {
uint128 _expiration = uint128(block.timestamp);
token.approve(address(collateralization), 1);
collateralization.deposit(1, _expiration, address(0));
collateralization.deposit(0, 1, _expiration, address(0));
}

function testFail_DepositExpirationBeforeBlock() public {
uint128 _expiration = uint128(block.timestamp) - 1;
token.approve(address(collateralization), 1);
collateralization.deposit(1, _expiration, address(0));
collateralization.deposit(0, 1, _expiration, address(0));
}

function test_Lock() public {
uint128 _expiration = uint128(block.timestamp) + 1;
token.approve(address(collateralization), 1);
uint128 _id = collateralization.deposit(1, _expiration, address(this));
uint128 _id = collateralization.deposit(0, 1, _expiration, address(this));
assertEq(uint256(collateralization.getDeposit(_id).state), uint256(DepositState.Unlocked));
collateralization.lock(_id);
assertEq(uint256(collateralization.getDeposit(_id).state), uint256(DepositState.Locked));
Expand All @@ -178,15 +189,15 @@ contract CollateralizationUnitTests is Test {
function testFail_LockAtExpiration() public {
uint128 _expiration = uint128(block.timestamp) + 1;
token.approve(address(collateralization), 1);
uint128 _id = collateralization.deposit(1, _expiration, address(this));
uint128 _id = collateralization.deposit(0, 1, _expiration, address(this));
vm.warp(_expiration);
collateralization.lock(_id);
}

function testFail_LockAfterExpiration() public {
uint128 _expiration = uint128(block.timestamp) + 1;
token.approve(address(collateralization), 1);
uint128 _id = collateralization.deposit(1, _expiration, address(this));
uint128 _id = collateralization.deposit(0, 1, _expiration, address(this));
vm.warp(_expiration + 1);
collateralization.lock(_id);
}
Expand All @@ -199,7 +210,7 @@ contract CollateralizationUnitTests is Test {
uint128 _expiration = uint128(block.timestamp) + 1;
uint256 _initialBalance = token.balanceOf(address(this));
token.approve(address(collateralization), 1);
uint128 _id = collateralization.deposit(1, _expiration, address(this));
uint128 _id = collateralization.deposit(0, 1, _expiration, address(this));
collateralization.lock(_id);
vm.warp(_expiration);
collateralization.withdraw(_id);
Expand All @@ -212,7 +223,7 @@ contract CollateralizationUnitTests is Test {
uint128 _expiration = uint128(block.timestamp) + 1;
uint256 _initialBalance = token.balanceOf(address(this));
token.approve(address(collateralization), 1);
uint128 _id = collateralization.deposit(1, _expiration, address(this));
uint128 _id = collateralization.deposit(0, 1, _expiration, address(this));
collateralization.lock(_id);
vm.warp(_expiration + 1);
collateralization.withdraw(_id);
Expand All @@ -223,7 +234,7 @@ contract CollateralizationUnitTests is Test {
function testFail_WithdrawBeforeExpiration() public {
token.approve(address(collateralization), 1);
uint128 _expiration = uint128(block.timestamp) + 3;
uint128 _id = collateralization.deposit(1, _expiration, address(this));
uint128 _id = collateralization.deposit(0, 1, _expiration, address(this));
collateralization.lock(_id);
vm.warp(_expiration - 1);
collateralization.withdraw(_id);
Expand All @@ -233,7 +244,7 @@ contract CollateralizationUnitTests is Test {
uint128 _expiration = uint128(block.timestamp) + 1;
uint256 _initialBalance = token.balanceOf(address(this));
token.approve(address(collateralization), 1);
uint128 _id = collateralization.deposit(1, _expiration, address(this));
uint128 _id = collateralization.deposit(0, 1, _expiration, address(this));
collateralization.lock(_id);
vm.warp(_expiration);
collateralization.withdraw(_id);
Expand All @@ -244,7 +255,7 @@ contract CollateralizationUnitTests is Test {
function testFail_WithdrawTwice() public {
uint128 _expiration = uint128(block.timestamp) + 1;
token.approve(address(collateralization), 2);
uint128 _id = collateralization.deposit(2, _expiration, address(this));
uint128 _id = collateralization.deposit(0, 2, _expiration, address(this));
collateralization.lock(_id);
vm.warp(_expiration);
collateralization.withdraw(_id);
Expand All @@ -256,7 +267,7 @@ contract CollateralizationUnitTests is Test {
uint256 _initialBalance = token.balanceOf(address(this));
address _other = 0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF;
token.approve(address(collateralization), 1);
uint128 _id = collateralization.deposit(1, _expiration, address(this));
uint128 _id = collateralization.deposit(0, 1, _expiration, address(this));
collateralization.lock(_id);
vm.warp(_expiration);
vm.prank(_other);
Expand All @@ -269,7 +280,7 @@ contract CollateralizationUnitTests is Test {
address _arbiter = 0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF;
uint256 _initialSupply = token.totalSupply();
token.approve(address(collateralization), 1);
uint128 _id = collateralization.deposit(1, _expiration, _arbiter);
uint128 _id = collateralization.deposit(0, 1, _expiration, _arbiter);
vm.startPrank(_arbiter);
collateralization.lock(_id);
vm.warp(_expiration - 1);
Expand All @@ -282,7 +293,7 @@ contract CollateralizationUnitTests is Test {
function testFail_SlashAtExpiration() public {
uint128 _expiration = uint128(block.timestamp) + 3;
token.approve(address(collateralization), 1);
uint128 _id = collateralization.deposit(1, _expiration, address(this));
uint128 _id = collateralization.deposit(0, 1, _expiration, address(this));
collateralization.lock(_id);
vm.warp(_expiration);
collateralization.slash(_id, 1);
Expand All @@ -291,7 +302,7 @@ contract CollateralizationUnitTests is Test {
function testFail_SlashAfterExpiration() public {
uint128 _expiration = uint128(block.timestamp) + 3;
token.approve(address(collateralization), 1);
uint128 _id = collateralization.deposit(1, _expiration, address(this));
uint128 _id = collateralization.deposit(0, 1, _expiration, address(this));
collateralization.lock(_id);
vm.warp(_expiration + 1);
collateralization.slash(_id, 1);
Expand All @@ -300,7 +311,7 @@ contract CollateralizationUnitTests is Test {
function testFail_SlashUnlocked() public {
uint128 _expiration = uint128(block.timestamp) + 3;
token.approve(address(collateralization), 1);
uint128 _id = collateralization.deposit(1, _expiration, address(this));
uint128 _id = collateralization.deposit(0, 1, _expiration, address(this));
vm.warp(_expiration + 1);
collateralization.slash(_id, 1);
}
Expand All @@ -309,7 +320,7 @@ contract CollateralizationUnitTests is Test {
uint128 _expiration = uint128(block.timestamp) + 3;
address _arbiter = 0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF;
token.approve(address(collateralization), 1);
uint128 _id = collateralization.deposit(1, _expiration, _arbiter);
uint128 _id = collateralization.deposit(0, 1, _expiration, _arbiter);
vm.warp(_expiration - 1);
collateralization.slash(_id, 1);
}
Expand Down

0 comments on commit f621d5d

Please sign in to comment.