Skip to content

Commit

Permalink
feat: integration test for purchase and redeem unlock
Browse files Browse the repository at this point in the history
  • Loading branch information
kyriediculous committed Dec 20, 2023
1 parent 444ce1c commit 92d6693
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 96 deletions.
12 changes: 6 additions & 6 deletions src/Swap.sol
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ abstract contract SwapStorage {
// last supply of a tenderizer when seen, tracked because they are rebasing tokens
mapping(address asset => SD59x18 lastSupply) lastSupplyForAsset;
// relayer fees
mapping(address relayer => uint256 fee) relayerFees;
mapping(address relayer => uint256 reward) relayerRewards;
}

function _loadStorageSlot() internal pure returns (Data storage $) {
Expand Down Expand Up @@ -224,9 +224,9 @@ contract TenderSwap is SwapStorage, Multicall, SelfPermit, ERC721Receiver {
function claimRelayerRewards() public returns (uint256 relayerReward) {
Data storage $ = _loadStorageSlot();

relayerReward = $.relayerFees[msg.sender];
relayerReward = $.relayerRewards[msg.sender];

delete $.relayerFees[msg.sender];
delete $.relayerRewards[msg.sender];

underlying.safeTransfer(msg.sender, relayerReward);

Expand All @@ -238,9 +238,9 @@ contract TenderSwap is SwapStorage, Multicall, SelfPermit, ERC721Receiver {
* @param relayer Address of the relayer
* @return relayerReward Amount of tokens that can be claimed
*/
function getPendingRelayerRewards(address relayer) external view returns (uint256) {
function pendingRelayerRewards(address relayer) external view returns (uint256) {
Data storage $ = _loadStorageSlot();
return $.relayerFees[relayer];
return $.relayerRewards[relayer];
}

/**
Expand Down Expand Up @@ -391,7 +391,7 @@ contract TenderSwap is SwapStorage, Multicall, SelfPermit, ERC721Receiver {
//calculate the relayer reward
uint256 relayerReward = ud(unlock.fee).mul(RELAYER_CUT).unwrap();
// update relayer rewards
$.relayerFees[msg.sender] += relayerReward;
$.relayerRewards[msg.sender] += relayerReward;

uint256 fee = unlock.fee - relayerReward;

Expand Down
5 changes: 5 additions & 0 deletions test/Swap.harness.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ contract SwapHarness is TenderSwap {
$.liabilities = _liabilities;
}

function exposed_setRelayerRewards(uint256 amount, address account) public {
Data storage $ = _loadStorageSlot();
$.relayerRewards[account] = amount;
}

function exposed_queueQuery(uint256 index) public view returns (UnlockQueue.Node memory) {
Data storage $ = _loadStorageSlot();
return $.unlockQ.nodes[index];
Expand Down
194 changes: 104 additions & 90 deletions test/Swap.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ contract TenderSwapTest is Test {
address addr1;
address addr2;

event RelayerRewardsClaimed(address indexed relayer, uint256 rewards);

function setUp() public {
underlying = new MockERC20("network.xyz", "XYZ", 18);
tToken0 = new MockERC20("tXYZ_0x00", "tXYZ_0x00", 18);
Expand Down Expand Up @@ -97,6 +99,20 @@ contract TenderSwapTest is Test {
assertEq(underlying.balanceOf(address(swap)), deposit1 + deposit2, "TenderSwap underlying balance");
}

function test_claimRelayerRewards(uint256 amount) public {
amount = 10 ether;
swap.exposed_setRelayerRewards(amount, addr1);
underlying.mint(address(swap), amount);
assertEq(swap.pendingRelayerRewards(addr1), amount, "pending rewards");
vm.expectEmit(true, true, true, true);
emit RelayerRewardsClaimed(addr1, amount);

vm.prank(addr1);
swap.claimRelayerRewards();
assertEq(swap.pendingRelayerRewards(addr1), 0, "pending rewards");
assertEq(underlying.balanceOf(addr1), amount, "addr1 balance");
}

// write end to end swap test with checking the queue
// make three swaps, check the queue state (check head and tail)
// buy up the last unlock and check all code paths
Expand Down Expand Up @@ -212,7 +228,7 @@ contract TenderSwapTest is Test {
liabilitiesBefore = swap.liabilities();
swap.redeemUnlock();
assertEq(swap.liabilities(), liabilitiesBefore + ud(head.fee).sub(ud(head.fee).mul(RELAYER_CUT)).unwrap(), "liabilities");
assertEq(swap.getPendingRelayerRewards(address(this)), ud(head.fee).mul(RELAYER_CUT).unwrap(), "relayer rewards");
assertEq(swap.pendingRelayerRewards(address(this)), ud(head.fee).mul(RELAYER_CUT).unwrap(), "relayer rewards");
assertEq(swap.exposed_unlocking(), 20 ether, "unlocking"); // unlock 2 remains
assertEq(swap.exposed_unlockingForAsset(address(tToken0)), 20 ether, "unlocking for asset"); // unlock 2 remains
head = swap.oldestUnlock();
Expand All @@ -237,118 +253,116 @@ contract TenderSwapTest is Test {
tToken0.approve(address(swap), 150 ether);
(uint256 out, uint256 fee) = swap.swap(address(tToken0), 10 ether, 5 ether);

// Fee should be 0.15% or 0.0015
// As utilisation after is 0.1 and 0.1^3 = 0.001
// Base fee is 0.005 so that makes 0.0015
// Since there is only 1 token drawing liquidity, its weight is 1
uint256 expFee = amount * 15 / 10_000;
uint256 expFee = amount * 75 / 100_000;

assertEq(fee, expFee, "swap fee");
assertEq(out, amount - expFee, "swap out");
assertEq(swap.liquidity(), 90 ether, "TenderSwap available liquidity");
}

function testFuzz_swap_other(
uint256 liquidity,
uint256 t0Supply,
uint256 t1Supply,
uint256 t0Amount,
uint256 t1Amount
)
public
{
vm.assume(liquidity >= 10 ether && liquidity <= type(uint128).max);
t0Supply = bound(t0Supply, 1 ether, liquidity);
t1Supply = bound(t1Supply, 1 ether, liquidity);
t0Amount = bound(t0Amount, 1 ether / 5, t0Supply / 5);
t1Amount = bound(t1Amount, 1 ether / 5, t1Supply / 5);

underlying.mint(address(this), liquidity);
underlying.approve(address(swap), liquidity);
swap.deposit(liquidity);

uint256 tokenId = _encodeTokenId(address(tToken0), 0);
// function testFuzz_swap_other(
// uint256 liquidity,
// uint256 t0Supply,
// uint256 t1Supply,
// uint256 t0Amount,
// uint256 t1Amount
// )
// public
// {
// vm.assume(liquidity >= 10 ether && liquidity <= type(uint128).max);
// t0Supply = bound(t0Supply, 1 ether, liquidity);
// t1Supply = bound(t1Supply, 1 ether, liquidity);
// t0Amount = bound(t0Amount, 1 ether / 5, t0Supply / 5);
// t1Amount = bound(t1Amount, 1 ether / 5, t1Supply / 5);

vm.mockCall(address(tToken0), abi.encodeWithSelector(Tenderizer.unlock.selector, t0Amount), abi.encode(0));
vm.mockCall(address(tToken0), abi.encodeWithSelector(Tenderizer.unlockMaturity.selector, 0), abi.encode(block.number + 100));

tToken0.mint(address(this), t0Amount);
tToken1.mint(address(this), t1Amount);
tToken0.approve(address(swap), t0Amount);
(uint256 out, uint256 fee) = swap.swap(address(tToken0), t0Amount, 0 ether);

(out, fee) = swap.quote(address(tToken1), t1Amount);
console.log("swap quote 1", out, fee);
// Fee should be 0.15% or 0.0015
// As utilisation after is 0.1 and 0.1^3 = 0.001
// Base fee is 0.005 so that makes 0.0015
// Since there is only 1 token drawing liquidity, its weight is 1

// uint256 expFee = amount * 15 / 10_000;
// underlying.mint(address(this), liquidity);
// underlying.approve(address(swap), liquidity);
// swap.deposit(liquidity);

// assertEq(fee, expFee, "swap fee");
// assertEq(out, amount - expFee, "swap out");
// assertEq(swap.liquidity(), 90 ether, "TenderSwap available liquidity");
}
// uint256 tokenId = _encodeTokenId(address(tToken0), 0);

function test_swap_other() public {
uint256 liquidity = 2_000_000 ether;
underlying.mint(address(this), liquidity);
underlying.approve(address(swap), liquidity);
swap.deposit(liquidity);
// vm.mockCall(address(tToken0), abi.encodeWithSelector(Tenderizer.unlock.selector, t0Amount), abi.encode(0));
// vm.mockCall(address(tToken0), abi.encodeWithSelector(Tenderizer.unlockMaturity.selector, 0), abi.encode(block.number +
// 100));

uint256 amount = 1 ether;
uint256 tokenId = _encodeTokenId(address(tToken0), 0);
// tToken0.mint(address(this), t0Amount);
// tToken1.mint(address(this), t1Amount);
// tToken0.approve(address(swap), t0Amount);
// (uint256 out, uint256 fee) = swap.swap(address(tToken0), t0Amount, 0 ether);

vm.mockCall(address(tToken0), abi.encodeWithSelector(Tenderizer.unlock.selector, amount), abi.encode(0));
vm.mockCall(address(tToken0), abi.encodeWithSelector(Tenderizer.unlockMaturity.selector, 0), abi.encode(block.number + 100));
// (out, fee) = swap.quote(address(tToken1), t1Amount);
// console.log("swap quote 1", out, fee);
// // Fee should be 0.15% or 0.0015
// // As utilisation after is 0.1 and 0.1^3 = 0.001
// // Base fee is 0.005 so that makes 0.0015
// // Since there is only 1 token drawing liquidity, its weight is 1

tToken0.mint(address(this), 34_000 ether);
tToken1.mint(address(this), 14_000 ether);
tToken0.approve(address(swap), 1500 ether);
(uint256 out, uint256 fee) = swap.swap(address(tToken0), amount, 0 ether);

(out, fee) = swap.quote(address(tToken1), 50 ether);
console.log("swap quote 1", out, fee);
// Fee should be 0.15% or 0.0015
// As utilisation after is 0.1 and 0.1^3 = 0.001
// Base fee is 0.005 so that makes 0.0015
// Since there is only 1 token drawing liquidity, its weight is 1
uint256 expFee = amount * 15 / 10_000;

// assertEq(fee, expFee, "swap fee");
// assertEq(out, amount - expFee, "swap out");
// assertEq(swap.liquidity(), 90 ether, "TenderSwap available liquidity");
}
// // uint256 expFee = amount * 15 / 10_000;

// function testFuzz_swap_basic(uint256 liquidity, uint256 amount) public {
// liquidity = bound(liquidity, 1e18, type(uint128).max);
// amount = bound(amount, 1e3, liquidity);
// // assertEq(fee, expFee, "swap fee");
// // assertEq(out, amount - expFee, "swap out");
// // assertEq(swap.liquidity(), 90 ether, "TenderSwap available liquidity");
// }

// function test_swap_other() public {
// uint256 liquidity = 2_000_000 ether;
// underlying.mint(address(this), liquidity);
// underlying.approve(address(swap), liquidity);
// swap.deposit(liquidity);

// uint256 amount = 1 ether;
// uint256 tokenId = _encodeTokenId(address(tToken0), 0);

// vm.mockCall(address(tToken0), abi.encodeWithSelector(Tenderizer.unlock.selector, amount), abi.encode(0));
// vm.mockCall(address(tToken0), abi.encodeWithSelector(Tenderizer.unlockMaturity.selector, 0), abi.encode(block.number +
// 100));

// tToken0.mint(address(this), liquidity);
// tToken0.approve(address(swap), amount);
// (uint256 out, uint256 fee) = swap.swap(address(tToken0), amount, 0);
// tToken0.mint(address(this), 34_000 ether);
// tToken1.mint(address(this), 14_000 ether);
// tToken0.approve(address(swap), 1500 ether);
// (uint256 out, uint256 fee) = swap.swap(address(tToken0), amount, 0 ether);

// (out, fee) = swap.quote(address(tToken1), 50 ether);
// console.log("swap quote 1", out, fee);
// // Fee should be 0.15% or 0.0015
// // As utilisation after is 0.1 and 0.1^3 = 0.001
// // Base fee is 0.005 so that makes 0.0015
// // Since there is only 1 token drawing liquidity, its weight is 1
// uint256 expFee = amount * 15 / 10_000;

// // assertEq(fee, expFee, "swap fee");
// // assertEq(out, amount - expFee, "swap out");
// // assertEq(swap.liquidity(), 90 ether, "TenderSwap available liquidity");
// }

// uint256 expFee = uint256(
// sd(int256(amount)).mul(BASE_FEE).add(
// sd(int256(amount)).mul((sd(int256(amount)).div(sd(int256(liquidity))).pow(sd(3e18))))
// ).unwrap()
// );
// expFee = expFee >= amount ? amount : expFee;
// // function testFuzz_swap_basic(uint256 liquidity, uint256 amount) public {
// // liquidity = bound(liquidity, 1e18, type(uint128).max);
// // amount = bound(amount, 1e3, liquidity);

// console.log("expFee", expFee);
// console.log("fee", fee);
// // underlying.mint(address(this), liquidity);
// // underlying.approve(address(swap), liquidity);
// // swap.deposit(liquidity);

// assertTrue(acceptableDelta(fee, expFee, 2), "fee amount");
// assertTrue(acceptableDelta(out, amount - expFee, 2), "swap out");
// assertEq(swap.liquidity(), liquidity - amount, "TenderSwap available liquidity");
// }
// // vm.mockCall(address(tToken0), abi.encodeWithSelector(Tenderizer.unlock.selector, amount), abi.encode(0));
// // vm.mockCall(address(tToken0), abi.encodeWithSelector(Tenderizer.unlockMaturity.selector, 0), abi.encode(block.number +
// // 100));

// // tToken0.mint(address(this), liquidity);
// // tToken0.approve(address(swap), amount);
// // (uint256 out, uint256 fee) = swap.swap(address(tToken0), amount, 0);

// // uint256 expFee = uint256(
// // sd(int256(amount)).mul(BASE_FEE).add(
// // sd(int256(amount)).mul((sd(int256(amount)).div(sd(int256(liquidity))).pow(sd(3e18))))
// // ).unwrap()
// // );
// // expFee = expFee >= amount ? amount : expFee;

// // console.log("expFee", expFee);
// // console.log("fee", fee);

// // assertTrue(acceptableDelta(fee, expFee, 2), "fee amount");
// // assertTrue(acceptableDelta(out, amount - expFee, 2), "swap out");
// // assertEq(swap.liquidity(), liquidity - amount, "TenderSwap available liquidity");
// // }
}

0 comments on commit 92d6693

Please sign in to comment.