diff --git a/src/ConstantSum/ConstantSumMath.sol b/src/ConstantSum/ConstantSumMath.sol index 0f26c7e0..10d3728c 100644 --- a/src/ConstantSum/ConstantSumMath.sol +++ b/src/ConstantSum/ConstantSumMath.sol @@ -50,3 +50,10 @@ function computeSwapDeltaLiquidity( return (params.swapFee).mulDivUp(delta, params.price); } } + +/** + * @dev Computes the price using the reserve of token X. + */ +function computePrice(ConstantSumParams memory params) pure returns (uint256) { + return params.price; +} diff --git a/src/ConstantSum/ConstantSumSolver.sol b/src/ConstantSum/ConstantSumSolver.sol index 644a2e77..8f93862b 100644 --- a/src/ConstantSum/ConstantSumSolver.sol +++ b/src/ConstantSum/ConstantSumSolver.sol @@ -9,43 +9,69 @@ import { encodeFeeUpdate, encodeControllerUpdate } from "./ConstantSumUtils.sol"; +import { + computeAllocationGivenX, + computeAllocationGivenY +} from "src/lib/StrategyLib.sol"; import { ONE, computeInitialPoolData, FixedPointMathLib, computeSwapDeltaLiquidity } from "./ConstantSumMath.sol"; +import { PairSolver } from "src/PairSolver.sol"; -contract ConstantSumSolver { +contract ConstantSumSolver is PairSolver { error NotEnoughLiquidity(); using FixedPointMathLib for uint256; + /// @dev Reserves struct to hold reserve amounts and liquidity struct Reserves { - uint256 rx; - uint256 ry; - uint256 L; + uint256 reserveX; + /// @dev Reserve amount of token X + uint256 reserveY; + /// @dev Reserve amount of token Y + uint256 liquidity; } + /// @dev Total liquidity + /// @dev Address of the strategy contract address public strategy; + /// @notice Constructor to set the strategy address + /// @param strategy_ Address of the strategy contract constructor(address strategy_) { strategy = strategy_; } + /// @notice Computes the initial pool data for a Constant Sum pool + /// @param reserveX The reserve amount of token X + /// @param reserveY The reserve amount of token Y + /// @param params The Constant Sum pool parameters + /// @return The initial pool data encoded as bytes function getInitialPoolData( - uint256 rx, - uint256 ry, + uint256 reserveX, + uint256 reserveY, ConstantSumParams memory params ) public pure returns (bytes memory) { - return computeInitialPoolData(rx, ry, params); + return computeInitialPoolData(reserveX, reserveY, params); } + /// @dev Struct to hold state variables for simulating a swap struct SimulateSwapState { uint256 amountOut; uint256 deltaLiquidity; } + /// @notice Simulates a swap in a Constant Sum pool + /// @dev Used by the kit to simulate a swap and check if it's valid + /// @param poolId The id of the pool to simulate the swap in + /// @param swapXIn Whether the swap is X in for Y out (true) or Y in for X out (false) + /// @param amountIn The amount of tokens to swap in + /// @return valid Whether the simulated swap is valid + /// @return amountOut The amount of tokens that would be received in the swap + /// @return swapData The encoded swap data that can be used to perform the actual swap function simulateSwap( uint256 poolId, bool swapXIn, @@ -91,6 +117,10 @@ contract ConstantSumSolver { return (valid, state.amountOut, swapData); } + /// @notice Prepares the data for updating the price + /// @dev Used by the kit to update the price + /// @param newPrice The new price to set + /// @return The encoded data for updating the price function preparePriceUpdate(uint256 newPrice) public pure @@ -99,6 +129,10 @@ contract ConstantSumSolver { return encodePriceUpdate(newPrice); } + /// @notice Prepares the data for updating the swap fee + /// @dev Used by the kit to update the swap fee + /// @param newSwapFee The new swap fee to set + /// @return The encoded data for updating the swap fee function prepareSwapFeeUpdate(uint256 newSwapFee) public pure @@ -107,6 +141,10 @@ contract ConstantSumSolver { return encodeFeeUpdate(newSwapFee); } + /// @notice Prepares the data for updating the controller address + /// @dev Used by the kit to update the controller + /// @param newController The address of the new controller + /// @return The encoded data for updating the controller function prepareControllerUpdate(address newController) public pure @@ -114,4 +152,54 @@ contract ConstantSumSolver { { return encodeControllerUpdate(newController); } + + /// @notice Gets the reserves and liquidity for a given pool + /// @param poolId The id of the pool + /// @return The reserve of token X, the reserve of token Y, and the total liquidity + function getReservesAndLiquidity(uint256 poolId) + public + view + override + returns (uint256, uint256, uint256) + { + Pool memory pool = IDFMM(IStrategy(strategy).dfmm()).pools(poolId); + return (pool.reserves[0], pool.reserves[1], pool.totalLiquidity); + } + + /// @dev gets the pool params + /// @param poolId The pool id + /// @return params The pool params + function getPoolParams(uint256 poolId) + public + view + returns (ConstantSumParams memory) + { + return abi.decode( + IStrategy(strategy).getPoolParams(poolId), (ConstantSumParams) + ); + } + + /// @dev Computes the change in allocation given a change in X reserve + /// @param poolId The pool id + /// @param deltaX The change in X reserve + /// @return encodedAllocationDelta The encoded change in allocation + function prepareAllocationDeltaGivenDeltaX( + uint256 poolId, + uint256 deltaX + ) public view returns (bytes memory) { + ConstantSumParams memory params = getPoolParams(poolId); + uint256 deltaL = deltaX.mulWadDown(params.price); + return abi.encode(deltaX, 0, deltaL); + } + + /// @dev Computes the change in allocation given a change in Y reserve + /// @param deltaY The change in Y reserve + /// @return encodedAllocationDelta The encoded change in allocation + function prepareAllocationDeltaGivenDeltaY(uint256 deltaY) + public + pure + returns (bytes memory) + { + return abi.encode(0, deltaY, deltaY); + } } diff --git a/src/ConstantSum/README.md b/src/ConstantSum/README.md index e5b414b3..1c826915 100644 --- a/src/ConstantSum/README.md +++ b/src/ConstantSum/README.md @@ -20,7 +20,7 @@ $$ where $L$ is the **liquidity** of the pool. ## Price -The reported price of the pool given the reseres is $P$. +The reported price of the pool given the reserves is $P$. ## Pool initialization The `ConstantSum` pool can be initialized with any given price and any given value of reserves. diff --git a/src/GeometricMean/GeometricMeanSolver.sol b/src/GeometricMean/GeometricMeanSolver.sol index fc87794d..bd50d7ff 100644 --- a/src/GeometricMean/GeometricMeanSolver.sol +++ b/src/GeometricMean/GeometricMeanSolver.sol @@ -22,8 +22,9 @@ import { computePrice, computeSwapDeltaLiquidity } from "./G3MMath.sol"; +import { PairSolver } from "src/PairSolver.sol"; -contract GeometricMeanSolver { +contract GeometricMeanSolver is PairSolver { using FixedPointMathLib for uint256; using FixedPointMathLib for int256; @@ -46,6 +47,7 @@ contract GeometricMeanSolver { function getReservesAndLiquidity(uint256 poolId) public view + override returns (uint256, uint256, uint256) { Pool memory pool = IDFMM(IStrategy(strategy).dfmm()).pools(poolId); @@ -94,50 +96,6 @@ contract GeometricMeanSolver { return computeInitialPoolData(rx, S, params); } - function allocateGivenDeltaX( - uint256 poolId, - uint256 deltaX - ) public view returns (uint256, uint256) { - (uint256 rX, uint256 rY, uint256 totalLiquidity) = - getReservesAndLiquidity(poolId); - (uint256 deltaY, uint256 deltaLiquidity) = - computeAllocationGivenDeltaX(deltaX, rX, rY, totalLiquidity); - return (deltaY, deltaLiquidity); - } - - function allocateGivenDeltaY( - uint256 poolId, - uint256 deltaY - ) public view returns (uint256, uint256) { - (uint256 rX, uint256 rY, uint256 totalLiquidity) = - getReservesAndLiquidity(poolId); - (uint256 deltaX, uint256 deltaLiquidity) = - computeAllocationGivenDeltaY(deltaY, rX, rY, totalLiquidity); - return (deltaX, deltaLiquidity); - } - - function deallocateGivenDeltaX( - uint256 poolId, - uint256 deltaX - ) public view returns (uint256, uint256) { - (uint256 rX, uint256 rY, uint256 totalLiquidity) = - getReservesAndLiquidity(poolId); - (uint256 deltaY, uint256 deltaLiquidity) = - computeDeallocationGivenDeltaX(deltaX, rX, rY, totalLiquidity); - return (deltaY, deltaLiquidity); - } - - function deallocateGivenDeltaY( - uint256 poolId, - uint256 deltaY - ) public view returns (uint256, uint256) { - (uint256 rX, uint256 rY, uint256 totalLiquidity) = - getReservesAndLiquidity(poolId); - (uint256 deltaX, uint256 deltaLiquidity) = - computeDeallocationGivenDeltaY(deltaY, rX, rY, totalLiquidity); - return (deltaX, deltaLiquidity); - } - function getNextReserveX( uint256 poolId, uint256 ry, diff --git a/src/LogNormal/LogNormalSolver.sol b/src/LogNormal/LogNormalSolver.sol index 9266fc85..bc8377fb 100644 --- a/src/LogNormal/LogNormalSolver.sol +++ b/src/LogNormal/LogNormalSolver.sol @@ -4,10 +4,6 @@ pragma solidity 0.8.22; import { FixedPointMathLib } from "solmate/utils/FixedPointMathLib.sol"; import { IStrategy } from "src/interfaces/IStrategy.sol"; import { Pool, IDFMM } from "src/interfaces/IDFMM.sol"; -import { - computeAllocationGivenX, - computeAllocationGivenY -} from "src/lib/StrategyLib.sol"; import { encodeFeeUpdate, encodeMeanUpdate, @@ -28,8 +24,9 @@ import { computeDeltaLXIn, computeDeltaLYIn } from "src/LogNormal/LogNormalMath.sol"; +import { PairSolver } from "src/PairSolver.sol"; -contract LogNormalSolver { +contract LogNormalSolver is PairSolver { using FixedPointMathLib for uint256; using FixedPointMathLib for int256; @@ -59,6 +56,7 @@ contract LogNormalSolver { ); } + /// @notice used by kit function prepareFeeUpdate(uint256 swapFee) external pure @@ -67,6 +65,7 @@ contract LogNormalSolver { return encodeFeeUpdate(swapFee); } + /// @notice used by kit function prepareMeanUpdate( uint256 targetMean, uint256 targetTimestamp @@ -74,6 +73,7 @@ contract LogNormalSolver { return encodeMeanUpdate(targetMean, targetTimestamp); } + /// @notice used by kit function prepareWidthUpdate( uint256 targetWidth, uint256 targetTimestamp @@ -81,6 +81,7 @@ contract LogNormalSolver { return encodeWidthUpdate(targetWidth, targetTimestamp); } + /// @notice used by kit function prepareControllerUpdate(address controller) external pure @@ -92,10 +93,11 @@ contract LogNormalSolver { function getReservesAndLiquidity(uint256 poolId) public view - returns (uint256[] memory, uint256) + override + returns (uint256, uint256, uint256) { Pool memory pool = IDFMM(IStrategy(strategy).dfmm()).pools(poolId); - return (pool.reserves, pool.totalLiquidity); + return (pool.reserves[0], pool.reserves[1], pool.totalLiquidity); } function getInitialPoolData( @@ -106,92 +108,6 @@ contract LogNormalSolver { return computeInitialPoolData(rx, S, params); } - function allocateGivenDeltaX( - uint256 poolId, - uint256 deltaX - ) public view returns (uint256 deltaY, uint256 deltaLiquidity) { - (uint256[] memory reserves, uint256 liquidity) = - getReservesAndLiquidity(poolId); - (uint256 adjustedReserveX, uint256 adjustedLiquidity) = - computeAllocationGivenX(true, deltaX, reserves[0], liquidity); - uint256 approximatedPrice = - getPriceGivenXL(poolId, adjustedReserveX, adjustedLiquidity); - uint256 adjustedReserveY = getNextReserveY( - poolId, adjustedReserveX, adjustedLiquidity, approximatedPrice - ); - deltaY = adjustedReserveY - reserves[1]; - deltaLiquidity = adjustedLiquidity - liquidity; - } - - function allocateGivenDeltaY( - uint256 poolId, - uint256 deltaY - ) public view returns (uint256 deltaX, uint256 deltaLiquidity) { - (uint256[] memory reserves, uint256 liquidity) = - getReservesAndLiquidity(poolId); - (uint256 adjustedReserveY, uint256 adjustedLiquidity) = - computeAllocationGivenY(true, deltaY, reserves[1], liquidity); - uint256 approximatedPrice = - getPriceGivenYL(poolId, adjustedReserveY, adjustedLiquidity); - uint256 adjustedReserveX = getNextReserveX( - poolId, adjustedReserveY, adjustedLiquidity, approximatedPrice - ); - deltaX = adjustedReserveX - reserves[0]; - deltaLiquidity = adjustedLiquidity - liquidity; - } - - function allocateGivenX( - uint256 poolId, - uint256 amountX - ) public view returns (uint256, uint256, uint256) { - (uint256[] memory reserves, uint256 L) = getReservesAndLiquidity(poolId); - (uint256 nextRx, uint256 nextL) = - computeAllocationGivenX(true, amountX, reserves[0], L); - uint256 approximatedPrice = getPriceGivenXL(poolId, nextRx, nextL); - uint256 nextRy = - getNextReserveY(poolId, nextRx, nextL, approximatedPrice); - return (nextRx, nextRy, nextL); - } - - function allocateGivenY( - uint256 poolId, - uint256 amountY - ) public view returns (uint256, uint256, uint256) { - (uint256[] memory reserves, uint256 L) = getReservesAndLiquidity(poolId); - (uint256 nextRy, uint256 nextL) = - computeAllocationGivenX(true, amountY, reserves[1], L); - uint256 approximatedPrice = getPriceGivenYL(poolId, nextRy, nextL); - uint256 nextRx = - getNextReserveX(poolId, nextRy, nextL, approximatedPrice); - return (nextRx, nextRy, nextL); - } - - function deallocateGivenX( - uint256 poolId, - uint256 amountX - ) public view returns (uint256, uint256, uint256) { - (uint256[] memory reserves, uint256 L) = getReservesAndLiquidity(poolId); - (uint256 nextRx, uint256 nextL) = - computeAllocationGivenX(false, amountX, reserves[0], L); - uint256 approximatedPrice = getPriceGivenXL(poolId, nextRx, nextL); - uint256 nextRy = - getNextReserveY(poolId, nextRx, nextL, approximatedPrice); - return (nextRx, nextRy, nextL); - } - - function deallocateGivenY( - uint256 poolId, - uint256 amountY - ) public view returns (uint256, uint256, uint256) { - (uint256[] memory reserves, uint256 L) = getReservesAndLiquidity(poolId); - (uint256 nextRy, uint256 nextL) = - computeAllocationGivenX(false, amountY, reserves[1], L); - uint256 approximatedPrice = getPriceGivenYL(poolId, nextRy, nextL); - uint256 nextRx = - getNextReserveX(poolId, nextRy, nextL, approximatedPrice); - return (nextRx, nextRy, nextL); - } - function getNextLiquidity( uint256 poolId, uint256 rx, @@ -236,6 +152,7 @@ contract LogNormalSolver { uint256 fees; } + /// @notice used by kit /// @dev Estimates a swap's reserves and adjustments and returns its validity. function simulateSwap( uint256 poolId, @@ -243,7 +160,7 @@ contract LogNormalSolver { uint256 amountIn ) public view returns (bool, uint256, uint256, bytes memory) { Reserves memory endReserves; - (uint256[] memory preReserves, uint256 preTotalLiquidity) = + (uint256 preReserveX, uint256 preReserveY, uint256 preTotalLiquidity) = getReservesAndLiquidity(poolId); LogNormalParams memory poolParams = getPoolParams(poolId); @@ -251,19 +168,19 @@ contract LogNormalSolver { { uint256 startComputedL = getNextLiquidity( - poolId, preReserves[0], preReserves[1], preTotalLiquidity + poolId, preReserveX, preReserveY, preTotalLiquidity ); if (swapXIn) { state.deltaLiquidity = computeDeltaLXIn( amountIn, - preReserves[0], - preReserves[1], + preReserveX, + preReserveY, preTotalLiquidity, poolParams ); - endReserves.rx = preReserves[0] + amountIn; + endReserves.rx = preReserveX + amountIn; endReserves.L = startComputedL + state.deltaLiquidity; uint256 approxPrice = getPriceGivenXL(poolId, endReserves.rx, endReserves.L); @@ -273,20 +190,20 @@ contract LogNormalSolver { ); require( - endReserves.ry < preReserves[1], + endReserves.ry < preReserveY, "invalid swap: y reserve increased!" ); - state.amountOut = preReserves[1] - endReserves.ry; + state.amountOut = preReserveY - endReserves.ry; } else { state.deltaLiquidity = computeDeltaLYIn( amountIn, - preReserves[0], - preReserves[1], + preReserveX, + preReserveY, preTotalLiquidity, poolParams ); - endReserves.ry = preReserves[1] + amountIn; + endReserves.ry = preReserveY + amountIn; endReserves.L = startComputedL + state.deltaLiquidity; uint256 approxPrice = getPriceGivenYL(poolId, endReserves.ry, endReserves.L); @@ -296,15 +213,17 @@ contract LogNormalSolver { ); require( - endReserves.rx < preReserves[0], + endReserves.rx < preReserveX, "invalid swap: x reserve increased!" ); - state.amountOut = preReserves[0] - endReserves.rx; + state.amountOut = preReserveX - endReserves.rx; } } Pool memory pool; - pool.reserves = preReserves; + pool.reserves = new uint256[](2); + pool.reserves[0] = endReserves.rx; + pool.reserves[1] = endReserves.ry; pool.totalLiquidity = preTotalLiquidity; bytes memory swapData; @@ -349,7 +268,7 @@ contract LogNormalSolver { view returns (uint256 price) { - (uint256[] memory reserves, uint256 L) = getReservesAndLiquidity(poolId); - price = computePriceGivenX(reserves[0], L, getPoolParams(poolId)); + (uint256 preReserveX,, uint256 L) = getReservesAndLiquidity(poolId); + price = computePriceGivenX(preReserveX, L, getPoolParams(poolId)); } } diff --git a/src/PairSolver.sol b/src/PairSolver.sol new file mode 100644 index 00000000..69b6b5ed --- /dev/null +++ b/src/PairSolver.sol @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity ^0.8.13; + +import { IStrategy, Pool } from "src/interfaces/IStrategy.sol"; +import { + computeDeltaXGivenDeltaY, + computeDeltaLGivenDeltaX, + computeDeltaLGivenDeltaY, + computeDeltaYGivenDeltaX, + computeDeltaXGivenDeltaL, + computeDeltaYGivenDeltaL +} from "src/lib/StrategyLib.sol"; + +/** + * @title Pair strategy base contract for DFMM. + * @notice This abstract contract defines the basic behavior of + * a two-token strategy for DFMM. It is meant to be inherited by + * a concrete strategy implementation. + * @author Primitive + */ +abstract contract PairSolver { + /** + * @notice Prepares the allocation deltas given a change in reserve X. + * @dev This function calculates the changes in reserves and liquidity based on the change in reserve X. + * @param poolId The ID of the pool. + * @param deltaX The change in reserve X. + * @return The encoded allocation deltas. + */ + function prepareAllocationDeltasGivenDeltaX( + uint256 poolId, + uint256 deltaX + ) public view returns (bytes memory) { + (uint256 rX, uint256 rY, uint256 liquidity) = + getReservesAndLiquidity(poolId); + return encodeAllocationDeltasGivenDeltaX(deltaX, rX, rY, liquidity); + } + + /** + * @notice Prepares the allocation deltas given a change in reserve Y. + * @dev This function calculates the changes in reserves and liquidity based on the change in reserve Y. + * @param poolId The ID of the pool. + * @param deltaY The change in reserve Y. + * @return The encoded allocation deltas. + */ + function prepareAllocationDeltasGivenDeltaY( + uint256 poolId, + uint256 deltaY + ) public view returns (bytes memory) { + (uint256 rX, uint256 rY, uint256 liquidity) = + getReservesAndLiquidity(poolId); + return encodeAllocationDeltasGivenDeltaY(deltaY, rX, rY, liquidity); + } + + /** + * @notice Prepares the allocation deltas given a change in liquidity. + * @dev This function calculates the changes in reserves based on the change in liquidity. + * @param poolId The ID of the pool. + * @param deltaL The change in liquidity. + * @return The encoded allocation deltas. + */ + function prepareAllocationDeltasGivenDeltaL( + uint256 poolId, + uint256 deltaL + ) public view returns (bytes memory) { + (uint256 rX, uint256 rY, uint256 liquidity) = + getReservesAndLiquidity(poolId); + return encodeAllocationDeltasGivenDeltaL(deltaL, rX, rY, liquidity); + } + + function encodeAllocationDeltasGivenDeltaX( + uint256 deltaX, + uint256 reserveX, + uint256 reserveY, + uint256 liquidity + ) internal pure returns (bytes memory) { + uint256 deltaY = computeDeltaYGivenDeltaX(deltaX, reserveX, reserveY); + uint256 deltaL = computeDeltaLGivenDeltaX(deltaX, liquidity, reserveX); + return abi.encode(deltaX, deltaY, deltaL); + } + + function encodeAllocationDeltasGivenDeltaY( + uint256 deltaY, + uint256 reserveX, + uint256 reserveY, + uint256 liquidity + ) internal pure returns (bytes memory) { + uint256 deltaX = computeDeltaXGivenDeltaY(deltaY, reserveX, reserveY); + uint256 deltaL = computeDeltaLGivenDeltaY(deltaY, liquidity, reserveY); + return abi.encode(deltaX, deltaY, deltaL); + } + + function encodeAllocationDeltasGivenDeltaL( + uint256 deltaL, + uint256 reserveX, + uint256 reserveY, + uint256 liquidity + ) internal pure returns (bytes memory) { + uint256 deltaX = computeDeltaXGivenDeltaL(deltaL, reserveX, liquidity); + uint256 deltaY = computeDeltaYGivenDeltaL(deltaL, reserveY, liquidity); + return abi.encode(deltaX, deltaY, deltaL); + } + + /** + * @notice Retrieves the reserves and liquidity for a given pool. + * @dev This function is virtual and should be overridden by the concrete implementation. + * @param poolId The ID of the pool. + * @return The reserve of token X, the reserve of token Y, and the total liquidity. + */ + function getReservesAndLiquidity(uint256 poolId) + public + view + virtual + returns (uint256, uint256, uint256); +} diff --git a/src/lib/StrategyLib.sol b/src/lib/StrategyLib.sol index 931e0b47..bf9f2903 100644 --- a/src/lib/StrategyLib.sol +++ b/src/lib/StrategyLib.sol @@ -57,6 +57,14 @@ function computeDeltaYGivenDeltaX( return reserveY.mulDivUp(deltaX, reserveX); } +function computeDeltaXGivenDeltaY( + uint256 deltaY, + uint256 reserveX, + uint256 reserveY +) pure returns (uint256 deltaX) { + return reserveX.mulDivUp(deltaY, reserveY); +} + function computeDeltaXGivenDeltaL( uint256 deltaL, uint256 liquidity, diff --git a/test/ConstantSum/unit/Init.t.sol b/test/ConstantSum/unit/Init.t.sol index ec4b9792..e3b61afa 100644 --- a/test/ConstantSum/unit/Init.t.sol +++ b/test/ConstantSum/unit/Init.t.sol @@ -42,10 +42,10 @@ contract ConstantSumInitTest is ConstantSumSetUp { assertEq(pool.reserves[1], reserveY); } - // This test doesn't pass because the `controller` param is not stored + // 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({ diff --git a/test/G3M/unit/Allocate.t.sol b/test/G3M/unit/Allocate.t.sol index c671ebf9..c97fb86a 100644 --- a/test/G3M/unit/Allocate.t.sol +++ b/test/G3M/unit/Allocate.t.sol @@ -11,15 +11,16 @@ contract G3MAllocateTest is G3MSetUp { function test_G3M_allocate_GivenX() public init { uint256 maxDeltaX = 0.1 ether; - (uint256 maxDeltaY, uint256 deltaLiquidity) = - solver.allocateGivenDeltaX(POOL_ID, maxDeltaX); + bytes memory allocateData = + solver.prepareAllocationDeltasGivenDeltaX(POOL_ID, maxDeltaX); (uint256[] memory reserves, uint256 liquidity) = getReservesAndLiquidity(POOL_ID); + (, uint256 maxDeltaY, uint256 deltaLiquidity) = + abi.decode(allocateData, (uint256, uint256, uint256)); uint256 preLiquidityBalance = liquidityOf(address(this), POOL_ID); - bytes memory data = abi.encode(maxDeltaX, maxDeltaY, deltaLiquidity); - (uint256[] memory deltas) = dfmm.allocate(POOL_ID, data); + (uint256[] memory deltas) = dfmm.allocate(POOL_ID, allocateData); (uint256[] memory adjustedReserves, uint256 adjustedLiquidity) = getReservesAndLiquidity(POOL_ID); @@ -39,15 +40,16 @@ contract G3MAllocateTest is G3MSetUp { function test_G3M_allocate_GivenX_large_delta() public init { uint256 maxDeltaX = 10_000 ether; - (uint256 maxDeltaY, uint256 deltaLiquidity) = - solver.allocateGivenDeltaX(POOL_ID, maxDeltaX); + bytes memory allocateData = + solver.prepareAllocationDeltasGivenDeltaX(POOL_ID, maxDeltaX); (uint256[] memory reserves, uint256 liquidity) = getReservesAndLiquidity(POOL_ID); + (, uint256 maxDeltaY, uint256 deltaLiquidity) = + abi.decode(allocateData, (uint256, uint256, uint256)); uint256 preLiquidityBalance = liquidityOf(address(this), POOL_ID); - bytes memory data = abi.encode(maxDeltaX, maxDeltaY, deltaLiquidity); - (uint256[] memory deltas) = dfmm.allocate(POOL_ID, data); + (uint256[] memory deltas) = dfmm.allocate(POOL_ID, allocateData); (uint256[] memory adjustedReserves, uint256 adjustedLiquidity) = getReservesAndLiquidity(POOL_ID); @@ -67,8 +69,10 @@ contract G3MAllocateTest is G3MSetUp { function test_G3M_allocate_MultipleTimes() public init { uint256 maxDeltaX = 0.1 ether; - (uint256 maxDeltaY, uint256 deltaLiquidity) = - solver.allocateGivenDeltaX(POOL_ID, maxDeltaX); + bytes memory allocateData = + solver.prepareAllocationDeltasGivenDeltaX(POOL_ID, maxDeltaX); + (, uint256 maxDeltaY, uint256 deltaLiquidity) = + abi.decode(allocateData, (uint256, uint256, uint256)); bytes memory data = abi.encode( maxDeltaX.mulDivUp(101, 100), @@ -82,8 +86,10 @@ contract G3MAllocateTest is G3MSetUp { function test_G3M_allocate_RevertsIfMoreThanMaxDeltaX() public init { uint256 maxDeltaX = 0.1 ether; - (uint256 maxDeltaY, uint256 deltaLiquidity) = - solver.allocateGivenDeltaX(POOL_ID, maxDeltaX); + bytes memory allocateData = + solver.prepareAllocationDeltasGivenDeltaX(POOL_ID, maxDeltaX); + (, uint256 maxDeltaY, uint256 deltaLiquidity) = + abi.decode(allocateData, (uint256, uint256, uint256)); bytes memory data = abi.encode(maxDeltaX - 1, maxDeltaY, deltaLiquidity); vm.expectRevert(); @@ -93,8 +99,10 @@ contract G3MAllocateTest is G3MSetUp { function test_G3M_allocate_RevertsIfMoreThanMaxDeltaY() public init { uint256 maxDeltaX = 0.1 ether; - (uint256 maxDeltaY, uint256 deltaLiquidity) = - solver.allocateGivenDeltaX(POOL_ID, maxDeltaX); + bytes memory allocateData = + solver.prepareAllocationDeltasGivenDeltaX(POOL_ID, maxDeltaX); + (, uint256 maxDeltaY, uint256 deltaLiquidity) = + abi.decode(allocateData, (uint256, uint256, uint256)); bytes memory data = abi.encode(maxDeltaX, maxDeltaY - 1, deltaLiquidity); vm.expectRevert(); @@ -104,8 +112,10 @@ contract G3MAllocateTest is G3MSetUp { function test_G3M_allocate_GivenY() public init { uint256 maxDeltaY = 0.1 ether; - (uint256 maxDeltaX, uint256 deltaLiquidity) = - solver.allocateGivenDeltaY(POOL_ID, maxDeltaY); + bytes memory allocateData = + solver.prepareAllocationDeltasGivenDeltaY(POOL_ID, maxDeltaY); + (uint256 maxDeltaX,, uint256 deltaLiquidity) = + abi.decode(allocateData, (uint256, uint256, uint256)); (uint256[] memory reserves, uint256 liquidity) = getReservesAndLiquidity(POOL_ID); console2.log("liquidity", liquidity); @@ -134,23 +144,26 @@ contract G3MAllocateTest is G3MSetUp { } function test_G3M_allocate_ReceiveAppropriateLpTokens() public init_100 { - (, uint256 initialL) = getReservesAndLiquidity(POOL_ID); - Pool memory pool = dfmm.pools(POOL_ID); - LPToken liquidityToken = LPToken(pool.liquidityToken); + (, uint256 initialL) = getReservesAndLiquidity(POOL_ID); + Pool memory pool = dfmm.pools(POOL_ID); + LPToken liquidityToken = LPToken(pool.liquidityToken); + + uint256 startBalance = liquidityToken.balanceOf(address(this)); - uint256 startBalance = liquidityToken.balanceOf(address(this)); + uint256 dyMax = 100 ether; + bytes memory allocateData = + solver.prepareAllocationDeltasGivenDeltaY(POOL_ID, dyMax); + (uint256 maxDeltaX,, uint256 deltaLiquidity) = + abi.decode(allocateData, (uint256, uint256, uint256)); + bytes memory data = abi.encode(maxDeltaX, dyMax, deltaLiquidity); - uint256 dyMax = 100 ether; - (uint256 dxMax, uint256 dL) = solver.allocateGivenDeltaY(POOL_ID, dyMax); - bytes memory data = abi.encode(dxMax, dyMax, dL); + dfmm.allocate(POOL_ID, data); - dfmm.allocate(POOL_ID, data); + (, uint256 nextL) = getReservesAndLiquidity(POOL_ID); + uint256 endBalance = liquidityToken.balanceOf(address(this)); - (, uint256 nextL) = getReservesAndLiquidity(POOL_ID); - uint256 endBalance = liquidityToken.balanceOf(address(this)); - - // Add 1_000 wei to account for liquidity that was burnt on init - assertEq(startBalance + 1_000, initialL); - assertEq(endBalance + 1_000, nextL); + // Add 1_000 wei to account for liquidity that was burnt on init + assertEq(startBalance + 1000, initialL); + assertEq(endBalance + 1000, nextL); } } diff --git a/test/G3M/unit/Deallocate.t.sol b/test/G3M/unit/Deallocate.t.sol index 4db35934..e8cc0761 100644 --- a/test/G3M/unit/Deallocate.t.sol +++ b/test/G3M/unit/Deallocate.t.sol @@ -10,16 +10,13 @@ contract G3MDeallocateTest is G3MSetUp { function test_G3M_deallocate_GivenX_DecreasesTotalLiquidity() public init { uint256 minDeltaX = 0.1 ether; - (uint256 deltaY, uint256 deltaLiquidity) = - solver.deallocateGivenDeltaX(POOL_ID, minDeltaX); - console2.log(deltaY); - console2.log(deltaLiquidity); + bytes memory deallocateData = + solver.prepareAllocationDeltasGivenDeltaX(POOL_ID, minDeltaX); uint256 preLiquidityBalance = liquidityOf(address(this), POOL_ID); (, uint256 preTotalLiquidity) = getReservesAndLiquidity(POOL_ID); - bytes memory data = abi.encode(minDeltaX, deltaY, deltaLiquidity); - dfmm.deallocate(POOL_ID, data); + dfmm.deallocate(POOL_ID, deallocateData); (, uint256 postTotalLiquidity) = getReservesAndLiquidity(POOL_ID); uint256 deltaTotalLiquidity = preTotalLiquidity - postTotalLiquidity; @@ -34,10 +31,12 @@ contract G3MDeallocateTest is G3MSetUp { (uint256 preReserveX, uint256 preReserveY,) = solver.getReservesAndLiquidity(POOL_ID); - (uint256 deltaY, uint256 deltaLiquidity) = - solver.deallocateGivenDeltaX(POOL_ID, minDeltaX); - bytes memory data = abi.encode(minDeltaX, deltaY, deltaLiquidity); - dfmm.deallocate(POOL_ID, data); + bytes memory deallocateData = + solver.prepareAllocationDeltasGivenDeltaX(POOL_ID, minDeltaX); + dfmm.deallocate(POOL_ID, deallocateData); + + (, uint256 deltaY, uint256 deltaL) = + abi.decode(deallocateData, (uint256, uint256, uint256)); (uint256 postReserveX, uint256 postReserveY,) = solver.getReservesAndLiquidity(POOL_ID); @@ -52,10 +51,11 @@ contract G3MDeallocateTest is G3MSetUp { uint256 preBalanceXDFMM = tokenX.balanceOf(address(dfmm)); uint256 preBalanceYDFMM = tokenY.balanceOf(address(dfmm)); - (uint256 deltaY, uint256 deltaLiquidity) = - solver.deallocateGivenDeltaX(POOL_ID, minDeltaX); - bytes memory data = abi.encode(minDeltaX, deltaY, deltaLiquidity); - dfmm.deallocate(POOL_ID, data); + bytes memory deallocateData = + solver.prepareAllocationDeltasGivenDeltaX(POOL_ID, minDeltaX); + (, uint256 deltaY,) = + abi.decode(deallocateData, (uint256, uint256, uint256)); + dfmm.deallocate(POOL_ID, deallocateData); assertEq(preBalanceX + minDeltaX, tokenX.balanceOf(address(this))); assertEq(preBalanceY + deltaY, tokenY.balanceOf(address(this))); @@ -66,13 +66,14 @@ contract G3MDeallocateTest is G3MSetUp { function test_G3M_deallocate_GivenY() public init { uint256 minDeltaY = 0.1 ether; - (uint256 minDeltaX, uint256 deltaLiquidity) = - solver.allocateGivenDeltaY(POOL_ID, minDeltaY); + bytes memory deallocateData = + solver.prepareAllocationDeltasGivenDeltaY(POOL_ID, minDeltaY); (uint256[] memory reserves, uint256 liquidity) = getReservesAndLiquidity(POOL_ID); + (,, uint256 deltaLiquidity) = + abi.decode(deallocateData, (uint256, uint256, uint256)); - bytes memory data = abi.encode(minDeltaX, minDeltaY, deltaLiquidity); - (uint256[] memory deltas) = dfmm.deallocate(POOL_ID, data); + (uint256[] memory deltas) = dfmm.deallocate(POOL_ID, deallocateData); (uint256[] memory adjustedReserves, uint256 adjustedLiquidity) = getReservesAndLiquidity(POOL_ID); diff --git a/test/G3M/unit/SetUp.sol b/test/G3M/unit/SetUp.sol index 24069a51..8690a6d2 100644 --- a/test/G3M/unit/SetUp.sol +++ b/test/G3M/unit/SetUp.sol @@ -32,7 +32,7 @@ contract G3MSetUp is SetUp { ); bytes default100InitialPoolData = computeInitialPoolData( - defaultReserveX * 100, defaultStrikePrice, defaultParams + defaultReserveX * 100, defaultStrikePrice, defaultParams ); function setUp() public override { @@ -64,7 +64,7 @@ contract G3MSetUp is SetUp { } modifier init_100() { - address[] memory tokens = new address[](2); + address[] memory tokens = new address[](2); tokens[0] = address(tokenX); tokens[1] = address(tokenY); diff --git a/test/LogNormal/LogNormalTest.t.sol b/test/LogNormal/LogNormalTest.t.sol index af887274..b8810176 100644 --- a/test/LogNormal/LogNormalTest.t.sol +++ b/test/LogNormal/LogNormalTest.t.sol @@ -182,10 +182,10 @@ contract LogNormalTest is Test { // todo: write assertApproxEq function test_price_formulas() public basic { - (uint256[] memory reserves, uint256 L) = + (uint256 rX, uint256 rY, uint256 L) = solver.getReservesAndLiquidity(POOL_ID); - uint256 priceGivenX = solver.getPriceGivenXL(POOL_ID, reserves[0], L); - uint256 priceGivenY = solver.getPriceGivenYL(POOL_ID, reserves[1], L); + uint256 priceGivenX = solver.getPriceGivenXL(POOL_ID, rX, L); + uint256 priceGivenY = solver.getPriceGivenYL(POOL_ID, rY, L); assertApproxEqAbs(priceGivenY, priceGivenX, 100); } diff --git a/test/LogNormal/unit/Allocate.t.sol b/test/LogNormal/unit/Allocate.t.sol index 1cd564d5..5e20c8d1 100644 --- a/test/LogNormal/unit/Allocate.t.sol +++ b/test/LogNormal/unit/Allocate.t.sol @@ -12,18 +12,16 @@ import { contract LogNormalAllocateTest is LogNormalSetUp { function test_LogNormal_allocate_GivenL() public init { - (uint256[] memory reserves, uint256 totalLiquidity) = + (uint256 rX, uint256 rY, uint256 totalLiquidity) = solver.getReservesAndLiquidity(POOL_ID); uint256 deltaLiquidity = 0.1 ether; - uint256 maxDeltaX = computeDeltaGivenDeltaLRoundUp( - reserves[0], deltaLiquidity, totalLiquidity - ); - uint256 maxDeltaY = computeDeltaGivenDeltaLRoundUp( - reserves[1], deltaLiquidity, totalLiquidity - ); + uint256 maxDeltaX = + computeDeltaGivenDeltaLRoundUp(rX, deltaLiquidity, totalLiquidity); + uint256 maxDeltaY = + computeDeltaGivenDeltaLRoundUp(rY, deltaLiquidity, totalLiquidity); - (, uint256 preTotalLiquidity) = solver.getReservesAndLiquidity(POOL_ID); + (,, uint256 preTotalLiquidity) = solver.getReservesAndLiquidity(POOL_ID); uint256 preLiquidityBalance = liquidityOf(address(this), POOL_ID); console2.log(preTotalLiquidity); console2.log(preLiquidityBalance); @@ -31,7 +29,8 @@ contract LogNormalAllocateTest is LogNormalSetUp { bytes memory data = abi.encode(maxDeltaX, maxDeltaY, deltaLiquidity); dfmm.allocate(POOL_ID, data); - (, uint256 postTotalLiquidity) = solver.getReservesAndLiquidity(POOL_ID); + (,, uint256 postTotalLiquidity) = + solver.getReservesAndLiquidity(POOL_ID); uint256 postLiquidityBalance = liquidityOf(address(this), POOL_ID); console2.log(postTotalLiquidity); console2.log(postLiquidityBalance); @@ -46,13 +45,12 @@ contract LogNormalAllocateTest is LogNormalSetUp { function test_LogNormal_allocate_GivenX() public init { uint256 deltaX = 0.1 ether; - (uint256[] memory reserves, uint256 liquidity) = + (uint256 rX, uint256 rY, uint256 liquidity) = solver.getReservesAndLiquidity(POOL_ID); - uint256 deltaLiquidity = - computeDeltaLGivenDeltaX(deltaX, liquidity, reserves[0]); + uint256 deltaLiquidity = computeDeltaLGivenDeltaX(deltaX, liquidity, rX); uint256 deltaYMax = - computeDeltaYGivenDeltaL(deltaLiquidity, liquidity, reserves[1]); + computeDeltaYGivenDeltaL(deltaLiquidity, liquidity, rY); // uint256 preLiquidityBalance = liquidityOf(address(this), POOL_ID); // (,, uint256 preTotalLiquidity) = dfmm.getReservesAndLiquidity(POOL_ID); @@ -74,13 +72,13 @@ contract LogNormalAllocateTest is LogNormalSetUp { function test_LogNormal_allocate_GivenY() public init { uint256 maxDeltaY = 0.1 ether; - (uint256[] memory reserves, uint256 liquidity) = + (uint256 rX, uint256 rY, uint256 liquidity) = solver.getReservesAndLiquidity(POOL_ID); uint256 deltaLiquidity = - computeDeltaLGivenDeltaY(maxDeltaY, liquidity, reserves[1]); + computeDeltaLGivenDeltaY(maxDeltaY, liquidity, rY); uint256 maxDeltaX = - computeDeltaXGivenDeltaL(deltaLiquidity, liquidity, reserves[0]); + computeDeltaXGivenDeltaL(deltaLiquidity, liquidity, rX); console2.log(maxDeltaX); // uint256 preLiquidityBalance = liquidityOf(address(this), POOL_ID); @@ -103,13 +101,12 @@ contract LogNormalAllocateTest is LogNormalSetUp { uint256 startPrice = solver.internalPrice(POOL_ID); uint256 deltaX = 0.77 ether; - (uint256[] memory reserves, uint256 liquidity) = + (uint256 rX, uint256 rY, uint256 liquidity) = solver.getReservesAndLiquidity(POOL_ID); - uint256 deltaLiquidity = - computeDeltaLGivenDeltaX(deltaX, liquidity, reserves[0]); + uint256 deltaLiquidity = computeDeltaLGivenDeltaX(deltaX, liquidity, rX); uint256 deltaYMax = - computeDeltaYGivenDeltaL(deltaLiquidity, liquidity, reserves[1]); + computeDeltaYGivenDeltaL(deltaLiquidity, liquidity, rY); bytes memory data = abi.encode(deltaX, deltaYMax, deltaLiquidity); dfmm.allocate(POOL_ID, data); @@ -123,13 +120,13 @@ contract LogNormalAllocateTest is LogNormalSetUp { uint256 maxDeltaY = 0.77 ether; uint256 startPrice = solver.internalPrice(POOL_ID); - (uint256[] memory reserves, uint256 liquidity) = + (uint256 rX, uint256 rY, uint256 liquidity) = solver.getReservesAndLiquidity(POOL_ID); uint256 deltaLiquidity = - computeDeltaLGivenDeltaY(maxDeltaY, liquidity, reserves[1]); + computeDeltaLGivenDeltaY(maxDeltaY, liquidity, rY); uint256 maxDeltaX = - computeDeltaXGivenDeltaL(deltaLiquidity, liquidity, reserves[0]); + computeDeltaXGivenDeltaL(deltaLiquidity, liquidity, rX); bytes memory data = abi.encode(maxDeltaX, maxDeltaY, deltaLiquidity); dfmm.allocate(POOL_ID, data); diff --git a/test/LogNormal/unit/Deallocate.t.sol b/test/LogNormal/unit/Deallocate.t.sol index 19914e12..c5022cc3 100644 --- a/test/LogNormal/unit/Deallocate.t.sol +++ b/test/LogNormal/unit/Deallocate.t.sol @@ -13,12 +13,11 @@ contract LogNormalDeallocateTest is LogNormalSetUp { function test_LogNormal_deallocate_GivenX() public init { uint256 minDeltaX = 0.1 ether; - (uint256[] memory reserves, uint256 liquidity) = + (uint256 rX, uint256 rY, uint256 liquidity) = solver.getReservesAndLiquidity(POOL_ID); uint256 deltaLiquidity = - computeDeltaLGivenDeltaX(minDeltaX, liquidity, reserves[0]); - uint256 minDeltaY = - computeDeltaYGivenDeltaX(minDeltaX, reserves[0], reserves[1]); + computeDeltaLGivenDeltaX(minDeltaX, liquidity, rX); + uint256 minDeltaY = computeDeltaYGivenDeltaX(minDeltaX, rX, rY); // uint256 preLiquidityBalance = liquidityOf(address(this), POOL_ID); // (,, uint256 preTotalLiquidity) = dfmm.getReservesAndLiquidity(POOL_ID); @@ -42,13 +41,13 @@ contract LogNormalDeallocateTest is LogNormalSetUp { function test_LogNormal_deallocate_GivenY() public init { uint256 minDeltaY = 0.1 ether; - (uint256[] memory reserves, uint256 liquidity) = + (uint256 rX, uint256 rY, uint256 liquidity) = solver.getReservesAndLiquidity(POOL_ID); uint256 deltaLiquidity = - computeDeltaLGivenDeltaY(minDeltaY, liquidity, reserves[1]); + computeDeltaLGivenDeltaY(minDeltaY, liquidity, rY); uint256 minDeltaX = - computeDeltaXGivenDeltaL(deltaLiquidity, liquidity, reserves[0]); + computeDeltaXGivenDeltaL(deltaLiquidity, liquidity, rX); // uint256 preLiquidityBalance = liquidityOf(address(this), POOL_ID); // (,, uint256 preTotalLiquidity) = dfmm.getReservesAndLiquidity(POOL_ID); diff --git a/test/LogNormal/unit/Init.t.sol b/test/LogNormal/unit/Init.t.sol index 615d0c2c..9598060f 100644 --- a/test/LogNormal/unit/Init.t.sol +++ b/test/LogNormal/unit/Init.t.sol @@ -42,10 +42,10 @@ contract LogNormalInitTest is LogNormalSetUp { } function test_LogNormal_init_ReturnsPriceOfOne() public init { - (uint256[] memory reserves, uint256 L) = + (uint256 rX, uint256 rY, uint256 L) = solver.getReservesAndLiquidity(POOL_ID); - uint256 priceGivenYL = solver.getPriceGivenYL(POOL_ID, reserves[1], L); - uint256 priceGivenXL = solver.getPriceGivenXL(POOL_ID, reserves[0], L); + uint256 priceGivenYL = solver.getPriceGivenYL(POOL_ID, rY, L); + uint256 priceGivenXL = solver.getPriceGivenXL(POOL_ID, rX, L); assertApproxEqAbs(priceGivenXL, ONE, 10); assertApproxEqAbs(priceGivenYL, ONE, 10); diff --git a/test/LogNormal/unit/Swap.t.sol b/test/LogNormal/unit/Swap.t.sol index 1d0cff69..73a70f34 100644 --- a/test/LogNormal/unit/Swap.t.sol +++ b/test/LogNormal/unit/Swap.t.sol @@ -67,17 +67,16 @@ contract LogNormalSwapTest is LogNormalSetUp { function test_LogNormal_swap_RevertsIfInvariantNegative() public init { uint256 amountIn = 0.23 ether; - (uint256[] memory preReserves, uint256 preTotalLiquidity) = + (uint256 rX, uint256 rY, uint256 preTotalLiquidity) = solver.getReservesAndLiquidity(POOL_ID); LogNormalParams memory poolParams = solver.getPoolParams(POOL_ID); - uint256 startL = solver.getNextLiquidity( - POOL_ID, preReserves[0], preReserves[1], preTotalLiquidity - ); + uint256 startL = + solver.getNextLiquidity(POOL_ID, rX, rY, preTotalLiquidity); uint256 deltaLiquidity = amountIn.mulWadUp(poolParams.swapFee).divWadUp(poolParams.mean); - uint256 ry = preReserves[1] + amountIn; + uint256 ry = rY + amountIn; uint256 L = startL + deltaLiquidity; uint256 approxPrice = solver.getPriceGivenYL(POOL_ID, ry, L); @@ -91,7 +90,7 @@ contract LogNormalSwapTest is LogNormalSetUp { console2.log(invariant); - uint256 amountOut = preReserves[0] - rx; + uint256 amountOut = rX - rx; bytes memory payload = abi.encode(1, 0, amountIn, amountOut, deltaLiquidity);