Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support SettleAndMintRefund in periphery #3

Merged
merged 1 commit into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1 +1 @@
79699
80435
Original file line number Diff line number Diff line change
@@ -1 +1 @@
627067
627803
Original file line number Diff line number Diff line change
@@ -1 +1 @@
918147
919685
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1268812
1270351
Original file line number Diff line number Diff line change
@@ -1 +1 @@
80824
80759
Original file line number Diff line number Diff line change
@@ -1 +1 @@
117826
117761
Original file line number Diff line number Diff line change
@@ -1 +1 @@
114631
114566
Original file line number Diff line number Diff line change
@@ -1 +1 @@
29390
9490
2 changes: 1 addition & 1 deletion .forge-snapshots/BinFungibleTokenTest#testMint.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
43594
43591
Original file line number Diff line number Diff line change
@@ -1 +1 @@
138752
139491
Original file line number Diff line number Diff line change
@@ -1 +1 @@
131484
132217
Original file line number Diff line number Diff line change
@@ -1 +1 @@
136297
137030
Original file line number Diff line number Diff line change
@@ -1 +1 @@
132258
132997
Original file line number Diff line number Diff line change
@@ -1 +1 @@
132333
133072
Original file line number Diff line number Diff line change
@@ -1 +1 @@
167590
168327
Original file line number Diff line number Diff line change
@@ -1 +1 @@
144076
144815
Original file line number Diff line number Diff line change
@@ -1 +1 @@
137582
138321
Original file line number Diff line number Diff line change
@@ -1 +1 @@
137669
138408
Original file line number Diff line number Diff line change
@@ -1 +1 @@
172111
172844
Original file line number Diff line number Diff line change
@@ -1 +1 @@
130040
130773
2 changes: 1 addition & 1 deletion .forge-snapshots/CLSwapRouterTest#ExactInput.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
250131
250868
2 changes: 1 addition & 1 deletion .forge-snapshots/CLSwapRouterTest#ExactInputSingle.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
180878
181611
2 changes: 1 addition & 1 deletion .forge-snapshots/CLSwapRouterTest#ExactOutput.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
256134
256867
2 changes: 1 addition & 1 deletion .forge-snapshots/CLSwapRouterTest#ExactOutputSingle.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
180439
181172
2 changes: 1 addition & 1 deletion .forge-snapshots/NonfungiblePositionManager#collect.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
199252
199079
Original file line number Diff line number Diff line change
@@ -1 +1 @@
75212
75144
Original file line number Diff line number Diff line change
@@ -1 +1 @@
80908
82440
2 changes: 1 addition & 1 deletion .forge-snapshots/NonfungiblePositionManager#mint.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
624939
626477
2 changes: 1 addition & 1 deletion lib/openzeppelin-contracts
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked, oz version keeps 4.9.x

