diff --git a/.forge-snapshots/BinPoolManagerTest#testBurnNativeCurrency.snap b/.forge-snapshots/BinPoolManagerTest#testBurnNativeCurrency.snap index 25e06cb1..85fd7303 100644 --- a/.forge-snapshots/BinPoolManagerTest#testBurnNativeCurrency.snap +++ b/.forge-snapshots/BinPoolManagerTest#testBurnNativeCurrency.snap @@ -1 +1 @@ -136931 \ No newline at end of file +137028 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testFuzzUpdateDynamicLPFee.snap b/.forge-snapshots/BinPoolManagerTest#testFuzzUpdateDynamicLPFee.snap index 31fc91f1..23353c28 100644 --- a/.forge-snapshots/BinPoolManagerTest#testFuzzUpdateDynamicLPFee.snap +++ b/.forge-snapshots/BinPoolManagerTest#testFuzzUpdateDynamicLPFee.snap @@ -1 +1 @@ -32533 \ No newline at end of file +32545 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasBurnHalfBin.snap b/.forge-snapshots/BinPoolManagerTest#testGasBurnHalfBin.snap index 5a99b3fd..1ae2ff16 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasBurnHalfBin.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasBurnHalfBin.snap @@ -1 +1 @@ -146635 \ No newline at end of file +146756 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasBurnNineBins.snap b/.forge-snapshots/BinPoolManagerTest#testGasBurnNineBins.snap index f6eb1c51..c2bdf5f8 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasBurnNineBins.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasBurnNineBins.snap @@ -1 +1 @@ -294227 \ No newline at end of file +294324 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasBurnOneBin.snap b/.forge-snapshots/BinPoolManagerTest#testGasBurnOneBin.snap index b2aeefb8..1a544c70 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasBurnOneBin.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasBurnOneBin.snap @@ -1 +1 @@ -130141 \ No newline at end of file +130237 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasDonate.snap b/.forge-snapshots/BinPoolManagerTest#testGasDonate.snap index d9a0fef9..4817dce1 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasDonate.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasDonate.snap @@ -1 +1 @@ -119261 \ No newline at end of file +119403 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-1.snap b/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-1.snap index 7f26f583..d26258fe 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-1.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-1.snap @@ -1 +1 @@ -975902 \ No newline at end of file +976020 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-2.snap b/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-2.snap index 9c235f3c..903f27f4 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-2.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasMintNneBins-2.snap @@ -1 +1 @@ -338092 \ No newline at end of file +338210 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-1.snap b/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-1.snap index ced025ae..e5201d55 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-1.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-1.snap @@ -1 +1 @@ -341673 \ No newline at end of file +341791 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-2.snap b/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-2.snap index 0eb6cb87..8b1d0b94 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-2.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasMintOneBin-2.snap @@ -1 +1 @@ -144616 \ No newline at end of file +144734 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap b/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap index 716e9990..501b9b92 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasSwapMultipleBins.snap @@ -1 +1 @@ -179041 \ No newline at end of file +179149 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap b/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap index 3d661fd1..4f109a91 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasSwapOverBigBinIdGate.snap @@ -1 +1 @@ -185024 \ No newline at end of file +185132 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap b/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap index 4efbe4df..86f743b7 100644 --- a/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap +++ b/.forge-snapshots/BinPoolManagerTest#testGasSwapSingleBin.snap @@ -1 +1 @@ -137479 \ No newline at end of file +137587 \ No newline at end of file diff --git a/.forge-snapshots/BinPoolManagerTest#testMintNativeCurrency.snap b/.forge-snapshots/BinPoolManagerTest#testMintNativeCurrency.snap index 5246259d..0d9f3a61 100644 --- a/.forge-snapshots/BinPoolManagerTest#testMintNativeCurrency.snap +++ b/.forge-snapshots/BinPoolManagerTest#testMintNativeCurrency.snap @@ -1 +1 @@ -308185 \ No newline at end of file +308270 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromEmpty.snap b/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromEmpty.snap index edf941ea..0795737a 100644 --- a/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromEmpty.snap +++ b/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromEmpty.snap @@ -1 +1 @@ -360013 \ No newline at end of file +360096 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromNonEmpty.snap b/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromNonEmpty.snap index c5b59360..98389e8f 100644 --- a/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromNonEmpty.snap +++ b/.forge-snapshots/CLPoolManagerTest#addLiquidity_fromNonEmpty.snap @@ -1 +1 @@ -175181 \ No newline at end of file +175264 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#addLiquidity_nativeToken.snap b/.forge-snapshots/CLPoolManagerTest#addLiquidity_nativeToken.snap index 00c76600..c34a119f 100644 --- a/.forge-snapshots/CLPoolManagerTest#addLiquidity_nativeToken.snap +++ b/.forge-snapshots/CLPoolManagerTest#addLiquidity_nativeToken.snap @@ -1 +1 @@ -245159 \ No newline at end of file +245205 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#donateBothTokens.snap b/.forge-snapshots/CLPoolManagerTest#donateBothTokens.snap index f2a9fd1d..7af5b451 100644 --- a/.forge-snapshots/CLPoolManagerTest#donateBothTokens.snap +++ b/.forge-snapshots/CLPoolManagerTest#donateBothTokens.snap @@ -1 +1 @@ -168435 \ No newline at end of file +168507 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#gasDonateOneToken.snap b/.forge-snapshots/CLPoolManagerTest#gasDonateOneToken.snap index 3eac678f..db65e4be 100644 --- a/.forge-snapshots/CLPoolManagerTest#gasDonateOneToken.snap +++ b/.forge-snapshots/CLPoolManagerTest#gasDonateOneToken.snap @@ -1 +1 @@ -112267 \ No newline at end of file +112314 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#removeLiquidity_toNonEmpty.snap b/.forge-snapshots/CLPoolManagerTest#removeLiquidity_toNonEmpty.snap index 1fbde7da..37949238 100644 --- a/.forge-snapshots/CLPoolManagerTest#removeLiquidity_toNonEmpty.snap +++ b/.forge-snapshots/CLPoolManagerTest#removeLiquidity_toNonEmpty.snap @@ -1 +1 @@ -121284 \ No newline at end of file +121359 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_againstLiquidity.snap b/.forge-snapshots/CLPoolManagerTest#swap_againstLiquidity.snap index 6d970cc2..4ad46bf1 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_againstLiquidity.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_againstLiquidity.snap @@ -1 +1 @@ -138632 \ No newline at end of file +138739 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_leaveSurplusTokenInVault.snap b/.forge-snapshots/CLPoolManagerTest#swap_leaveSurplusTokenInVault.snap index 222ee60d..feeab8a1 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_leaveSurplusTokenInVault.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_leaveSurplusTokenInVault.snap @@ -1 +1 @@ -172143 \ No newline at end of file +172226 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_runOutOfLiquidity.snap b/.forge-snapshots/CLPoolManagerTest#swap_runOutOfLiquidity.snap index 7d230889..54a8227c 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_runOutOfLiquidity.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_runOutOfLiquidity.snap @@ -1 +1 @@ -158546 \ No newline at end of file +158653 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_simple.snap b/.forge-snapshots/CLPoolManagerTest#swap_simple.snap index 5b98bde8..224938da 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_simple.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_simple.snap @@ -1 +1 @@ -76575 \ No newline at end of file +76594 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_useSurplusTokenAsInput.snap b/.forge-snapshots/CLPoolManagerTest#swap_useSurplusTokenAsInput.snap index 7ab32893..b1069de2 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_useSurplusTokenAsInput.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_useSurplusTokenAsInput.snap @@ -1 +1 @@ -150789 \ No newline at end of file +150915 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_withHooks.snap b/.forge-snapshots/CLPoolManagerTest#swap_withHooks.snap index cdb2bf9a..b8d66524 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_withHooks.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_withHooks.snap @@ -1 +1 @@ -93467 \ No newline at end of file +93486 \ No newline at end of file diff --git a/.forge-snapshots/CLPoolManagerTest#swap_withNative.snap b/.forge-snapshots/CLPoolManagerTest#swap_withNative.snap index 30883964..ad442b5b 100644 --- a/.forge-snapshots/CLPoolManagerTest#swap_withNative.snap +++ b/.forge-snapshots/CLPoolManagerTest#swap_withNative.snap @@ -1 +1 @@ -76578 \ No newline at end of file +76597 \ No newline at end of file diff --git a/src/types/Currency.sol b/src/types/Currency.sol index 0f56ea2a..8758dc14 100644 --- a/src/types/Currency.sol +++ b/src/types/Currency.sol @@ -6,6 +6,7 @@ import {IERC20Minimal} from "../interfaces/IERC20Minimal.sol"; type Currency is address; using {greaterThan as >, lessThan as <, greaterThanOrEqualTo as >=, equals as ==} for Currency global; +using CurrencyLibrary for Currency global; function equals(Currency currency, Currency other) pure returns (bool) { return Currency.unwrap(currency) == Currency.unwrap(other); diff --git a/test/helpers/CurrencySettlement.sol b/test/helpers/CurrencySettlement.sol new file mode 100644 index 00000000..6b60eb83 --- /dev/null +++ b/test/helpers/CurrencySettlement.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (C) 2024 PancakeSwap +pragma solidity ^0.8.24; + +import {Currency} from "../../src/types/Currency.sol"; +import {IVault} from "../../src/interfaces/IVault.sol"; +import {IERC20Minimal} from "../../src/interfaces/IERC20Minimal.sol"; + +/// @notice Helper library for currency settlement +/// @dev It is advised to consider referencing this library for currency settlement +library CurrencySettlement { + /// @notice Settle (pay) a currency to vault + /// @param currency Currency to settle + /// @param vault Vault address + /// @param payer Address of the payer, the token sender + /// @param amount Amount to send + /// @param burn If true, burn the VaultToken obtained by vault.mint() earlier, otherwise ERC20-transfer to vault + function settle(Currency currency, IVault vault, address payer, uint256 amount, bool burn) internal { + // for native currencies or burns, calling sync is not required + if (burn) { + vault.burn(payer, currency, amount); + } else if (currency.isNative()) { + vault.settle{value: amount}(currency); + } else { + vault.sync(currency); + if (payer != address(this)) { + IERC20Minimal(Currency.unwrap(currency)).transferFrom(payer, address(vault), amount); + } else { + IERC20Minimal(Currency.unwrap(currency)).transfer(address(vault), amount); + } + vault.settle(currency); + } + } + + /// @notice Take (receive) a currency from vault + /// @param currency Currency to take + /// @param vault Vault address + /// @param recipient Address of the recipient, the token receiver + /// @param amount Amount to receive + /// @param claims If true, mint VaultToken, otherwise ERC20-transfer from the vault to recipient + function take(Currency currency, IVault vault, address recipient, uint256 amount, bool claims) internal { + claims ? vault.mint(recipient, currency, amount) : vault.take(currency, recipient, amount); + } +} diff --git a/test/libraries/Currency.t.sol b/test/libraries/Currency.t.sol index dd5d9664..e8c62d88 100644 --- a/test/libraries/Currency.t.sol +++ b/test/libraries/Currency.t.sol @@ -7,7 +7,6 @@ import {Currency, CurrencyLibrary} from "../../src/types/Currency.sol"; import {TokenRejecter} from "../helpers/TokenRejecter.sol"; contract TestCurrency is Test { - using CurrencyLibrary for Currency; using CurrencyLibrary for uint256; uint256 constant initialERC20Balance = 1000 ether; diff --git a/test/pool-bin/helpers/BinDonateHelper.sol b/test/pool-bin/helpers/BinDonateHelper.sol index 033099e7..6a892063 100644 --- a/test/pool-bin/helpers/BinDonateHelper.sol +++ b/test/pool-bin/helpers/BinDonateHelper.sol @@ -7,9 +7,10 @@ import {IBinPoolManager} from "../../../src/pool-bin/interfaces/IBinPoolManager. import {BalanceDelta} from "../../../src/types/BalanceDelta.sol"; import {CurrencyLibrary, Currency} from "../../../src/types/Currency.sol"; import {PoolKey} from "../../../src/types/PoolKey.sol"; +import {CurrencySettlement} from "../../helpers/CurrencySettlement.sol"; contract BinDonateHelper { - using CurrencyLibrary for Currency; + using CurrencySettlement for Currency; IBinPoolManager public immutable binManager; IVault public immutable vault; @@ -50,25 +51,8 @@ contract BinDonateHelper { (BalanceDelta delta,) = binManager.donate(data.key, data.amount0, data.amount1, data.hookData); - if (delta.amount0() < 0) { - if (key.currency0.isNative()) { - vault.settle{value: uint128(-delta.amount0())}(key.currency0); - } else { - vault.sync(key.currency0); - IERC20(Currency.unwrap(key.currency0)).transferFrom(sender, address(vault), uint128(-delta.amount0())); - vault.settle(key.currency0); - } - } - - if (delta.amount1() < 0) { - if (key.currency1.isNative()) { - vault.settle{value: uint128(-delta.amount1())}(key.currency1); - } else { - vault.sync(key.currency1); - IERC20(Currency.unwrap(key.currency1)).transferFrom(sender, address(vault), uint128(-delta.amount1())); - vault.settle(key.currency1); - } - } + if (delta.amount0() < 0) key.currency0.settle(vault, sender, uint128(-delta.amount0()), false); + if (delta.amount1() < 0) key.currency1.settle(vault, sender, uint128(-delta.amount1()), false); return abi.encode(delta); } diff --git a/test/pool-bin/helpers/BinLiquidityHelper.sol b/test/pool-bin/helpers/BinLiquidityHelper.sol index c7eabf6d..f60aa32a 100644 --- a/test/pool-bin/helpers/BinLiquidityHelper.sol +++ b/test/pool-bin/helpers/BinLiquidityHelper.sol @@ -5,12 +5,13 @@ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IVault} from "../../../src/interfaces/IVault.sol"; import {IBinPoolManager} from "../../../src/pool-bin/interfaces/IBinPoolManager.sol"; import {BalanceDelta, BalanceDeltaLibrary} from "../../../src/types/BalanceDelta.sol"; -import {CurrencyLibrary, Currency} from "../../../src/types/Currency.sol"; +import {Currency} from "../../../src/types/Currency.sol"; import {PoolKey} from "../../../src/types/PoolKey.sol"; import {Hooks} from "../../../src/libraries/Hooks.sol"; +import {CurrencySettlement} from "../../helpers/CurrencySettlement.sol"; contract BinLiquidityHelper { - using CurrencyLibrary for Currency; + using CurrencySettlement for Currency; using Hooks for bytes32; error HookMissingNoOpPermission(); @@ -85,32 +86,10 @@ contract BinLiquidityHelper { (delta,) = binManager.mint(data.key, data.params, data.hookData); } - if (delta.amount0() < 0) { - if (key.currency0.isNative()) { - vault.settle{value: uint128(-delta.amount0())}(key.currency0); - } else { - vault.sync(key.currency0); - IERC20(Currency.unwrap(key.currency0)).transferFrom(sender, address(vault), uint128(-delta.amount0())); - vault.settle(key.currency0); - } - } - - if (delta.amount1() < 0) { - if (key.currency1.isNative()) { - vault.settle{value: uint128(-delta.amount1())}(key.currency1); - } else { - vault.sync(key.currency1); - IERC20(Currency.unwrap(key.currency1)).transferFrom(sender, address(vault), uint128(-delta.amount1())); - vault.settle(key.currency1); - } - } - - if (delta.amount0() > 0) { - vault.take(key.currency0, sender, uint128(delta.amount0())); - } - if (delta.amount1() > 0) { - vault.take(key.currency1, sender, uint128(delta.amount1())); - } + if (delta.amount0() < 0) key.currency0.settle(vault, sender, uint128(-delta.amount0()), false); + if (delta.amount0() > 0) key.currency0.take(vault, sender, uint128(delta.amount0()), false); + if (delta.amount1() < 0) key.currency1.settle(vault, sender, uint128(-delta.amount1()), false); + if (delta.amount1() > 0) key.currency1.take(vault, sender, uint128(delta.amount1()), false); return abi.encode(delta); } diff --git a/test/pool-bin/helpers/BinReturnsDeltaHook.sol b/test/pool-bin/helpers/BinReturnsDeltaHook.sol index 6ceb712a..d4812ca7 100644 --- a/test/pool-bin/helpers/BinReturnsDeltaHook.sol +++ b/test/pool-bin/helpers/BinReturnsDeltaHook.sol @@ -5,16 +5,17 @@ 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, CurrencyLibrary} from "../../../src/types/Currency.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 BinReturnsDeltaHook is BaseBinTestHook { error InvalidAction(); - using CurrencyLibrary for Currency; + using CurrencySettlement for Currency; using Hooks for bytes32; IVault public immutable vault; @@ -94,37 +95,25 @@ contract BinReturnsDeltaHook is BaseBinTestHook { if (swapForY) { // the specified token is token0 - if (hookDeltaSpecified < 0) { - vault.sync(key.currency0); - key.currency0.transfer(address(vault), uint128(-hookDeltaSpecified)); - vault.settle(key.currency0); - } else { - vault.take(key.currency0, address(this), uint128(hookDeltaSpecified)); - } + if (hookDeltaSpecified < 0) key.currency0.settle(vault, address(this), uint128(-hookDeltaSpecified), false); + if (hookDeltaSpecified > 0) key.currency0.take(vault, address(this), uint128(hookDeltaSpecified), false); if (hookDeltaUnspecified < 0) { - vault.sync(key.currency1); - key.currency1.transfer(address(vault), uint128(-hookDeltaUnspecified)); - vault.settle(key.currency1); - } else { - vault.take(key.currency1, address(this), uint128(hookDeltaUnspecified)); + key.currency1.settle(vault, address(this), uint128(-hookDeltaUnspecified), false); + } + if (hookDeltaUnspecified > 0) { + key.currency1.take(vault, address(this), uint128(hookDeltaUnspecified), false); } } else { // the specified token is token1 - if (hookDeltaSpecified < 0) { - vault.sync(key.currency1); - key.currency1.transfer(address(vault), uint128(-hookDeltaSpecified)); - vault.settle(key.currency1); - } else { - vault.take(key.currency1, address(this), uint128(hookDeltaSpecified)); - } + if (hookDeltaSpecified < 0) key.currency1.settle(vault, address(this), uint128(-hookDeltaSpecified), false); + if (hookDeltaSpecified > 0) key.currency1.take(vault, address(this), uint128(hookDeltaSpecified), false); if (hookDeltaUnspecified < 0) { - vault.sync(key.currency0); - key.currency0.transfer(address(vault), uint128(-hookDeltaUnspecified)); - vault.settle(key.currency0); - } else { - vault.take(key.currency0, address(this), uint128(hookDeltaUnspecified)); + key.currency0.settle(vault, address(this), uint128(-hookDeltaUnspecified), false); + } + if (hookDeltaUnspecified > 0) { + key.currency0.take(vault, address(this), uint128(hookDeltaUnspecified), false); } } @@ -145,20 +134,18 @@ contract BinReturnsDeltaHook is BaseBinTestHook { if (swapForY) { // the unspecified token is token1 if (hookDeltaUnspecified < 0) { - vault.sync(key.currency1); - key.currency1.transfer(address(vault), uint128(-hookDeltaUnspecified)); - vault.settle(key.currency1); - } else { - vault.take(key.currency1, address(this), uint128(hookDeltaUnspecified)); + key.currency1.settle(vault, address(this), uint128(-hookDeltaUnspecified), false); + } + if (hookDeltaUnspecified > 0) { + key.currency1.take(vault, address(this), uint128(hookDeltaUnspecified), false); } } else { // the unspecified token is token0 if (hookDeltaUnspecified < 0) { - vault.sync(key.currency0); - key.currency0.transfer(address(vault), uint128(-hookDeltaUnspecified)); - vault.settle(key.currency0); - } else { - vault.take(key.currency0, address(this), uint128(hookDeltaUnspecified)); + key.currency0.settle(vault, address(this), uint128(-hookDeltaUnspecified), false); + } + if (hookDeltaUnspecified > 0) { + key.currency0.take(vault, address(this), uint128(hookDeltaUnspecified), false); } } diff --git a/test/pool-bin/helpers/BinSkipCallbackHook.sol b/test/pool-bin/helpers/BinSkipCallbackHook.sol index 3b40573e..9933c5e6 100644 --- a/test/pool-bin/helpers/BinSkipCallbackHook.sol +++ b/test/pool-bin/helpers/BinSkipCallbackHook.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.24; import {IVault} from "../../../src/interfaces/IVault.sol"; import {Currency, CurrencyLibrary} from "../../../src/types/Currency.sol"; +import {CurrencySettlement} from "../../helpers/CurrencySettlement.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {PoolKey} from "../../../src/types/PoolKey.sol"; @@ -17,7 +18,7 @@ import {BaseBinTestHook} from "./BaseBinTestHook.sol"; contract BinSkipCallbackHook is BaseBinTestHook { error InvalidAction(); - using CurrencyLibrary for Currency; + using CurrencySettlement for Currency; using Hooks for bytes32; IBinPoolManager public immutable poolManager; @@ -189,32 +190,10 @@ contract BinSkipCallbackHook is BaseBinTestHook { (delta,) = poolManager.donate(data.key, data.amount0, data.amount1, data.hookData); } - if (delta.amount0() < 0) { - if (key.currency0.isNative()) { - vault.settle{value: uint128(-delta.amount0())}(key.currency0); - } else { - vault.sync(key.currency0); - IERC20(Currency.unwrap(key.currency0)).transferFrom(sender, address(vault), uint128(-delta.amount0())); - vault.settle(key.currency0); - } - } - - if (delta.amount1() < 0) { - if (key.currency1.isNative()) { - vault.settle{value: uint128(-delta.amount1())}(key.currency1); - } else { - vault.sync(key.currency1); - IERC20(Currency.unwrap(key.currency1)).transferFrom(sender, address(vault), uint128(-delta.amount1())); - vault.settle(key.currency1); - } - } - - if (delta.amount0() > 0) { - vault.take(key.currency0, sender, uint128(delta.amount0())); - } - if (delta.amount1() > 0) { - vault.take(key.currency1, sender, uint128(delta.amount1())); - } + if (delta.amount0() < 0) key.currency0.settle(vault, sender, uint128(-delta.amount0()), false); + if (delta.amount0() > 0) key.currency0.take(vault, sender, uint128(delta.amount0()), false); + if (delta.amount1() < 0) key.currency1.settle(vault, sender, uint128(-delta.amount1()), false); + if (delta.amount1() > 0) key.currency1.take(vault, sender, uint128(delta.amount1()), false); return abi.encode(delta); } diff --git a/test/pool-bin/helpers/BinSwapHelper.sol b/test/pool-bin/helpers/BinSwapHelper.sol index 94c2f896..93340902 100644 --- a/test/pool-bin/helpers/BinSwapHelper.sol +++ b/test/pool-bin/helpers/BinSwapHelper.sol @@ -8,9 +8,10 @@ import {BalanceDelta, BalanceDeltaLibrary} from "../../../src/types/BalanceDelta import {CurrencyLibrary, Currency} from "../../../src/types/Currency.sol"; import {PoolKey} from "../../../src/types/PoolKey.sol"; import {Hooks} from "../../../src/libraries/Hooks.sol"; +import {CurrencySettlement} from "../../helpers/CurrencySettlement.sol"; contract BinSwapHelper { - using CurrencyLibrary for Currency; + using CurrencySettlement for Currency; using Hooks for bytes32; error HookMissingNoOpPermission(); @@ -62,54 +63,28 @@ contract BinSwapHelper { if (data.swapForY) { if (delta.amount0() < 0) { - if (data.testSettings.settleUsingTransfer) { - if (data.key.currency0.isNative()) { - vault.settle{value: uint128(-delta.amount0())}(data.key.currency0); - } else { - vault.sync(data.key.currency0); - IERC20(Currency.unwrap(data.key.currency0)).transferFrom( - data.sender, address(vault), uint128(-delta.amount0()) - ); - vault.settle(data.key.currency0); - } - } else { - // the received hook on this transfer will burn the tokens - vault.transferFrom(data.sender, address(this), data.key.currency0, uint128(-delta.amount0())); - vault.burn(address(this), data.key.currency0, uint128(-delta.amount0())); - } - } - if (delta.amount1() > 0) { - if (data.testSettings.withdrawTokens) { - vault.take(data.key.currency1, data.sender, uint128(delta.amount1())); - } else { - vault.mint(data.sender, data.key.currency1, uint128(delta.amount1())); - } + bool burn = !data.testSettings.settleUsingTransfer; + // transfer VaultToken to vault before calling settle if burn + if (burn) vault.transferFrom(data.sender, address(this), data.key.currency0, uint128(-delta.amount0())); + data.key.currency0.settle(vault, data.sender, uint128(-delta.amount0()), burn); } + + bool claims = !data.testSettings.withdrawTokens; + if (delta.amount1() > 0) data.key.currency1.take(vault, data.sender, uint128(delta.amount1()), claims); } else { if (delta.amount1() < 0) { - if (data.testSettings.settleUsingTransfer) { - if (data.key.currency1.isNative()) { - vault.settle{value: uint128(-delta.amount1())}(data.key.currency1); - } else { - vault.sync(data.key.currency1); - IERC20(Currency.unwrap(data.key.currency1)).transferFrom( - data.sender, address(vault), uint128(-delta.amount1()) - ); - vault.settle(data.key.currency1); - } - } else { - // the received hook on this transfer will burn the tokens + bool burn = !data.testSettings.settleUsingTransfer; + // transfer VaultToken to vault before calling settle if burn + if (burn) { vault.transferFrom(data.sender, address(this), data.key.currency1, uint128(-delta.amount1())); - vault.burn(address(this), data.key.currency1, uint128(-delta.amount1())); - } - } - if (delta.amount0() > 0) { - if (data.testSettings.withdrawTokens) { - vault.take(data.key.currency0, data.sender, uint128(delta.amount0())); + data.key.currency1.settle(vault, address(this), uint128(-delta.amount1()), burn); } else { - vault.mint(data.sender, data.key.currency0, uint128(delta.amount0())); + data.key.currency1.settle(vault, data.sender, uint128(-delta.amount1()), burn); } } + + bool claims = !data.testSettings.withdrawTokens; + if (delta.amount0() > 0) data.key.currency0.take(vault, data.sender, uint128(delta.amount0()), claims); } return abi.encode(delta); diff --git a/test/pool-cl/CLFees.t.sol b/test/pool-cl/CLFees.t.sol index faec2a53..dbda935d 100644 --- a/test/pool-cl/CLFees.t.sol +++ b/test/pool-cl/CLFees.t.sol @@ -32,7 +32,6 @@ contract CLFeesTest is Test, Deployers, TokenFixture, GasSnapshot { using Hooks for IHooks; using CLPool for CLPool.State; using PoolIdLibrary for PoolKey; - using CurrencyLibrary for Currency; IVault vault; CLPool.State state; diff --git a/test/pool-cl/CLHookReturnsDelta.t.sol b/test/pool-cl/CLHookReturnsDelta.t.sol index fd99001d..d5b93b54 100644 --- a/test/pool-cl/CLHookReturnsDelta.t.sol +++ b/test/pool-cl/CLHookReturnsDelta.t.sol @@ -26,7 +26,6 @@ import {TickMath} from "../../src/pool-cl/libraries/TickMath.sol"; contract CLHookReturnsDeltaTest is Test, Deployers, TokenFixture, GasSnapshot { using PoolIdLibrary for PoolKey; - using CurrencyLibrary for Currency; using CLPoolParametersHelper for bytes32; using LPFeeLibrary for uint24; diff --git a/test/pool-cl/CLHookSkipCallback.t.sol b/test/pool-cl/CLHookSkipCallback.t.sol index 95cd91f1..39db6e77 100644 --- a/test/pool-cl/CLHookSkipCallback.t.sol +++ b/test/pool-cl/CLHookSkipCallback.t.sol @@ -25,7 +25,6 @@ import {CLSkipCallbackHook} from "./helpers/CLSkipCallbackHook.sol"; contract CLHookSkipCallbackTest is Test, Deployers, TokenFixture, GasSnapshot { using PoolIdLibrary for PoolKey; - using CurrencyLibrary for Currency; using CLPoolParametersHelper for bytes32; using ParametersHelper for bytes32; using LPFeeLibrary for uint24; diff --git a/test/pool-cl/CLPoolManager.t.sol b/test/pool-cl/CLPoolManager.t.sol index c525e79e..60698b44 100644 --- a/test/pool-cl/CLPoolManager.t.sol +++ b/test/pool-cl/CLPoolManager.t.sol @@ -39,7 +39,6 @@ import {NoIsolate} from "../helpers/NoIsolate.sol"; contract CLPoolManagerTest is Test, NoIsolate, Deployers, TokenFixture, GasSnapshot { using PoolIdLibrary for PoolKey; - using CurrencyLibrary for Currency; using CLPoolParametersHelper for bytes32; using ParametersHelper for bytes32; using LPFeeLibrary for uint24; diff --git a/test/pool-cl/helpers/CLPoolManagerRouter.sol b/test/pool-cl/helpers/CLPoolManagerRouter.sol index dce5e1b6..6c4919db 100644 --- a/test/pool-cl/helpers/CLPoolManagerRouter.sol +++ b/test/pool-cl/helpers/CLPoolManagerRouter.sol @@ -10,12 +10,13 @@ import {console2} from "forge-std/console2.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {BalanceDelta, BalanceDeltaLibrary} from "../../../src/types/BalanceDelta.sol"; import {Hooks} from "../../../src/libraries/Hooks.sol"; +import {CurrencySettlement} from "../../helpers/CurrencySettlement.sol"; contract CLPoolManagerRouter { error InvalidAction(); error HookMissingNoOpPermission(); - using CurrencyLibrary for Currency; + using CurrencySettlement for Currency; using Hooks for bytes32; IVault public immutable vault; @@ -63,35 +64,10 @@ contract CLPoolManagerRouter { // delta already takes feeDelta into account (BalanceDelta delta, BalanceDelta feeDelta) = poolManager.modifyLiquidity(data.key, data.params, data.hookData); - if (delta.amount0() < 0) { - if (data.key.currency0.isNative()) { - vault.settle{value: uint128(-delta.amount0())}(data.key.currency0); - } else { - vault.sync(data.key.currency0); - IERC20(Currency.unwrap(data.key.currency0)).transferFrom( - data.sender, address(vault), uint128(-delta.amount0()) - ); - vault.settle(data.key.currency0); - } - } - if (delta.amount1() < 0) { - if (data.key.currency1.isNative()) { - vault.settle{value: uint128(-delta.amount1())}(data.key.currency1); - } else { - vault.sync(data.key.currency1); - IERC20(Currency.unwrap(data.key.currency1)).transferFrom( - data.sender, address(vault), uint128(-delta.amount1()) - ); - vault.settle(data.key.currency1); - } - } - - if (delta.amount0() > 0) { - vault.take(data.key.currency0, data.sender, uint128(delta.amount0())); - } - if (delta.amount1() > 0) { - vault.take(data.key.currency1, data.sender, uint128(delta.amount1())); - } + if (delta.amount0() < 0) data.key.currency0.settle(vault, data.sender, uint128(-delta.amount0()), false); + if (delta.amount1() < 0) data.key.currency1.settle(vault, data.sender, uint128(-delta.amount1()), false); + if (delta.amount0() > 0) data.key.currency0.take(vault, data.sender, uint128(delta.amount0()), false); + if (delta.amount1() > 0) data.key.currency1.take(vault, data.sender, uint128(delta.amount1()), false); return abi.encode(delta, feeDelta); } @@ -133,54 +109,30 @@ contract CLPoolManagerRouter { if (data.params.zeroForOne) { if (delta.amount0() < 0) { - if (data.testSettings.settleUsingTransfer) { - if (data.key.currency0.isNative()) { - vault.settle{value: uint128(-delta.amount0())}(data.key.currency0); - } else { - vault.sync(data.key.currency0); - IERC20(Currency.unwrap(data.key.currency0)).transferFrom( - data.sender, address(vault), uint128(-delta.amount0()) - ); - vault.settle(data.key.currency0); - } - } else { - // the received hook on this transfer will burn the tokens + bool burn = !data.testSettings.settleUsingTransfer; + if (burn) { vault.transferFrom(data.sender, address(this), data.key.currency0, uint128(-delta.amount0())); - vault.burn(address(this), data.key.currency0, uint128(-delta.amount0())); - } - } - if (delta.amount1() > 0) { - if (data.testSettings.withdrawTokens) { - vault.take(data.key.currency1, data.sender, uint128(delta.amount1())); + data.key.currency0.settle(vault, address(this), uint128(-delta.amount0()), burn); } else { - vault.mint(data.sender, data.key.currency1, uint128(delta.amount1())); + data.key.currency0.settle(vault, data.sender, uint128(-delta.amount0()), burn); } } + + bool claims = !data.testSettings.withdrawTokens; + if (delta.amount1() > 0) data.key.currency1.take(vault, data.sender, uint128(delta.amount1()), claims); } else { if (delta.amount1() < 0) { - if (data.testSettings.settleUsingTransfer) { - if (data.key.currency1.isNative()) { - vault.settle{value: uint128(-delta.amount1())}(data.key.currency1); - } else { - vault.sync(data.key.currency1); - IERC20(Currency.unwrap(data.key.currency1)).transferFrom( - data.sender, address(vault), uint128(-delta.amount1()) - ); - vault.settle(data.key.currency1); - } - } else { - // the received hook on this transfer will burn the tokens + bool burn = !data.testSettings.settleUsingTransfer; + if (burn) { vault.transferFrom(data.sender, address(this), data.key.currency1, uint128(-delta.amount1())); - vault.burn(address(this), data.key.currency1, uint128(-delta.amount1())); - } - } - if (delta.amount0() > 0) { - if (data.testSettings.withdrawTokens) { - vault.take(data.key.currency0, data.sender, uint128(delta.amount0())); + data.key.currency1.settle(vault, address(this), uint128(-delta.amount1()), burn); } else { - vault.mint(data.sender, data.key.currency0, uint128(delta.amount0())); + data.key.currency1.settle(vault, data.sender, uint128(-delta.amount1()), burn); } } + + bool claims = !data.testSettings.withdrawTokens; + if (delta.amount0() > 0) data.key.currency0.take(vault, data.sender, uint128(delta.amount0()), claims); } return abi.encode(delta); @@ -217,28 +169,8 @@ contract CLPoolManagerRouter { BalanceDelta delta = poolManager.donate(data.key, data.amount0, data.amount1, data.hookData); - if (delta.amount0() < 0) { - if (data.key.currency0.isNative()) { - vault.settle{value: uint128(-delta.amount0())}(data.key.currency0); - } else { - vault.sync(data.key.currency0); - IERC20(Currency.unwrap(data.key.currency0)).transferFrom( - data.sender, address(vault), uint128(-delta.amount0()) - ); - vault.settle(data.key.currency0); - } - } - if (delta.amount1() < 0) { - if (data.key.currency1.isNative()) { - vault.settle{value: uint128(-delta.amount1())}(data.key.currency1); - } else { - vault.sync(data.key.currency1); - IERC20(Currency.unwrap(data.key.currency1)).transferFrom( - data.sender, address(vault), uint128(-delta.amount1()) - ); - vault.settle(data.key.currency1); - } - } + if (delta.amount0() < 0) data.key.currency0.settle(vault, data.sender, uint128(-delta.amount0()), false); + if (delta.amount1() < 0) data.key.currency1.settle(vault, data.sender, uint128(-delta.amount1()), false); return abi.encode(delta); } @@ -263,15 +195,7 @@ contract CLPoolManagerRouter { uint256 balAfter = data.key.currency0.balanceOf(data.sender); require(balAfter - balBefore == data.amount0); - if (data.key.currency0.isNative()) { - vault.settle{value: uint256(data.amount0)}(data.key.currency0); - } else { - vault.sync(data.key.currency0); - IERC20(Currency.unwrap(data.key.currency0)).transferFrom( - data.sender, address(vault), uint256(data.amount0) - ); - vault.settle(data.key.currency0); - } + data.key.currency0.settle(vault, data.sender, uint128(data.amount0), false); } if (data.amount1 > 0) { @@ -280,15 +204,7 @@ contract CLPoolManagerRouter { uint256 balAfter = data.key.currency1.balanceOf(data.sender); require(balAfter - balBefore == data.amount1); - if (data.key.currency1.isNative()) { - vault.settle{value: uint256(data.amount1)}(data.key.currency1); - } else { - vault.sync(data.key.currency1); - IERC20(Currency.unwrap(data.key.currency1)).transferFrom( - data.sender, address(vault), uint256(data.amount1) - ); - vault.settle(data.key.currency1); - } + data.key.currency1.settle(vault, data.sender, uint128(data.amount1), false); } return abi.encode(0); diff --git a/test/pool-cl/helpers/CLReturnsDeltaHook.sol b/test/pool-cl/helpers/CLReturnsDeltaHook.sol index 0a1fbfd3..3cf4042e 100644 --- a/test/pool-cl/helpers/CLReturnsDeltaHook.sol +++ b/test/pool-cl/helpers/CLReturnsDeltaHook.sol @@ -5,16 +5,18 @@ import {IVault} from "../../../src/interfaces/IVault.sol"; import {Hooks} from "../../../src/libraries/Hooks.sol"; import {ICLPoolManager} from "../../../src/pool-cl/interfaces/ICLPoolManager.sol"; import {PoolKey} from "../../../src/types/PoolKey.sol"; -import {Currency, CurrencyLibrary} from "../../../src/types/Currency.sol"; +import {Currency} from "../../../src/types/Currency.sol"; +import {CurrencySettlement} from "../../helpers/CurrencySettlement.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {BalanceDelta, BalanceDeltaLibrary} from "../../../src/types/BalanceDelta.sol"; import {BaseCLTestHook} from "./BaseCLTestHook.sol"; import {BeforeSwapDelta, BeforeSwapDeltaLibrary, toBeforeSwapDelta} from "../../../src/types/BeforeSwapDelta.sol"; +import {CurrencySettlement} from "../../helpers/CurrencySettlement.sol"; contract CLReturnsDeltaHook is BaseCLTestHook { error InvalidAction(); - using CurrencyLibrary for Currency; + using CurrencySettlement for Currency; using Hooks for bytes32; IVault public immutable vault; @@ -87,37 +89,25 @@ contract CLReturnsDeltaHook is BaseCLTestHook { if (params.zeroForOne == params.amountSpecified < 0) { // the specified token is token0 - if (hookDeltaSpecified < 0) { - vault.sync(key.currency0); - key.currency0.transfer(address(vault), uint128(-hookDeltaSpecified)); - vault.settle(key.currency0); - } else { - vault.take(key.currency0, address(this), uint128(hookDeltaSpecified)); - } + if (hookDeltaSpecified < 0) key.currency0.settle(vault, address(this), uint128(-hookDeltaSpecified), false); + if (hookDeltaSpecified > 0) key.currency0.take(vault, address(this), uint128(hookDeltaSpecified), false); if (hookDeltaUnspecified < 0) { - vault.sync(key.currency1); - key.currency1.transfer(address(vault), uint128(-hookDeltaUnspecified)); - vault.settle(key.currency1); - } else { - vault.take(key.currency1, address(this), uint128(hookDeltaUnspecified)); + key.currency1.settle(vault, address(this), uint128(-hookDeltaUnspecified), false); + } + if (hookDeltaUnspecified > 0) { + key.currency1.take(vault, address(this), uint128(hookDeltaUnspecified), false); } } else { // the specified token is token1 - if (hookDeltaSpecified < 0) { - vault.sync(key.currency1); - key.currency1.transfer(address(vault), uint128(-hookDeltaSpecified)); - vault.settle(key.currency1); - } else { - vault.take(key.currency1, address(this), uint128(hookDeltaSpecified)); - } + if (hookDeltaSpecified < 0) key.currency1.settle(vault, address(this), uint128(-hookDeltaSpecified), false); + if (hookDeltaSpecified > 0) key.currency1.take(vault, address(this), uint128(hookDeltaSpecified), false); if (hookDeltaUnspecified < 0) { - vault.sync(key.currency0); - key.currency0.transfer(address(vault), uint128(-hookDeltaUnspecified)); - vault.settle(key.currency0); - } else { - vault.take(key.currency0, address(this), uint128(hookDeltaUnspecified)); + key.currency0.settle(vault, address(this), uint128(-hookDeltaUnspecified), false); + } + if (hookDeltaUnspecified > 0) { + key.currency0.take(vault, address(this), uint128(hookDeltaUnspecified), false); } } return (this.beforeSwap.selector, toBeforeSwapDelta(hookDeltaSpecified, hookDeltaUnspecified), 0); @@ -139,20 +129,18 @@ contract CLReturnsDeltaHook is BaseCLTestHook { if (params.zeroForOne == params.amountSpecified < 0) { // the unspecified token is token1 if (hookDeltaUnspecified < 0) { - vault.sync(key.currency1); - key.currency1.transfer(address(vault), uint128(-hookDeltaUnspecified)); - vault.settle(key.currency1); - } else { - vault.take(key.currency1, address(this), uint128(hookDeltaUnspecified)); + key.currency1.settle(vault, address(this), uint128(-hookDeltaUnspecified), false); + } + if (hookDeltaUnspecified > 0) { + key.currency1.take(vault, address(this), uint128(hookDeltaUnspecified), false); } } else { // the unspecified token is token0 if (hookDeltaUnspecified < 0) { - vault.sync(key.currency0); - key.currency0.transfer(address(vault), uint128(-hookDeltaUnspecified)); - vault.settle(key.currency0); - } else { - vault.take(key.currency0, address(this), uint128(hookDeltaUnspecified)); + key.currency0.settle(vault, address(this), uint128(-hookDeltaUnspecified), false); + } + if (hookDeltaUnspecified > 0) { + key.currency0.take(vault, address(this), uint128(hookDeltaUnspecified), false); } } diff --git a/test/pool-cl/helpers/CLSkipCallbackHook.sol b/test/pool-cl/helpers/CLSkipCallbackHook.sol index 71ff65c6..bbdd671e 100644 --- a/test/pool-cl/helpers/CLSkipCallbackHook.sol +++ b/test/pool-cl/helpers/CLSkipCallbackHook.sol @@ -10,12 +10,13 @@ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {BalanceDelta, BalanceDeltaLibrary} from "../../../src/types/BalanceDelta.sol"; import {BaseCLTestHook} from "./BaseCLTestHook.sol"; import {BeforeSwapDelta, BeforeSwapDeltaLibrary} from "../../../src/types/BeforeSwapDelta.sol"; +import {CurrencySettlement} from "../../helpers/CurrencySettlement.sol"; /// @notice CL hook which does a callback contract CLSkipCallbackHook is BaseCLTestHook { error InvalidAction(); - using CurrencyLibrary for Currency; + using CurrencySettlement for Currency; using Hooks for bytes32; IVault public immutable vault; @@ -90,35 +91,10 @@ contract CLSkipCallbackHook is BaseCLTestHook { (BalanceDelta delta,) = poolManager.modifyLiquidity(data.key, data.params, data.hookData); - if (delta.amount0() < 0) { - if (data.key.currency0.isNative()) { - vault.settle{value: uint128(-delta.amount0())}(data.key.currency0); - } else { - vault.sync(data.key.currency0); - IERC20(Currency.unwrap(data.key.currency0)).transferFrom( - data.sender, address(vault), uint128(-delta.amount0()) - ); - vault.settle(data.key.currency0); - } - } - if (delta.amount1() < 0) { - if (data.key.currency1.isNative()) { - vault.settle{value: uint128(-delta.amount1())}(data.key.currency1); - } else { - vault.sync(data.key.currency1); - IERC20(Currency.unwrap(data.key.currency1)).transferFrom( - data.sender, address(vault), uint128(-delta.amount1()) - ); - vault.settle(data.key.currency1); - } - } - - if (delta.amount0() > 0) { - vault.take(data.key.currency0, data.sender, uint128(delta.amount0())); - } - if (delta.amount1() > 0) { - vault.take(data.key.currency1, data.sender, uint128(delta.amount1())); - } + if (delta.amount0() < 0) data.key.currency0.settle(vault, data.sender, uint128(-delta.amount0()), false); + if (delta.amount0() > 0) data.key.currency0.take(vault, data.sender, uint128(delta.amount0()), false); + if (delta.amount1() < 0) data.key.currency1.settle(vault, data.sender, uint128(-delta.amount1()), false); + if (delta.amount1() > 0) data.key.currency1.take(vault, data.sender, uint128(delta.amount1()), false); return abi.encode(delta); } @@ -159,54 +135,30 @@ contract CLSkipCallbackHook is BaseCLTestHook { BalanceDelta delta = poolManager.swap(data.key, data.params, data.hookData); if (data.params.zeroForOne) { if (delta.amount0() < 0) { - if (data.testSettings.settleUsingTransfer) { - if (data.key.currency0.isNative()) { - vault.settle{value: uint128(-delta.amount0())}(data.key.currency0); - } else { - vault.sync(data.key.currency0); - IERC20(Currency.unwrap(data.key.currency0)).transferFrom( - data.sender, address(vault), uint128(-delta.amount0()) - ); - vault.settle(data.key.currency0); - } - } else { - // the received hook on this transfer will burn the tokens + bool burn = !data.testSettings.settleUsingTransfer; + if (burn) { vault.transferFrom(data.sender, address(this), data.key.currency0, uint128(-delta.amount0())); - vault.burn(address(this), data.key.currency0, uint128(-delta.amount0())); - } - } - if (delta.amount1() > 0) { - if (data.testSettings.withdrawTokens) { - vault.take(data.key.currency1, data.sender, uint128(delta.amount1())); + data.key.currency0.settle(vault, address(this), uint128(-delta.amount0()), burn); } else { - vault.mint(data.sender, data.key.currency1, uint128(delta.amount1())); + data.key.currency0.settle(vault, data.sender, uint128(-delta.amount0()), burn); } } + + bool claims = !data.testSettings.withdrawTokens; + if (delta.amount1() > 0) data.key.currency1.take(vault, data.sender, uint128(delta.amount1()), claims); } else { if (delta.amount1() < 0) { - if (data.testSettings.settleUsingTransfer) { - if (data.key.currency1.isNative()) { - vault.settle{value: uint128(-delta.amount1())}(data.key.currency1); - } else { - vault.sync(data.key.currency1); - IERC20(Currency.unwrap(data.key.currency1)).transferFrom( - data.sender, address(vault), uint128(-delta.amount1()) - ); - vault.settle(data.key.currency1); - } - } else { - // the received hook on this transfer will burn the tokens + bool burn = !data.testSettings.settleUsingTransfer; + if (burn) { vault.transferFrom(data.sender, address(this), data.key.currency1, uint128(-delta.amount1())); - vault.burn(address(this), data.key.currency1, uint128(-delta.amount1())); - } - } - if (delta.amount0() > 0) { - if (data.testSettings.withdrawTokens) { - vault.take(data.key.currency0, data.sender, uint128(delta.amount0())); + data.key.currency1.settle(vault, address(this), uint128(-delta.amount1()), burn); } else { - vault.mint(data.sender, data.key.currency0, uint128(delta.amount0())); + data.key.currency1.settle(vault, data.sender, uint128(-delta.amount1()), burn); } } + + bool claims = !data.testSettings.withdrawTokens; + if (delta.amount0() > 0) data.key.currency0.take(vault, data.sender, uint128(delta.amount0()), claims); } return abi.encode(delta); @@ -242,28 +194,9 @@ contract CLSkipCallbackHook is BaseCLTestHook { DonateCallbackData memory data = abi.decode(rawData, (DonateCallbackData)); BalanceDelta delta = poolManager.donate(data.key, data.amount0, data.amount1, data.hookData); - if (delta.amount0() < 0) { - if (data.key.currency0.isNative()) { - vault.settle{value: uint128(-delta.amount0())}(data.key.currency0); - } else { - vault.sync(data.key.currency0); - IERC20(Currency.unwrap(data.key.currency0)).transferFrom( - data.sender, address(vault), uint128(-delta.amount0()) - ); - vault.settle(data.key.currency0); - } - } - if (delta.amount1() < 0) { - if (data.key.currency1.isNative()) { - vault.settle{value: uint128(-delta.amount1())}(data.key.currency1); - } else { - vault.sync(data.key.currency1); - IERC20(Currency.unwrap(data.key.currency1)).transferFrom( - data.sender, address(vault), uint128(-delta.amount1()) - ); - vault.settle(data.key.currency1); - } - } + + if (delta.amount0() < 0) data.key.currency0.settle(vault, data.sender, uint128(-delta.amount0()), false); + if (delta.amount1() < 0) data.key.currency1.settle(vault, data.sender, uint128(-delta.amount1()), false); return abi.encode(delta); } diff --git a/test/pool-cl/helpers/PoolModifyPositionTest.sol b/test/pool-cl/helpers/PoolModifyPositionTest.sol index fdbcaedb..8f19d4a5 100644 --- a/test/pool-cl/helpers/PoolModifyPositionTest.sol +++ b/test/pool-cl/helpers/PoolModifyPositionTest.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.24; import {console2} from "forge-std/console2.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {CurrencyLibrary, Currency} from "../../../src/types/Currency.sol"; +import {CurrencySettlement} from "../../helpers/CurrencySettlement.sol"; import {ILockCallback} from "../../../src/interfaces//ILockCallback.sol"; import {ICLPoolManager} from "../../../src/pool-cl/interfaces/ICLPoolManager.sol"; import {IVault} from "../../../src/interfaces/IVault.sol"; @@ -12,7 +13,7 @@ import {BalanceDelta} from "../../../src/types/BalanceDelta.sol"; import {PoolKey} from "../../../src/types/PoolKey.sol"; contract PoolModifyPositionTest is ILockCallback { - using CurrencyLibrary for Currency; + using CurrencySettlement for Currency; IVault public immutable vault; ICLPoolManager public immutable manager; @@ -53,34 +54,17 @@ contract PoolModifyPositionTest is ILockCallback { BalanceDelta totalDelta = delta + feeDelta; if (totalDelta.amount0() > 0) { - if (data.key.currency0.isNative()) { - vault.settle{value: uint128(totalDelta.amount0())}(data.key.currency0); - } else { - vault.sync(data.key.currency0); - IERC20(Currency.unwrap(data.key.currency0)).transferFrom( - data.sender, address(vault), uint128(totalDelta.amount0()) - ); - vault.settle(data.key.currency0); - } + data.key.currency0.settle(vault, data.sender, uint128(totalDelta.amount0()), false); } - if (totalDelta.amount1() > 0) { - if (data.key.currency1.isNative()) { - vault.settle{value: uint128(delta.amount1())}(data.key.currency1); - } else { - vault.sync(data.key.currency1); - IERC20(Currency.unwrap(data.key.currency1)).transferFrom( - data.sender, address(vault), uint128(totalDelta.amount1()) - ); - vault.settle(data.key.currency1); - } + data.key.currency1.settle(vault, data.sender, uint128(totalDelta.amount1()), false); } if (totalDelta.amount0() < 0) { - vault.take(data.key.currency0, data.sender, uint128(-totalDelta.amount0())); + data.key.currency0.take(vault, data.sender, uint128(-totalDelta.amount0()), false); } if (totalDelta.amount1() < 0) { - vault.take(data.key.currency1, data.sender, uint128(-totalDelta.amount1())); + data.key.currency1.take(vault, data.sender, uint128(-totalDelta.amount0()), false); } return abi.encode(totalDelta); diff --git a/test/vault/FakePoolManagerRouter.sol b/test/vault/FakePoolManagerRouter.sol index 41e48c33..f1ed5df9 100644 --- a/test/vault/FakePoolManagerRouter.sol +++ b/test/vault/FakePoolManagerRouter.sol @@ -10,8 +10,6 @@ import {IPoolManager} from "../../src/interfaces/IPoolManager.sol"; import {toBalanceDelta} from "../../src/types/BalanceDelta.sol"; contract FakePoolManagerRouter is Test { - using CurrencyLibrary for Currency; - event LockAcquired(); IVault vault; diff --git a/test/vault/Vault.t.sol b/test/vault/Vault.t.sol index 003c429d..2a8215b5 100644 --- a/test/vault/Vault.t.sol +++ b/test/vault/Vault.t.sol @@ -24,7 +24,6 @@ import {NoIsolate} from "../helpers/NoIsolate.sol"; * More tests in terms of security and edge cases will be covered by VaultReentracy.t.sol & VaultInvariant.t.sol */ contract VaultTest is Test, NoIsolate, GasSnapshot { - using CurrencyLibrary for Currency; using PoolIdLibrary for PoolKey; event PoolManagerRegistered(address indexed poolManager); diff --git a/test/vault/VaultReentrancy.t.sol b/test/vault/VaultReentrancy.t.sol index aa80db00..14fe1528 100644 --- a/test/vault/VaultReentrancy.t.sol +++ b/test/vault/VaultReentrancy.t.sol @@ -44,7 +44,6 @@ contract TokenLocker is ILockCallback { } contract VaultReentrancyTest is Test, TokenFixture { - using CurrencyLibrary for Currency; using SafeCast for *; Vault vault; diff --git a/test/vault/VaultSync.t.sol b/test/vault/VaultSync.t.sol index 5d440210..29b20c54 100644 --- a/test/vault/VaultSync.t.sol +++ b/test/vault/VaultSync.t.sol @@ -16,8 +16,6 @@ import {PoolKey} from "../../src/types/PoolKey.sol"; import {IHooks} from "../../src/interfaces/IHooks.sol"; contract VaultSyncTest is Test, TokenFixture, GasSnapshot, NoIsolate { - using CurrencyLibrary for Currency; - Vault public vault; FakePoolManager public fakePoolManager; FakePoolManagerRouter public router;