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..0cc35155 100644 --- a/.forge-snapshots/BinHookTest#testSwapSucceedsWithHook.snap +++ b/.forge-snapshots/BinHookTest#testSwapSucceedsWithHook.snap @@ -1 +1 @@ -189430 \ 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 0bbd03da..93d1048f 100644 --- a/.forge-snapshots/BinPoolManagerBytecodeSize.snap +++ b/.forge-snapshots/BinPoolManagerBytecodeSize.snap @@ -1 +1 @@ -24175 \ No newline at end of file +25587 \ 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..b696a4b0 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap @@ -1 +1 @@ -172918 \ 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 c290063a..567b974a 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap @@ -1 +1 @@ -178946 \ 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 94bbfdd8..49b99871 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap @@ -1 +1 @@ -132949 \ No newline at end of file +137536 \ 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/Vault.sol b/src/Vault.sol index d3c0502c..2c9a0d28 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; diff --git a/src/pool-bin/BinPoolManager.sol b/src/pool-bin/BinPoolManager.sol index 707449df..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 *; @@ -181,11 +183,39 @@ 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)); + // } + + // vault.accountAppBalanceDelta(key.currency0, key.currency1, delta, msg.sender); + if (hookDelta != BalanceDeltaLibrary.ZERO_DELTA) { - vault.accountAppBalanceDelta(key.currency0, key.currency1, hookDelta, address(key.hooks)); - } + int128 hookDelta0 = hookDelta.amount0(); + int128 hookDelta1 = hookDelta.amount1(); + 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); + } - vault.accountAppBalanceDelta(key.currency0, key.currency1, delta, 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.currency0, key.currency1, delta, 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; diff --git a/test/pool-bin/BinReturnsDeltaOverwriteSwap.t.sol b/test/pool-bin/BinReturnsDeltaOverwriteSwap.t.sol new file mode 100644 index 00000000..78928fa7 --- /dev/null +++ b/test/pool-bin/BinReturnsDeltaOverwriteSwap.t.sol @@ -0,0 +1,170 @@ +// 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"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.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) + }); + + 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); + + // assume hook has some liqudiity from earlier add liqudiity + // 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 { + 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 {} +} diff --git a/test/pool-bin/helpers/BinReturnsDeltaHookOverwriteSwap.sol b/test/pool-bin/helpers/BinReturnsDeltaHookOverwriteSwap.sol new file mode 100644 index 00000000..8542834c --- /dev/null +++ b/test/pool-bin/helpers/BinReturnsDeltaHookOverwriteSwap.sol @@ -0,0 +1,107 @@ +// 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"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import {console2} from "forge-std/console2.sol"; + +contract BinReturnsDeltaHookOverwriteSwap is BaseBinTestHook { + error InvalidAction(); + + using CurrencySettlement for Currency; + using Hooks for bytes32; + + 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({ + 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 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 + 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, true); + + // 2. Give output currency and amount achieving a 1:1 swap + outputCurrency.settle(vault, address(this), amount, true); + + 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); + } +}