2 changes: 1 addition & 1 deletion lib/pancake-v4-core
Submodule pancake-v4-core updated 48 files
+1 −1 .forge-snapshots/BinPoolManagerTest#testBurnNativeCurrency.snap
+1 −1 .forge-snapshots/BinPoolManagerTest#testGasBurnHalfBin.snap
+1 −1 .forge-snapshots/BinPoolManagerTest#testGasBurnNineBins.snap
+1 −1 .forge-snapshots/BinPoolManagerTest#testGasBurnOneBin.snap
+1 −1 .forge-snapshots/BinPoolManagerTest#testGasDonate.snap
+1 −1 .forge-snapshots/BinPoolManagerTest#testGasMintNneBins-1.snap
+1 −1 .forge-snapshots/BinPoolManagerTest#testGasMintNneBins-2.snap
+1 −1 .forge-snapshots/BinPoolManagerTest#testGasMintOneBin-1.snap
+1 −1 .forge-snapshots/BinPoolManagerTest#testGasMintOneBin-2.snap
+1 −1 .forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap
+1 −1 .forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap
+1 −1 .forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap
+1 −1 .forge-snapshots/BinPoolManagerTest#testMintNativeCurrency.snap
+1 −1 .forge-snapshots/BinPoolManagerTest#testNoOpGas_Burn.snap
+1 −1 .forge-snapshots/BinPoolManagerTest#testNoOpGas_Donate.snap
+1 −1 .forge-snapshots/BinPoolManagerTest#testNoOpGas_Mint.snap
+1 −1 .forge-snapshots/BinPoolManagerTest#testNoOpGas_Swap.snap
+1 −1 .forge-snapshots/CLPoolManagerTest#addLiquidity_fromEmpty.snap
+1 −1 .forge-snapshots/CLPoolManagerTest#addLiquidity_fromNonEmpty.snap
+1 −1 .forge-snapshots/CLPoolManagerTest#addLiquidity_nativeToken.snap
+1 −1 .forge-snapshots/CLPoolManagerTest#donateBothTokens.snap
+1 −1 .forge-snapshots/CLPoolManagerTest#gasDonateOneToken.snap
+1 −1 .forge-snapshots/CLPoolManagerTest#removeLiquidity_toNonEmpty.snap
+1 −1 .forge-snapshots/CLPoolManagerTest#swap_againstLiquidity.snap
+1 −1 .forge-snapshots/CLPoolManagerTest#swap_leaveSurplusTokenInVault.snap
+1 −1 .forge-snapshots/CLPoolManagerTest#swap_runOutOfLiquidity.snap
+1 −1 .forge-snapshots/CLPoolManagerTest#swap_simple.snap
+1 −1 .forge-snapshots/CLPoolManagerTest#swap_useSurplusTokenAsInput.snap
+1 −1 .forge-snapshots/CLPoolManagerTest#swap_withHooks.snap
+1 −1 .forge-snapshots/CLPoolManagerTest#swap_withNative.snap
+1 −1 .forge-snapshots/CLPoolManagerTest#testNoOp_gas_Donate.snap
+1 −1 .forge-snapshots/CLPoolManagerTest#testNoOp_gas_ModifyPosition.snap
+1 −1 .forge-snapshots/CLPoolManagerTest#testNoOp_gas_Swap.snap
+1 −1 .forge-snapshots/VaultTest#Vault.snap
+1 −0 .forge-snapshots/VaultTest#lockSettledWhenAddLiquidity.snap
+1 −1 .forge-snapshots/VaultTest#lockSettledWhenFlashloan.snap
+1 −1 .forge-snapshots/VaultTest#lockSettledWhenMultiHopSwap.snap
+1 −1 .forge-snapshots/VaultTest#lockSettledWhenSwap.snap
+1 −1 .forge-snapshots/VaultTest#registerPoolManager.snap
+1 −1 .forge-snapshots/VaultTest#testLock_NoOp.snap
+1 −0 .forge-snapshots/VaultTest#testSettleAndMintRefund_WithMint.snap
+1 −0 .forge-snapshots/VaultTest#testSettleAndMintRefund_WithoutMint.snap
+25 −0 src/Vault.sol
+11 −0 src/interfaces/IVault.sol
+3 −0 test/VaultToken.t.sol
+12 −0 test/vault/FakePoolManagerRouter.sol
+46 −1 test/vault/Vault.t.sol
+30 −1 test/vault/VaultInvariant.t.sol
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"test": "forge test",
"dev": "forge test -vvv -w",
"snapshot": "rm -fr .forge-snapshots && forge test",
"prettier": "forge fmt contracts/ && forge fmt test/ && forge fmt script/",
"prettier": "forge fmt src/ && forge fmt test/ && forge fmt script/",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice catch 😂

"prettier-check": "forge fmt --check"
}
}
2 changes: 1 addition & 1 deletion src/SwapRouterBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ abstract contract SwapRouterBase is ISwapRouterBase {

function _payAndSettle(Currency currency, address msgSender, int128 settleAmount) internal virtual {
_pay(currency, msgSender, address(vault), uint256(uint128(settleAmount)));
vault.settle(currency);
vault.settleAndMintRefund(currency, msgSender);
}

function _pay(Currency currency, address payer, address recipient, uint256 amount) internal virtual;
Expand Down
4 changes: 2 additions & 2 deletions src/pool-bin/BinFungiblePositionManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -227,14 +227,14 @@ contract BinFungiblePositionManager is
function _settleDeltas(address user, PoolKey memory poolKey, BalanceDelta delta) internal {
if (delta.amount0() > 0) {
pay(poolKey.currency0, user, address(vault), uint256(int256(delta.amount0())));
vault.settle(poolKey.currency0);
vault.settleAndMintRefund(poolKey.currency0, user);
} else if (delta.amount0() < 0) {
vault.take(poolKey.currency0, user, uint128(-delta.amount0()));
}

if (delta.amount1() > 0) {
pay(poolKey.currency1, user, address(vault), uint256(int256(delta.amount1())));
vault.settle(poolKey.currency1);
vault.settleAndMintRefund(poolKey.currency1, user);
} else if (delta.amount1() < 0) {
vault.take(poolKey.currency1, user, uint128(-delta.amount1()));
}
Expand Down
4 changes: 2 additions & 2 deletions src/pool-cl/base/LiquidityManagement.sol
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,13 @@ abstract contract LiquidityManagement is CLPeripheryImmutableState, PeripheryPay
function settleDeltas(address sender, PoolKey memory poolKey, BalanceDelta delta) internal {
if (delta.amount0() > 0) {
pay(poolKey.currency0, sender, address(vault), uint256(int256(delta.amount0())));
vault.settle(poolKey.currency0);
vault.settleAndMintRefund(poolKey.currency0, sender);
} else if (delta.amount0() < 0) {
vault.take(poolKey.currency0, sender, uint128(-delta.amount0()));
}
if (delta.amount1() > 0) {
pay(poolKey.currency1, sender, address(vault), uint256(int256(delta.amount1())));
vault.settle(poolKey.currency1);
vault.settleAndMintRefund(poolKey.currency1, sender);
} else if (delta.amount1() < 0) {
vault.take(poolKey.currency1, sender, uint128(-delta.amount1()));
}
Expand Down
37 changes: 37 additions & 0 deletions test/pool-bin/BinFungiblePositionManager_AddLiquidity.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -538,4 +538,41 @@ contract BinFungiblePositionManager_AddLiquidityTest is Test, GasSnapshot, Liqui
deadline: block.timestamp + 600
});
}

