From 95b692876491600d17f508a119cde28ec2d3e1d9 Mon Sep 17 00:00:00 2001 From: kinrezc Date: Mon, 18 Mar 2024 12:31:56 -0400 Subject: [PATCH 01/38] test for LP token balance delta on allocate --- test/G3M/unit/Allocate.t.sol | 28 ++++++++++++++++++++++++++-- test/G3M/unit/SetUp.sol | 24 ++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/test/G3M/unit/Allocate.t.sol b/test/G3M/unit/Allocate.t.sol index a2a4ef2c..9851f0d7 100644 --- a/test/G3M/unit/Allocate.t.sol +++ b/test/G3M/unit/Allocate.t.sol @@ -107,8 +107,10 @@ contract G3MAllocateTest is G3MSetUp { solver.allocateGivenDeltaY(POOL_ID, maxDeltaY); (uint256[] memory reserves, uint256 liquidity) = getReservesAndLiquidity(POOL_ID); + console2.log("liquidity", liquidity); uint256 preLiquidityBalance = liquidityOf(address(this), POOL_ID); + console2.log(preLiquidityBalance); bytes memory data = abi.encode(maxDeltaX, maxDeltaY, deltaLiquidity); console2.log(maxDeltaX); @@ -124,11 +126,33 @@ contract G3MAllocateTest is G3MSetUp { assertEq(adjustedReserves[1], reserves[1] + deltas[1]); assertEq(adjustedLiquidity, liquidity + deltaLiquidity); - /* assertEq( preLiquidityBalance + deltaLiquidity, liquidityOf(address(this), POOL_ID) ); - */ + } + + function test_G3M_allocate_ReceiveAppropriateLpTokens() public init_100 { + + (uint256[] memory initialReserves, uint256 initialL) = getReservesAndLiquidity(POOL_ID); + + console2.log("Initial Liquidity", initialL); + + uint256 dyMax = 100 ether; + (uint256 dxMax, uint256 dL) = solver.allocateGivenDeltaY(POOL_ID, dyMax); + + uint256 preLpTokens = liquidityOf(address(this), POOL_ID); + + bytes memory data = abi.encode(dxMax, dyMax, dL); + + (uint256[] memory deltas) = dfmm.allocate(POOL_ID, data); + + (uint256[] memory nextReserves, uint256 nextL) = getReservesAndLiquidity(POOL_ID); + uint256 postLpTokens = liquidityOf(address(this), POOL_ID); + + console2.log("preLp", preLpTokens); + console2.log("postLp", postLpTokens); + + assertApproxEqAbs(preLpTokens + dL, postLpTokens, 1000); } } diff --git a/test/G3M/unit/SetUp.sol b/test/G3M/unit/SetUp.sol index 1cd97be1..24069a51 100644 --- a/test/G3M/unit/SetUp.sol +++ b/test/G3M/unit/SetUp.sol @@ -31,6 +31,10 @@ contract G3MSetUp is SetUp { defaultReserveX, defaultStrikePrice, defaultParams ); + bytes default100InitialPoolData = computeInitialPoolData( + defaultReserveX * 100, defaultStrikePrice, defaultParams + ); + function setUp() public override { SetUp.setUp(); g3m = new GeometricMean(address(dfmm)); @@ -58,4 +62,24 @@ contract G3MSetUp is SetUp { _; } + + modifier init_100() { + address[] memory tokens = new address[](2); + tokens[0] = address(tokenX); + tokens[1] = address(tokenY); + + InitParams memory defaultInitParams = InitParams({ + name: "", + symbol: "", + strategy: address(g3m), + tokens: tokens, + data: default100InitialPoolData, + feeCollector: address(0), + controllerFee: 0 + }); + + (POOL_ID,,) = dfmm.init(defaultInitParams); + + _; + } } From 8cff3fc93faebd503bd56348830ddea6b5d880a0 Mon Sep 17 00:00:00 2001 From: kinrezc Date: Mon, 18 Mar 2024 14:04:27 -0400 Subject: [PATCH 02/38] reproduce audit finding --- src/DFMM.sol | 1 + test/G3M/unit/Allocate.t.sol | 19 ++++++++----------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/DFMM.sol b/src/DFMM.sol index ea727b3e..d55462cf 100644 --- a/src/DFMM.sol +++ b/src/DFMM.sol @@ -161,6 +161,7 @@ contract DFMM is IDFMM { _pools[poolId].reserves[i] += deltas[i]; } + _pools[poolId].totalLiquidity += deltaLiquidity; _manageTokens(msg.sender, poolId, true, deltaLiquidity); diff --git a/test/G3M/unit/Allocate.t.sol b/test/G3M/unit/Allocate.t.sol index 9851f0d7..8700c82a 100644 --- a/test/G3M/unit/Allocate.t.sol +++ b/test/G3M/unit/Allocate.t.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.13; import "./SetUp.sol"; import "solmate/utils/FixedPointMathLib.sol"; +import { LPToken } from "src/LPToken.sol"; contract G3MAllocateTest is G3MSetUp { using FixedPointMathLib for uint256; @@ -133,26 +134,22 @@ contract G3MAllocateTest is G3MSetUp { } function test_G3M_allocate_ReceiveAppropriateLpTokens() public init_100 { - (uint256[] memory initialReserves, uint256 initialL) = getReservesAndLiquidity(POOL_ID); + Pool memory pool = dfmm.pools(POOL_ID); + LPToken liquidityToken = LPToken(pool.liquidityToken); - console2.log("Initial Liquidity", initialL); + uint256 startBalance = liquidityToken.balanceOf(address(this)); uint256 dyMax = 100 ether; (uint256 dxMax, uint256 dL) = solver.allocateGivenDeltaY(POOL_ID, dyMax); - - uint256 preLpTokens = liquidityOf(address(this), POOL_ID); - bytes memory data = abi.encode(dxMax, dyMax, dL); - (uint256[] memory deltas) = dfmm.allocate(POOL_ID, data); + dfmm.allocate(POOL_ID, data); (uint256[] memory nextReserves, uint256 nextL) = getReservesAndLiquidity(POOL_ID); - uint256 postLpTokens = liquidityOf(address(this), POOL_ID); - - console2.log("preLp", preLpTokens); - console2.log("postLp", postLpTokens); + uint256 endBalance = liquidityToken.balanceOf(address(this)); - assertApproxEqAbs(preLpTokens + dL, postLpTokens, 1000); + console2.log("startBalance", startBalance); + console2.log("endBalance", endBalance); } } From 8c675ccff8962b6a2bcee65b381ed3c90b44a02d Mon Sep 17 00:00:00 2001 From: kinrezc Date: Mon, 18 Mar 2024 14:06:19 -0400 Subject: [PATCH 03/38] fix liquidity management order of ops --- src/DFMM.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/DFMM.sol b/src/DFMM.sol index d55462cf..1c3851b2 100644 --- a/src/DFMM.sol +++ b/src/DFMM.sol @@ -161,9 +161,8 @@ contract DFMM is IDFMM { _pools[poolId].reserves[i] += deltas[i]; } - - _pools[poolId].totalLiquidity += deltaLiquidity; _manageTokens(msg.sender, poolId, true, deltaLiquidity); + _pools[poolId].totalLiquidity += deltaLiquidity; for (uint256 i = 0; i < length; i++) { _transferFrom(_pools[poolId].tokens[i], deltas[i]); From 0557365106c4cebad9bb257b7720eb0233cc73ce Mon Sep 17 00:00:00 2001 From: kinrezc Date: Mon, 18 Mar 2024 14:11:12 -0400 Subject: [PATCH 04/38] fix lptoken allocate test assertions --- test/G3M/unit/Allocate.t.sol | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/G3M/unit/Allocate.t.sol b/test/G3M/unit/Allocate.t.sol index 8700c82a..c671ebf9 100644 --- a/test/G3M/unit/Allocate.t.sol +++ b/test/G3M/unit/Allocate.t.sol @@ -134,7 +134,7 @@ contract G3MAllocateTest is G3MSetUp { } function test_G3M_allocate_ReceiveAppropriateLpTokens() public init_100 { - (uint256[] memory initialReserves, uint256 initialL) = getReservesAndLiquidity(POOL_ID); + (, uint256 initialL) = getReservesAndLiquidity(POOL_ID); Pool memory pool = dfmm.pools(POOL_ID); LPToken liquidityToken = LPToken(pool.liquidityToken); @@ -146,10 +146,11 @@ contract G3MAllocateTest is G3MSetUp { dfmm.allocate(POOL_ID, data); - (uint256[] memory nextReserves, uint256 nextL) = getReservesAndLiquidity(POOL_ID); + (, uint256 nextL) = getReservesAndLiquidity(POOL_ID); uint256 endBalance = liquidityToken.balanceOf(address(this)); - - console2.log("startBalance", startBalance); - console2.log("endBalance", endBalance); + + // Add 1_000 wei to account for liquidity that was burnt on init + assertEq(startBalance + 1_000, initialL); + assertEq(endBalance + 1_000, nextL); } } From 27381eddfad873d23cefc14e93a5538c5be36364 Mon Sep 17 00:00:00 2001 From: clemlak Date: Tue, 19 Mar 2024 10:41:17 +0400 Subject: [PATCH 05/38] fix: optimize duplicate tokens loop check --- src/DFMM.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DFMM.sol b/src/DFMM.sol index ea727b3e..d496a2c9 100644 --- a/src/DFMM.sol +++ b/src/DFMM.sol @@ -109,8 +109,8 @@ contract DFMM is IDFMM { for (uint256 i = 0; i < tokensLength; i++) { address token = params.tokens[i]; - for (uint256 j = 0; j < tokensLength; j++) { - if (i != j && token == params.tokens[j]) { + for (uint256 j = i + 1; j < tokensLength; j++) { + if (token == params.tokens[j]) { revert InvalidDuplicateTokens(); } } From 80407890eb22f61f54e7b69fe1af71a1771510af Mon Sep 17 00:00:00 2001 From: clemlak Date: Tue, 19 Mar 2024 11:25:00 +0400 Subject: [PATCH 06/38] fix: DFMM init now returns the totalLiquidity of the pool --- src/DFMM.sol | 2 +- test/DFMM/unit/Init.t.sol | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/DFMM.sol b/src/DFMM.sol index ea727b3e..7251bb4e 100644 --- a/src/DFMM.sol +++ b/src/DFMM.sol @@ -136,7 +136,7 @@ contract DFMM is IDFMM { pool.totalLiquidity ); - return (poolId, reserves, totalLiquidity - BURNT_LIQUIDITY); + return (poolId, reserves, totalLiquidity); } /// @inheritdoc IDFMM diff --git a/test/DFMM/unit/Init.t.sol b/test/DFMM/unit/Init.t.sol index 07625d3f..695d967d 100644 --- a/test/DFMM/unit/Init.t.sol +++ b/test/DFMM/unit/Init.t.sol @@ -31,8 +31,7 @@ contract DFMMInit is DFMMSetUp, Script { function test_DFMM_init_ReturnsStrategyInitialReserves() public { (, uint256[] memory reserves, uint256 totalLiquidity) = dfmm.init(getDefaultPoolParams(defaultData)); - // A bit of the liquidity is burnt - assertEq(initialLiquidity - 1000, totalLiquidity); + assertEq(initialLiquidity, totalLiquidity); assertEq(initialReserveX, reserves[0]); assertEq(initialReserveY, reserves[1]); } From fe89db10054e5f08764b53e2e59fbb5694bb0bea Mon Sep 17 00:00:00 2001 From: clemlak Date: Tue, 19 Mar 2024 13:09:15 +0400 Subject: [PATCH 07/38] chore: add commit to OZ clone function link --- src/DFMM.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DFMM.sol b/src/DFMM.sol index ea727b3e..49d41a6b 100644 --- a/src/DFMM.sol +++ b/src/DFMM.sol @@ -362,7 +362,7 @@ contract DFMM is IDFMM { * @dev Deploys and returns the address of a clone contract that mimics * the behaviour of the contract deployed at the address `implementation`. * This function uses the `CREATE` opcode, which should never revert. - * This function was taken from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/Clones.sol#L23. + * This function was taken from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/7bd2b2aaf68c21277097166a9a51eb72ae239b34/contracts/proxy/Clones.sol#L23-L41. */ function clone(address implementation) internal From bf1102c20ac5f54981179b205d52f051f9ed2667 Mon Sep 17 00:00:00 2001 From: clemlak Date: Tue, 19 Mar 2024 13:25:37 +0400 Subject: [PATCH 08/38] feat: add InvalidReserves error --- src/interfaces/IDFMM.sol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/interfaces/IDFMM.sol b/src/interfaces/IDFMM.sol index 1adab2cf..6b61696a 100644 --- a/src/interfaces/IDFMM.sol +++ b/src/interfaces/IDFMM.sol @@ -56,6 +56,9 @@ interface IDFMM { /// @dev Thrown when pool tokens are identical. error InvalidDuplicateTokens(); + /// @dev Thrown when a strategy is returning an invalid amount of reserves. + error InvalidReserves(); + /// @dev Thrown when a pool is being initalized with less than two tokens. error InvalidMinimumTokens(); From ed37a9bc544dedb772076fb6d5ca4fd048e000a1 Mon Sep 17 00:00:00 2001 From: clemlak Date: Tue, 19 Mar 2024 13:26:31 +0400 Subject: [PATCH 09/38] fix: compare reserves and tokens length in init --- src/DFMM.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/DFMM.sol b/src/DFMM.sol index ea727b3e..c84604ef 100644 --- a/src/DFMM.sol +++ b/src/DFMM.sol @@ -92,6 +92,8 @@ contract DFMM is IDFMM { msg.sender, _pools.length, pool, params.data ); + if (reserves.length != params.tokens.length) revert InvalidReserves(); + if (!valid) revert InvalidInvariant(invariant); liquidityToken.initialize(params.name, params.symbol); From 051f786ae186b18baa92d8c17bdfe5ea262b9172 Mon Sep 17 00:00:00 2001 From: clemlak Date: Tue, 19 Mar 2024 13:55:33 +0400 Subject: [PATCH 10/38] fix: typo in _computeDeallocateDeltasGivenDeltaL NatSpec --- src/PairStrategy.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PairStrategy.sol b/src/PairStrategy.sol index 5dcff55b..18f8e258 100644 --- a/src/PairStrategy.sol +++ b/src/PairStrategy.sol @@ -182,7 +182,7 @@ abstract contract PairStrategy is IStrategy { ) internal view virtual returns (uint256[] memory); /** - * @dev Computes the deltas to de de allocate given a liquidity. + * @dev Computes the deltas to deallocate given a liquidity. * delta. This function is meant to be implemented by the * strategy inheriting from this contract. * @param deltaLiquidity Amount of liquidity to deallocate. From cfd7ddc377d40a278e3a6d72971f42e64d426656 Mon Sep 17 00:00:00 2001 From: clemlak Date: Tue, 19 Mar 2024 14:00:06 +0400 Subject: [PATCH 11/38] fix: add missing NatSpec to Pool and InitParams structs --- src/interfaces/IDFMM.sol | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/interfaces/IDFMM.sol b/src/interfaces/IDFMM.sol index 1adab2cf..7e089674 100644 --- a/src/interfaces/IDFMM.sol +++ b/src/interfaces/IDFMM.sol @@ -8,6 +8,8 @@ pragma solidity ^0.8.13; * @param reserves Array of token reserves in the pool in WAD. * @param totalLiquidity Total liquidity in the pool. * @param liquidityToken Address of the LP token contract. + * @param feeCollector Address receiving controller fees. + * @param controllerFee Fees charged on the swap fee (in WAD). */ struct Pool { address strategy; @@ -26,6 +28,8 @@ struct Pool { * @param strategy Address of the associated strategy contract. * @param tokens Array of token addresses in the pool. * @param data An array of bytes used by the strategy contract. + * @param feeCollector Address receiving controller fees. + * @param controllerFee Fees charged on the swap fee (in WAD). */ struct InitParams { string name; From 163d7d300f6358e9c8983045915b000ba521159f Mon Sep 17 00:00:00 2001 From: clemlak Date: Tue, 19 Mar 2024 15:15:05 +0400 Subject: [PATCH 12/38] fix: return controller in ConstantSum getPoolParams --- src/ConstantSum/ConstantSum.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ConstantSum/ConstantSum.sol b/src/ConstantSum/ConstantSum.sol index 08a1c27d..5e9a44a9 100644 --- a/src/ConstantSum/ConstantSum.sol +++ b/src/ConstantSum/ConstantSum.sol @@ -105,6 +105,7 @@ contract ConstantSum is PairStrategy { params.price = internalParams[poolId].price; params.swapFee = internalParams[poolId].swapFee; + params.controller = internalParams[poolId].controller; return abi.encode(params); } From 21031b5e4bc0ba0324a28fbfff0db57526d1ac46 Mon Sep 17 00:00:00 2001 From: clemlak Date: Tue, 19 Mar 2024 15:15:29 +0400 Subject: [PATCH 13/38] test: add test_ConstantSum_getPoolParams --- test/ConstantSum/unit/GetPoolParams.t.sol | 41 +++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/test/ConstantSum/unit/GetPoolParams.t.sol b/test/ConstantSum/unit/GetPoolParams.t.sol index 8381be67..742b7c05 100644 --- a/test/ConstantSum/unit/GetPoolParams.t.sol +++ b/test/ConstantSum/unit/GetPoolParams.t.sol @@ -1,6 +1,43 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; -import { ConstantSumSetUp } from "./SetUp.sol"; +import { ConstantSumSetUp, ConstantSumParams, InitParams } from "./SetUp.sol"; -contract ConstantSumGetPoolParamsTest is ConstantSumSetUp { } +contract ConstantSumGetPoolParamsTest is ConstantSumSetUp { + function test_ConstantSum_getPoolParams() public { + ConstantSumParams memory initialParams = ConstantSumParams({ + price: 1 ether, + swapFee: TEST_SWAP_FEE, + controller: address(this) + }); + + uint256 reserveX = 1 ether; + uint256 reserveY = 1 ether; + + bytes memory initData = + solver.getInitialPoolData(reserveX, reserveY, initialParams); + + address[] memory tokens = new address[](2); + tokens[0] = address(tokenX); + tokens[1] = address(tokenY); + + InitParams memory initParams = InitParams({ + name: "", + symbol: "", + strategy: address(constantSum), + tokens: tokens, + data: initData, + feeCollector: address(0), + controllerFee: 0 + }); + + dfmm.init(initParams); + + ConstantSumParams memory poolParams = + abi.decode(constantSum.getPoolParams(0), (ConstantSumParams)); + + assertEq(poolParams.price, initialParams.price); + assertEq(poolParams.swapFee, initialParams.swapFee); + assertEq(poolParams.controller, initialParams.controller); + } +} From fa84ff188a4fb789db3fce9313806a5c32ed4aa3 Mon Sep 17 00:00:00 2001 From: clemlak Date: Tue, 19 Mar 2024 18:40:50 +0400 Subject: [PATCH 14/38] test: update ConstantSum getPoolParams test --- test/ConstantSum/unit/GetPoolParams.t.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/ConstantSum/unit/GetPoolParams.t.sol b/test/ConstantSum/unit/GetPoolParams.t.sol index 742b7c05..67f74d09 100644 --- a/test/ConstantSum/unit/GetPoolParams.t.sol +++ b/test/ConstantSum/unit/GetPoolParams.t.sol @@ -31,10 +31,10 @@ contract ConstantSumGetPoolParamsTest is ConstantSumSetUp { controllerFee: 0 }); - dfmm.init(initParams); + (uint256 poolId,,) = dfmm.init(initParams); ConstantSumParams memory poolParams = - abi.decode(constantSum.getPoolParams(0), (ConstantSumParams)); + abi.decode(constantSum.getPoolParams(poolId), (ConstantSumParams)); assertEq(poolParams.price, initialParams.price); assertEq(poolParams.swapFee, initialParams.swapFee); From 88b596be688d73593e56ced76e07832e432077fc Mon Sep 17 00:00:00 2001 From: clemlak Date: Tue, 19 Mar 2024 18:41:10 +0400 Subject: [PATCH 15/38] fix: add missing controller param in ConstantSum init --- src/ConstantSum/ConstantSum.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ConstantSum/ConstantSum.sol b/src/ConstantSum/ConstantSum.sol index 5e9a44a9..aaa2d170 100644 --- a/src/ConstantSum/ConstantSum.sol +++ b/src/ConstantSum/ConstantSum.sol @@ -63,6 +63,7 @@ contract ConstantSum is PairStrategy { internalParams[poolId].price = params.price; internalParams[poolId].swapFee = params.swapFee; + internalParams[poolId].controller = params.controller; // Get the trading function and check this is valid invariant = From 982765a778c38b401473244699d079addb520d81 Mon Sep 17 00:00:00 2001 From: clemlak Date: Wed, 20 Mar 2024 19:23:46 +0400 Subject: [PATCH 16/38] fix: ConstantSum computeTradingFunction, computeInitialPoolData --- src/ConstantSum/ConstantSumMath.sol | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/ConstantSum/ConstantSumMath.sol b/src/ConstantSum/ConstantSumMath.sol index 5e58f9e2..f7e5d9ff 100644 --- a/src/ConstantSum/ConstantSumMath.sol +++ b/src/ConstantSum/ConstantSumMath.sol @@ -13,8 +13,10 @@ function computeTradingFunction( uint256 totalLiquidity, uint256 price ) pure returns (int256) { - return int256(reserves[0].divWadUp(totalLiquidity)) - + int256(reserves[1].divWadUp(totalLiquidity.mulWadUp(price))) - int256(ONE); + return int256( + price.mulWadUp(reserves[0].divWadUp(totalLiquidity)) + + reserves[1].divWadUp(totalLiquidity) + ) - int256(ONE); } function computeInitialPoolData( @@ -24,13 +26,21 @@ function computeInitialPoolData( ) pure returns (bytes memory) { // The pool can be initialized with any non-negative amount of rx, and ry. // so we have to allow a user to pass an amount of both even if one is zero. - uint256 L = rx + ry.divWadUp(params.price); + uint256 L = rx.mulWadDown(params.price) + ry; uint256[] memory reserves = new uint256[](2); reserves[0] = rx; reserves[1] = ry; return abi.encode(reserves, L, params); } +function computeDeltaLiquidity( + uint256 deltaX, + uint256 deltaY, + uint256 price +) pure returns (uint256) { + return price.mulWadUp(deltaX) + deltaY; +} + function computeDeallocateGivenDeltaX( uint256 deltaX, uint256 rX, From 746cbc1283cc49a3b3f57c4451ca40cb7c1d292a Mon Sep 17 00:00:00 2001 From: clemlak Date: Wed, 20 Mar 2024 19:25:14 +0400 Subject: [PATCH 17/38] fix: compute deltaLiquidity in validateAllocate in ConstantSum --- src/ConstantSum/ConstantSum.sol | 50 +++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/src/ConstantSum/ConstantSum.sol b/src/ConstantSum/ConstantSum.sol index 08a1c27d..81811702 100644 --- a/src/ConstantSum/ConstantSum.sol +++ b/src/ConstantSum/ConstantSum.sol @@ -2,7 +2,9 @@ pragma solidity 0.8.22; import { - FixedPointMathLib, computeTradingFunction + FixedPointMathLib, + computeTradingFunction, + computeDeltaLiquidity } from "./ConstantSumMath.sol"; import { decodePriceUpdate, @@ -33,6 +35,9 @@ enum UpdateCode { contract ConstantSum is PairStrategy { using FixedPointMathLib for uint256; + /// @notice Thrown when the expected liquidity is not met. + error InvalidDeltaLiquidity(); + /// @inheritdoc IStrategy string public constant name = "ConstantSum"; @@ -73,6 +78,45 @@ contract ConstantSum is PairStrategy { return (valid, invariant, reserves, totalLiquidity); } + function validateAllocate( + address, + uint256 poolId, + Pool memory pool, + bytes calldata data + ) + external + view + override + returns ( + bool valid, + int256 invariant, + uint256[] memory deltas, + uint256 deltaLiquidity + ) + { + (uint256 deltaX, uint256 deltaY, uint256 minDeltaL) = + abi.decode(data, (uint256, uint256, uint256)); + + deltaLiquidity = + computeDeltaLiquidity(deltaX, deltaY, internalParams[poolId].price); + if (deltaLiquidity < minDeltaL) revert InvalidDeltaLiquidity(); + + deltas = new uint256[](2); + deltas[0] = deltaX; + deltas[1] = deltaY; + + pool.reserves[0] += deltaX; + pool.reserves[1] += deltaY; + + invariant = tradingFunction( + pool.reserves, + pool.totalLiquidity + deltaLiquidity, + getPoolParams(poolId) + ); + + valid = invariant >= 0; + } + /// @inheritdoc IStrategy function update( address sender, @@ -128,7 +172,7 @@ contract ConstantSum is PairStrategy { Pool memory, bytes memory ) internal pure override returns (uint256[] memory) { - return new uint256[](0); + return new uint256[](2); } /// @inheritdoc PairStrategy @@ -137,6 +181,6 @@ contract ConstantSum is PairStrategy { Pool memory, bytes memory ) internal pure override returns (uint256[] memory) { - return new uint256[](0); + return new uint256[](2); } } From 3f2bd90fc883ab379fb2818ea1fedf07b57ce28f Mon Sep 17 00:00:00 2001 From: clemlak Date: Wed, 20 Mar 2024 19:43:35 +0400 Subject: [PATCH 18/38] fix: override validateDeallocate in ConstantSum --- src/ConstantSum/ConstantSum.sol | 39 +++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/ConstantSum/ConstantSum.sol b/src/ConstantSum/ConstantSum.sol index 81811702..b8032da5 100644 --- a/src/ConstantSum/ConstantSum.sol +++ b/src/ConstantSum/ConstantSum.sol @@ -117,6 +117,45 @@ contract ConstantSum is PairStrategy { valid = invariant >= 0; } + function validateDeallocate( + address, + uint256 poolId, + Pool memory pool, + bytes calldata data + ) + external + view + override + returns ( + bool valid, + int256 invariant, + uint256[] memory deltas, + uint256 deltaLiquidity + ) + { + (uint256 deltaX, uint256 deltaY, uint256 maxDeltaL) = + abi.decode(data, (uint256, uint256, uint256)); + + deltaLiquidity = + computeDeltaLiquidity(deltaX, deltaY, internalParams[poolId].price); + if (maxDeltaL > deltaLiquidity) revert InvalidDeltaLiquidity(); + + deltas = new uint256[](2); + deltas[0] = deltaX; + deltas[1] = deltaY; + + pool.reserves[0] -= deltaX; + pool.reserves[1] -= deltaY; + + invariant = tradingFunction( + pool.reserves, + pool.totalLiquidity - deltaLiquidity, + getPoolParams(poolId) + ); + + valid = invariant >= 0; + } + /// @inheritdoc IStrategy function update( address sender, From f3698b1a9bc580ac97896006f47ff1f775d552e6 Mon Sep 17 00:00:00 2001 From: clemlak Date: Wed, 20 Mar 2024 19:44:00 +0400 Subject: [PATCH 19/38] fix: remove incorrect functions in ConstantSumMath --- src/ConstantSum/ConstantSumMath.sol | 68 ----------------------------- 1 file changed, 68 deletions(-) diff --git a/src/ConstantSum/ConstantSumMath.sol b/src/ConstantSum/ConstantSumMath.sol index f7e5d9ff..94dc3aeb 100644 --- a/src/ConstantSum/ConstantSumMath.sol +++ b/src/ConstantSum/ConstantSumMath.sol @@ -40,71 +40,3 @@ function computeDeltaLiquidity( ) pure returns (uint256) { return price.mulWadUp(deltaX) + deltaY; } - -function computeDeallocateGivenDeltaX( - uint256 deltaX, - uint256 rX, - uint256 rY, - uint256 totalLiquidity -) pure returns (uint256 deltaY, uint256 deltaL) { - uint256 a = deltaX.divWadDown(rX); - if (rY > 0) { - deltaY = a.mulWadDown(rY); - } - deltaL = a.mulWadDown(totalLiquidity); -} - -function computeDeallocateGivenDeltaY( - uint256 deltaY, - uint256 rX, - uint256 rY, - uint256 totalLiquidity -) pure returns (uint256 deltaX, uint256 deltaL) { - uint256 a = deltaY.divWadDown(rY); - if (rX > 0) { - deltaX = a.mulWadDown(rX); - } - deltaL = a.mulWadDown(totalLiquidity); -} - -function computeAllocateGivenDeltaX( - uint256 deltaX, - uint256 rX, - uint256 rY, - uint256 totalLiquidity -) pure returns (uint256 deltaY, uint256 deltaL) { - uint256 a = deltaX.divWadUp(rX); - if (rY > 0) { - deltaY = a.mulWadUp(rY); - } - deltaL = a.mulWadUp(totalLiquidity); -} - -function computeAllocateGivenDeltaY( - uint256 deltaY, - uint256 rX, - uint256 rY, - uint256 totalLiquidity -) pure returns (uint256 deltaX, uint256 deltaL) { - uint256 a = deltaY.divWadUp(rY); - if (rX > 0) { - deltaX = a.mulWadUp(rX); - } - deltaL = a.mulWadUp(totalLiquidity); -} - -function computeDeltaGivenDeltaLRoundUp( - uint256 reserve, - uint256 deltaLiquidity, - uint256 totalLiquidity -) pure returns (uint256) { - return reserve.mulWadUp(deltaLiquidity.divWadUp(totalLiquidity)); -} - -function computeDeltaGivenDeltaLRoundDown( - uint256 reserve, - uint256 deltaLiquidity, - uint256 totalLiquidity -) pure returns (uint256) { - return reserve.mulWadDown(deltaLiquidity.divWadDown(totalLiquidity)); -} From 5fcbba3008026ce926e448f98610ebac1c8b6787 Mon Sep 17 00:00:00 2001 From: clemlak Date: Wed, 20 Mar 2024 19:44:12 +0400 Subject: [PATCH 20/38] test: update test_ConstantSum_allocate_Works --- test/ConstantSum/unit/Allocate.t.sol | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/test/ConstantSum/unit/Allocate.t.sol b/test/ConstantSum/unit/Allocate.t.sol index 94c19cc6..3e21e32b 100644 --- a/test/ConstantSum/unit/Allocate.t.sol +++ b/test/ConstantSum/unit/Allocate.t.sol @@ -1,17 +1,21 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; -import { console } from "forge-std/console.sol"; import { ConstantSumSetUp } from "./SetUp.sol"; +import { + computeDeltaLiquidity, + ConstantSumParams +} from "src/ConstantSum/ConstantSumMath.sol"; contract ConstantSumAllocateTest is ConstantSumSetUp { -/* function test_ConstantSum_allocate_Works() public defaultPool { uint256 deltaX = 0.1 ether; uint256 deltaY = 0.1 ether; - (bool valid, bytes memory data) = - solver.simulateAllocate(POOL_ID, deltaX, deltaY); - console.log("valid", valid); + + ConstantSumParams memory params = + abi.decode(constantSum.getPoolParams(POOL_ID), (ConstantSumParams)); + + uint256 deltaL = computeDeltaLiquidity(deltaX, deltaY, params.price); + dfmm.allocate(POOL_ID, abi.encode(deltaX, deltaY, deltaL)); } - */ } From 94a304d353e67a8357702e6ee00f97f7d4dfe9a5 Mon Sep 17 00:00:00 2001 From: clemlak Date: Thu, 21 Mar 2024 08:43:30 +0400 Subject: [PATCH 21/38] test: fix ConstantSum init test --- test/ConstantSum/ConstantSumTest.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ConstantSum/ConstantSumTest.t.sol b/test/ConstantSum/ConstantSumTest.t.sol index 3d7060c7..cb2bcc9d 100644 --- a/test/ConstantSum/ConstantSumTest.t.sol +++ b/test/ConstantSum/ConstantSumTest.t.sol @@ -111,7 +111,7 @@ contract ConstantSumTest is Test { assertEq(pool.reserves[0], 1 ether); assertEq(pool.reserves[1], 1 ether); - assertEq(pool.totalLiquidity, 1.5 ether); + assertEq(pool.totalLiquidity, 3 ether); } function test_constant_sum_swap_x_in_no_fee() public basic_feeless { From bd3c6807ad1ae681a8d91337435d70bb2e503500 Mon Sep 17 00:00:00 2001 From: clemlak Date: Thu, 21 Mar 2024 08:46:01 +0400 Subject: [PATCH 22/38] test: add test_ConstantSum_init_TransfersTokens --- test/ConstantSum/unit/Init.t.sol | 50 ++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/test/ConstantSum/unit/Init.t.sol b/test/ConstantSum/unit/Init.t.sol index f5792377..1d81a4dc 100644 --- a/test/ConstantSum/unit/Init.t.sol +++ b/test/ConstantSum/unit/Init.t.sol @@ -37,4 +37,54 @@ contract ConstantSumInitTest is ConstantSumSetUp { dfmm.init(initParams); } + + function test_ConstantSum_init_TransfersTokens() public { + uint256 price = 1 ether; + + ConstantSumParams memory params = ConstantSumParams({ + price: price, + swapFee: TEST_SWAP_FEE, + controller: address(this) + }); + + uint256 reserveX = 1 ether; + uint256 reserveY = 1 ether; + + bytes memory initData = + solver.getInitialPoolData(reserveX, reserveY, params); + + address[] memory tokens = new address[](2); + tokens[0] = address(tokenX); + tokens[1] = address(tokenY); + + InitParams memory initParams = InitParams({ + name: "", + symbol: "", + strategy: address(constantSum), + tokens: tokens, + data: initData, + feeCollector: address(0), + controllerFee: 0 + }); + + uint256 dfmmPreTokenXBalance = tokenX.balanceOf(address(dfmm)); + uint256 dfmmPreTokenYBalance = tokenY.balanceOf(address(dfmm)); + uint256 userPreTokenXBalance = tokenX.balanceOf(address(this)); + uint256 userPreTokenYBalance = tokenY.balanceOf(address(this)); + + dfmm.init(initParams); + + uint256 dfmmPostTokenXBalance = tokenX.balanceOf(address(dfmm)); + uint256 dfmmPostTokenYBalance = tokenY.balanceOf(address(dfmm)); + uint256 userPostTokenXBalance = tokenX.balanceOf(address(this)); + uint256 userPostTokenYBalance = tokenY.balanceOf(address(this)); + + assertEq(dfmmPreTokenXBalance + reserveX, dfmmPostTokenXBalance); + + assertEq(dfmmPreTokenYBalance + reserveY, dfmmPostTokenYBalance); + + assertEq(userPreTokenXBalance - reserveX, userPostTokenXBalance); + + assertEq(userPreTokenYBalance - reserveY, userPostTokenYBalance); + } } From b30f8b462a47348fbc3b8e69d4ab7c0135144dea Mon Sep 17 00:00:00 2001 From: clemlak Date: Thu, 21 Mar 2024 08:48:37 +0400 Subject: [PATCH 23/38] test: update test_ConstantSum_init_InitializesPool --- test/ConstantSum/unit/Init.t.sol | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/ConstantSum/unit/Init.t.sol b/test/ConstantSum/unit/Init.t.sol index 1d81a4dc..1794f26b 100644 --- a/test/ConstantSum/unit/Init.t.sol +++ b/test/ConstantSum/unit/Init.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; -import { ConstantSumSetUp } from "./SetUp.sol"; import { ConstantSum, ConstantSumParams } from "src/ConstantSum/ConstantSum.sol"; -import { DFMM, IDFMM, InitParams } from "src/DFMM.sol"; +import { Pool, InitParams } from "src/interfaces/IDFMM.sol"; +import { ConstantSumSetUp } from "./SetUp.sol"; contract ConstantSumInitTest is ConstantSumSetUp { function test_ConstantSum_init_InitializesPool() public { @@ -35,7 +35,11 @@ contract ConstantSumInitTest is ConstantSumSetUp { controllerFee: 0 }); - dfmm.init(initParams); + (POOL_ID,,) = dfmm.init(initParams); + Pool memory pool = dfmm.pools(POOL_ID); + + assertEq(pool.reserves[0], reserveX); + assertEq(pool.reserves[1], reserveY); } function test_ConstantSum_init_TransfersTokens() public { @@ -80,11 +84,8 @@ contract ConstantSumInitTest is ConstantSumSetUp { uint256 userPostTokenYBalance = tokenY.balanceOf(address(this)); assertEq(dfmmPreTokenXBalance + reserveX, dfmmPostTokenXBalance); - assertEq(dfmmPreTokenYBalance + reserveY, dfmmPostTokenYBalance); - assertEq(userPreTokenXBalance - reserveX, userPostTokenXBalance); - assertEq(userPreTokenYBalance - reserveY, userPostTokenYBalance); } } From f82f84ce335b6ec2de1ec3ffb944c10e4eafc922 Mon Sep 17 00:00:00 2001 From: clemlak Date: Fri, 22 Mar 2024 12:47:26 +0400 Subject: [PATCH 24/38] test: move ConstantSum init test to dedicated test file --- test/ConstantSum/ConstantSumTest.t.sol | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/test/ConstantSum/ConstantSumTest.t.sol b/test/ConstantSum/ConstantSumTest.t.sol index cb2bcc9d..cbe629be 100644 --- a/test/ConstantSum/ConstantSumTest.t.sol +++ b/test/ConstantSum/ConstantSumTest.t.sol @@ -100,20 +100,6 @@ contract ConstantSumTest is Test { _; } - function test_init() public basic { - (ConstantSumParams memory params) = - abi.decode(constantSum.getPoolParams(POOL_ID), (ConstantSumParams)); - assertEq(params.price, 2 ether); - assertEq(params.swapFee, 0.003 ether); - assertEq(params.controller, address(0)); - - Pool memory pool = dfmm.pools(POOL_ID); - - assertEq(pool.reserves[0], 1 ether); - assertEq(pool.reserves[1], 1 ether); - assertEq(pool.totalLiquidity, 3 ether); - } - function test_constant_sum_swap_x_in_no_fee() public basic_feeless { uint256 preDfmmBalanceX = tokenX.balanceOf(address(dfmm)); uint256 preDfmmBalanceY = tokenY.balanceOf(address(dfmm)); From 4f29be90660aadf387745587489d3e39ba5251b9 Mon Sep 17 00:00:00 2001 From: clemlak Date: Fri, 22 Mar 2024 12:47:35 +0400 Subject: [PATCH 25/38] test: add test_ConstantSum_init_StoresPoolParams --- test/ConstantSum/unit/Init.t.sol | 41 ++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/test/ConstantSum/unit/Init.t.sol b/test/ConstantSum/unit/Init.t.sol index 1794f26b..ec4b9792 100644 --- a/test/ConstantSum/unit/Init.t.sol +++ b/test/ConstantSum/unit/Init.t.sol @@ -42,6 +42,47 @@ contract ConstantSumInitTest is ConstantSumSetUp { assertEq(pool.reserves[1], reserveY); } + // This test doesn't pass because the `controller` param is not stored + function test_ConstantSum_init_StoresPoolParams() public { + skip(); + + uint256 price = 1 ether; + + ConstantSumParams memory params = ConstantSumParams({ + price: price, + swapFee: TEST_SWAP_FEE, + controller: address(this) + }); + + uint256 reserveX = 1 ether; + uint256 reserveY = 1 ether; + + bytes memory initData = + solver.getInitialPoolData(reserveX, reserveY, params); + + address[] memory tokens = new address[](2); + tokens[0] = address(tokenX); + tokens[1] = address(tokenY); + + InitParams memory initParams = InitParams({ + name: "", + symbol: "", + strategy: address(constantSum), + tokens: tokens, + data: initData, + feeCollector: address(0), + controllerFee: 0 + }); + + (POOL_ID,,) = dfmm.init(initParams); + ConstantSumParams memory poolParams = + abi.decode(constantSum.getPoolParams(POOL_ID), (ConstantSumParams)); + + assertEq(poolParams.price, price); + assertEq(poolParams.swapFee, TEST_SWAP_FEE); + assertEq(poolParams.controller, address(this)); + } + function test_ConstantSum_init_TransfersTokens() public { uint256 price = 1 ether; From 9f6da08427761b854b392c802614466456604e87 Mon Sep 17 00:00:00 2001 From: clemlak Date: Fri, 22 Mar 2024 13:41:12 +0400 Subject: [PATCH 26/38] test: move ConstantSum no swap fees tests --- test/ConstantSum/ConstantSumTest.t.sol | 47 ------------------------ test/ConstantSum/unit/SetUp.sol | 26 ++++++++++++++ test/ConstantSum/unit/Swap.t.sol | 49 +++++++++++++++++++++++++- 3 files changed, 74 insertions(+), 48 deletions(-) diff --git a/test/ConstantSum/ConstantSumTest.t.sol b/test/ConstantSum/ConstantSumTest.t.sol index cbe629be..ef31ddbe 100644 --- a/test/ConstantSum/ConstantSumTest.t.sol +++ b/test/ConstantSum/ConstantSumTest.t.sol @@ -100,53 +100,6 @@ contract ConstantSumTest is Test { _; } - function test_constant_sum_swap_x_in_no_fee() public basic_feeless { - uint256 preDfmmBalanceX = tokenX.balanceOf(address(dfmm)); - uint256 preDfmmBalanceY = tokenY.balanceOf(address(dfmm)); - uint256 preUserBalanceX = tokenX.balanceOf(address(this)); - uint256 preUserBalanceY = tokenY.balanceOf(address(this)); - - bool isSwapXForY = true; - uint256 amountIn = 0.1 ether; - - (,, bytes memory swapData) = - solver.simulateSwap(POOL_ID, isSwapXForY, amountIn); - (,, uint256 inputAmount, uint256 outputAmount) = - dfmm.swap(POOL_ID, address(this), swapData); - - assertEq(tokenX.balanceOf(address(dfmm)), preDfmmBalanceX + inputAmount); - assertEq( - tokenY.balanceOf(address(dfmm)), preDfmmBalanceY - outputAmount - ); - assertEq(tokenX.balanceOf(address(this)), preUserBalanceX - inputAmount); - assertEq( - tokenY.balanceOf(address(this)), preUserBalanceY + outputAmount - ); - } - - function test_constant_sum_swap_y_in_no_fee() public basic_feeless { - uint256 preDfmmBalanceX = tokenX.balanceOf(address(dfmm)); - uint256 preDfmmBalanceY = tokenY.balanceOf(address(dfmm)); - uint256 preUserBalanceX = tokenX.balanceOf(address(this)); - uint256 preUserBalanceY = tokenY.balanceOf(address(this)); - - bool isSwapXForY = false; - uint256 amountIn = 0.1 ether; - (,, bytes memory swapData) = - solver.simulateSwap(POOL_ID, isSwapXForY, amountIn); - (,, uint256 inputAmount, uint256 outputAmount) = - dfmm.swap(POOL_ID, address(this), swapData); - - assertEq( - tokenX.balanceOf(address(dfmm)), preDfmmBalanceX - outputAmount - ); - assertEq(tokenY.balanceOf(address(dfmm)), preDfmmBalanceY + inputAmount); - assertEq( - tokenX.balanceOf(address(this)), preUserBalanceX + outputAmount - ); - assertEq(tokenY.balanceOf(address(this)), preUserBalanceY - inputAmount); - } - function test_constant_sum_swap_x_in_invalid() public basic_feeless { bool xIn = true; uint256 amountIn = 1.1 ether; diff --git a/test/ConstantSum/unit/SetUp.sol b/test/ConstantSum/unit/SetUp.sol index 4a6acad2..0e7e3100 100644 --- a/test/ConstantSum/unit/SetUp.sol +++ b/test/ConstantSum/unit/SetUp.sol @@ -55,4 +55,30 @@ contract ConstantSumSetUp is SetUp { _; } + + modifier zeroFeePool() { + uint256 reserveX = 1 ether; + uint256 reserveY = 1 ether; + + bytes memory initData = + solver.getInitialPoolData(reserveX, reserveY, zeroFeeParams); + + address[] memory tokens = new address[](2); + tokens[0] = address(tokenX); + tokens[1] = address(tokenY); + + InitParams memory initParams = InitParams({ + name: "", + symbol: "", + strategy: address(constantSum), + tokens: tokens, + data: initData, + feeCollector: address(0), + controllerFee: 0 + }); + + (POOL_ID,,) = dfmm.init(initParams); + + _; + } } diff --git a/test/ConstantSum/unit/Swap.t.sol b/test/ConstantSum/unit/Swap.t.sol index 6c27f322..7f7ec1f3 100644 --- a/test/ConstantSum/unit/Swap.t.sol +++ b/test/ConstantSum/unit/Swap.t.sol @@ -3,4 +3,51 @@ pragma solidity ^0.8.13; import { ConstantSumSetUp } from "./SetUp.sol"; -contract ConstantSumSwapTest is ConstantSumSetUp { } +contract ConstantSumSwapTest is ConstantSumSetUp { + function test_ConstantSum_swap_SwapsXNoFee() public zeroFeePool { + uint256 preDfmmBalanceX = tokenX.balanceOf(address(dfmm)); + uint256 preDfmmBalanceY = tokenY.balanceOf(address(dfmm)); + uint256 preUserBalanceX = tokenX.balanceOf(address(this)); + uint256 preUserBalanceY = tokenY.balanceOf(address(this)); + + bool isSwapXForY = true; + uint256 amountIn = 0.1 ether; + + (,, bytes memory swapData) = + solver.simulateSwap(POOL_ID, isSwapXForY, amountIn); + (,, uint256 inputAmount, uint256 outputAmount) = + dfmm.swap(POOL_ID, address(this), swapData); + + assertEq(tokenX.balanceOf(address(dfmm)), preDfmmBalanceX + inputAmount); + assertEq( + tokenY.balanceOf(address(dfmm)), preDfmmBalanceY - outputAmount + ); + assertEq(tokenX.balanceOf(address(this)), preUserBalanceX - inputAmount); + assertEq( + tokenY.balanceOf(address(this)), preUserBalanceY + outputAmount + ); + } + + function test_ConstantSum_swap_SwapsYNoFee() public zeroFeePool { + uint256 preDfmmBalanceX = tokenX.balanceOf(address(dfmm)); + uint256 preDfmmBalanceY = tokenY.balanceOf(address(dfmm)); + uint256 preUserBalanceX = tokenX.balanceOf(address(this)); + uint256 preUserBalanceY = tokenY.balanceOf(address(this)); + + bool isSwapXForY = false; + uint256 amountIn = 0.1 ether; + (,, bytes memory swapData) = + solver.simulateSwap(POOL_ID, isSwapXForY, amountIn); + (,, uint256 inputAmount, uint256 outputAmount) = + dfmm.swap(POOL_ID, address(this), swapData); + + assertEq( + tokenX.balanceOf(address(dfmm)), preDfmmBalanceX - outputAmount + ); + assertEq(tokenY.balanceOf(address(dfmm)), preDfmmBalanceY + inputAmount); + assertEq( + tokenX.balanceOf(address(this)), preUserBalanceX + outputAmount + ); + assertEq(tokenY.balanceOf(address(this)), preUserBalanceY - inputAmount); + } +} From c63ce0c809278d52326861e014a72774c2c4b256 Mon Sep 17 00:00:00 2001 From: clemlak Date: Fri, 22 Mar 2024 14:47:01 +0400 Subject: [PATCH 27/38] test: move ConstantSum validateSwap tests to dedicated test file --- test/ConstantSum/ConstantSumTest.t.sol | 14 -------------- test/ConstantSum/unit/ValidateSwap.t.sol | 23 ++++++++++++++++++++++- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/test/ConstantSum/ConstantSumTest.t.sol b/test/ConstantSum/ConstantSumTest.t.sol index ef31ddbe..43a67025 100644 --- a/test/ConstantSum/ConstantSumTest.t.sol +++ b/test/ConstantSum/ConstantSumTest.t.sol @@ -100,20 +100,6 @@ contract ConstantSumTest is Test { _; } - function test_constant_sum_swap_x_in_invalid() public basic_feeless { - bool xIn = true; - uint256 amountIn = 1.1 ether; - vm.expectRevert(ConstantSumSolver.NotEnoughLiquidity.selector); - solver.simulateSwap(POOL_ID, xIn, amountIn); - } - - function test_constant_sum_swap_y_in_invalid() public basic_feeless { - bool xIn = false; - uint256 amountIn = 2.1 ether; - vm.expectRevert(ConstantSumSolver.NotEnoughLiquidity.selector); - solver.simulateSwap(POOL_ID, xIn, amountIn); - } - function test_constant_sum_swap_x_in_with_fee() public basic { uint256 preDfmmBalanceX = tokenX.balanceOf(address(dfmm)); uint256 preDfmmBalanceY = tokenY.balanceOf(address(dfmm)); diff --git a/test/ConstantSum/unit/ValidateSwap.t.sol b/test/ConstantSum/unit/ValidateSwap.t.sol index 382faf8e..6327d061 100644 --- a/test/ConstantSum/unit/ValidateSwap.t.sol +++ b/test/ConstantSum/unit/ValidateSwap.t.sol @@ -1,6 +1,27 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; +import { ConstantSumSolver } from "src/ConstantSum/ConstantSumSolver.sol"; import { ConstantSumSetUp } from "./SetUp.sol"; -contract ConstantSumValidateSwapTest is ConstantSumSetUp { } +contract ConstantSumValidateSwapTest is ConstantSumSetUp { + function test_ConstantSum_simulateSwap_RevertsInvalidSwapX() + public + defaultPool + { + bool xIn = true; + uint256 amountIn = 1.1 ether; + vm.expectRevert(ConstantSumSolver.NotEnoughLiquidity.selector); + solver.simulateSwap(POOL_ID, xIn, amountIn); + } + + function test_ConstantSum_simulateSwap_RevertsInvalidSwapY() + public + defaultPool + { + bool xIn = false; + uint256 amountIn = 2.1 ether; + vm.expectRevert(ConstantSumSolver.NotEnoughLiquidity.selector); + solver.simulateSwap(POOL_ID, xIn, amountIn); + } +} From 8fbbc8c31c9553a20aea9555343f44fe1dccb0a9 Mon Sep 17 00:00:00 2001 From: clemlak Date: Fri, 22 Mar 2024 14:48:34 +0400 Subject: [PATCH 28/38] test: move ConstantSum swap tests to dedicated test file --- test/ConstantSum/ConstantSumTest.t.sol | 45 ------------------------- test/ConstantSum/unit/Swap.t.sol | 46 ++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 45 deletions(-) diff --git a/test/ConstantSum/ConstantSumTest.t.sol b/test/ConstantSum/ConstantSumTest.t.sol index 43a67025..86466253 100644 --- a/test/ConstantSum/ConstantSumTest.t.sol +++ b/test/ConstantSum/ConstantSumTest.t.sol @@ -100,51 +100,6 @@ contract ConstantSumTest is Test { _; } - function test_constant_sum_swap_x_in_with_fee() public basic { - uint256 preDfmmBalanceX = tokenX.balanceOf(address(dfmm)); - uint256 preDfmmBalanceY = tokenY.balanceOf(address(dfmm)); - uint256 preUserBalanceX = tokenX.balanceOf(address(this)); - uint256 preUserBalanceY = tokenY.balanceOf(address(this)); - - bool isSwapXForY = true; - uint256 amountIn = 0.1 ether; - (,, bytes memory swapData) = - solver.simulateSwap(POOL_ID, isSwapXForY, amountIn); - (,, uint256 inputAmount, uint256 outputAmount) = - dfmm.swap(POOL_ID, address(this), swapData); - - assertEq(tokenX.balanceOf(address(dfmm)), preDfmmBalanceX + inputAmount); - assertEq( - tokenY.balanceOf(address(dfmm)), preDfmmBalanceY - outputAmount - ); - assertEq(tokenX.balanceOf(address(this)), preUserBalanceX - inputAmount); - assertEq( - tokenY.balanceOf(address(this)), preUserBalanceY + outputAmount - ); - } - - function test_constant_sum_swap_y_in_with_fee() public basic { - uint256 preDfmmBalanceX = tokenX.balanceOf(address(dfmm)); - uint256 preDfmmBalanceY = tokenY.balanceOf(address(dfmm)); - uint256 preUserBalanceX = tokenX.balanceOf(address(this)); - uint256 preUserBalanceY = tokenY.balanceOf(address(this)); - - bool isSwapXForY = false; - uint256 amountIn = 0.1 ether; - (,, bytes memory swapData) = - solver.simulateSwap(POOL_ID, isSwapXForY, amountIn); - (,, uint256 inputAmount, uint256 outputAmount) = - dfmm.swap(POOL_ID, address(this), swapData); - - assertEq( - tokenX.balanceOf(address(dfmm)), preDfmmBalanceX - outputAmount - ); - assertEq(tokenY.balanceOf(address(dfmm)), preDfmmBalanceY + inputAmount); - assertEq( - tokenX.balanceOf(address(this)), preUserBalanceX + outputAmount - ); - assertEq(tokenY.balanceOf(address(this)), preUserBalanceY - inputAmount); - } /* function test_constant_sum_allocate() public basic { uint256 poolId = dfmm.nonce() - 1; diff --git a/test/ConstantSum/unit/Swap.t.sol b/test/ConstantSum/unit/Swap.t.sol index 7f7ec1f3..17384f7c 100644 --- a/test/ConstantSum/unit/Swap.t.sol +++ b/test/ConstantSum/unit/Swap.t.sol @@ -28,6 +28,52 @@ contract ConstantSumSwapTest is ConstantSumSetUp { ); } + function test_ConstantSum_swap_SwapsX() public defaultPool { + uint256 preDfmmBalanceX = tokenX.balanceOf(address(dfmm)); + uint256 preDfmmBalanceY = tokenY.balanceOf(address(dfmm)); + uint256 preUserBalanceX = tokenX.balanceOf(address(this)); + uint256 preUserBalanceY = tokenY.balanceOf(address(this)); + + bool isSwapXForY = true; + uint256 amountIn = 0.1 ether; + (,, bytes memory swapData) = + solver.simulateSwap(POOL_ID, isSwapXForY, amountIn); + (,, uint256 inputAmount, uint256 outputAmount) = + dfmm.swap(POOL_ID, address(this), swapData); + + assertEq(tokenX.balanceOf(address(dfmm)), preDfmmBalanceX + inputAmount); + assertEq( + tokenY.balanceOf(address(dfmm)), preDfmmBalanceY - outputAmount + ); + assertEq(tokenX.balanceOf(address(this)), preUserBalanceX - inputAmount); + assertEq( + tokenY.balanceOf(address(this)), preUserBalanceY + outputAmount + ); + } + + function test_ConstantSum_swap_SwapsY() public defaultPool { + uint256 preDfmmBalanceX = tokenX.balanceOf(address(dfmm)); + uint256 preDfmmBalanceY = tokenY.balanceOf(address(dfmm)); + uint256 preUserBalanceX = tokenX.balanceOf(address(this)); + uint256 preUserBalanceY = tokenY.balanceOf(address(this)); + + bool isSwapXForY = false; + uint256 amountIn = 0.1 ether; + (,, bytes memory swapData) = + solver.simulateSwap(POOL_ID, isSwapXForY, amountIn); + (,, uint256 inputAmount, uint256 outputAmount) = + dfmm.swap(POOL_ID, address(this), swapData); + + assertEq( + tokenX.balanceOf(address(dfmm)), preDfmmBalanceX - outputAmount + ); + assertEq(tokenY.balanceOf(address(dfmm)), preDfmmBalanceY + inputAmount); + assertEq( + tokenX.balanceOf(address(this)), preUserBalanceX + outputAmount + ); + assertEq(tokenY.balanceOf(address(this)), preUserBalanceY - inputAmount); + } + function test_ConstantSum_swap_SwapsYNoFee() public zeroFeePool { uint256 preDfmmBalanceX = tokenX.balanceOf(address(dfmm)); uint256 preDfmmBalanceY = tokenY.balanceOf(address(dfmm)); From a946a7cd442114971bc14856a8911fb02fabebb0 Mon Sep 17 00:00:00 2001 From: clemlak Date: Fri, 22 Mar 2024 14:49:00 +0400 Subject: [PATCH 29/38] test: remove old ConstantSumTest --- test/ConstantSum/ConstantSumTest.t.sol | 159 ------------------------- 1 file changed, 159 deletions(-) delete mode 100644 test/ConstantSum/ConstantSumTest.t.sol diff --git a/test/ConstantSum/ConstantSumTest.t.sol b/test/ConstantSum/ConstantSumTest.t.sol deleted file mode 100644 index 86466253..00000000 --- a/test/ConstantSum/ConstantSumTest.t.sol +++ /dev/null @@ -1,159 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.13; - -import "forge-std/Test.sol"; -import "solmate/test/utils/mocks/MockERC20.sol"; -import "src/DFMM.sol"; -import "src/ConstantSum/ConstantSum.sol"; -import "src/ConstantSum/ConstantSumSolver.sol"; - -contract ConstantSumTest is Test { - using stdStorage for StdStorage; - - DFMM dfmm; - ConstantSum constantSum; - ConstantSumSolver solver; - MockERC20 tokenX; - MockERC20 tokenY; - - uint256 POOL_ID; - - uint256 public constant TEST_ZERO_FEE = 0; - uint256 public constant TEST_SWAP_FEE = 0.003 ether; - - function setUp() public { - tokenX = new MockERC20("tokenX", "X", 18); - tokenY = new MockERC20("tokenY", "Y", 18); - tokenX.mint(address(this), 100_000_000 ether); - tokenY.mint(address(this), 100_000_000 ether); - - dfmm = new DFMM(address(0)); - constantSum = new ConstantSum(address(dfmm)); - solver = new ConstantSumSolver(address(constantSum)); - tokenX.approve(address(dfmm), type(uint256).max); - tokenY.approve(address(dfmm), type(uint256).max); - } - - modifier basic_feeless() { - vm.warp(0); - - ConstantSumParams memory params = ConstantSumParams({ - price: ONE * 2, - swapFee: 0, - controller: address(0) - }); - - uint256 init_x = ONE * 1; - uint256 init_y = ONE * 1; - - bytes memory initData = - solver.getInitialPoolData(init_x, init_y, params); - - address[] memory tokens = new address[](2); - tokens[0] = address(tokenX); - tokens[1] = address(tokenY); - - InitParams memory initParams = InitParams({ - name: "", - symbol: "", - strategy: address(constantSum), - tokens: tokens, - data: initData, - feeCollector: address(0), - controllerFee: 0 - }); - - (POOL_ID,,) = dfmm.init(initParams); - _; - } - - modifier basic() { - vm.warp(0); - - ConstantSumParams memory params = ConstantSumParams({ - price: ONE * 2, - swapFee: TEST_SWAP_FEE, - controller: address(0) - }); - - uint256 init_x = ONE * 1; - uint256 init_y = ONE * 1; - - bytes memory initData = - solver.getInitialPoolData(init_x, init_y, params); - - address[] memory tokens = new address[](2); - tokens[0] = address(tokenX); - tokens[1] = address(tokenY); - - InitParams memory initParams = InitParams({ - name: "", - symbol: "", - strategy: address(constantSum), - tokens: tokens, - data: initData, - feeCollector: address(0), - controllerFee: 0 - }); - - (POOL_ID,,) = dfmm.init(initParams); - _; - } - - /* - function test_constant_sum_allocate() public basic { - uint256 poolId = dfmm.nonce() - 1; - uint256 amountX = 0.1 ether; - uint256 amountY = 0.1 ether; - (bool valid, bytes memory swapData) = - solver.simulateAllocate(poolId, amountX, amountY); - console2.log("Valid: ", valid); - assert(valid); - - (uint256 endReservesRx, uint256 endReservesRy, uint256 endReservesL) = - abi.decode(swapData, (uint256, uint256, uint256)); - - console2.log("endReservesRx: ", endReservesRx); - assertEq(endReservesRx, 1.1 ether); - - console2.log("endReservesRy: ", endReservesRy); - assertEq(endReservesRy, 1.1 ether); - - console2.log("endReservesL: ", endReservesL); - assertEq(endReservesL, 1.65 ether); - - dfmm.allocate(poolId, swapData); - } - - function test_constant_sum_deallocate() public basic { - uint256 poolId = dfmm.nonce() - 1; - uint256 amountX = 0.1 ether; - uint256 amountY = 0.1 ether; - (, bytes memory swapData) = - solver.simulateDeallocate(poolId, amountX, amountY); - dfmm.deallocate(poolId, swapData); - } - - function test_constant_sum_fail_deallocate() public basic { - uint256 poolId = dfmm.nonce() - 1; - uint256 amountX = 1.2 ether; - uint256 amountY = 1.2 ether; - vm.expectRevert(ConstantSumSolver.NotEnoughLiquidity.selector); - solver.simulateDeallocate(poolId, amountX, amountY); - } - - function test_constant_sum_price_update() public basic { - uint256 poolId = dfmm.nonce() - 1; - uint256 newPrice = 3 ether; - bytes memory data = encodePriceUpdate(newPrice); - - vm.prank(address(0)); - DFMM(dfmm).update(poolId, data); - - (ConstantSumParams memory newParams) = abi.decode( - constantSum.getPoolParams(poolId), (ConstantSumParams) - ); - assertEq(newParams.price, 3 ether); - } - */ -} From 1fe5af1bf3f8fc6ac70f393ee78053cd4053d9f4 Mon Sep 17 00:00:00 2001 From: clemlak Date: Fri, 22 Mar 2024 14:53:14 +0400 Subject: [PATCH 30/38] test: add ConstantSum update tests --- test/ConstantSum/unit/Update.t.sol | 36 ++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/test/ConstantSum/unit/Update.t.sol b/test/ConstantSum/unit/Update.t.sol index 8ed75a73..26312886 100644 --- a/test/ConstantSum/unit/Update.t.sol +++ b/test/ConstantSum/unit/Update.t.sol @@ -1,6 +1,38 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; -import { ConstantSumSetUp } from "./SetUp.sol"; +import { ConstantSumSetUp, ConstantSumParams } from "./SetUp.sol"; +import { + encodeFeeUpdate, + encodePriceUpdate, + encodeControllerUpdate +} from "src/ConstantSum/ConstantSumUtils.sol"; -contract ConstantSumUpdateTest is ConstantSumSetUp { } +contract ConstantSumUpdateTest is ConstantSumSetUp { + function test_ConstantSum_update_SetsSwapFee() public defaultPool { + skip(); + uint256 newSwapFee = 0.004 ether; + dfmm.update(POOL_ID, encodeFeeUpdate(newSwapFee)); + ConstantSumParams memory poolParams = + abi.decode(constantSum.getPoolParams(POOL_ID), (ConstantSumParams)); + assertEq(poolParams.swapFee, newSwapFee); + } + + function test_ConstantSum_update_SetsPrice() public defaultPool { + skip(); + uint256 newPrice = 3 ether; + dfmm.update(POOL_ID, encodePriceUpdate(newPrice)); + ConstantSumParams memory poolParams = + abi.decode(constantSum.getPoolParams(POOL_ID), (ConstantSumParams)); + assertEq(poolParams.price, newPrice); + } + + function test_ConstantSum_update_SetsController() public defaultPool { + skip(); + address newController = address(this); + dfmm.update(POOL_ID, encodeControllerUpdate(newController)); + ConstantSumParams memory poolParams = + abi.decode(constantSum.getPoolParams(POOL_ID), (ConstantSumParams)); + assertEq(poolParams.controller, newController); + } +} From fb905596bef562e19a3f60c3cd96fd6d24d87f0f Mon Sep 17 00:00:00 2001 From: clemlak Date: Fri, 22 Mar 2024 15:00:34 +0400 Subject: [PATCH 31/38] test: add test_ConstantSum_getPoolParams_ReturnsPoolParams --- test/ConstantSum/unit/GetPoolParams.t.sol | 42 +++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/test/ConstantSum/unit/GetPoolParams.t.sol b/test/ConstantSum/unit/GetPoolParams.t.sol index 8381be67..ced8ae4c 100644 --- a/test/ConstantSum/unit/GetPoolParams.t.sol +++ b/test/ConstantSum/unit/GetPoolParams.t.sol @@ -1,6 +1,44 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; -import { ConstantSumSetUp } from "./SetUp.sol"; +import { ConstantSumParams } from "src/ConstantSum/ConstantSum.sol"; +import { ConstantSumSetUp, InitParams } from "./SetUp.sol"; -contract ConstantSumGetPoolParamsTest is ConstantSumSetUp { } +contract ConstantSumGetPoolParamsTest is ConstantSumSetUp { + function test_ConstantSum_getPoolParams_ReturnsPoolParams() public { + skip(); + ConstantSumParams memory initPoolParams = ConstantSumParams({ + price: 2 ether, + swapFee: TEST_SWAP_FEE, + controller: address(this) + }); + + uint256 reserveX = 1 ether; + uint256 reserveY = 1 ether; + + bytes memory initData = + solver.getInitialPoolData(reserveX, reserveY, defaultParams); + + address[] memory tokens = new address[](2); + tokens[0] = address(tokenX); + tokens[1] = address(tokenY); + + InitParams memory initParams = InitParams({ + name: "", + symbol: "", + strategy: address(constantSum), + tokens: tokens, + data: initData, + feeCollector: address(0), + controllerFee: 0 + }); + + (POOL_ID,,) = dfmm.init(initParams); + + ConstantSumParams memory poolParams = + abi.decode(constantSum.getPoolParams(POOL_ID), (ConstantSumParams)); + assertEq(poolParams.swapFee, initPoolParams.swapFee); + assertEq(poolParams.price, initPoolParams.price); + assertEq(poolParams.controller, initPoolParams.controller); + } +} From 8d8f8cb3e47e8c2f13022c3d160ef823fa3c2e1e Mon Sep 17 00:00:00 2001 From: clemlak Date: Fri, 22 Mar 2024 15:13:22 +0400 Subject: [PATCH 32/38] test: add test_ConstantSum_constructor --- test/ConstantSum/unit/Constructor.t.sol | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/ConstantSum/unit/Constructor.t.sol b/test/ConstantSum/unit/Constructor.t.sol index 136878bb..026e56d3 100644 --- a/test/ConstantSum/unit/Constructor.t.sol +++ b/test/ConstantSum/unit/Constructor.t.sol @@ -1,6 +1,11 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; -import { ConstantSumSetUp } from "./SetUp.sol"; +import { ConstantSumSetUp, ConstantSum } from "./SetUp.sol"; -contract ConstantSumConstructorTest is ConstantSumSetUp { } +contract ConstantSumConstructorTest is ConstantSumSetUp { + function test_ConstantSum_constructor() public { + ConstantSum constantSum = new ConstantSum(address(dfmm)); + assertEq(constantSum.dfmm(), address(dfmm)); + } +} From 0903141b64091fcecfaab14f8504bb2eaee96e62 Mon Sep 17 00:00:00 2001 From: clemlak Date: Fri, 22 Mar 2024 16:39:13 +0400 Subject: [PATCH 33/38] fix: add InvalidReservesLength error to PairStrategy --- src/interfaces/IStrategy.sol | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/interfaces/IStrategy.sol b/src/interfaces/IStrategy.sol index 40027f55..0b10cd9a 100644 --- a/src/interfaces/IStrategy.sol +++ b/src/interfaces/IStrategy.sol @@ -23,6 +23,9 @@ interface IStrategy { /// @dev Thrown when an expected delta does not match the actual delta. error DeltaError(uint256 expected, uint256 actual); + /// @dev Thrown when the reserves length is not 2. + error InvalidReservesLength(); + // Setters /** From af737451449b4d302fe19393caa0cd9449095cbd Mon Sep 17 00:00:00 2001 From: clemlak Date: Fri, 22 Mar 2024 16:39:32 +0400 Subject: [PATCH 34/38] fix: check reserves and tokens array length in ConstantSum --- src/ConstantSum/ConstantSum.sol | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ConstantSum/ConstantSum.sol b/src/ConstantSum/ConstantSum.sol index 08a1c27d..37a5f358 100644 --- a/src/ConstantSum/ConstantSum.sol +++ b/src/ConstantSum/ConstantSum.sol @@ -45,7 +45,7 @@ contract ConstantSum is PairStrategy { function init( address, uint256 poolId, - Pool calldata, + Pool calldata pool, bytes calldata data ) public @@ -61,6 +61,10 @@ contract ConstantSum is PairStrategy { (reserves, totalLiquidity, params) = abi.decode(data, (uint256[], uint256, ConstantSumParams)); + if (pool.reserves.length != 2 || reserves.length != 2) { + revert InvalidReservesLength(); + } + internalParams[poolId].price = params.price; internalParams[poolId].swapFee = params.swapFee; From ca780dcb9498536cd533dd7800363b43d1deb367 Mon Sep 17 00:00:00 2001 From: clemlak Date: Fri, 22 Mar 2024 18:35:30 +0400 Subject: [PATCH 35/38] fix: add pool reserves length check in G3M --- src/GeometricMean/GeometricMean.sol | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/GeometricMean/GeometricMean.sol b/src/GeometricMean/GeometricMean.sol index 1dcf1942..44e372bc 100644 --- a/src/GeometricMean/GeometricMean.sol +++ b/src/GeometricMean/GeometricMean.sol @@ -74,7 +74,7 @@ contract GeometricMean is PairStrategy { function init( address, uint256 poolId, - Pool calldata, + Pool calldata pool, bytes calldata data ) external onlyDFMM returns (bool, int256, uint256[] memory, uint256) { InitState memory state; @@ -92,6 +92,10 @@ contract GeometricMean is PairStrategy { data, (uint256, uint256, uint256, uint256, uint256, address) ); + if (pool.reserves.length != 2) { + revert InvalidReservesLength(); + } + if (state.wX >= ONE) { revert InvalidWeightX(); } From 3bd1bc3d94dd1f2447c01b88b89e15c79bb5187a Mon Sep 17 00:00:00 2001 From: clemlak Date: Fri, 22 Mar 2024 18:37:16 +0400 Subject: [PATCH 36/38] fix: add reserves and tokens array length check in LogNormal --- src/LogNormal/LogNormal.sol | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/LogNormal/LogNormal.sol b/src/LogNormal/LogNormal.sol index 1bcd5513..ccdb3e1a 100644 --- a/src/LogNormal/LogNormal.sol +++ b/src/LogNormal/LogNormal.sol @@ -58,7 +58,7 @@ contract LogNormal is PairStrategy { function init( address, uint256 poolId, - Pool calldata, + Pool calldata pool, bytes calldata data ) public @@ -74,6 +74,10 @@ contract LogNormal is PairStrategy { (reserves, totalLiquidity, params) = abi.decode(data, (uint256[], uint256, LogNormalParams)); + if (pool.reserves.length != 2 || reserves.length != 2) { + revert InvalidReservesLength(); + } + internalParams[poolId].mean.lastComputedValue = params.mean; internalParams[poolId].width.lastComputedValue = params.width; internalParams[poolId].swapFee = params.swapFee; From 22967e49380d76a135c5f92c2565fa90fa3cd6eb Mon Sep 17 00:00:00 2001 From: clemlak Date: Mon, 25 Mar 2024 15:26:30 +0400 Subject: [PATCH 37/38] test: fix test_ConstantSum_getPoolParams_ReturnsPoolParams --- test/ConstantSum/unit/GetPoolParams.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ConstantSum/unit/GetPoolParams.t.sol b/test/ConstantSum/unit/GetPoolParams.t.sol index 47d61f5a..7213df12 100644 --- a/test/ConstantSum/unit/GetPoolParams.t.sol +++ b/test/ConstantSum/unit/GetPoolParams.t.sol @@ -16,7 +16,7 @@ contract ConstantSumGetPoolParamsTest is ConstantSumSetUp { uint256 reserveY = 1 ether; bytes memory initData = - solver.getInitialPoolData(reserveX, reserveY, defaultParams); + solver.getInitialPoolData(reserveX, reserveY, initPoolParams); address[] memory tokens = new address[](2); tokens[0] = address(tokenX); From e3f07d2b3d5a313164f2e0093fab166a8557f3c4 Mon Sep 17 00:00:00 2001 From: clemlak Date: Mon, 25 Mar 2024 17:17:43 +0400 Subject: [PATCH 38/38] feat: G3M init pool data now expects array of reserves --- src/GeometricMean/G3MMath.sol | 7 +++++-- src/GeometricMean/GeometricMean.sol | 11 +++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/GeometricMean/G3MMath.sol b/src/GeometricMean/G3MMath.sol index 0e409569..d5aff9e3 100644 --- a/src/GeometricMean/G3MMath.sol +++ b/src/GeometricMean/G3MMath.sol @@ -251,6 +251,9 @@ function computeInitialPoolData( L = computeNextLiquidity(amountX, rY, invariant, L, params); - return - abi.encode(amountX, rY, L, params.wX, params.swapFee, params.controller); + uint256[] memory reserves = new uint256[](2); + reserves[0] = amountX; + reserves[1] = rY; + + return abi.encode(reserves, L, params.wX, params.swapFee, params.controller); } diff --git a/src/GeometricMean/GeometricMean.sol b/src/GeometricMean/GeometricMean.sol index 44e372bc..3d20d9b2 100644 --- a/src/GeometricMean/GeometricMean.sol +++ b/src/GeometricMean/GeometricMean.sol @@ -79,20 +79,15 @@ contract GeometricMean is PairStrategy { ) external onlyDFMM returns (bool, int256, uint256[] memory, uint256) { InitState memory state; - state.reserves = new uint256[](2); - ( - state.reserves[0], - state.reserves[1], + state.reserves, state.totalLiquidity, state.wX, state.swapFee, state.controller - ) = abi.decode( - data, (uint256, uint256, uint256, uint256, uint256, address) - ); + ) = abi.decode(data, (uint256[], uint256, uint256, uint256, address)); - if (pool.reserves.length != 2) { + if (pool.reserves.length != 2 || state.reserves.length != 2) { revert InvalidReservesLength(); }