From 8d00880c129759c5fc08f468b46047f98c1725e1 Mon Sep 17 00:00:00 2001 From: kinrezc Date: Mon, 22 Apr 2024 14:33:08 -0400 Subject: [PATCH] fix SY swap tests --- src/SYCoveredCall/SYCoveredCall.sol | 28 +++++++++----------- src/SYCoveredCall/SYCoveredCallSolver.sol | 25 +++++++++++++++--- test/SYCoveredCall/unit/SetUp.sol | 5 ++-- test/SYCoveredCall/unit/Swap.t.sol | 32 ++++++++++++++++++++--- 4 files changed, 65 insertions(+), 25 deletions(-) diff --git a/src/SYCoveredCall/SYCoveredCall.sol b/src/SYCoveredCall/SYCoveredCall.sol index d6857e96..51afd74e 100644 --- a/src/SYCoveredCall/SYCoveredCall.sol +++ b/src/SYCoveredCall/SYCoveredCall.sol @@ -5,6 +5,7 @@ import { Pool } from "src/interfaces/IDFMM.sol"; import { PairStrategy, IStrategy } from "src/PairStrategy.sol"; import { IDFMM } from "src/interfaces/IDFMM.sol"; import { DynamicParamLib, DynamicParam } from "src/lib/DynamicParamLib.sol"; +import { SignedWadMathLib } from "src/lib/SignedWadMath.sol"; import { FixedPointMathLib } from "solmate/utils/FixedPointMathLib.sol"; import { computeTradingFunction, @@ -12,7 +13,7 @@ import { computeDeltaGivenDeltaLRoundDown, computeDeltaLXIn, computeDeltaLYIn, - computeTau, + computePriceGivenX, computeKGivenLastPrice } from "src/SYCoveredCall/SYCoveredCallMath.sol"; import { @@ -24,6 +25,7 @@ import { IPPrincipalToken } from "pendle/interfaces/IPPrincipalToken.sol"; import { IStandardizedYield } from "pendle/interfaces/IStandardizedYield.sol"; import { IPYieldToken } from "pendle/interfaces/IPYieldToken.sol"; import "forge-std/console2.sol"; +import { Gaussian } from "solstat/Gaussian.sol"; enum UpdateCode { Invalid, @@ -120,19 +122,11 @@ contract SYCoveredCall is PairStrategy { (reserves, totalLiquidity, params) = abi.decode(data, (uint256[], uint256, SYCoveredCallParams)); - IStandardizedYield SY = IStandardizedYield(pool.tokens[0]); - IPPrincipalToken PT = IPPrincipalToken(pool.tokens[1]); params.lastTimestamp = block.timestamp; - int256 tau = int256(computeTau(params)); - - console2.log("got here1"); - console2.log("pt.sy", params.PT.SY()); - console2.log("sy", address(params.SY)); if (params.PT.SY() != address(params.SY)) { revert InvalidPair(); } - console2.log("got here2"); if (params.PT.expiry() <= block.timestamp) { revert InvalidMaturity(); @@ -155,6 +149,7 @@ contract SYCoveredCall is PairStrategy { internalParams[poolId].width = params.width; internalParams[poolId].swapFee = params.swapFee; internalParams[poolId].controller = params.controller; + internalParams[poolId].lastTimestamp = block.timestamp; invariant = tradingFunction(reserves, totalLiquidity, abi.encode(params)); @@ -222,7 +217,6 @@ contract SYCoveredCall is PairStrategy { params = getPoolParams(poolId); SYCoveredCallParams memory ccParams = abi.decode(params, (SYCoveredCallParams)); - console2.log("got here"); uint256 computedL; uint256 swapTimestamp; @@ -236,7 +230,9 @@ contract SYCoveredCall is PairStrategy { ) = abi.decode( data, (uint256, uint256, uint256, uint256, uint256, uint256) ); - console2.log("got here2"); + + console2.log("swapTimestamp", swapTimestamp); + console2.log("block.timestamp", block.timestamp); if ( swapTimestamp < internalParams[poolId].lastTimestamp @@ -249,31 +245,33 @@ contract SYCoveredCall is PairStrategy { // if timestamp is valid, append it to the poolParams for validation check ccParams.lastTimestamp = swapTimestamp; - // compute new K ccParams.mean = computeKGivenLastPrice(pool.reserves[0], computedL, ccParams); int256 computedInvariant = - tradingFunction(pool.reserves, computedL, abi.encode(params)); + tradingFunction(pool.reserves, computedL, abi.encode(ccParams)); + console2.log("got here"); if (computedInvariant < 0 || computedInvariant > EPSILON) { revert InvalidComputedLiquidity(computedInvariant); } + console2.log("now we compute dl"); deltaLiquidity = _computeSwapDeltaLiquidity( pool, - abi.encode(params), + abi.encode(ccParams), tokenInIndex, tokenOutIndex, amountIn, amountOut ); + console2.log("deltaLiquidity", deltaLiquidity); pool.reserves[tokenInIndex] += amountIn; pool.reserves[tokenOutIndex] -= amountOut; invariant = tradingFunction( - pool.reserves, computedL + deltaLiquidity, abi.encode(params) + pool.reserves, computedL + deltaLiquidity, abi.encode(ccParams) ); params = abi.encode(ccParams); diff --git a/src/SYCoveredCall/SYCoveredCallSolver.sol b/src/SYCoveredCall/SYCoveredCallSolver.sol index 4546890b..c51b8d38 100644 --- a/src/SYCoveredCall/SYCoveredCallSolver.sol +++ b/src/SYCoveredCall/SYCoveredCallSolver.sol @@ -215,6 +215,7 @@ contract SYCoveredCallSolver { uint256 amountOut; uint256 deltaLiquidity; uint256 fees; + uint256 timestamp; } function simulateSwap( @@ -230,6 +231,10 @@ contract SYCoveredCallSolver { getPoolParamsCustomTimestamp(poolId, timestamp); SimulateSwapState memory state; + state.timestamp = timestamp; + console2.log("preTotalLiquidity", preTotalLiquidity); + console2.log("preReserves[0]", preReserves[0]); + console2.log("preReserves[1]", preReserves[1]); uint256 startComputedL = getNextLiquidity( poolId, preReserves[0], preReserves[1], preTotalLiquidity @@ -298,11 +303,23 @@ contract SYCoveredCallSolver { bytes memory swapData; if (swapXToY) { - swapData = - abi.encode(0, 1, swapAmountIn, state.amountOut, startComputedL); + swapData = abi.encode( + 0, + 1, + swapAmountIn, + state.amountOut, + startComputedL, + state.timestamp + ); } else { - swapData = - abi.encode(1, 0, swapAmountIn, state.amountOut, startComputedL); + swapData = abi.encode( + 1, + 0, + swapAmountIn, + state.amountOut, + startComputedL, + state.timestamp + ); } (bool valid,,,,,,,) = IStrategy(strategy).validateSwap( diff --git a/test/SYCoveredCall/unit/SetUp.sol b/test/SYCoveredCall/unit/SetUp.sol index 3756f9c2..3a4411e8 100644 --- a/test/SYCoveredCall/unit/SetUp.sol +++ b/test/SYCoveredCall/unit/SetUp.sol @@ -89,8 +89,6 @@ contract SYCoveredCallSetUp is SetUp { } modifier init() { - vm.warp(0); - address[] memory tokens = new address[](2); tokens[0] = address(tokenX); tokens[1] = address(tokenY); @@ -99,7 +97,7 @@ contract SYCoveredCallSetUp is SetUp { mean: uint256(pendleRateAnchor), width: 0.1 ether, maturity: PT.expiry(), - swapFee: TEST_SWAP_FEE, + swapFee: 0.0005 ether, lastTimestamp: block.timestamp, controller: address(this), SY: SY, @@ -120,6 +118,7 @@ contract SYCoveredCallSetUp is SetUp { feeCollector: address(0), controllerFee: 0 }); + console2.log("timestamp", block.timestamp); (POOL_ID,,) = dfmm.init(defaultInitParams); diff --git a/test/SYCoveredCall/unit/Swap.t.sol b/test/SYCoveredCall/unit/Swap.t.sol index b28c17d6..019d374d 100644 --- a/test/SYCoveredCall/unit/Swap.t.sol +++ b/test/SYCoveredCall/unit/Swap.t.sol @@ -34,15 +34,16 @@ contract SYCoveredCallSwapTest is SYCoveredCallSetUp { ); } - function test_SYCoveredCall_swap_SwapsXforY_WarpToMaturity() public init { - vm.warp(370 days); + function test_SYCoveredCall_swap_SwapsXforY_Warp2Days() public init { + vm.warp(block.timestamp + 2 days); + uint256 preDfmmBalanceX = tokenX.balanceOf(address(dfmm)); uint256 preDfmmBalanceY = tokenY.balanceOf(address(dfmm)); uint256 preUserBalanceX = tokenX.balanceOf(address(this)); uint256 preUserBalanceY = tokenY.balanceOf(address(this)); - uint256 amountIn = 99.9999999 ether; + uint256 amountIn = 0.1 ether; bool swapXForY = true; (bool valid, uint256 amountOut,, bytes memory payload) = @@ -126,4 +127,29 @@ contract SYCoveredCallSwapTest is SYCoveredCallSetUp { vm.expectRevert(); dfmm.swap(POOL_ID, address(this), payload, ""); } + + function _computeDeltaLXIn( + uint256 amountIn, + uint256 rx, + uint256 ry, + uint256 L, + SYCoveredCallParams memory params + ) external view returns (uint256 deltaL) { + uint256 fees = params.swapFee.mulWadUp(amountIn); + uint256 px = computePriceGivenX(rx, L, params); + deltaL = + px.mulWadUp(L).mulWadUp(fees).divWadDown(px.mulWadDown(rx) + ry); + } + + function _computeDeltaLYIn( + uint256 amountIn, + uint256 rx, + uint256 ry, + uint256 L, + SYCoveredCallParams memory params + ) external returns (uint256 deltaL) { + uint256 fees = params.swapFee.mulWadUp(amountIn); + uint256 px = computePriceGivenX(rx, L, params); + deltaL = L.mulWadUp(fees).divWadDown(px.mulWadDown(rx) + ry); + } }