function testSettleAndMintRefund() public {
// transfer excess token to vault
uint256 excessTokenAmount = 1 ether;
address hacker = address(1);
token0.mint(hacker, excessTokenAmount);
vm.startPrank(hacker);
token0.transfer(address(vault), excessTokenAmount);
vm.stopPrank();

// pre-test, verify alice has 1e18 token0 and token1
token0.mint(alice, 1 ether);
token1.mint(alice, 1 ether);
assertEq(token0.balanceOf(alice), 1 ether);
assertEq(token1.balanceOf(alice), 1 ether);

vm.startPrank(alice);
uint24[] memory binIds = getBinIds(activeId, 3);
IBinFungiblePositionManager.AddLiquidityParams memory params;
params = _getAddParams(key1, binIds, 1 ether, 1 ether, activeId, alice);
(,, uint256[] memory tokenIds,) = binFungiblePositionManager.addLiquidity(params);

for (uint256 i; i < tokenIds.length; i++) {
(Currency curr0, Currency curr1, uint24 fee, uint24 binId) =
binFungiblePositionManager.positions(tokenIds[i]);
assertEq(Currency.unwrap(curr0), Currency.unwrap(key1.currency0));
assertEq(Currency.unwrap(curr1), Currency.unwrap(key1.currency1));
assertEq(fee, key1.fee);
assertEq(binId, binIds[i]);
}

// check currency balance in vault
{
uint256 currency0Balance = vault.balanceOf(alice, currency0);
assertEq(currency0Balance, excessTokenAmount, "Unexpected currency0 balance in vault");
}
}
}
41 changes: 41 additions & 0 deletions test/pool-bin/BinSwapRouter.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,47 @@ contract BinSwapRouterTest is Test, GasSnapshot, LiquidityParamsHelper {
assertEq(token0.balanceOf(alice), abi.decode(result[0], (uint256)));
}

function testSettleAndMintRefund() public {
// transfer excess token to vault
uint256 excessTokenAmount = 1 ether;
address hacker = address(1);
token0.mint(hacker, excessTokenAmount);
vm.startPrank(hacker);
token0.transfer(address(vault), excessTokenAmount);
vm.stopPrank();

vm.startPrank(alice);
token0.mint(alice, 1 ether);

ISwapRouterBase.PathKey[] memory path = new ISwapRouterBase.PathKey[](1);
path[0] = ISwapRouterBase.PathKey({
intermediateCurrency: Currency.wrap(address(token1)),
fee: key.fee,
hooks: key.hooks,
hookData: new bytes(0),
poolManager: key.poolManager,
parameters: key.parameters
});

uint256 amountOut = router.exactInput(
IBinSwapRouterBase.V4BinExactInputParams({
currencyIn: Currency.wrap(address(token0)),
path: path,
recipient: alice,
amountIn: 1 ether,
amountOutMinimum: 0
}),
block.timestamp + 60
);
assertEq(token1.balanceOf(alice), amountOut);

// check currency balance in vault
{
uint256 currency0Balance = vault.balanceOf(alice, Currency.wrap(address(token0)));
assertEq(currency0Balance, excessTokenAmount, "Unexpected currency0 balance in vault");
}
}

// function testExactOutput_InsufficientAmountOut() public {
// //todo: in order to simulate this error, require
// // 1. hooks at beforeSwap do something funny on the pool resulting in actual amountOut lesser
Expand Down
34 changes: 34 additions & 0 deletions test/pool-cl/CLSwapRouter.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,40 @@ contract CLSwapRouterTest is TokenFixture, Test, GasSnapshot {
snapEnd();
}

function testSettleAndMintRefund() external {
// transfer excess token to vault
uint256 excessTokenAmount = 1 ether;
address hacker = address(1);
MockERC20(Currency.unwrap(currency0)).mint(hacker, excessTokenAmount);
vm.startPrank(hacker);
MockERC20(Currency.unwrap(currency0)).transfer(address(vault), excessTokenAmount);
vm.stopPrank();

uint256 amountOut = router.exactInputSingle(
ICLSwapRouterBase.V4CLExactInputSingleParams({
poolKey: poolKey0,
zeroForOne: true,
recipient: makeAddr("recipient"),
amountIn: 0.01 ether,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0,
hookData: new bytes(0)
}),
block.timestamp + 100
);

uint256 received = IERC20(Currency.unwrap(currency1)).balanceOf(makeAddr("recipient"));
assertEq(received, amountOut);
// considering slippage and fee, tolerance is 1%
assertApproxEqAbs(amountOut, 1 ether, amountOut / 100);

// check currency balance in vault
{
uint256 currency0Balance = vault.balanceOf(address(this), currency0);
assertEq(currency0Balance, excessTokenAmount, "Unexpected currency0 balance in vault");
}
}

// allow refund of ETH
receive() external payable {}
}
Loading
Loading