From 9d1cf7054b979e71f83f8d745460cdd0016e6a5a Mon Sep 17 00:00:00 2001 From: ChefMist <133624774+ChefMist@users.noreply.github.com> Date: Fri, 1 Nov 2024 18:28:14 +0800 Subject: [PATCH 1/4] feat: add issue example --- src/Vault.sol | 5 + .../BinReturnsDeltaOverwriteSwap.t.sol | 105 ++++++++++++++++++ .../BinReturnsDeltaHookOverwriteSwap.sol | 78 +++++++++++++ 3 files changed, 188 insertions(+) create mode 100644 test/pool-bin/BinReturnsDeltaOverwriteSwap.t.sol create mode 100644 test/pool-bin/helpers/BinReturnsDeltaHookOverwriteSwap.sol diff --git a/src/Vault.sol b/src/Vault.sol index d3c0502c..475431b4 100644 --- a/src/Vault.sol +++ b/src/Vault.sol @@ -12,6 +12,8 @@ import {SafeCast} from "./libraries/SafeCast.sol"; import {VaultReserve} from "./libraries/VaultReserve.sol"; import {VaultToken} from "./VaultToken.sol"; +import {console2} from "forge-std/console2.sol"; + contract Vault is IVault, VaultToken, Ownable { using SafeCast for *; using CurrencyLibrary for Currency; @@ -173,6 +175,9 @@ contract Vault is IVault, VaultToken, Ownable { /// @dev optimization: msg.sender will always be app address, verification should be done on caller address if (delta >= 0) { + console2.log("before deduct from reservesOfApp"); + console2.log("reservesOfApp[msg.sender][currency]", reservesOfApp[msg.sender][currency]); + console2.log("delta", uint128(delta)); /// @dev arithmetic underflow make sure trader can't withdraw too much from app reservesOfApp[msg.sender][currency] -= uint128(delta); } else { diff --git a/test/pool-bin/BinReturnsDeltaOverwriteSwap.t.sol b/test/pool-bin/BinReturnsDeltaOverwriteSwap.t.sol new file mode 100644 index 00000000..181a11e7 --- /dev/null +++ b/test/pool-bin/BinReturnsDeltaOverwriteSwap.t.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.24; + +import "forge-std/Test.sol"; +import {GasSnapshot} from "forge-gas-snapshot/GasSnapshot.sol"; +import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; +import {IVault} from "../../src/interfaces/IVault.sol"; +import {IPoolManager} from "../../src/interfaces/IPoolManager.sol"; +import {IBinPoolManager} from "../../src/pool-bin/interfaces/IBinPoolManager.sol"; +import {Vault} from "../../src/Vault.sol"; +import {Currency} from "../../src/types/Currency.sol"; +import {PoolKey} from "../../src/types/PoolKey.sol"; +import {BalanceDelta, BalanceDeltaLibrary} from "../../src/types/BalanceDelta.sol"; +import {BinPoolManager} from "../../src/pool-bin/BinPoolManager.sol"; +import {BinPool} from "../../src/pool-bin/libraries/BinPool.sol"; +import {PackedUint128Math} from "../../src/pool-bin/libraries/math/PackedUint128Math.sol"; +import {SafeCast} from "../../src/pool-bin/libraries/math/SafeCast.sol"; +import {BinPoolParametersHelper} from "../../src/pool-bin/libraries/BinPoolParametersHelper.sol"; +import {Constants} from "../../src/pool-bin/libraries/Constants.sol"; +import {IBinHooks} from "../../src/pool-bin/interfaces/IBinHooks.sol"; +import {IHooks} from "../../src/interfaces/IHooks.sol"; +import {IBinHooks} from "../../src/pool-bin/interfaces/IBinHooks.sol"; +import {BinSwapHelper} from "./helpers/BinSwapHelper.sol"; +import {BinLiquidityHelper} from "./helpers/BinLiquidityHelper.sol"; +import {BinTestHelper} from "./helpers/BinTestHelper.sol"; +import {Hooks} from "../../src/libraries/Hooks.sol"; +import {BinReturnsDeltaHookOverwriteSwap} from "./helpers/BinReturnsDeltaHookOverwriteSwap.sol"; + +contract BinReturnsDeltaOverwriteSwap is Test, GasSnapshot, BinTestHelper { + using SafeCast for uint256; + using PackedUint128Math for bytes32; + using PackedUint128Math for uint128; + using BinPoolParametersHelper for bytes32; + + Vault public vault; + BinPoolManager public poolManager; + BinReturnsDeltaHookOverwriteSwap public binReturnsDeltaHookOverwriteSwap; + + BinSwapHelper public binSwapHelper; + BinLiquidityHelper public binLiquidityHelper; + + uint24 activeId = 2 ** 23; // where token0 and token1 price is the same + + PoolKey key; + bytes32 poolParam; + MockERC20 token0; + MockERC20 token1; + Currency currency0; + Currency currency1; + + function setUp() public { + vault = new Vault(); + poolManager = new BinPoolManager(IVault(address(vault))); + + vault.registerApp(address(poolManager)); + + token0 = new MockERC20("TestA", "A", 18); + token1 = new MockERC20("TestB", "B", 18); + (token0, token1) = token0 < token1 ? (token0, token1) : (token1, token0); + currency0 = Currency.wrap(address(token0)); + currency1 = Currency.wrap(address(token1)); + + token0.mint(address(this), 1000 ether); + token1.mint(address(this), 1000 ether); + + IBinPoolManager iBinPoolManager = IBinPoolManager(address(poolManager)); + IVault iVault = IVault(address(vault)); + + binSwapHelper = new BinSwapHelper(iBinPoolManager, iVault); + binLiquidityHelper = new BinLiquidityHelper(iBinPoolManager, iVault); + token0.approve(address(binSwapHelper), 1000 ether); + token1.approve(address(binSwapHelper), 1000 ether); + token0.approve(address(binLiquidityHelper), 1000 ether); + token1.approve(address(binLiquidityHelper), 1000 ether); + + binReturnsDeltaHookOverwriteSwap = new BinReturnsDeltaHookOverwriteSwap(iVault, iBinPoolManager); + token0.approve(address(binReturnsDeltaHookOverwriteSwap), 1000 ether); + token1.approve(address(binReturnsDeltaHookOverwriteSwap), 1000 ether); + + key = PoolKey({ + currency0: currency0, + currency1: currency1, + hooks: binReturnsDeltaHookOverwriteSwap, + poolManager: IPoolManager(address(poolManager)), + fee: uint24(3000), // 3000 = 0.3% + parameters: bytes32(uint256(binReturnsDeltaHookOverwriteSwap.getHooksRegistrationBitmap())).setBinStep(10) + }); + + poolManager.initialize(key, activeId); + } + + function testSwap_xx() external { + // assume liquidity added via hook and sent to the vault + token0.mint(address(vault), 100 ether); + token1.mint(address(vault), 100 ether); + + // assume hook has some liqudiity from earlier add liqudiity + token0.mint(address(binReturnsDeltaHookOverwriteSwap), 100 ether); + token1.mint(address(binReturnsDeltaHookOverwriteSwap), 100 ether); + + BalanceDelta delta = binSwapHelper.swap(key, true, -int128(1 ether), BinSwapHelper.TestSettings(true, true), ""); + } + + receive() external payable {} +} diff --git a/test/pool-bin/helpers/BinReturnsDeltaHookOverwriteSwap.sol b/test/pool-bin/helpers/BinReturnsDeltaHookOverwriteSwap.sol new file mode 100644 index 00000000..da315461 --- /dev/null +++ b/test/pool-bin/helpers/BinReturnsDeltaHookOverwriteSwap.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.24; + +import {IVault} from "../../../src/interfaces/IVault.sol"; +import {Hooks} from "../../../src/libraries/Hooks.sol"; +import {IBinPoolManager} from "../../../src/pool-bin/interfaces/IBinPoolManager.sol"; +import {PoolKey} from "../../../src/types/PoolKey.sol"; +import {Currency} from "../../../src/types/Currency.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {toBalanceDelta, BalanceDelta, BalanceDeltaLibrary} from "../../../src/types/BalanceDelta.sol"; +import {BeforeSwapDelta, toBeforeSwapDelta} from "../../../src/types/BeforeSwapDelta.sol"; +import {BaseBinTestHook} from "./BaseBinTestHook.sol"; +import {CurrencySettlement} from "../../helpers/CurrencySettlement.sol"; + +contract BinReturnsDeltaHookOverwriteSwap is BaseBinTestHook { + error InvalidAction(); + + using CurrencySettlement for Currency; + using Hooks for bytes32; + + IVault public immutable vault; + IBinPoolManager public immutable poolManager; + + constructor(IVault _vault, IBinPoolManager _poolManager) { + vault = _vault; + poolManager = _poolManager; + } + + function getHooksRegistrationBitmap() external pure override returns (uint16) { + return _hooksRegistrationBitmapFrom( + Permissions({ + beforeInitialize: false, + afterInitialize: false, + beforeMint: false, + afterMint: false, + beforeBurn: false, + afterBurn: false, + beforeSwap: true, + afterSwap: false, + beforeDonate: false, + afterDonate: false, + beforeSwapReturnsDelta: true, + afterSwapReturnsDelta: false, + afterMintReturnsDelta: false, + afterBurnReturnsDelta: false + }) + ); + } + + function beforeSwap(address, PoolKey calldata key, bool swapForY, int128 amountSpecified, bytes calldata data) + external + override + returns (bytes4, BeforeSwapDelta, uint24) + { + (Currency inputCurrency, Currency outputCurrency, uint256 amount) = + _getInputOutputAndAmount(key, swapForY, amountSpecified); + + // 1. Take input currency and amount + inputCurrency.take(vault, address(this), amount, false); + + // 2. Give output currency and amount achieving a 1:1 swap + outputCurrency.settle(vault, address(this), amount, false); + + BeforeSwapDelta hookDelta = toBeforeSwapDelta(-amountSpecified, amountSpecified); + return (this.beforeSwap.selector, hookDelta, 0); + } + + /// @notice Get input, output currencies and amount from swap params + function _getInputOutputAndAmount(PoolKey calldata key, bool swapForY, int128 amountSpecified) + internal + pure + returns (Currency input, Currency output, uint256 amount) + { + (input, output) = swapForY ? (key.currency0, key.currency1) : (key.currency1, key.currency0); + + amount = amountSpecified < 0 ? uint128(-amountSpecified) : uint128(amountSpecified); + } +} From 952b4b8925ad47c98406106ef27a6c174fe75e16 Mon Sep 17 00:00:00 2001 From: Chef Snoopy Date: Tue, 5 Nov 2024 01:23:43 +0800 Subject: [PATCH 2/4] fix: Update Bin swap accountAppBalanceDelta logic --- .../BinHookTest#testBurnSucceedsWithHook.snap | 2 +- ...inHookTest#testDonateSucceedsWithHook.snap | 2 +- .../BinHookTest#testMintSucceedsWithHook.snap | 2 +- .../BinHookTest#testSwapSucceedsWithHook.snap | 2 +- .../BinPoolManagerBytecodeSize.snap | 2 +- ...oolManagerTest#testBurnNativeCurrency.snap | 2 +- ...BinPoolManagerTest#testGasBurnHalfBin.snap | 2 +- ...inPoolManagerTest#testGasBurnNineBins.snap | 2 +- .../BinPoolManagerTest#testGasBurnOneBin.snap | 2 +- .../BinPoolManagerTest#testGasDonate.snap | 2 +- ...nPoolManagerTest#testGasMintNneBins-1.snap | 2 +- ...nPoolManagerTest#testGasMintNneBins-2.snap | 2 +- ...inPoolManagerTest#testGasMintOneBin-1.snap | 2 +- ...inPoolManagerTest#testGasMintOneBin-2.snap | 2 +- ...olManagerTest#testGasSwapMultipleBins.snap | 2 +- ...nagerTest#testGasSwapOverBigBinIdGate.snap | 2 +- ...nPoolManagerTest#testGasSwapSingleBin.snap | 2 +- ...oolManagerTest#testMintNativeCurrency.snap | 2 +- ...oolManagerTest#addLiquidity_fromEmpty.snap | 2 +- ...ManagerTest#addLiquidity_fromNonEmpty.snap | 2 +- ...lManagerTest#addLiquidity_nativeToken.snap | 2 +- .../CLPoolManagerTest#donateBothTokens.snap | 2 +- .../CLPoolManagerTest#gasDonateOneToken.snap | 2 +- ...anagerTest#removeLiquidity_toNonEmpty.snap | 2 +- ...PoolManagerTest#swap_againstLiquidity.snap | 2 +- ...gerTest#swap_leaveSurplusTokenInVault.snap | 2 +- ...oolManagerTest#swap_runOutOfLiquidity.snap | 2 +- .../CLPoolManagerTest#swap_simple.snap | 2 +- ...nagerTest#swap_useSurplusTokenAsInput.snap | 2 +- .../CLPoolManagerTest#swap_withHooks.snap | 2 +- .../CLPoolManagerTest#swap_withNative.snap | 2 +- .forge-snapshots/VaultBytecodeSize.snap | 2 +- src/pool-bin/BinPoolManager.sol | 26 ++++++++++++++++--- src/test/MockVault.sol | 4 +++ 34 files changed, 59 insertions(+), 35 deletions(-) diff --git a/.forge-snapshots/BinHookTest#testBurnSucceedsWithHook.snap b/.forge-snapshots/BinHookTest#testBurnSucceedsWithHook.snap index 2b568eb5..12c6cee0 100644 --- a/.forge-snapshots/BinHookTest#testBurnSucceedsWithHook.snap +++ b/.forge-snapshots/BinHookTest#testBurnSucceedsWithHook.snap @@ -1 +1 @@ -178172 \ No newline at end of file +178194 \ No newline at end of file diff --git a/.forge-snapshots/BinHookTest#testDonateSucceedsWithHook.snap b/.forge-snapshots/BinHookTest#testDonateSucceedsWithHook.snap index ebc63de1..89d165bd 100644 --- a/.forge-snapshots/BinHookTest#testDonateSucceedsWithHook.snap +++ b/.forge-snapshots/BinHookTest#testDonateSucceedsWithHook.snap @@ -1 +1 @@ -188435 \ No newline at end of file +188457 \ No newline at end of file diff --git a/.forge-snapshots/BinHookTest#testMintSucceedsWithHook.snap b/.forge-snapshots/BinHookTest#testMintSucceedsWithHook.snap index c3de81a3..7672d375 100644 --- a/.forge-snapshots/BinHookTest#testMintSucceedsWithHook.snap +++ b/.forge-snapshots/BinHookTest#testMintSucceedsWithHook.snap @@ -1 +1 @@ -311226 \ No newline at end of file +311248 \ No newline at end of file diff --git a/.forge-snapshots/BinHookTest#testSwapSucceedsWithHook.snap b/.forge-snapshots/BinHookTest#testSwapSucceedsWithHook.snap index f263fba9..2413854f 100644 --- a/.forge-snapshots/BinHookTest#testSwapSucceedsWithHook.snap +++ b/.forge-snapshots/BinHookTest#testSwapSucceedsWithHook.snap @@ -1 +1 @@ -189430 \ No newline at end of file +188203 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerBytecodeSize.snap b/.forge-snapshots/BinPoolManagerBytecodeSize.snap index 0bbd03da..01dee154 100644 --- a/.forge-snapshots/BinPoolManagerBytecodeSize.snap +++ b/.forge-snapshots/BinPoolManagerBytecodeSize.snap @@ -1 +1 @@ -24175 \ No newline at end of file +25155 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testBurnNativeCurrency.snap b/.forge-snapshots/BinPoolManagerTest#testBurnNativeCurrency.snap index d39cabe9..a6bc86f2 100644 --- a/.forge-snapshots/BinPoolManagerTest#testBurnNativeCurrency.snap +++ b/.forge-snapshots/BinPoolManagerTest#testBurnNativeCurrency.snap @@ -1 +1 @@ -133811 \ No newline at end of file +139117 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasBurnHalfBin.snap b/.forge-snapshots/BinPoolManagerTest#testGasBurnHalfBin.snap index 1afcdd5b..864911d9 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasBurnHalfBin.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasBurnHalfBin.snap @@ -1 +1 @@ -142616 \ No newline at end of file +149248 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasBurnNineBins.snap b/.forge-snapshots/BinPoolManagerTest#testGasBurnNineBins.snap index caeaa75a..e93505ca 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasBurnNineBins.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasBurnNineBins.snap @@ -1 +1 @@ -289602 \ No newline at end of file +294908 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasBurnOneBin.snap b/.forge-snapshots/BinPoolManagerTest#testGasBurnOneBin.snap index 25d6f235..03c01b09 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasBurnOneBin.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasBurnOneBin.snap @@ -1 +1 @@ -126984 \ No newline at end of file +132289 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasDonate.snap b/.forge-snapshots/BinPoolManagerTest#testGasDonate.snap index c263e782..eb074bac 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasDonate.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasDonate.snap @@ -1 +1 @@ -118513 \ No newline at end of file +118552 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-1.snap b/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-1.snap index 82fe3898..0581c3e4 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-1.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-1.snap @@ -1 +1 @@ -968244 \ No newline at end of file +968283 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-2.snap b/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-2.snap index d9bb8fa3..b623b415 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-2.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-2.snap @@ -1 +1 @@ -327556 \ No newline at end of file +327595 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-1.snap b/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-1.snap index 4b29f52e..267f7e94 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-1.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-1.snap @@ -1 +1 @@ -337280 \ No newline at end of file +337319 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-2.snap b/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-2.snap index 78acc12b..8be1b95e 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-2.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-2.snap @@ -1 +1 @@ -139831 \ No newline at end of file +139870 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap b/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap index 64d97ebe..fe9c6eb4 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap @@ -1 +1 @@ -172918 \ No newline at end of file +182003 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap b/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap index c290063a..1c511f55 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap @@ -1 +1 @@ -178946 \ No newline at end of file +188031 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap b/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap index 94bbfdd8..02f83f9d 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap @@ -1 +1 @@ -132949 \ No newline at end of file +142034 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testMintNativeCurrency.snap b/.forge-snapshots/BinPoolManagerTest#testMintNativeCurrency.snap index 2a930d48..6f52405b 100644 --- a/.forge-snapshots/BinPoolManagerTest#testMintNativeCurrency.snap +++ b/.forge-snapshots/BinPoolManagerTest#testMintNativeCurrency.snap @@ -1 +1 @@ -304363 \ No newline at end of file +304402 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromEmpty.snap b/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromEmpty.snap index 40f0c110..a3e928a0 100644 --- a/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromEmpty.snap +++ b/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromEmpty.snap @@ -1 +1 @@ -347359 \ No newline at end of file +347398 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromNonEmpty.snap b/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromNonEmpty.snap index 3966f9c9..02b49cf2 100644 --- a/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromNonEmpty.snap +++ b/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromNonEmpty.snap @@ -1 +1 @@ -162820 \ No newline at end of file +162859 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#addLiquidity_nativeToken.snap b/.forge-snapshots/CLPoolManagerTest#addLiquidity_nativeToken.snap index 96897662..f60319ae 100644 --- a/.forge-snapshots/CLPoolManagerTest#addLiquidity_nativeToken.snap +++ b/.forge-snapshots/CLPoolManagerTest#addLiquidity_nativeToken.snap @@ -1 +1 @@ -238365 \ No newline at end of file +238404 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#donateBothTokens.snap b/.forge-snapshots/CLPoolManagerTest#donateBothTokens.snap index f46f6004..ea78d9c8 100644 --- a/.forge-snapshots/CLPoolManagerTest#donateBothTokens.snap +++ b/.forge-snapshots/CLPoolManagerTest#donateBothTokens.snap @@ -1 +1 @@ -163100 \ No newline at end of file +163139 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#gasDonateOneToken.snap b/.forge-snapshots/CLPoolManagerTest#gasDonateOneToken.snap index 2927ac50..188a1a26 100644 --- a/.forge-snapshots/CLPoolManagerTest#gasDonateOneToken.snap +++ b/.forge-snapshots/CLPoolManagerTest#gasDonateOneToken.snap @@ -1 +1 @@ -108172 \ No newline at end of file +108211 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#removeLiquidity_toNonEmpty.snap b/.forge-snapshots/CLPoolManagerTest#removeLiquidity_toNonEmpty.snap index 08abc4d2..9862ef24 100644 --- a/.forge-snapshots/CLPoolManagerTest#removeLiquidity_toNonEmpty.snap +++ b/.forge-snapshots/CLPoolManagerTest#removeLiquidity_toNonEmpty.snap @@ -1 +1 @@ -112713 \ No newline at end of file +117296 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_againstLiquidity.snap b/.forge-snapshots/CLPoolManagerTest#swap_againstLiquidity.snap index 42fb48cf..4f0da6ca 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_againstLiquidity.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_againstLiquidity.snap @@ -1 +1 @@ -130739 \ No newline at end of file +135323 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_leaveSurplusTokenInVault.snap b/.forge-snapshots/CLPoolManagerTest#swap_leaveSurplusTokenInVault.snap index f46f6004..19d8e01c 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_leaveSurplusTokenInVault.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_leaveSurplusTokenInVault.snap @@ -1 +1 @@ -163100 \ No newline at end of file +167684 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_runOutOfLiquidity.snap b/.forge-snapshots/CLPoolManagerTest#swap_runOutOfLiquidity.snap index df9ce9e6..cbc85180 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_runOutOfLiquidity.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_runOutOfLiquidity.snap @@ -1 +1 @@ -148519 \ No newline at end of file +153103 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_simple.snap b/.forge-snapshots/CLPoolManagerTest#swap_simple.snap index c56a2c56..d00b0068 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_simple.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_simple.snap @@ -1 +1 @@ -71220 \ No newline at end of file +71259 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_useSurplusTokenAsInput.snap b/.forge-snapshots/CLPoolManagerTest#swap_useSurplusTokenAsInput.snap index 7e74d396..f38fe7d7 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_useSurplusTokenAsInput.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_useSurplusTokenAsInput.snap @@ -1 +1 @@ -143103 \ No newline at end of file +147687 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_withHooks.snap b/.forge-snapshots/CLPoolManagerTest#swap_withHooks.snap index a0fa5b33..e5820e96 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_withHooks.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_withHooks.snap @@ -1 +1 @@ -87408 \ No newline at end of file +87447 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_withNative.snap b/.forge-snapshots/CLPoolManagerTest#swap_withNative.snap index 255b0f96..d609b05e 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_withNative.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_withNative.snap @@ -1 +1 @@ -71223 \ No newline at end of file +71262 \ No newline at end of file diff --git a/.forge-snapshots/VaultBytecodeSize.snap b/.forge-snapshots/VaultBytecodeSize.snap index d25ee827..86c2e0ea 100644 --- a/.forge-snapshots/VaultBytecodeSize.snap +++ b/.forge-snapshots/VaultBytecodeSize.snap @@ -1 +1 @@ -7792 \ No newline at end of file +8394 \ No newline at end of file diff --git a/src/pool-bin/BinPoolManager.sol b/src/pool-bin/BinPoolManager.sol index 707449df..ac4f0bb8 100644 --- a/src/pool-bin/BinPoolManager.sol +++ b/src/pool-bin/BinPoolManager.sol @@ -181,11 +181,31 @@ contract BinPoolManager is IBinPoolManager, ProtocolFees, Extsload { BalanceDelta hookDelta; (delta, hookDelta) = BinHooks.afterSwap(key, swapForY, amountSpecified, delta, hookData, beforeSwapDelta); - if (hookDelta != BalanceDeltaLibrary.ZERO_DELTA) { - vault.accountAppBalanceDelta(key.currency0, key.currency1, hookDelta, address(key.hooks)); + // if (hookDelta != BalanceDeltaLibrary.ZERO_DELTA) { + // vault.accountAppBalanceDelta(key.currency0, key.currency1, hookDelta, address(key.hooks)); + // } + + // vault.accountAppBalanceDelta(key.currency0, key.currency1, delta, msg.sender); + int128 hookDelta0 = hookDelta.amount0(); + int128 hookDelta1 = hookDelta.amount1(); + int128 delta0 = delta.amount0(); + int128 delta1 = delta.amount1(); + + if (delta0 < 0) { + vault.accountAppBalanceDelta(key.currency0, delta0, msg.sender); + vault.accountAppBalanceDelta(key.currency0, hookDelta0, address(key.hooks)); + } else { + vault.accountAppBalanceDelta(key.currency0, hookDelta0, address(key.hooks)); + vault.accountAppBalanceDelta(key.currency0, delta0, msg.sender); } - vault.accountAppBalanceDelta(key.currency0, key.currency1, delta, msg.sender); + if (delta1 < 0) { + vault.accountAppBalanceDelta(key.currency1, delta1, msg.sender); + vault.accountAppBalanceDelta(key.currency1, hookDelta1, address(key.hooks)); + } else { + vault.accountAppBalanceDelta(key.currency1, hookDelta1, address(key.hooks)); + vault.accountAppBalanceDelta(key.currency1, delta1, msg.sender); + } } /// @inheritdoc IBinPoolManager diff --git a/src/test/MockVault.sol b/src/test/MockVault.sol index 4d76108d..e6ddc574 100644 --- a/src/test/MockVault.sol +++ b/src/test/MockVault.sol @@ -40,6 +40,10 @@ contract MockVault { _accountDeltaForApp(currency1, delta.amount1()); } + function accountAppBalanceDelta(Currency currency, int128 delta, address settler) external { + _accountDeltaForApp(currency, delta); + } + function _accountDeltaForApp(Currency currency, int128 delta) internal { if (delta == 0) return; From c490cab0364f979d4dfecd9f38c20f52a9146d97 Mon Sep 17 00:00:00 2001 From: Chef Snoopy Date: Tue, 5 Nov 2024 10:26:09 +0800 Subject: [PATCH 3/4] feat: Update hook delta logic , add fuzz test cases --- .../BinHookTest#testSwapSucceedsWithHook.snap | 2 +- .../BinPoolManagerBytecodeSize.snap | 2 +- ...olManagerTest#testGasSwapMultipleBins.snap | 2 +- ...nagerTest#testGasSwapOverBigBinIdGate.snap | 2 +- ...nPoolManagerTest#testGasSwapSingleBin.snap | 2 +- src/pool-bin/BinPoolManager.sol | 39 +++++++++++-------- .../BinReturnsDeltaOverwriteSwap.t.sol | 19 +++++++++ 7 files changed, 46 insertions(+), 22 deletions(-) diff --git a/.forge-snapshots/BinHookTest#testSwapSucceedsWithHook.snap b/.forge-snapshots/BinHookTest#testSwapSucceedsWithHook.snap index 2413854f..0cc35155 100644 --- a/.forge-snapshots/BinHookTest#testSwapSucceedsWithHook.snap +++ b/.forge-snapshots/BinHookTest#testSwapSucceedsWithHook.snap @@ -1 +1 @@ -188203 \ No newline at end of file +189455 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerBytecodeSize.snap b/.forge-snapshots/BinPoolManagerBytecodeSize.snap index 01dee154..93d1048f 100644 --- a/.forge-snapshots/BinPoolManagerBytecodeSize.snap +++ b/.forge-snapshots/BinPoolManagerBytecodeSize.snap @@ -1 +1 @@ -25155 \ No newline at end of file +25587 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap b/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap index fe9c6eb4..b696a4b0 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap @@ -1 +1 @@ -182003 \ No newline at end of file +177505 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap b/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap index 1c511f55..567b974a 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap @@ -1 +1 @@ -188031 \ No newline at end of file +183533 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap b/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap index 02f83f9d..49b99871 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap @@ -1 +1 @@ -142034 \ No newline at end of file +137536 \ No newline at end of file diff --git a/src/pool-bin/BinPoolManager.sol b/src/pool-bin/BinPoolManager.sol index ac4f0bb8..31b8fe42 100644 --- a/src/pool-bin/BinPoolManager.sol +++ b/src/pool-bin/BinPoolManager.sol @@ -186,25 +186,30 @@ contract BinPoolManager is IBinPoolManager, ProtocolFees, Extsload { // } // vault.accountAppBalanceDelta(key.currency0, key.currency1, delta, msg.sender); - int128 hookDelta0 = hookDelta.amount0(); - int128 hookDelta1 = hookDelta.amount1(); - int128 delta0 = delta.amount0(); - int128 delta1 = delta.amount1(); - - if (delta0 < 0) { - vault.accountAppBalanceDelta(key.currency0, delta0, msg.sender); - vault.accountAppBalanceDelta(key.currency0, hookDelta0, address(key.hooks)); - } else { - vault.accountAppBalanceDelta(key.currency0, hookDelta0, address(key.hooks)); - vault.accountAppBalanceDelta(key.currency0, delta0, msg.sender); - } - if (delta1 < 0) { - vault.accountAppBalanceDelta(key.currency1, delta1, msg.sender); - vault.accountAppBalanceDelta(key.currency1, hookDelta1, address(key.hooks)); + if (hookDelta != BalanceDeltaLibrary.ZERO_DELTA) { + int128 hookDelta0 = hookDelta.amount0(); + int128 hookDelta1 = hookDelta.amount1(); + int128 delta0 = delta.amount0(); + int128 delta1 = delta.amount1(); + + if (delta0 < 0) { + vault.accountAppBalanceDelta(key.currency0, delta0, msg.sender); + if (hookDelta0 != 0) vault.accountAppBalanceDelta(key.currency0, hookDelta0, address(key.hooks)); + } else { + if (hookDelta0 != 0) vault.accountAppBalanceDelta(key.currency0, hookDelta0, address(key.hooks)); + if (delta0 != 0) vault.accountAppBalanceDelta(key.currency0, delta0, msg.sender); + } + + if (delta1 < 0) { + vault.accountAppBalanceDelta(key.currency1, delta1, msg.sender); + if (hookDelta1 != 0) vault.accountAppBalanceDelta(key.currency1, hookDelta1, address(key.hooks)); + } else { + if (hookDelta1 != 0) vault.accountAppBalanceDelta(key.currency1, hookDelta1, address(key.hooks)); + if (delta1 != 0) vault.accountAppBalanceDelta(key.currency1, delta1, msg.sender); + } } else { - vault.accountAppBalanceDelta(key.currency1, hookDelta1, address(key.hooks)); - vault.accountAppBalanceDelta(key.currency1, delta1, msg.sender); + vault.accountAppBalanceDelta(key.currency0, key.currency1, delta, msg.sender); } } diff --git a/test/pool-bin/BinReturnsDeltaOverwriteSwap.t.sol b/test/pool-bin/BinReturnsDeltaOverwriteSwap.t.sol index 181a11e7..054fa48a 100644 --- a/test/pool-bin/BinReturnsDeltaOverwriteSwap.t.sol +++ b/test/pool-bin/BinReturnsDeltaOverwriteSwap.t.sol @@ -101,5 +101,24 @@ contract BinReturnsDeltaOverwriteSwap is Test, GasSnapshot, BinTestHelper { BalanceDelta delta = binSwapHelper.swap(key, true, -int128(1 ether), BinSwapHelper.TestSettings(true, true), ""); } + function testFuzz_Swap_xx(bool swapForY, uint256 swapAmount, bool exactInput) external { + swapAmount = bound(swapAmount, 0.1 ether, 99 ether); + int128 swapAmountInt = int128(uint128(swapAmount)); + if (exactInput) { + swapAmountInt = -swapAmountInt; + } + + // assume liquidity added via hook and sent to the vault + token0.mint(address(vault), 100 ether); + token1.mint(address(vault), 100 ether); + + // assume hook has some liqudiity from earlier add liqudiity + token0.mint(address(binReturnsDeltaHookOverwriteSwap), 100 ether); + token1.mint(address(binReturnsDeltaHookOverwriteSwap), 100 ether); + + BalanceDelta delta = + binSwapHelper.swap(key, swapForY, swapAmountInt, BinSwapHelper.TestSettings(true, true), ""); + } + receive() external payable {} } From 93c949f35e5ca0ef55a7347b0682b778afe18d29 Mon Sep 17 00:00:00 2001 From: ChefMist <133624774+ChefMist@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:43:24 +0800 Subject: [PATCH 4/4] feat: include more detail to make it concrete --- src/Vault.sol | 3 -- src/pool-bin/BinPoolManager.sol | 5 ++ .../BinReturnsDeltaOverwriteSwap.t.sol | 54 +++++++++++++++++-- .../BinReturnsDeltaHookOverwriteSwap.sol | 33 +++++++++++- 4 files changed, 86 insertions(+), 9 deletions(-) diff --git a/src/Vault.sol b/src/Vault.sol index 475431b4..2c9a0d28 100644 --- a/src/Vault.sol +++ b/src/Vault.sol @@ -175,9 +175,6 @@ contract Vault is IVault, VaultToken, Ownable { /// @dev optimization: msg.sender will always be app address, verification should be done on caller address if (delta >= 0) { - console2.log("before deduct from reservesOfApp"); - console2.log("reservesOfApp[msg.sender][currency]", reservesOfApp[msg.sender][currency]); - console2.log("delta", uint128(delta)); /// @dev arithmetic underflow make sure trader can't withdraw too much from app reservesOfApp[msg.sender][currency] -= uint128(delta); } else { diff --git a/src/pool-bin/BinPoolManager.sol b/src/pool-bin/BinPoolManager.sol index 31b8fe42..eadfb38d 100644 --- a/src/pool-bin/BinPoolManager.sol +++ b/src/pool-bin/BinPoolManager.sol @@ -24,6 +24,8 @@ import {BeforeSwapDelta} from "../types/BeforeSwapDelta.sol"; import "./interfaces/IBinHooks.sol"; import {BinSlot0} from "./types/BinSlot0.sol"; +import {console2} from "forge-std/console2.sol"; + /// @notice Holds the state for all bin pools contract BinPoolManager is IBinPoolManager, ProtocolFees, Extsload { using BinPool for *; @@ -193,10 +195,13 @@ contract BinPoolManager is IBinPoolManager, ProtocolFees, Extsload { int128 delta0 = delta.amount0(); int128 delta1 = delta.amount1(); + // positive deduct reservesOfApp if (delta0 < 0) { + /// @dev account for delta0 first so reserveOfApp will be positive, then deduct hookDelta if required vault.accountAppBalanceDelta(key.currency0, delta0, msg.sender); if (hookDelta0 != 0) vault.accountAppBalanceDelta(key.currency0, hookDelta0, address(key.hooks)); } else { + /// @dev account for hookDelta0 first if (hookDelta0 != 0) vault.accountAppBalanceDelta(key.currency0, hookDelta0, address(key.hooks)); if (delta0 != 0) vault.accountAppBalanceDelta(key.currency0, delta0, msg.sender); } diff --git a/test/pool-bin/BinReturnsDeltaOverwriteSwap.t.sol b/test/pool-bin/BinReturnsDeltaOverwriteSwap.t.sol index 054fa48a..78928fa7 100644 --- a/test/pool-bin/BinReturnsDeltaOverwriteSwap.t.sol +++ b/test/pool-bin/BinReturnsDeltaOverwriteSwap.t.sol @@ -25,6 +25,7 @@ import {BinLiquidityHelper} from "./helpers/BinLiquidityHelper.sol"; import {BinTestHelper} from "./helpers/BinTestHelper.sol"; import {Hooks} from "../../src/libraries/Hooks.sol"; import {BinReturnsDeltaHookOverwriteSwap} from "./helpers/BinReturnsDeltaHookOverwriteSwap.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; contract BinReturnsDeltaOverwriteSwap is Test, GasSnapshot, BinTestHelper { using SafeCast for uint256; @@ -86,19 +87,64 @@ contract BinReturnsDeltaOverwriteSwap is Test, GasSnapshot, BinTestHelper { parameters: bytes32(uint256(binReturnsDeltaHookOverwriteSwap.getHooksRegistrationBitmap())).setBinStep(10) }); + binReturnsDeltaHookOverwriteSwap.setPoolKey(key); + poolManager.initialize(key, activeId); } function testSwap_xx() external { // assume liquidity added via hook and sent to the vault - token0.mint(address(vault), 100 ether); - token1.mint(address(vault), 100 ether); + // token0.mint(address(vault), 100 ether); + // token1.mint(address(vault), 100 ether); // assume hook has some liqudiity from earlier add liqudiity - token0.mint(address(binReturnsDeltaHookOverwriteSwap), 100 ether); - token1.mint(address(binReturnsDeltaHookOverwriteSwap), 100 ether); + // token0.mint(address(binReturnsDeltaHookOverwriteSwap), 100 ether); + // token1.mint(address(binReturnsDeltaHookOverwriteSwap), 100 ether); + + address hAddr = address(binReturnsDeltaHookOverwriteSwap); + + token0.mint(address(this), 10 ether); + token1.mint(address(this), 10 ether); + + console2.log("---------start of testSwap_xx add liquidity----------------------"); + console2.log(" balanceof user t0: ", IERC20(Currency.unwrap(currency0)).balanceOf(address(this)) / 1 ether); + console2.log(" balanceof user t1: ", IERC20(Currency.unwrap(currency1)).balanceOf(address(this)) / 1 ether); + console2.log(" balanceof user hAddr: ", IERC20(Currency.unwrap(currency0)).balanceOf(address(hAddr)) / 1 ether); + console2.log(" balanceof user hAddr: ", IERC20(Currency.unwrap(currency1)).balanceOf(address(hAddr)) / 1 ether); + console2.log(" balanceof user vault: ", IERC20(Currency.unwrap(currency0)).balanceOf(address(vault)) / 1 ether); + console2.log(" balanceof user vault: ", IERC20(Currency.unwrap(currency1)).balanceOf(address(vault)) / 1 ether); + console2.log("-------------------------------"); + + binReturnsDeltaHookOverwriteSwap.addLiquidity(1 ether, 1 ether); + + console2.log("---------end of testSwap_xx add liquidity ----------------------"); + console2.log(" balanceof user t0: ", IERC20(Currency.unwrap(currency0)).balanceOf(address(this)) / 1 ether); + console2.log(" balanceof user t1: ", IERC20(Currency.unwrap(currency1)).balanceOf(address(this)) / 1 ether); + console2.log(" balanceof user hAddr: ", IERC20(Currency.unwrap(currency0)).balanceOf(address(hAddr)) / 1 ether); + console2.log(" balanceof user hAddr: ", IERC20(Currency.unwrap(currency1)).balanceOf(address(hAddr)) / 1 ether); + console2.log(" balanceof user vault: ", IERC20(Currency.unwrap(currency0)).balanceOf(address(vault)) / 1 ether); + console2.log(" balanceof user vault: ", IERC20(Currency.unwrap(currency1)).balanceOf(address(vault)) / 1 ether); + console2.log("-------------------------------"); + + console2.log("---------start of testSwap_xx swap----------------------"); + console2.log(" reserveOfApp t0 (ethers)", vault.reservesOfApp(address(poolManager), key.currency0) / 1 ether); + console2.log(" reserveOfApp t1 (ethers)", vault.reservesOfApp(address(poolManager), key.currency1) / 1 ether); + console2.log(" balanceof user t0: ", IERC20(Currency.unwrap(currency0)).balanceOf(address(this)) / 1 ether); + console2.log(" balanceof user t1: ", IERC20(Currency.unwrap(currency1)).balanceOf(address(this)) / 1 ether); + console2.log(" balanceof user hAddr: ", IERC20(Currency.unwrap(currency0)).balanceOf(address(hAddr)) / 1 ether); + console2.log(" balanceof user hAddr: ", IERC20(Currency.unwrap(currency1)).balanceOf(address(hAddr)) / 1 ether); + console2.log("-------------------------------"); BalanceDelta delta = binSwapHelper.swap(key, true, -int128(1 ether), BinSwapHelper.TestSettings(true, true), ""); + + console2.log("---------end of testSwap_xx swap----------------------"); + console2.log(" reserveOfApp t0 (ethers)", vault.reservesOfApp(address(poolManager), key.currency0) / 1 ether); + console2.log(" reserveOfApp t1 (ethers)", vault.reservesOfApp(address(poolManager), key.currency1) / 1 ether); + console2.log(" balanceof user t0: ", IERC20(Currency.unwrap(currency0)).balanceOf(address(this)) / 1 ether); + console2.log(" balanceof user t1: ", IERC20(Currency.unwrap(currency1)).balanceOf(address(this)) / 1 ether); + console2.log(" balanceof user hAddr: ", IERC20(Currency.unwrap(currency0)).balanceOf(address(hAddr)) / 1 ether); + console2.log(" balanceof user hAddr: ", IERC20(Currency.unwrap(currency1)).balanceOf(address(hAddr)) / 1 ether); + console2.log("-------------------------------"); } function testFuzz_Swap_xx(bool swapForY, uint256 swapAmount, bool exactInput) external { diff --git a/test/pool-bin/helpers/BinReturnsDeltaHookOverwriteSwap.sol b/test/pool-bin/helpers/BinReturnsDeltaHookOverwriteSwap.sol index da315461..8542834c 100644 --- a/test/pool-bin/helpers/BinReturnsDeltaHookOverwriteSwap.sol +++ b/test/pool-bin/helpers/BinReturnsDeltaHookOverwriteSwap.sol @@ -11,6 +11,9 @@ import {toBalanceDelta, BalanceDelta, BalanceDeltaLibrary} from "../../../src/ty import {BeforeSwapDelta, toBeforeSwapDelta} from "../../../src/types/BeforeSwapDelta.sol"; import {BaseBinTestHook} from "./BaseBinTestHook.sol"; import {CurrencySettlement} from "../../helpers/CurrencySettlement.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import {console2} from "forge-std/console2.sol"; contract BinReturnsDeltaHookOverwriteSwap is BaseBinTestHook { error InvalidAction(); @@ -20,12 +23,17 @@ contract BinReturnsDeltaHookOverwriteSwap is BaseBinTestHook { IVault public immutable vault; IBinPoolManager public immutable poolManager; + PoolKey key; constructor(IVault _vault, IBinPoolManager _poolManager) { vault = _vault; poolManager = _poolManager; } + function setPoolKey(PoolKey memory _poolKey) external { + key = _poolKey; + } + function getHooksRegistrationBitmap() external pure override returns (uint16) { return _hooksRegistrationBitmapFrom( Permissions({ @@ -47,6 +55,27 @@ contract BinReturnsDeltaHookOverwriteSwap is BaseBinTestHook { ); } + function addLiquidity(uint256 amt0, uint256 amt1) public { + // do any logic + + // 1. Take input currency and amount from user + IERC20(Currency.unwrap(key.currency0)).transferFrom(msg.sender, address(this), amt0); + IERC20(Currency.unwrap(key.currency1)).transferFrom(msg.sender, address(this), amt1); + + // 2. Mint -- so vault has token balance + vault.lock(abi.encode(amt0, amt1)); + } + + function lockAcquired(bytes calldata callbackData) external returns (bytes memory) { + (uint256 amt0, uint256 amt1) = abi.decode(callbackData, (uint256, uint256)); + + vault.mint(address(this), key.currency0, amt0); + key.currency0.settle(vault, address(this), amt0, false); + + vault.mint(address(this), key.currency1, amt1); + key.currency1.settle(vault, address(this), amt1, false); + } + function beforeSwap(address, PoolKey calldata key, bool swapForY, int128 amountSpecified, bytes calldata data) external override @@ -56,10 +85,10 @@ contract BinReturnsDeltaHookOverwriteSwap is BaseBinTestHook { _getInputOutputAndAmount(key, swapForY, amountSpecified); // 1. Take input currency and amount - inputCurrency.take(vault, address(this), amount, false); + inputCurrency.take(vault, address(this), amount, true); // 2. Give output currency and amount achieving a 1:1 swap - outputCurrency.settle(vault, address(this), amount, false); + outputCurrency.settle(vault, address(this), amount, true); BeforeSwapDelta hookDelta = toBeforeSwapDelta(-amountSpecified, amountSpecified); return (this.beforeSwap.selector, hookDelta, 0);