Skip to content

Commit

Permalink
feat: example if we remove share to 0 if only lockup shares are left
Browse files Browse the repository at this point in the history
  • Loading branch information
chefburger committed Nov 13, 2024
1 parent 19ecc15 commit e7bf244
Show file tree
Hide file tree
Showing 16 changed files with 65 additions and 47 deletions.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
137654
142478
2 changes: 1 addition & 1 deletion .forge-snapshots/BinHookTest#testBurnSucceedsWithHook.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
196277
179611
2 changes: 1 addition & 1 deletion .forge-snapshots/BinMintBurnFeeHookTest#test_Burn.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
184559
167865
2 changes: 1 addition & 1 deletion .forge-snapshots/BinPoolManagerBytecodeSize.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
23389
23766
Original file line number Diff line number Diff line change
@@ -1 +1 @@
146654
135054
Original file line number Diff line number Diff line change
@@ -1 +1 @@
142933
143286
Original file line number Diff line number Diff line change
@@ -1 +1 @@
287239
297444
2 changes: 1 addition & 1 deletion .forge-snapshots/BinPoolManagerTest#testGasBurnOneBin.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
138120
128227
Original file line number Diff line number Diff line change
@@ -1 +1 @@
137102
109014
10 changes: 9 additions & 1 deletion src/pool-bin/BinPoolManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,8 @@ contract BinPoolManager is IBinPoolManager, ProtocolFees, Extsload {

uint256[] memory binIds;
bytes32[] memory amountRemoved;
(delta, binIds, amountRemoved) = pool.burn(
bytes32 feeAmountToProtocol;
(delta, binIds, amountRemoved, feeAmountToProtocol) = pool.burn(
BinPool.BurnParams({
from: msg.sender,
ids: params.ids,
Expand All @@ -248,6 +249,13 @@ contract BinPoolManager is IBinPoolManager, ProtocolFees, Extsload {
})
);

unchecked {
if (feeAmountToProtocol > 0) {
protocolFeesAccrued[key.currency0] += feeAmountToProtocol.decodeX();
protocolFeesAccrued[key.currency1] += feeAmountToProtocol.decodeY();
}
}

/// @notice Make sure the first event is noted, so that later events from afterHook won't get mixed up with this one
emit Burn(id, msg.sender, binIds, params.salt, amountRemoved);

Expand Down
23 changes: 18 additions & 5 deletions src/pool-bin/libraries/BinPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ library BinPool {
/// @return result the delta of the token balance of the pool
function burn(State storage self, BurnParams memory params)
internal
returns (BalanceDelta result, uint256[] memory ids, bytes32[] memory amounts)
returns (BalanceDelta result, uint256[] memory ids, bytes32[] memory amounts, bytes32 feeAmountToProtocol)
{
ids = params.ids;
uint256 idsLength = ids.length;
Expand All @@ -317,15 +317,21 @@ library BinPool {
bytes32 binReserves = self.reserveOfBin[id];
uint256 supply = self.shareOfBin[id];

_subShare(self, params.from, id, params.salt, amountToBurn);
amountToBurn = _subShare(self, params.from, id, params.salt, amountToBurn);

bytes32 amountsOutFromBin = binReserves.getAmountOutOfBin(amountToBurn, supply);
if (supply == amountToBurn) feeAmountToProtocol = binReserves.getAmountOutOfBin(MINIMUM_SHARE, supply);

if (amountsOutFromBin == 0) revert BinPool__ZeroAmountsOut(id);

binReserves = binReserves.sub(amountsOutFromBin);

if (supply == amountToBurn) _removeBinIdToTree(self, id);
if (supply == amountToBurn) {
_removeBinIdToTree(self, id);

/// @notice withdraw all the liquidity from the bin, the locked up share will be withdrawn as protocol fee
amountsOutFromBin.sub(feeAmountToProtocol);
}

self.reserveOfBin[id] = binReserves;
amounts[i] = amountsOutFromBin;
Expand Down Expand Up @@ -465,9 +471,16 @@ library BinPool {
}

/// @notice Subtract share from user's position and update total share supply of bin
function _subShare(State storage self, address owner, uint24 binId, bytes32 salt, uint256 shares) internal {
function _subShare(State storage self, address owner, uint24 binId, bytes32 salt, uint256 shares)
internal
returns (uint256 amountsToBurn)
{
self.positions.get(owner, binId, salt).subShare(shares);
self.shareOfBin[binId] -= shares;
amountsToBurn = shares;
if (self.shareOfBin[binId] - shares == MINIMUM_SHARE) {
amountsToBurn += MINIMUM_SHARE;
}
self.shareOfBin[binId] -= amountsToBurn;
}

/// @notice Add share to user's position and update total share supply of bin
Expand Down
10 changes: 5 additions & 5 deletions test/pool-bin/BinHookReturnsDelta.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,11 @@ contract BinHookReturnsDelta is Test, GasSnapshot, BinTestHelper {
binLiquidityHelper.burn(key, burnParams, "");

(uint128 reserveXAfter, uint128 reserveYAfter,,) = poolManager.getBin(key.toId(), activeId);
// reserve non zero due to min liquidity (1e3) locked up in the bin
assertEq(reserveXAfter, 1);
assertEq(reserveYAfter, 1);
assertEq(token0.balanceOf(address(binReturnsDeltaHook)), 0.1 ether - 1);
assertEq(token1.balanceOf(address(binReturnsDeltaHook)), 0.1 ether - 1);
// reserve non zero due to min liquidity locked up in the bin
assertEq(reserveXAfter, 0);
assertEq(reserveYAfter, 0);
assertEq(token0.balanceOf(address(binReturnsDeltaHook)), 0.1 ether);
assertEq(token1.balanceOf(address(binReturnsDeltaHook)), 0.1 ether);
}

function testSwap_noSwap_specifyInput() external {
Expand Down
21 changes: 9 additions & 12 deletions test/pool-bin/BinMintBurnFeeHook.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -120,18 +120,15 @@ contract BinMintBurnFeeHookTest is Test, GasSnapshot, BinTestHelper {
binLiquidityHelper.burn(key, burnParams, "");
snapEnd();

// +1 eth from remove liqudiity, -4 eth from hook fee
// +3 from min_liquidity amount as -1 (min_liquidity) + 1 * 4 (fee)
assertEq(token0.balanceOf(address(this)), 7 ether + 1 ether - 4 ether + 3);
assertEq(token1.balanceOf(address(this)), 7 ether + 1 ether - 4 ether + 3);

// -1 eth from remove liquidity, +4 eth from hook calling vault.mint
assertEq(token0.balanceOf(address(vault)), 3 ether - 1 ether + 4 ether - 3);
assertEq(token1.balanceOf(address(vault)), 3 ether - 1 ether + 4 ether - 3);

// -4 as due to min_liquidity = 1, hook took 4 token less fee
assertEq(vault.balanceOf(address(binMintBurnFeeHook), key.currency0), 2 ether + 4 ether - 4);
assertEq(vault.balanceOf(address(binMintBurnFeeHook), key.currency1), 2 ether + 4 ether - 4);
// +1 from remove liqudiity, -4 from hook fee
assertEq(token0.balanceOf(address(this)), 7 ether + 1 ether - 4 ether);
assertEq(token1.balanceOf(address(this)), 7 ether + 1 ether - 4 ether);

// -1 from remove liquidity, +4 from hook calling vault.mint
assertEq(token0.balanceOf(address(vault)), 3 ether - 1 ether + 4 ether);
assertEq(token1.balanceOf(address(vault)), 3 ether - 1 ether + 4 ether);
assertEq(vault.balanceOf(address(binMintBurnFeeHook), key.currency0), 2 ether + 4 ether);
assertEq(vault.balanceOf(address(binMintBurnFeeHook), key.currency1), 2 ether + 4 ether);
}

receive() external payable {}
Expand Down
12 changes: 6 additions & 6 deletions test/pool-bin/BinPoolManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -461,13 +461,13 @@ contract BinPoolManagerTest is Test, GasSnapshot, BinTestHelper {
// should have 1 token left due to min liquidity
if (binIds[i] < activeId) {
assertEq(binReserveX, 0);
assertEq(binReserveY, 1);
assertEq(binReserveY, 0);
} else if (binIds[i] > activeId) {
assertEq(binReserveX, 1);
assertEq(binReserveX, 0);
assertEq(binReserveY, 0);
} else {
assertEq(binReserveX, 1);
assertEq(binReserveY, 1);
assertEq(binReserveX, 0);
assertEq(binReserveY, 0);
}

BinPosition.Info memory position =
Expand Down Expand Up @@ -641,7 +641,7 @@ contract BinPoolManagerTest is Test, GasSnapshot, BinTestHelper {
uint256[] memory ids = new uint256[](1);
bytes32[] memory amounts = new bytes32[](1);
ids[0] = activeId;
amounts[0] = uint128(1e18 - 1).encode(uint128(1e18 - 1)); // -1 due to minshare locked up
amounts[0] = 0x00000000000000000de0b6b3a764000000000000000000000de0b6b3a7640000; // <wip> uint128(1e18).encode(uint128(1e18));
vm.expectEmit();
emit IBinPoolManager.Burn(key.toId(), address(binLiquidityHelper), ids, 0, amounts);

Expand Down Expand Up @@ -710,7 +710,7 @@ contract BinPoolManagerTest is Test, GasSnapshot, BinTestHelper {
uint256[] memory ids = new uint256[](1);
bytes32[] memory amounts = new bytes32[](1);
ids[0] = activeId;
amounts[0] = uint128(1e18 - 1).encode(uint128(1e18 - 1)); // -1 due to minshare locked up
amounts[0] = 0x00000000000000000de0b6b3a764000000000000000000000de0b6b3a7640000; // <wip> to fill in numbers uint128(1e18).encode(uint128(1e18));
vm.expectEmit();
emit IBinPoolManager.Burn(key.toId(), address(binLiquidityHelper), ids, 0, amounts);

Expand Down
10 changes: 5 additions & 5 deletions test/pool-bin/libraries/BinPoolDonate.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,15 @@ contract BinPoolDonateTest is BinTestHelper {

// lesser than 2e18 as alice is the first lp provider and liquidity locked up
BalanceDelta removeDelta2 = removeLiquidityFromBin(key, poolManager, alice, activeId, aliceShare, "");
assertEq(removeDelta2.amount0(), 2e18 - 1);
assertEq(removeDelta2.amount1(), 2e18 - 1);
assertEq(removeDelta2.amount0(), 2e18);
assertEq(removeDelta2.amount1(), 2e18);

// Verify only min_liquidity worth of token locked up
(reserveX, reserveY,,) = poolManager.getBin(poolId, activeId);
assertEq(reserveX, 1);
assertEq(reserveY, 1);
assertEq(reserveX, 0);
assertEq(reserveY, 0);

vm.expectRevert(abi.encodeWithSelector(IBinPoolManager.InsufficientBinShareForDonate.selector, 1e3));
vm.expectRevert(abi.encodeWithSelector(IBinPoolManager.InsufficientBinShareForDonate.selector, 0));
poolManager.donate(key, 1e18, 1e18, "");
}

Expand Down
8 changes: 4 additions & 4 deletions test/pool-bin/libraries/BinPoolLiquidity.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ contract BinPoolLiquidityTest is BinTestHelper {
uint256 aliceBal = poolManager.getPosition(key.toId(), alice, activeId, 0).share;
BalanceDelta aliceDelta = removeLiquidityFromBin(key, poolManager, alice, activeId, aliceBal, "");
// -1 tokenX and -1 tokenY as they are locked as min liquidity
assertEq(aliceDelta.amount0() + bobDelta.amount0(), 200 ether - 1);
assertEq(aliceDelta.amount1() + bobDelta.amount1(), 1 ether - 1);
assertEq(aliceDelta.amount0() + bobDelta.amount0(), 200 ether);
assertEq(aliceDelta.amount1() + bobDelta.amount1(), 1 ether);
}

function test_MintWithDifferentBins() external {
Expand Down Expand Up @@ -317,7 +317,7 @@ contract BinPoolLiquidityTest is BinTestHelper {
removeLiquidity(key, poolManager, bob, ids, balances);

// 6 as liquidity was added to 6 bins, each bin lock 1 token due to min share
uint256 lockedTokenDueToMinShare = 6;
uint256 lockedTokenDueToMinShare = 0;
{
// balanceDelta positive (so user need to call take/mint)
uint256 balanceDelta0 = uint128(vault.balanceDeltaOfPool(poolId).amount0());
Expand Down Expand Up @@ -376,7 +376,7 @@ contract BinPoolLiquidityTest is BinTestHelper {
removeLiquidity(key, poolManager, bob, ids, halfbalances);

// 6 as liquidity was added to 6 bins, each bin lock 1 token due to min share
uint256 lockedTokenDueToMinShare = 6;
uint256 lockedTokenDueToMinShare = 0;
reserveX = vault.reservesOfApp(address(key.poolManager), key.currency0); // vault.reservesOfPool(poolId, 0);
reserveY = vault.reservesOfApp(address(key.poolManager), key.currency1); // vault.reservesOfPool(poolId, 1);
assertEq(reserveX, lockedTokenDueToMinShare, "test_BurnPartial::5");
Expand Down

0 comments on commit e7bf244

Please sign in to comment.