diff --git a/pkg/liquidity-source/fluid/dex-t1/abis/dexReservesResolver.json b/pkg/liquidity-source/fluid/dex-t1/abis/dexReservesResolver.json index 9e5c92896..07221ef72 100644 --- a/pkg/liquidity-source/fluid/dex-t1/abis/dexReservesResolver.json +++ b/pkg/liquidity-source/fluid/dex-t1/abis/dexReservesResolver.json @@ -117,6 +117,11 @@ { "internalType": "address", "name": "token0", "type": "address" }, { "internalType": "address", "name": "token1", "type": "address" }, { "internalType": "uint256", "name": "fee", "type": "uint256" }, + { + "internalType": "uint256", + "name": "centerPrice", + "type": "uint256" + }, { "components": [ { @@ -295,6 +300,11 @@ { "internalType": "address", "name": "token0", "type": "address" }, { "internalType": "address", "name": "token1", "type": "address" }, { "internalType": "uint256", "name": "fee", "type": "uint256" }, + { + "internalType": "uint256", + "name": "centerPrice", + "type": "uint256" + }, { "components": [ { @@ -976,6 +986,11 @@ { "internalType": "address", "name": "token0", "type": "address" }, { "internalType": "address", "name": "token1", "type": "address" }, { "internalType": "uint256", "name": "fee", "type": "uint256" }, + { + "internalType": "uint256", + "name": "centerPrice", + "type": "uint256" + }, { "components": [ { @@ -1156,6 +1171,11 @@ { "internalType": "address", "name": "token0", "type": "address" }, { "internalType": "address", "name": "token1", "type": "address" }, { "internalType": "uint256", "name": "fee", "type": "uint256" }, + { + "internalType": "uint256", + "name": "centerPrice", + "type": "uint256" + }, { "components": [ { @@ -1348,6 +1368,11 @@ { "internalType": "address", "name": "token0", "type": "address" }, { "internalType": "address", "name": "token1", "type": "address" }, { "internalType": "uint256", "name": "fee", "type": "uint256" }, + { + "internalType": "uint256", + "name": "centerPrice", + "type": "uint256" + }, { "components": [ { @@ -1528,6 +1553,11 @@ { "internalType": "address", "name": "token0", "type": "address" }, { "internalType": "address", "name": "token1", "type": "address" }, { "internalType": "uint256", "name": "fee", "type": "uint256" }, + { + "internalType": "uint256", + "name": "centerPrice", + "type": "uint256" + }, { "components": [ { diff --git a/pkg/liquidity-source/fluid/dex-t1/constant.go b/pkg/liquidity-source/fluid/dex-t1/constant.go index 61a014355..06dc07d6d 100644 --- a/pkg/liquidity-source/fluid/dex-t1/constant.go +++ b/pkg/liquidity-source/fluid/dex-t1/constant.go @@ -1,38 +1,38 @@ package dexT1 -import "math/big" +import ( + "math/big" + + "github.com/KyberNetwork/kyberswap-dex-lib/pkg/util/bignumber" +) const ( DexType = "fluid-dex-t1" ) -const ( - // DexReservesResolver methods +const ( // DexReservesResolver methods DRRMethodGetAllPoolsReservesAdjusted = "getAllPoolsReservesAdjusted" DRRMethodGetPoolReservesAdjusted = "getPoolReservesAdjusted" - // ERC20 Token methods + // TokenMethodDecimals - ERC20 Token methods TokenMethodDecimals = "decimals" - // StorageRead methods + // SRMethodReadFromStorage - StorageRead methods SRMethodReadFromStorage = "readFromStorage" ) const ( - String1e18 = "1000000000000000000" - String1e27 = "1000000000000000000000000000" - DexAmountsDecimals = 12 - FeePercentPrecision int64 = 1e4 - Fee100PercentPrecision int64 = 1e6 + FeePercentPrecision float64 = 1e4 +) - MaxPriceDiff int64 = 5 // 5% +var ( + MaxPriceDiff = big.NewInt(5) // 5% + MinSwapLiquidity = big.NewInt(2e4) // on-chain we use 1e4 but use extra buffer to avoid reverts + Fee100PercentPrecision = big.NewInt(1e6) - MinSwapLiquidity int64 = 6667 // on-chain we use 1e4 but use extra buffer for potential price diff using pool price vs center price at the check + bI100 = big.NewInt(100) + bI1e18 = bignumber.TenPowInt(18) + bI1e27 = bignumber.TenPowInt(27) ) - -var bI1e18, _ = new(big.Int).SetString(String1e18, 10) // 1e18 -var bI1e27, _ = new(big.Int).SetString(String1e27, 10) // 1e27 -var bI10 = new(big.Int).SetInt64(10) -var bI100 = new(big.Int).SetInt64(100) diff --git a/pkg/liquidity-source/fluid/dex-t1/pool_list_updater.go b/pkg/liquidity-source/fluid/dex-t1/pool_list_updater.go index e7acabdf9..05db55b08 100644 --- a/pkg/liquidity-source/fluid/dex-t1/pool_list_updater.go +++ b/pkg/liquidity-source/fluid/dex-t1/pool_list_updater.go @@ -84,6 +84,7 @@ func (u *PoolsListUpdater) GetNewPools(ctx context.Context, metadataBytes []byte CollateralReserves: curPool.CollateralReserves, DebtReserves: curPool.DebtReserves, DexLimits: curPool.Limits, + CenterPrice: curPool.CenterPrice, } extraBytes, err := json.Marshal(extra) @@ -124,7 +125,7 @@ func (u *PoolsListUpdater) GetNewPools(ctx context.Context, metadataBytes []byte Decimals: token1Decimals, }, }, - SwapFee: float64(curPool.Fee.Int64()) / float64(FeePercentPrecision), + SwapFee: float64(curPool.Fee.Int64()) / FeePercentPrecision, Extra: string(extraBytes), StaticExtra: string(staticExtraBytes), } diff --git a/pkg/liquidity-source/fluid/dex-t1/pool_list_updater_test.go b/pkg/liquidity-source/fluid/dex-t1/pool_list_updater_test.go index d51b1474b..516928085 100644 --- a/pkg/liquidity-source/fluid/dex-t1/pool_list_updater_test.go +++ b/pkg/liquidity-source/fluid/dex-t1/pool_list_updater_test.go @@ -2,7 +2,6 @@ package dexT1 import ( "context" - "math/big" "os" "strings" "testing" @@ -29,7 +28,7 @@ func TestPoolListUpdater(t *testing.T) { err error config = Config{ - DexReservesResolver: "0x45f4ad57e300da55c33dea579a40fcee000d7b94", + DexReservesResolver: "0xb387f9C2092cF7c4943F97842887eBff7AE96EB3", } ) @@ -83,16 +82,17 @@ func TestPoolListUpdater(t *testing.T) { require.NotEqual(t, "0", pools[0].Reserves[0], "Reserve should not be zero") require.NotEqual(t, "0", pools[0].Reserves[1], "Reserve should not be zero") - require.True(t, extra.CollateralReserves.Token0RealReserves.Cmp(big.NewInt(0)) > 0) - require.True(t, extra.CollateralReserves.Token1RealReserves.Cmp(big.NewInt(0)) > 0) - require.True(t, extra.CollateralReserves.Token0ImaginaryReserves.Cmp(big.NewInt(0)) > 0) - require.True(t, extra.CollateralReserves.Token1ImaginaryReserves.Cmp(big.NewInt(0)) > 0) - require.True(t, extra.DebtReserves.Token0Debt.Cmp(big.NewInt(0)) > 0) - require.True(t, extra.DebtReserves.Token1Debt.Cmp(big.NewInt(0)) > 0) - require.True(t, extra.DebtReserves.Token0RealReserves.Cmp(big.NewInt(0)) > 0) - require.True(t, extra.DebtReserves.Token1RealReserves.Cmp(big.NewInt(0)) > 0) - require.True(t, extra.DebtReserves.Token0ImaginaryReserves.Cmp(big.NewInt(0)) > 0) - require.True(t, extra.DebtReserves.Token1ImaginaryReserves.Cmp(big.NewInt(0)) > 0) + require.True(t, extra.CollateralReserves.Token0RealReserves.Sign() > 0) + require.True(t, extra.CollateralReserves.Token1RealReserves.Sign() > 0) + require.True(t, extra.CollateralReserves.Token0ImaginaryReserves.Sign() > 0) + require.True(t, extra.CollateralReserves.Token1ImaginaryReserves.Sign() > 0) + require.True(t, extra.DebtReserves.Token0Debt.Sign() > 0) + require.True(t, extra.DebtReserves.Token1Debt.Sign() > 0) + require.True(t, extra.DebtReserves.Token0RealReserves.Sign() > 0) + require.True(t, extra.DebtReserves.Token1RealReserves.Sign() > 0) + require.True(t, extra.DebtReserves.Token0ImaginaryReserves.Sign() > 0) + require.True(t, extra.DebtReserves.Token1ImaginaryReserves.Sign() > 0) + require.True(t, extra.CenterPrice.Sign() > 0) // Log all pools // for i, pool := range pools { diff --git a/pkg/liquidity-source/fluid/dex-t1/pool_simulator.go b/pkg/liquidity-source/fluid/dex-t1/pool_simulator.go index 19923f582..ce47ab381 100644 --- a/pkg/liquidity-source/fluid/dex-t1/pool_simulator.go +++ b/pkg/liquidity-source/fluid/dex-t1/pool_simulator.go @@ -25,7 +25,7 @@ var ( ErrInsufficientMaxPrice = errors.New("insufficient reserve: tokenOut amount exceeds max price limit") - ErrVerifyReservesRatiosInvalid = errors.New(("invalid reserves ratio")) + ErrVerifyReservesRatiosInvalid = errors.New("invalid reserves ratio") ) type PoolSimulator struct { @@ -35,6 +35,7 @@ type PoolSimulator struct { CollateralReserves CollateralReserves DebtReserves DebtReserves DexLimits DexLimits + CenterPrice *big.Int Token0Decimals uint8 Token1Decimals uint8 @@ -61,8 +62,7 @@ func NewPoolSimulator(entityPool entity.Pool) (*PoolSimulator, error) { return nil, err } - fee := new(big.Int) - fee.SetInt64(int64(entityPool.SwapFee * float64(FeePercentPrecision))) + fee := big.NewInt(int64(entityPool.SwapFee * FeePercentPrecision)) return &PoolSimulator{ Pool: poolpkg.Pool{Info: poolpkg.PoolInfo{ @@ -79,6 +79,7 @@ func NewPoolSimulator(entityPool entity.Pool) (*PoolSimulator, error) { CollateralReserves: extra.CollateralReserves, DebtReserves: extra.DebtReserves, DexLimits: extra.DexLimits, + CenterPrice: extra.CenterPrice, Token0Decimals: entityPool.Tokens[0].Decimals, Token1Decimals: entityPool.Tokens[1].Decimals, StaticExtra: staticExtra, @@ -92,7 +93,7 @@ func (s *PoolSimulator) CalcAmountOut(param poolpkg.CalcAmountOutParams) (*poolp return nil, ErrSwapAndArbitragePaused } - if param.TokenAmountIn.Amount.Cmp(bignumber.ZeroBI) <= 0 { + if param.TokenAmountIn.Amount.Sign() <= 0 { return nil, ErrInvalidAmountIn } @@ -109,51 +110,18 @@ func (s *PoolSimulator) CalcAmountOut(param poolpkg.CalcAmountOutParams) (*poolp // fee is applied on token in fee := new(big.Int).Mul(param.TokenAmountIn.Amount, s.Pool.Info.SwapFee) - fee = new(big.Int).Div(fee, big.NewInt(Fee100PercentPrecision)) + fee = fee.Div(fee, Fee100PercentPrecision) amountInAfterFee := new(big.Int).Sub(param.TokenAmountIn.Amount, fee) - collateralReserves := CollateralReserves{ - Token0RealReserves: new(big.Int).Set(s.CollateralReserves.Token0RealReserves), - Token1RealReserves: new(big.Int).Set(s.CollateralReserves.Token1RealReserves), - Token0ImaginaryReserves: new(big.Int).Set(s.CollateralReserves.Token0ImaginaryReserves), - Token1ImaginaryReserves: new(big.Int).Set(s.CollateralReserves.Token1ImaginaryReserves), - } - - debtReserves := DebtReserves{ - Token0RealReserves: new(big.Int).Set(s.DebtReserves.Token0RealReserves), - Token1RealReserves: new(big.Int).Set(s.DebtReserves.Token1RealReserves), - Token0ImaginaryReserves: new(big.Int).Set(s.DebtReserves.Token0ImaginaryReserves), - Token1ImaginaryReserves: new(big.Int).Set(s.DebtReserves.Token1ImaginaryReserves), - } - - dexLimits := DexLimits{ - BorrowableToken0: TokenLimit{ - Available: new(big.Int).Set(s.DexLimits.BorrowableToken0.Available), - ExpandsTo: new(big.Int).Set(s.DexLimits.BorrowableToken0.ExpandsTo), - ExpandDuration: new(big.Int).Set(s.DexLimits.BorrowableToken0.ExpandDuration), - }, - BorrowableToken1: TokenLimit{ - Available: new(big.Int).Set(s.DexLimits.BorrowableToken1.Available), - ExpandsTo: new(big.Int).Set(s.DexLimits.BorrowableToken1.ExpandsTo), - ExpandDuration: new(big.Int).Set(s.DexLimits.BorrowableToken1.ExpandDuration), - }, - WithdrawableToken0: TokenLimit{ - Available: new(big.Int).Set(s.DexLimits.WithdrawableToken0.Available), - ExpandsTo: new(big.Int).Set(s.DexLimits.WithdrawableToken0.ExpandsTo), - ExpandDuration: new(big.Int).Set(s.DexLimits.WithdrawableToken0.ExpandDuration), - }, - WithdrawableToken1: TokenLimit{ - Available: new(big.Int).Set(s.DexLimits.WithdrawableToken1.Available), - ExpandsTo: new(big.Int).Set(s.DexLimits.WithdrawableToken1.ExpandsTo), - ExpandDuration: new(big.Int).Set(s.DexLimits.WithdrawableToken1.ExpandDuration), - }, - } - + collateralReserves := s.CollateralReserves.Clone() + debtReserves := s.DebtReserves.Clone() + dexLimits := s.DexLimits.Clone() syncTimestamp := s.SyncTimestamp + centerPrice := s.CenterPrice tokenAmountOut, err := swapIn(swap0To1, amountInAfterFee, collateralReserves, debtReserves, - int64(tokenInDecimals), int64(tokenOutDecimals), dexLimits, syncTimestamp) + int64(tokenInDecimals), int64(tokenOutDecimals), dexLimits, centerPrice, syncTimestamp) if err != nil { return nil, err } @@ -188,7 +156,7 @@ func (s *PoolSimulator) CalcAmountIn(param poolpkg.CalcAmountInParams) (*poolpkg return nil, ErrSwapAndArbitragePaused } - if param.TokenAmountOut.Amount.Cmp(bignumber.ZeroBI) <= 0 { + if param.TokenAmountOut.Amount.Sign() <= 0 { return nil, ErrInvalidAmountOut } @@ -207,54 +175,21 @@ func (s *PoolSimulator) CalcAmountIn(param poolpkg.CalcAmountInParams) (*poolpkg tokenInDecimals = s.Token1Decimals } - collateralReserves := CollateralReserves{ - Token0RealReserves: new(big.Int).Set(s.CollateralReserves.Token0RealReserves), - Token1RealReserves: new(big.Int).Set(s.CollateralReserves.Token1RealReserves), - Token0ImaginaryReserves: new(big.Int).Set(s.CollateralReserves.Token0ImaginaryReserves), - Token1ImaginaryReserves: new(big.Int).Set(s.CollateralReserves.Token1ImaginaryReserves), - } - - debtReserves := DebtReserves{ - Token0RealReserves: new(big.Int).Set(s.DebtReserves.Token0RealReserves), - Token1RealReserves: new(big.Int).Set(s.DebtReserves.Token1RealReserves), - Token0ImaginaryReserves: new(big.Int).Set(s.DebtReserves.Token0ImaginaryReserves), - Token1ImaginaryReserves: new(big.Int).Set(s.DebtReserves.Token1ImaginaryReserves), - } - - dexLimits := DexLimits{ - BorrowableToken0: TokenLimit{ - Available: new(big.Int).Set(s.DexLimits.BorrowableToken0.Available), - ExpandsTo: new(big.Int).Set(s.DexLimits.BorrowableToken0.ExpandsTo), - ExpandDuration: new(big.Int).Set(s.DexLimits.BorrowableToken0.ExpandDuration), - }, - BorrowableToken1: TokenLimit{ - Available: new(big.Int).Set(s.DexLimits.BorrowableToken1.Available), - ExpandsTo: new(big.Int).Set(s.DexLimits.BorrowableToken1.ExpandsTo), - ExpandDuration: new(big.Int).Set(s.DexLimits.BorrowableToken1.ExpandDuration), - }, - WithdrawableToken0: TokenLimit{ - Available: new(big.Int).Set(s.DexLimits.WithdrawableToken0.Available), - ExpandsTo: new(big.Int).Set(s.DexLimits.WithdrawableToken0.ExpandsTo), - ExpandDuration: new(big.Int).Set(s.DexLimits.WithdrawableToken0.ExpandDuration), - }, - WithdrawableToken1: TokenLimit{ - Available: new(big.Int).Set(s.DexLimits.WithdrawableToken1.Available), - ExpandsTo: new(big.Int).Set(s.DexLimits.WithdrawableToken1.ExpandsTo), - ExpandDuration: new(big.Int).Set(s.DexLimits.WithdrawableToken1.ExpandDuration), - }, - } - + collateralReserves := s.CollateralReserves.Clone() + debtReserves := s.DebtReserves.Clone() + dexLimits := s.DexLimits.Clone() syncTimestamp := s.SyncTimestamp + centerPrice := s.CenterPrice tokenAmountIn, err := swapOut(swap0To1, param.TokenAmountOut.Amount, collateralReserves, debtReserves, - int64(tokenInDecimals), int64(tokenOutDecimals), dexLimits, syncTimestamp) + int64(tokenInDecimals), int64(tokenOutDecimals), dexLimits, centerPrice, syncTimestamp) if err != nil { return nil, err } // fee is applied on token in fee := new(big.Int).Mul(tokenAmountIn, s.Pool.Info.SwapFee) - fee = new(big.Int).Div(fee, big.NewInt(Fee100PercentPrecision)) + fee = fee.Div(fee, Fee100PercentPrecision) amountInAfterFee := new(big.Int).Add(tokenAmountIn, fee) @@ -273,8 +208,7 @@ func (s *PoolSimulator) CalcAmountIn(param poolpkg.CalcAmountInParams) (*poolpkg func (t *PoolSimulator) UpdateBalance(params poolpkg.UpdateBalanceParams) { input, output := params.TokenAmountIn, params.TokenAmountOut - var inputAmount = input.Amount - var outputAmount = output.Amount + inputAmount, outputAmount := input.Amount, output.Amount for i := range t.Info.Tokens { if t.Info.Tokens[i] == input.Token { @@ -319,7 +253,7 @@ func getAmountOut(amountIn *big.Int, iReserveIn *big.Int, iReserveOut *big.Int) denominator := new(big.Int).Add(iReserveIn, amountIn) // Using the swap formula: (AmountIn * iReserveY) / (iReserveX + AmountIn) - return new(big.Int).Div(numerator, denominator) + return numerator.Div(numerator, denominator) } /** @@ -335,7 +269,7 @@ func getAmountIn(amountOut *big.Int, iReserveIn *big.Int, iReserveOut *big.Int) denominator := new(big.Int).Sub(iReserveOut, amountOut) // Using the swap formula: (AmountOut * iReserveX) / (iReserveY - AmountOut) - return new(big.Int).Div(numerator, denominator) + return numerator.Div(numerator, denominator) } /** @@ -396,7 +330,7 @@ func swapRoutingOut(t *big.Int, x *big.Int, y *big.Int, x2 *big.Int, y2 *big.Int */ func verifyToken0Reserves(token0Reserves *big.Int, token1Reserves *big.Int, price *big.Int) bool { numerator := new(big.Int).Mul(token1Reserves, bI1e27) - denominator := new(big.Int).Mul(price, big.NewInt(MinSwapLiquidity)) + denominator := new(big.Int).Mul(price, MinSwapLiquidity) return token0Reserves.Cmp(numerator.Div(numerator, denominator)) >= 0 } @@ -410,7 +344,7 @@ func verifyToken0Reserves(token0Reserves *big.Int, token1Reserves *big.Int, pric */ func verifyToken1Reserves(token0Reserves *big.Int, token1Reserves *big.Int, price *big.Int) bool { numerator := new(big.Int).Mul(token0Reserves, price) - denominator := new(big.Int).Mul(bI1e27, big.NewInt(MinSwapLiquidity)) + denominator := new(big.Int).Mul(bI1e27, MinSwapLiquidity) return token1Reserves.Cmp(numerator.Div(numerator, denominator)) >= 0 } @@ -446,11 +380,13 @@ func verifyToken1Reserves(token0Reserves *big.Int, token1Reserves *big.Int, pric * @param {number} currentLimits.withdrawableToken1.available - token1 instant withdrawable available * @param {number} currentLimits.withdrawableToken1.expandsTo - token1 maximum amount the available withdraw amount expands to * @param {number} currentLimits.withdrawableToken1.expandDuration - duration for token1 available to grow to expandsTo + * @param {number} centerPrice - current center price used to verify reserves ratio * @param {number} syncTime - timestamp in seconds when the limits were synced * @returns {number} amountOut - The calculated output amount. * @returns {error} - An error object if the operation fails. */ -func swapInAdjusted(swap0To1 bool, amountToSwap *big.Int, colReserves CollateralReserves, debtReserves DebtReserves, outDecimals int64, currentLimits DexLimits, syncTime int64) (*big.Int, error) { +func swapInAdjusted(swap0To1 bool, amountToSwap *big.Int, colReserves CollateralReserves, debtReserves DebtReserves, + outDecimals int64, currentLimits DexLimits, centerPrice *big.Int, syncTime int64) (*big.Int, error) { var ( colIReserveIn, colIReserveOut, debtIReserveIn, debtIReserveOut *big.Int colReserveIn, colReserveOut, debtReserveIn, debtReserveOut *big.Int @@ -484,26 +420,26 @@ func swapInAdjusted(swap0To1 bool, amountToSwap *big.Int, colReserves Collateral // bring borrowable and withdrawable from token decimals to 1e12 decimals, same as amounts var factor *big.Int if DexAmountsDecimals > outDecimals { - factor = new(big.Int).Exp(bI10, big.NewInt(DexAmountsDecimals-outDecimals), nil) + factor = bignumber.TenPowInt(DexAmountsDecimals - outDecimals) borrowable = new(big.Int).Mul(borrowable, factor) withdrawable = new(big.Int).Mul(withdrawable, factor) } else { - factor = new(big.Int).Exp(bI10, big.NewInt(outDecimals-DexAmountsDecimals), nil) + factor = bignumber.TenPowInt(outDecimals - DexAmountsDecimals) borrowable = new(big.Int).Div(borrowable, factor) withdrawable = new(big.Int).Div(withdrawable, factor) } // Check if all reserves of collateral pool are greater than 0 - colPoolEnabled := colReserves.Token0RealReserves.Cmp(bignumber.ZeroBI) > 0 && - colReserves.Token1RealReserves.Cmp(bignumber.ZeroBI) > 0 && - colReserves.Token0ImaginaryReserves.Cmp(bignumber.ZeroBI) > 0 && - colReserves.Token1ImaginaryReserves.Cmp(bignumber.ZeroBI) > 0 + colPoolEnabled := colReserves.Token0RealReserves.Sign() > 0 && + colReserves.Token1RealReserves.Sign() > 0 && + colReserves.Token0ImaginaryReserves.Sign() > 0 && + colReserves.Token1ImaginaryReserves.Sign() > 0 // Check if all reserves of debt pool are greater than 0 - debtPoolEnabled := debtReserves.Token0RealReserves.Cmp(bignumber.ZeroBI) > 0 && - debtReserves.Token1RealReserves.Cmp(bignumber.ZeroBI) > 0 && - debtReserves.Token0ImaginaryReserves.Cmp(bignumber.ZeroBI) > 0 && - debtReserves.Token1ImaginaryReserves.Cmp(bignumber.ZeroBI) > 0 + debtPoolEnabled := debtReserves.Token0RealReserves.Sign() > 0 && + debtReserves.Token1RealReserves.Sign() > 0 && + debtReserves.Token0ImaginaryReserves.Sign() > 0 && + debtReserves.Token1ImaginaryReserves.Sign() > 0 var a *big.Int if colPoolEnabled && debtPoolEnabled { @@ -511,20 +447,20 @@ func swapInAdjusted(swap0To1 bool, amountToSwap *big.Int, colReserves Collateral } else if debtPoolEnabled { a = big.NewInt(-1) // Route from debt pool } else if colPoolEnabled { - a = new(big.Int).Add(amountToSwap, big.NewInt(1)) // Route from collateral pool + a = new(big.Int).Add(amountToSwap, bignumber.One) // Route from collateral pool } else { return nil, errors.New("no pools are enabled") } - amountInCollateral := big.NewInt(0) - amountOutCollateral := big.NewInt(0) - amountInDebt := big.NewInt(0) - amountOutDebt := big.NewInt(0) + amountInCollateral := new(big.Int) + amountOutCollateral := new(big.Int) + amountInDebt := new(big.Int) + amountOutDebt := new(big.Int) triggerUpdateDebtReserves := false triggerUpdateColReserves := false - if a.Cmp(bignumber.ZeroBI) <= 0 { + if a.Sign() <= 0 { // Entire trade routes through debt pool amountInDebt = amountToSwap amountOutDebt = getAmountOut(amountToSwap, debtIReserveIn, debtIReserveOut) @@ -550,84 +486,90 @@ func swapInAdjusted(swap0To1 bool, amountToSwap *big.Int, colReserves Collateral } if amountOutDebt.Cmp(debtReserveOut) > 0 { - return nil, errors.New(ErrInsufficientReserve.Error()) + return nil, ErrInsufficientReserve } if amountOutCollateral.Cmp(colReserveOut) > 0 { - return nil, errors.New(ErrInsufficientReserve.Error()) + return nil, ErrInsufficientReserve } if amountOutDebt.Cmp(borrowable) > 0 { - return nil, errors.New(ErrInsufficientBorrowable.Error()) + return nil, ErrInsufficientBorrowable } if amountOutCollateral.Cmp(withdrawable) > 0 { - return nil, errors.New(ErrInsufficientWithdrawable.Error()) + return nil, ErrInsufficientWithdrawable } - oldPrice := big.NewInt(0) - newPrice := big.NewInt(0) - priceDiff := big.NewInt(0) - maxPriceDiff := big.NewInt(0) + if amountInCollateral.Sign() > 0 { + reservesRatioValid := false + if swap0To1 { + reservesRatioValid = verifyToken1Reserves(new(big.Int).Add(colReserveIn, amountInCollateral), + new(big.Int).Sub(colReserveOut, amountOutCollateral), centerPrice) + } else { + reservesRatioValid = verifyToken0Reserves(new(big.Int).Sub(colReserveOut, amountOutCollateral), + new(big.Int).Add(colReserveIn, amountInCollateral), centerPrice) + } + if !reservesRatioValid { + return nil, ErrVerifyReservesRatiosInvalid + } + } + if amountInDebt.Sign() > 0 { + reservesRatioValid := false + if swap0To1 { + reservesRatioValid = verifyToken1Reserves(new(big.Int).Add(debtReserveIn, amountInDebt), + new(big.Int).Sub(debtReserveOut, amountOutDebt), centerPrice) + } else { + reservesRatioValid = verifyToken0Reserves(new(big.Int).Sub(debtReserveOut, amountOutDebt), + new(big.Int).Add(debtReserveIn, amountInDebt), centerPrice) + } + if !reservesRatioValid { + return nil, ErrVerifyReservesRatiosInvalid + } + } + + oldPrice, newPrice := new(big.Int), new(big.Int) + priceDiff, maxPriceDiff := new(big.Int), new(big.Int) // from whatever pool higher amount of swap is routing we are taking that as final price, does not matter much because both pools final price should be same if amountInCollateral.Cmp(amountInDebt) > 0 { // new pool price from col pool if swap0To1 { oldPrice.Div(oldPrice.Mul(colIReserveOut, bI1e27), colIReserveIn) - newPrice.Div(newPrice.Mul(new(big.Int).Sub(colIReserveOut, amountOutCollateral), bI1e27), new(big.Int).Add(colIReserveIn, amountInCollateral)) + newPrice.Div(newPrice.Mul(newPrice.Sub(colIReserveOut, amountOutCollateral), bI1e27), + new(big.Int).Add(colIReserveIn, amountInCollateral)) } else { oldPrice.Div(oldPrice.Mul(colIReserveIn, bI1e27), colIReserveOut) - newPrice.Div(newPrice.Mul(new(big.Int).Add(colIReserveIn, amountInCollateral), bI1e27), new(big.Int).Sub(colIReserveOut, amountOutCollateral)) + newPrice.Div(newPrice.Mul(newPrice.Add(colIReserveIn, amountInCollateral), bI1e27), + new(big.Int).Sub(colIReserveOut, amountOutCollateral)) } } else { // new pool price from debt pool if swap0To1 { oldPrice.Div(oldPrice.Mul(debtIReserveOut, bI1e27), debtIReserveIn) - newPrice.Div(newPrice.Mul(new(big.Int).Sub(debtIReserveOut, amountOutDebt), bI1e27), new(big.Int).Add(debtIReserveIn, amountInDebt)) + newPrice.Div(newPrice.Mul(newPrice.Sub(debtIReserveOut, amountOutDebt), bI1e27), + new(big.Int).Add(debtIReserveIn, amountInDebt)) } else { oldPrice.Div(oldPrice.Mul(debtIReserveIn, bI1e27), debtIReserveOut) - newPrice.Div(newPrice.Mul(new(big.Int).Add(debtIReserveIn, amountInDebt), bI1e27), new(big.Int).Sub(debtIReserveOut, amountOutDebt)) + newPrice.Div(newPrice.Mul(newPrice.Add(debtIReserveIn, amountInDebt), bI1e27), + new(big.Int).Sub(debtIReserveOut, amountOutDebt)) } } priceDiff.Abs(priceDiff.Sub(oldPrice, newPrice)) - maxPriceDiff.Div(maxPriceDiff.Mul(oldPrice, big.NewInt(MaxPriceDiff)), bI100) + maxPriceDiff.Div(maxPriceDiff.Mul(oldPrice, MaxPriceDiff), bI100) if priceDiff.Cmp(maxPriceDiff) > 0 { // if price diff is > 5% then swap would revert. - return nil, errors.New(ErrInsufficientMaxPrice.Error()) + return nil, ErrInsufficientMaxPrice } - if amountInCollateral.Cmp(bignumber.ZeroBI) > 0 { - reservesRatioValid := false - if swap0To1 { - reservesRatioValid = verifyToken1Reserves(new(big.Int).Add(colReserveIn, amountInCollateral), new(big.Int).Sub(colReserveOut, amountOutCollateral), oldPrice) - } else { - reservesRatioValid = verifyToken0Reserves(new(big.Int).Sub(colReserveOut, amountOutCollateral), new(big.Int).Add(colReserveIn, amountInCollateral), oldPrice) - } - if !reservesRatioValid { - return nil, errors.New(ErrVerifyReservesRatiosInvalid.Error()) - } - } - if amountInDebt.Cmp(bignumber.ZeroBI) > 0 { - reservesRatioValid := false - if swap0To1 { - reservesRatioValid = verifyToken1Reserves(new(big.Int).Add(debtReserveIn, amountInDebt), new(big.Int).Sub(debtReserveOut, amountOutDebt), oldPrice) - } else { - reservesRatioValid = verifyToken0Reserves(new(big.Int).Sub(debtReserveOut, amountOutDebt), new(big.Int).Add(debtReserveIn, amountInDebt), oldPrice) - } - if !reservesRatioValid { - return nil, errors.New(ErrVerifyReservesRatiosInvalid.Error()) - } + if triggerUpdateColReserves { + updateCollateralReservesAndLimits(swap0To1, amountToSwap, amountOutCollateral, colReserves, currentLimits) } - if triggerUpdateColReserves && triggerUpdateDebtReserves { - updateBothReservesAndLimits(swap0To1, amountInCollateral, amountOutCollateral, amountInDebt, amountOutDebt, colReserves, debtReserves, currentLimits) - } else if triggerUpdateColReserves { - updateCollateralReservesAndLimits(swap0To1, amountToSwap, amountOutCollateral, colReserves, currentLimits) - } else if triggerUpdateDebtReserves { + if triggerUpdateDebtReserves { updateDebtReservesAndLimits(swap0To1, amountToSwap, amountOutDebt, debtReserves, currentLimits) } - return new(big.Int).Add(amountOutCollateral, amountOutDebt), nil + return amountOutCollateral.Add(amountOutCollateral, amountOutDebt), nil } /** @@ -663,6 +605,7 @@ func swapInAdjusted(swap0To1 bool, amountToSwap *big.Int, colReserves Collateral * @param {number} currentLimits.withdrawableToken1.available - token1 instant withdrawable available * @param {number} currentLimits.withdrawableToken1.expandsTo - token1 maximum amount the available withdraw amount expands to * @param {number} currentLimits.withdrawableToken1.expandDuration - duration for token1 available to grow to expandsTo + * @param {number} centerPrice - current center price used to verify reserves ratio * @param {number} syncTime - timestamp in seconds when the limits were synced * @returns {number} amountOut - The calculated output amount. * @returns {error} - An error object if the operation fails. @@ -675,26 +618,28 @@ func swapIn( inDecimals int64, outDecimals int64, currentLimits DexLimits, + centerPrice *big.Int, syncTime int64, ) (*big.Int, error) { var amountInAdjusted *big.Int if inDecimals > DexAmountsDecimals { - amountInAdjusted = new(big.Int).Div(amountIn, new(big.Int).Exp(bI10, big.NewInt(inDecimals-DexAmountsDecimals), nil)) + amountInAdjusted = new(big.Int).Div(amountIn, bignumber.TenPowInt(inDecimals-DexAmountsDecimals)) } else { - amountInAdjusted = new(big.Int).Mul(amountIn, new(big.Int).Exp(bI10, big.NewInt(DexAmountsDecimals-inDecimals), nil)) + amountInAdjusted = new(big.Int).Mul(amountIn, bignumber.TenPowInt(DexAmountsDecimals-inDecimals)) } - amountOut, err := swapInAdjusted(swap0To1, amountInAdjusted, colReserves, debtReserves, outDecimals, currentLimits, syncTime) + amountOut, err := swapInAdjusted(swap0To1, amountInAdjusted, colReserves, debtReserves, outDecimals, currentLimits, + centerPrice, syncTime) if err != nil { return nil, err } if outDecimals > DexAmountsDecimals { - amountOut = new(big.Int).Mul(amountOut, new(big.Int).Exp(bI10, big.NewInt(outDecimals-DexAmountsDecimals), nil)) + amountOut = new(big.Int).Mul(amountOut, bignumber.TenPowInt(outDecimals-DexAmountsDecimals)) } else { - amountOut = new(big.Int).Div(amountOut, new(big.Int).Exp(bI10, big.NewInt(DexAmountsDecimals-outDecimals), nil)) + amountOut = new(big.Int).Div(amountOut, bignumber.TenPowInt(DexAmountsDecimals-outDecimals)) } return amountOut, nil @@ -732,6 +677,7 @@ func swapIn( * @param {number} currentLimits.withdrawableToken1.available - token1 instant withdrawable available * @param {number} currentLimits.withdrawableToken1.expandsTo - token1 maximum amount the available withdraw amount expands to * @param {number} currentLimits.withdrawableToken1.expandDuration - duration for token1 available to grow to expandsTo + * @param {number} centerPrice - current center price used to verify reserves ratio * @param {number} syncTime - timestamp in seconds when the limits were synced * @returns {number} amountIn - The calculated input amount required for the swap. * @returns {error} - An error object if the operation fails. @@ -743,6 +689,7 @@ func swapOutAdjusted( debtReserves DebtReserves, outDecimals int64, currentLimits DexLimits, + centerPrice *big.Int, syncTime int64, ) (*big.Int, error) { var ( @@ -778,26 +725,26 @@ func swapOutAdjusted( // bring borrowable and withdrawable from token decimals to 1e12 decimals, same as amounts var factor *big.Int if DexAmountsDecimals > outDecimals { - factor = new(big.Int).Exp(bI10, big.NewInt(DexAmountsDecimals-outDecimals), nil) + factor = bignumber.TenPowInt(DexAmountsDecimals - outDecimals) borrowable = new(big.Int).Mul(borrowable, factor) withdrawable = new(big.Int).Mul(withdrawable, factor) } else { - factor = new(big.Int).Exp(bI10, big.NewInt(outDecimals-DexAmountsDecimals), nil) + factor = bignumber.TenPowInt(outDecimals - DexAmountsDecimals) borrowable = new(big.Int).Div(borrowable, factor) withdrawable = new(big.Int).Div(withdrawable, factor) } // Check if all reserves of collateral pool are greater than 0 - colPoolEnabled := colReserves.Token0RealReserves.Cmp(bignumber.ZeroBI) > 0 && - colReserves.Token1RealReserves.Cmp(bignumber.ZeroBI) > 0 && - colReserves.Token0ImaginaryReserves.Cmp(bignumber.ZeroBI) > 0 && - colReserves.Token1ImaginaryReserves.Cmp(bignumber.ZeroBI) > 0 + colPoolEnabled := colReserves.Token0RealReserves.Sign() > 0 && + colReserves.Token1RealReserves.Sign() > 0 && + colReserves.Token0ImaginaryReserves.Sign() > 0 && + colReserves.Token1ImaginaryReserves.Sign() > 0 // Check if all reserves of debt pool are greater than 0 - debtPoolEnabled := debtReserves.Token0RealReserves.Cmp(bignumber.ZeroBI) > 0 && - debtReserves.Token1RealReserves.Cmp(bignumber.ZeroBI) > 0 && - debtReserves.Token0ImaginaryReserves.Cmp(bignumber.ZeroBI) > 0 && - debtReserves.Token1ImaginaryReserves.Cmp(bignumber.ZeroBI) > 0 + debtPoolEnabled := debtReserves.Token0RealReserves.Sign() > 0 && + debtReserves.Token1RealReserves.Sign() > 0 && + debtReserves.Token0ImaginaryReserves.Sign() > 0 && + debtReserves.Token1ImaginaryReserves.Sign() > 0 var a *big.Int if colPoolEnabled && debtPoolEnabled { @@ -805,26 +752,24 @@ func swapOutAdjusted( } else if debtPoolEnabled { a = big.NewInt(-1) // Route from debt pool } else if colPoolEnabled { - a = new(big.Int).Add(amountOut, big.NewInt(1)) // Route from collateral pool + a = new(big.Int).Add(amountOut, bignumber.One) // Route from collateral pool } else { return nil, errors.New("no pools are enabled") } - amountInCollateral := big.NewInt(0) - amountOutCollateral := big.NewInt(0) - amountInDebt := big.NewInt(0) - amountOutDebt := big.NewInt(0) + amountInCollateral, amountOutCollateral := new(big.Int), new(big.Int) + amountInDebt, amountOutDebt := new(big.Int), new(big.Int) triggerUpdateDebtReserves := false triggerUpdateColReserves := false - if a.Cmp(bignumber.ZeroBI) <= 0 { + if a.Sign() <= 0 { // Entire trade routes through debt pool amountOutDebt = amountOut amountInDebt = getAmountIn(amountOut, debtIReserveIn, debtIReserveOut) if amountOut.Cmp(debtReserveOut) > 0 { - return nil, errors.New(ErrInsufficientReserve.Error()) + return nil, ErrInsufficientReserve } triggerUpdateDebtReserves = true @@ -833,7 +778,7 @@ func swapOutAdjusted( amountOutCollateral = amountOut amountInCollateral = getAmountIn(amountOut, colIReserveIn, colIReserveOut) if amountOut.Cmp(colReserveOut) > 0 { - return nil, errors.New(ErrInsufficientReserve.Error()) + return nil, ErrInsufficientReserve } triggerUpdateColReserves = true @@ -845,7 +790,7 @@ func swapOutAdjusted( amountInDebt = getAmountIn(amountOutDebt, debtIReserveIn, debtIReserveOut) if amountOutDebt.Cmp(debtReserveOut) > 0 || amountOutCollateral.Cmp(colReserveOut) > 0 { - return nil, errors.New(ErrInsufficientReserve.Error()) + return nil, ErrInsufficientReserve } triggerUpdateDebtReserves = true @@ -853,76 +798,82 @@ func swapOutAdjusted( } if amountOutDebt.Cmp(borrowable) > 0 { - return nil, errors.New(ErrInsufficientBorrowable.Error()) + return nil, ErrInsufficientBorrowable } if amountOutCollateral.Cmp(withdrawable) > 0 { - return nil, errors.New(ErrInsufficientWithdrawable.Error()) + return nil, ErrInsufficientWithdrawable } - oldPrice := big.NewInt(0) - newPrice := big.NewInt(0) - priceDiff := big.NewInt(0) - maxPriceDiff := big.NewInt(0) + if amountInCollateral.Sign() > 0 { + reservesRatioValid := false + if swap0To1 { + reservesRatioValid = verifyToken1Reserves(new(big.Int).Add(colReserveIn, amountInCollateral), + new(big.Int).Sub(colReserveOut, amountOutCollateral), centerPrice) + } else { + reservesRatioValid = verifyToken0Reserves(new(big.Int).Sub(colReserveOut, amountOutCollateral), + new(big.Int).Add(colReserveIn, amountInCollateral), centerPrice) + } + if !reservesRatioValid { + return nil, ErrVerifyReservesRatiosInvalid + } + } + if amountInDebt.Sign() > 0 { + reservesRatioValid := false + if swap0To1 { + reservesRatioValid = verifyToken1Reserves(new(big.Int).Add(debtReserveIn, amountInDebt), + new(big.Int).Sub(debtReserveOut, amountOutDebt), centerPrice) + } else { + reservesRatioValid = verifyToken0Reserves(new(big.Int).Sub(debtReserveOut, amountOutDebt), + new(big.Int).Add(debtReserveIn, amountInDebt), centerPrice) + } + if !reservesRatioValid { + return nil, ErrVerifyReservesRatiosInvalid + } + } + + oldPrice, newPrice := new(big.Int), new(big.Int) + priceDiff, maxPriceDiff := new(big.Int), new(big.Int) // from whatever pool higher amount of swap is routing we are taking that as final price, does not matter much because both pools final price should be same if amountOutCollateral.Cmp(amountOutDebt) > 0 { // new pool price from col pool if swap0To1 { oldPrice.Div(oldPrice.Mul(colIReserveOut, bI1e27), colIReserveIn) - newPrice.Div(newPrice.Mul(new(big.Int).Sub(colIReserveOut, amountOutCollateral), bI1e27), new(big.Int).Add(colIReserveIn, amountInCollateral)) + newPrice.Div(newPrice.Mul(newPrice.Sub(colIReserveOut, amountOutCollateral), bI1e27), + new(big.Int).Add(colIReserveIn, amountInCollateral)) } else { oldPrice.Div(oldPrice.Mul(colIReserveIn, bI1e27), colIReserveOut) - newPrice.Div(newPrice.Mul(new(big.Int).Add(colIReserveIn, amountInCollateral), bI1e27), new(big.Int).Sub(colIReserveOut, amountOutCollateral)) + newPrice.Div(newPrice.Mul(newPrice.Add(colIReserveIn, amountInCollateral), bI1e27), + new(big.Int).Sub(colIReserveOut, amountOutCollateral)) } } else { // new pool price from debt pool if swap0To1 { oldPrice.Div(oldPrice.Mul(debtIReserveOut, bI1e27), debtIReserveIn) - newPrice.Div(newPrice.Mul(new(big.Int).Sub(debtIReserveOut, amountOutDebt), bI1e27), new(big.Int).Add(debtIReserveIn, amountInDebt)) + newPrice.Div(newPrice.Mul(newPrice.Sub(debtIReserveOut, amountOutDebt), bI1e27), + new(big.Int).Add(debtIReserveIn, amountInDebt)) } else { oldPrice.Div(oldPrice.Mul(debtIReserveIn, bI1e27), debtIReserveOut) - newPrice.Div(newPrice.Mul(new(big.Int).Add(debtIReserveIn, amountInDebt), bI1e27), new(big.Int).Sub(debtIReserveOut, amountOutDebt)) + newPrice.Div(newPrice.Mul(newPrice.Add(debtIReserveIn, amountInDebt), bI1e27), + new(big.Int).Sub(debtIReserveOut, amountOutDebt)) } } priceDiff.Abs(priceDiff.Sub(oldPrice, newPrice)) - maxPriceDiff.Div(maxPriceDiff.Mul(oldPrice, big.NewInt(MaxPriceDiff)), bI100) + maxPriceDiff.Div(maxPriceDiff.Mul(oldPrice, MaxPriceDiff), bI100) if priceDiff.Cmp(maxPriceDiff) > 0 { // if price diff is > 5% then swap would revert. - return nil, errors.New(ErrInsufficientMaxPrice.Error()) + return nil, ErrInsufficientMaxPrice } - if amountInCollateral.Cmp(bignumber.ZeroBI) > 0 { - reservesRatioValid := false - if swap0To1 { - reservesRatioValid = verifyToken1Reserves(new(big.Int).Add(colReserveIn, amountInCollateral), new(big.Int).Sub(colReserveOut, amountOutCollateral), oldPrice) - } else { - reservesRatioValid = verifyToken0Reserves(new(big.Int).Sub(colReserveOut, amountOutCollateral), new(big.Int).Add(colReserveIn, amountInCollateral), oldPrice) - } - if !reservesRatioValid { - return nil, errors.New(ErrVerifyReservesRatiosInvalid.Error()) - } - } - if amountInDebt.Cmp(bignumber.ZeroBI) > 0 { - reservesRatioValid := false - if swap0To1 { - reservesRatioValid = verifyToken1Reserves(new(big.Int).Add(debtReserveIn, amountInDebt), new(big.Int).Sub(debtReserveOut, amountOutDebt), oldPrice) - } else { - reservesRatioValid = verifyToken0Reserves(new(big.Int).Sub(debtReserveOut, amountOutDebt), new(big.Int).Add(debtReserveIn, amountInDebt), oldPrice) - } - if !reservesRatioValid { - return nil, errors.New(ErrVerifyReservesRatiosInvalid.Error()) - } + if triggerUpdateColReserves { + updateCollateralReservesAndLimits(swap0To1, amountInCollateral, amountOutCollateral, colReserves, currentLimits) } - if triggerUpdateColReserves && triggerUpdateDebtReserves { - updateBothReservesAndLimits(swap0To1, amountInCollateral, amountOutCollateral, amountInDebt, amountOutDebt, colReserves, debtReserves, currentLimits) - } else if triggerUpdateColReserves { - updateCollateralReservesAndLimits(swap0To1, amountInCollateral, amountOutCollateral, colReserves, currentLimits) - } else if triggerUpdateDebtReserves { + if triggerUpdateDebtReserves { updateDebtReservesAndLimits(swap0To1, amountInDebt, amountOutDebt, debtReserves, currentLimits) } - return new(big.Int).Add(amountInCollateral, amountInDebt), nil + return amountInCollateral.Add(amountInCollateral, amountInDebt), nil } /** @@ -958,6 +909,7 @@ func swapOutAdjusted( * @param {number} currentLimits.withdrawableToken1.available - token1 instant withdrawable available * @param {number} currentLimits.withdrawableToken1.expandsTo - token1 maximum amount the available withdraw amount expands to * @param {number} currentLimits.withdrawableToken1.expandDuration - duration for token1 available to grow to expandsTo + * @param {number} centerPrice - current center price used to verify reserves ratio * @param {number} syncTime - timestamp in seconds when the limits were synced * @returns {number} amountIn - The calculated input amount required for the swap. * @returns {error} - An error object if the operation fails. @@ -970,30 +922,30 @@ func swapOut( inDecimals int64, outDecimals int64, currentLimits DexLimits, + centerPrice *big.Int, syncTime int64, ) (*big.Int, error) { var amountOutAdjusted *big.Int if outDecimals > DexAmountsDecimals { amountOutAdjusted = new(big.Int).Div(amountOut, - new(big.Int).Exp(bI10, big.NewInt(outDecimals-DexAmountsDecimals), nil)) + bignumber.TenPowInt(outDecimals-DexAmountsDecimals)) } else { amountOutAdjusted = new(big.Int).Mul(amountOut, - new(big.Int).Exp(bI10, big.NewInt(DexAmountsDecimals-outDecimals), nil)) + bignumber.TenPowInt(DexAmountsDecimals-outDecimals)) } - amountIn, err := swapOutAdjusted(swap0To1, amountOutAdjusted, colReserves, debtReserves, outDecimals, currentLimits, syncTime) + amountIn, err := swapOutAdjusted(swap0To1, amountOutAdjusted, colReserves, debtReserves, outDecimals, currentLimits, + centerPrice, syncTime) if err != nil { return nil, err } if inDecimals > DexAmountsDecimals { - amountIn = new(big.Int).Mul(amountIn, - new(big.Int).Exp(bI10, big.NewInt(inDecimals-DexAmountsDecimals), nil)) + amountIn = new(big.Int).Mul(amountIn, bignumber.TenPowInt(inDecimals-DexAmountsDecimals)) } else { - amountIn = new(big.Int).Div(amountIn, - new(big.Int).Exp(bI10, big.NewInt(DexAmountsDecimals-inDecimals), nil)) + amountIn = new(big.Int).Div(amountIn, bignumber.TenPowInt(DexAmountsDecimals-inDecimals)) } return amountIn, nil @@ -1004,28 +956,46 @@ func getExpandedLimit(syncTime int64, limit TokenLimit) *big.Int { currentTime := time.Now().Unix() // get current time in seconds elapsedTime := currentTime - syncTime - expandedAmount := big.NewInt(0).Set(limit.Available) + expandedAmount := limit.Available if elapsedTime < 10 { // if almost no time has elapsed, return available amount return expandedAmount - } - - if elapsedTime >= limit.ExpandDuration.Int64() { + } else if elapsedTime >= limit.ExpandDuration.Int64() { // if duration has passed, return max amount - expandedAmount = limit.ExpandsTo - return expandedAmount + return limit.ExpandsTo } expandedAmount = new(big.Int).Sub(limit.ExpandsTo, limit.Available) expandedAmount.Mul(expandedAmount, big.NewInt(elapsedTime)) expandedAmount.Div(expandedAmount, limit.ExpandDuration) expandedAmount.Add(expandedAmount, limit.Available) - return expandedAmount } -func updateDebtReservesAndLimits(swap0To1 bool, amountIn, amountOut *big.Int, debtReserves DebtReserves, limits DexLimits) { +func updateCollateralReservesAndLimits(swap0To1 bool, amountIn, amountOut *big.Int, colReserves CollateralReserves, + limits DexLimits) { + if swap0To1 { + colReserves.Token0RealReserves.Add(colReserves.Token0RealReserves, amountIn) + colReserves.Token0ImaginaryReserves.Add(colReserves.Token0ImaginaryReserves, amountIn) + colReserves.Token1RealReserves.Sub(colReserves.Token1RealReserves, amountOut) + colReserves.Token1ImaginaryReserves.Sub(colReserves.Token1ImaginaryReserves, amountOut) + + limits.WithdrawableToken1.Available.Sub(limits.WithdrawableToken1.Available, amountOut) + limits.WithdrawableToken1.ExpandsTo.Sub(limits.WithdrawableToken1.ExpandsTo, amountOut) + } else { + colReserves.Token0RealReserves.Sub(colReserves.Token0RealReserves, amountOut) + colReserves.Token0ImaginaryReserves.Sub(colReserves.Token0ImaginaryReserves, amountOut) + colReserves.Token1RealReserves.Add(colReserves.Token1RealReserves, amountIn) + colReserves.Token1ImaginaryReserves.Add(colReserves.Token1ImaginaryReserves, amountIn) + + limits.WithdrawableToken0.Available.Sub(limits.WithdrawableToken0.Available, amountOut) + limits.WithdrawableToken0.ExpandsTo.Sub(limits.WithdrawableToken0.ExpandsTo, amountOut) + } +} + +func updateDebtReservesAndLimits(swap0To1 bool, amountIn, amountOut *big.Int, debtReserves DebtReserves, + limits DexLimits) { if swap0To1 { debtReserves.Token0RealReserves.Add(debtReserves.Token0RealReserves, amountIn) debtReserves.Token0ImaginaryReserves.Add(debtReserves.Token0ImaginaryReserves, amountIn) @@ -1050,58 +1020,3 @@ func updateDebtReservesAndLimits(swap0To1 bool, amountIn, amountOut *big.Int, de limits.BorrowableToken0.ExpandsTo.Sub(limits.BorrowableToken0.ExpandsTo, amountOut) } } - -func updateCollateralReservesAndLimits(swap0To1 bool, amountIn, amountOut *big.Int, colReserves CollateralReserves, limits DexLimits) { - if swap0To1 { - colReserves.Token0RealReserves.Add(colReserves.Token0RealReserves, amountIn) - colReserves.Token0ImaginaryReserves.Add(colReserves.Token0ImaginaryReserves, amountIn) - colReserves.Token1RealReserves.Sub(colReserves.Token1RealReserves, amountOut) - colReserves.Token1ImaginaryReserves.Sub(colReserves.Token1ImaginaryReserves, amountOut) - - limits.WithdrawableToken1.Available.Sub(limits.WithdrawableToken1.Available, amountOut) - limits.WithdrawableToken1.ExpandsTo.Sub(limits.WithdrawableToken1.ExpandsTo, amountOut) - } else { - colReserves.Token0RealReserves.Sub(colReserves.Token0RealReserves, amountOut) - colReserves.Token0ImaginaryReserves.Sub(colReserves.Token0ImaginaryReserves, amountOut) - colReserves.Token1RealReserves.Add(colReserves.Token1RealReserves, amountIn) - colReserves.Token1ImaginaryReserves.Add(colReserves.Token1ImaginaryReserves, amountIn) - - limits.WithdrawableToken0.Available.Sub(limits.WithdrawableToken0.Available, amountOut) - limits.WithdrawableToken0.ExpandsTo.Sub(limits.WithdrawableToken0.ExpandsTo, amountOut) - } -} - -func updateBothReservesAndLimits(swap0To1 bool, amountInCollateral, amountOutCollateral, amountInDebt, amountOutDebt *big.Int, - colReserves CollateralReserves, debtReserves DebtReserves, limits DexLimits) { - if swap0To1 { - colReserves.Token1RealReserves.Sub(colReserves.Token1RealReserves, amountOutCollateral) - colReserves.Token1ImaginaryReserves.Sub(colReserves.Token1ImaginaryReserves, amountOutCollateral) - colReserves.Token0RealReserves.Add(colReserves.Token0RealReserves, amountInCollateral) - colReserves.Token0ImaginaryReserves.Add(colReserves.Token0ImaginaryReserves, amountInCollateral) - - debtReserves.Token1RealReserves.Sub(debtReserves.Token1RealReserves, amountOutDebt) - debtReserves.Token1ImaginaryReserves.Sub(debtReserves.Token1ImaginaryReserves, amountOutDebt) - debtReserves.Token0RealReserves.Add(debtReserves.Token0RealReserves, amountInDebt) - debtReserves.Token0ImaginaryReserves.Add(debtReserves.Token0ImaginaryReserves, amountInDebt) - - limits.BorrowableToken1.Available.Sub(limits.BorrowableToken1.Available, amountOutDebt) - limits.BorrowableToken1.ExpandsTo.Sub(limits.BorrowableToken1.ExpandsTo, amountOutDebt) - limits.WithdrawableToken1.Available.Sub(limits.WithdrawableToken1.Available, amountOutCollateral) - limits.WithdrawableToken1.ExpandsTo.Sub(limits.WithdrawableToken1.ExpandsTo, amountOutCollateral) - } else { - colReserves.Token1RealReserves.Add(colReserves.Token1RealReserves, amountInCollateral) - colReserves.Token1ImaginaryReserves.Add(colReserves.Token1ImaginaryReserves, amountInCollateral) - colReserves.Token0RealReserves.Sub(colReserves.Token0RealReserves, amountOutCollateral) - colReserves.Token0ImaginaryReserves.Sub(colReserves.Token0ImaginaryReserves, amountOutCollateral) - - debtReserves.Token1RealReserves.Add(debtReserves.Token1RealReserves, amountInDebt) - debtReserves.Token1ImaginaryReserves.Add(debtReserves.Token1ImaginaryReserves, amountInDebt) - debtReserves.Token0RealReserves.Sub(debtReserves.Token0RealReserves, amountOutDebt) - debtReserves.Token0ImaginaryReserves.Sub(debtReserves.Token0ImaginaryReserves, amountOutDebt) - - limits.BorrowableToken0.Available.Sub(limits.BorrowableToken0.Available, amountOutDebt) - limits.BorrowableToken0.ExpandsTo.Sub(limits.BorrowableToken0.ExpandsTo, amountOutDebt) - limits.WithdrawableToken0.Available.Sub(limits.WithdrawableToken0.Available, amountOutCollateral) - limits.WithdrawableToken0.ExpandsTo.Sub(limits.WithdrawableToken0.ExpandsTo, amountOutCollateral) - } -} diff --git a/pkg/liquidity-source/fluid/dex-t1/pool_simulator_test.go b/pkg/liquidity-source/fluid/dex-t1/pool_simulator_test.go index 35fafccbb..2922e09c8 100644 --- a/pkg/liquidity-source/fluid/dex-t1/pool_simulator_test.go +++ b/pkg/liquidity-source/fluid/dex-t1/pool_simulator_test.go @@ -1,6 +1,7 @@ package dexT1 import ( + "errors" "math/big" "testing" "time" @@ -37,6 +38,138 @@ func calculateReservesOutsideRange(geometricMeanPrice, priceAtRange, reserveX, r return reserveXOutside, reserveYOutside } +func getApproxCenterPriceIn(amountToSwap *big.Int, swap0To1 bool, colReserves CollateralReserves, debtReserves DebtReserves) (*big.Int, error) { + colPoolEnabled := colReserves.Token0RealReserves.Sign() > 0 && + colReserves.Token1RealReserves.Sign() > 0 && + colReserves.Token0ImaginaryReserves.Sign() > 0 && + colReserves.Token1ImaginaryReserves.Sign() > 0 + + debtPoolEnabled := debtReserves.Token0RealReserves.Sign() > 0 && + debtReserves.Token1RealReserves.Sign() > 0 && + debtReserves.Token0ImaginaryReserves.Sign() > 0 && + debtReserves.Token1ImaginaryReserves.Sign() > 0 + + var colIReserveIn, colIReserveOut, debtIReserveIn, debtIReserveOut *big.Int + + if swap0To1 { + colIReserveIn = colReserves.Token0ImaginaryReserves + colIReserveOut = colReserves.Token1ImaginaryReserves + debtIReserveIn = debtReserves.Token0ImaginaryReserves + debtIReserveOut = debtReserves.Token1ImaginaryReserves + } else { + colIReserveIn = colReserves.Token1ImaginaryReserves + colIReserveOut = colReserves.Token0ImaginaryReserves + debtIReserveIn = debtReserves.Token1ImaginaryReserves + debtIReserveOut = debtReserves.Token0ImaginaryReserves + } + + var a *big.Int + if colPoolEnabled && debtPoolEnabled { + a = swapRoutingIn(amountToSwap, colIReserveOut, colIReserveIn, debtIReserveOut, debtIReserveIn) + } else if debtPoolEnabled { + a = big.NewInt(-1) // Route from debt pool + } else if colPoolEnabled { + a = new(big.Int).Add(amountToSwap, big.NewInt(1)) // Route from collateral pool + } else { + return nil, errors.New("No pools are enabled") + } + + amountInCollateral := new(big.Int) + amountInDebt := new(big.Int) + + if a.Sign() <= 0 { + amountInDebt = amountToSwap + } else if a.Cmp(amountToSwap) >= 0 { + amountInCollateral = amountToSwap + } else { + amountInCollateral = a + amountInDebt = new(big.Int).Sub(amountToSwap, a) + } + + var price *big.Int + if amountInCollateral.Cmp(amountInDebt) > 0 { + if swap0To1 { + price = new(big.Int).Div(new(big.Int).Mul(colIReserveOut, bI1e27), colIReserveIn) + } else { + price = new(big.Int).Div(new(big.Int).Mul(colIReserveIn, bI1e27), colIReserveOut) + } + } else { + if swap0To1 { + price = new(big.Int).Div(new(big.Int).Mul(debtIReserveOut, bI1e27), debtIReserveIn) + } else { + price = new(big.Int).Div(new(big.Int).Mul(debtIReserveIn, bI1e27), debtIReserveOut) + } + } + + return price, nil +} + +func getApproxCenterPriceOut(amountOut *big.Int, swap0To1 bool, colReserves CollateralReserves, debtReserves DebtReserves) (*big.Int, error) { + colPoolEnabled := colReserves.Token0RealReserves.Sign() > 0 && + colReserves.Token1RealReserves.Sign() > 0 && + colReserves.Token0ImaginaryReserves.Sign() > 0 && + colReserves.Token1ImaginaryReserves.Sign() > 0 + + debtPoolEnabled := debtReserves.Token0RealReserves.Sign() > 0 && + debtReserves.Token1RealReserves.Sign() > 0 && + debtReserves.Token0ImaginaryReserves.Sign() > 0 && + debtReserves.Token1ImaginaryReserves.Sign() > 0 + + var colIReserveIn, colIReserveOut, debtIReserveIn, debtIReserveOut *big.Int + + if swap0To1 { + colIReserveIn = colReserves.Token0ImaginaryReserves + colIReserveOut = colReserves.Token1ImaginaryReserves + debtIReserveIn = debtReserves.Token0ImaginaryReserves + debtIReserveOut = debtReserves.Token1ImaginaryReserves + } else { + colIReserveIn = colReserves.Token1ImaginaryReserves + colIReserveOut = colReserves.Token0ImaginaryReserves + debtIReserveIn = debtReserves.Token1ImaginaryReserves + debtIReserveOut = debtReserves.Token0ImaginaryReserves + } + + var a *big.Int + if colPoolEnabled && debtPoolEnabled { + a = swapRoutingOut(amountOut, colIReserveIn, colIReserveOut, debtIReserveIn, debtIReserveOut) + } else if debtPoolEnabled { + a = big.NewInt(-1) // Route from debt pool + } else if colPoolEnabled { + a = new(big.Int).Add(amountOut, big.NewInt(1)) // Route from collateral pool + } else { + return nil, errors.New("No pools are enabled") + } + + amountInCollateral := new(big.Int) + amountInDebt := new(big.Int) + + if a.Sign() <= 0 { + amountInDebt = getAmountIn(amountOut, debtIReserveIn, debtIReserveOut) + } else if a.Cmp(amountOut) >= 0 { + amountInCollateral = getAmountIn(amountOut, colIReserveIn, colIReserveOut) + } else { + amountInCollateral = getAmountIn(a, colIReserveIn, colIReserveOut) + amountInDebt = getAmountIn(new(big.Int).Sub(amountOut, a), debtIReserveIn, debtIReserveOut) + } + + var price *big.Int + if amountInCollateral.Cmp(amountInDebt) > 0 { + if swap0To1 { + price = new(big.Int).Div(new(big.Int).Mul(colIReserveOut, bI1e27), colIReserveIn) + } else { + price = new(big.Int).Div(new(big.Int).Mul(colIReserveIn, bI1e27), colIReserveOut) + } + } else { + if swap0To1 { + price = new(big.Int).Div(new(big.Int).Mul(debtIReserveOut, bI1e27), debtIReserveIn) + } else { + price = new(big.Int).Div(new(big.Int).Mul(debtIReserveIn, bI1e27), debtIReserveOut) + } + } + + return price, nil +} + func TestPoolSimulator_CalcAmountOut(t *testing.T) { testCases := []struct { name string @@ -74,6 +207,7 @@ func TestPoolSimulator_CalcAmountOut(t *testing.T) { Token1ImaginaryReserves: bignumber.NewBig("73766803277429176"), }, DexLimits: limitsWide, + CenterPrice: big.NewInt(1), SyncTimestamp: time.Now().Unix() - 10, Token0Decimals: 18, Token1Decimals: 18, @@ -120,6 +254,7 @@ func TestPoolSimulator_CalcAmountOut(t *testing.T) { Token1ImaginaryReserves: bignumber.NewBig("73766803277429176"), }, DexLimits: limitsWide, + CenterPrice: big.NewInt(1), SyncTimestamp: time.Now().Unix() - 10, Token0Decimals: 18, Token1Decimals: 18, @@ -165,6 +300,7 @@ func TestPoolSimulator_CalcAmountOut(t *testing.T) { Token1ImaginaryReserves: bignumber.NewBig("73766803277429176"), }, DexLimits: limitsWide, + CenterPrice: new(big.Int).Mul(big.NewInt(1.2e18), big.NewInt(1e9)), SyncTimestamp: time.Now().Unix() - 10, Token0Decimals: 18, Token1Decimals: 18, @@ -211,6 +347,7 @@ func TestPoolSimulator_CalcAmountOut(t *testing.T) { Token1ImaginaryReserves: bignumber.NewBig("73766803277429176"), }, DexLimits: limitsWide, + CenterPrice: big.NewInt(1), SyncTimestamp: time.Now().Unix() - 10, Token0Decimals: 18, Token1Decimals: 18, @@ -235,12 +372,18 @@ func TestPoolSimulator_CalcAmountOut(t *testing.T) { assert.ErrorIs(t, err, tc.expectedError) } else { t.Logf("Expected Amount Out: %s", tc.expectedAmountOut.String()) - t.Logf("Result Amount: %s", result.TokenAmountOut.Amount.String()) - t.Logf("Fee Amount: %s", result.Fee.Amount.String()) + if result == nil { + t.Log("Result is nil") + } else { + t.Logf("Result Amount: %s", result.TokenAmountOut.Amount.String()) + t.Logf("Fee Amount: %s", result.Fee.Amount.String()) + + } if tc.expectedAmountOut != nil { assert.Zero(t, tc.expectedAmountOut.Cmp(result.TokenAmountOut.Amount)) } + } }) } @@ -283,6 +426,7 @@ func TestPoolSimulator_CalcAmountIn(t *testing.T) { Token1ImaginaryReserves: bignumber.NewBig("73766803277429176"), }, DexLimits: limitsWide, + CenterPrice: big.NewInt(1), SyncTimestamp: time.Now().Unix() - 10, Token0Decimals: 18, Token1Decimals: 18, @@ -326,6 +470,7 @@ func TestPoolSimulator_CalcAmountIn(t *testing.T) { Token1ImaginaryReserves: bignumber.NewBig("73766803277429176"), }, DexLimits: limitsWide, + CenterPrice: big.NewInt(1), SyncTimestamp: time.Now().Unix() - 10, Token0Decimals: 18, Token1Decimals: 18, @@ -369,6 +514,7 @@ func TestPoolSimulator_CalcAmountIn(t *testing.T) { Token1ImaginaryReserves: bignumber.NewBig("73766803277429176"), }, DexLimits: limitsWide, + CenterPrice: new(big.Int).Mul(big.NewInt(1.2e18), big.NewInt(1e9)), SyncTimestamp: time.Now().Unix() - 10, Token0Decimals: 18, Token1Decimals: 18, @@ -412,6 +558,7 @@ func TestPoolSimulator_CalcAmountIn(t *testing.T) { Token1ImaginaryReserves: bignumber.NewBig("73766803277429176"), }, DexLimits: limitsWide, + CenterPrice: big.NewInt(1), SyncTimestamp: time.Now().Unix() - 10, Token0Decimals: 18, Token1Decimals: 18, @@ -450,22 +597,22 @@ var limitExpandTight, _ = new(big.Int).SetString("711907234052361388866", 10) var limitsTight = DexLimits{ WithdrawableToken0: TokenLimit{ Available: big.NewInt(456740438880263), - ExpandsTo: big.NewInt(0).Set(limitExpandTight), + ExpandsTo: new(big.Int).Set(limitExpandTight), ExpandDuration: big.NewInt(600), }, WithdrawableToken1: TokenLimit{ Available: big.NewInt(825179383432029), - ExpandsTo: big.NewInt(0).Set(limitExpandTight), + ExpandsTo: new(big.Int).Set(limitExpandTight), ExpandDuration: big.NewInt(600), }, BorrowableToken0: TokenLimit{ Available: big.NewInt(941825058374170), - ExpandsTo: big.NewInt(0).Set(limitExpandTight), + ExpandsTo: new(big.Int).Set(limitExpandTight), ExpandDuration: big.NewInt(600), }, BorrowableToken1: TokenLimit{ Available: big.NewInt(941825058374170), - ExpandsTo: big.NewInt(0).Set(limitExpandTight), + ExpandsTo: new(big.Int).Set(limitExpandTight), ExpandDuration: big.NewInt(600), }, } @@ -473,23 +620,23 @@ var limitsTight = DexLimits{ var limitWide, _ = new(big.Int).SetString("34242332879776515083099999", 10) var limitsWide = DexLimits{ WithdrawableToken0: TokenLimit{ - Available: big.NewInt(0).Set(limitWide), - ExpandsTo: big.NewInt(0).Set(limitWide), + Available: new(big.Int).Set(limitWide), + ExpandsTo: new(big.Int).Set(limitWide), ExpandDuration: bignumber.ZeroBI, }, WithdrawableToken1: TokenLimit{ - Available: big.NewInt(0).Set(limitWide), - ExpandsTo: big.NewInt(0).Set(limitWide), + Available: new(big.Int).Set(limitWide), + ExpandsTo: new(big.Int).Set(limitWide), ExpandDuration: big.NewInt(22), }, BorrowableToken0: TokenLimit{ - Available: big.NewInt(0).Set(limitWide), - ExpandsTo: big.NewInt(0).Set(limitWide), + Available: new(big.Int).Set(limitWide), + ExpandsTo: new(big.Int).Set(limitWide), ExpandDuration: bignumber.ZeroBI, }, BorrowableToken1: TokenLimit{ - Available: big.NewInt(0).Set(limitWide), - ExpandsTo: big.NewInt(0).Set(limitWide), + Available: new(big.Int).Set(limitWide), + ExpandsTo: new(big.Int).Set(limitWide), ExpandDuration: big.NewInt(308), }, } @@ -505,19 +652,19 @@ func NewColReservesOne() CollateralReserves { func NewColReservesEmpty() CollateralReserves { return CollateralReserves{ - Token0RealReserves: big.NewInt(0), - Token1RealReserves: big.NewInt(0), - Token0ImaginaryReserves: big.NewInt(0), - Token1ImaginaryReserves: big.NewInt(0), + Token0RealReserves: new(big.Int), + Token1RealReserves: new(big.Int), + Token0ImaginaryReserves: new(big.Int), + Token1ImaginaryReserves: new(big.Int), } } func NewDebtReservesEmpty() DebtReserves { return DebtReserves{ - Token0RealReserves: big.NewInt(0), - Token1RealReserves: big.NewInt(0), - Token0ImaginaryReserves: big.NewInt(0), - Token1ImaginaryReserves: big.NewInt(0), + Token0RealReserves: new(big.Int), + Token1RealReserves: new(big.Int), + Token0ImaginaryReserves: new(big.Int), + Token1ImaginaryReserves: new(big.Int), } } @@ -531,14 +678,16 @@ func NewDebtReservesOne() DebtReserves { } func assertSwapInResult(t *testing.T, swap0To1 bool, amountIn *big.Int, colReserves CollateralReserves, debtReserves DebtReserves, expectedAmountIn string, expectedAmountOut string, outDecimals int64, limits DexLimits, syncTime int64) { - outAmt, _ := swapInAdjusted(swap0To1, amountIn, colReserves, debtReserves, outDecimals, limits, syncTime) + price, _ := getApproxCenterPriceIn(amountIn, swap0To1, colReserves, debtReserves) + outAmt, _ := swapInAdjusted(swap0To1, amountIn, colReserves, debtReserves, outDecimals, limits, price, syncTime) require.Equal(t, expectedAmountIn, amountIn.String()) require.Equal(t, expectedAmountOut, outAmt.String()) } func assertSwapOutResult(t *testing.T, swap0To1 bool, amountOut *big.Int, colReserves CollateralReserves, debtReserves DebtReserves, expectedAmountIn string, expectedAmountOut string, outDecimals int64, limits DexLimits, syncTime int64) { - inAmt, _ := swapOutAdjusted(swap0To1, amountOut, colReserves, debtReserves, outDecimals, limits, syncTime) + price, _ := getApproxCenterPriceOut(amountOut, swap0To1, colReserves, debtReserves) + inAmt, _ := swapOutAdjusted(swap0To1, amountOut, colReserves, debtReserves, outDecimals, limits, price, syncTime) require.Equal(t, expectedAmountIn, inAmt.String()) require.Equal(t, expectedAmountOut, amountOut.String()) @@ -558,21 +707,25 @@ func TestPoolSimulator_SwapIn(t *testing.T) { func TestPoolSimulator_SwapInLimits(t *testing.T) { t.Run("TestPoolSimulator_SwapInLimits", func(t *testing.T) { // when limits hit - outAmt, err := swapInAdjusted(true, big.NewInt(1e15), NewColReservesOne(), NewDebtReservesOne(), 18, limitsTight, time.Now().Unix()-10) + price, _ := getApproxCenterPriceIn(big.NewInt(1e15), true, NewColReservesOne(), NewDebtReservesOne()) + outAmt, err := swapInAdjusted(true, big.NewInt(1e15), NewColReservesOne(), NewDebtReservesOne(), 18, limitsTight, price, time.Now().Unix()-10) require.Nil(t, outAmt) require.EqualError(t, err, ErrInsufficientBorrowable.Error()) // when expanded - outAmt, _ = swapInAdjusted(true, big.NewInt(1e15), NewColReservesOne(), NewDebtReservesOne(), 18, limitsTight, time.Now().Unix()-6000) + price, _ = getApproxCenterPriceIn(big.NewInt(1e15), true, NewColReservesOne(), NewDebtReservesOne()) + outAmt, _ = swapInAdjusted(true, big.NewInt(1e15), NewColReservesOne(), NewDebtReservesOne(), 18, limitsTight, price, time.Now().Unix()-6000) require.Equal(t, "998262697204710", outAmt.String()) // when price diff hit - outAmt, err = swapInAdjusted(true, big.NewInt(3e16), NewColReservesOne(), NewDebtReservesOne(), 18, limitsWide, time.Now().Unix()-10) + price, _ = getApproxCenterPriceIn(big.NewInt(3e16), true, NewColReservesOne(), NewDebtReservesOne()) + outAmt, err = swapInAdjusted(true, big.NewInt(3e16), NewColReservesOne(), NewDebtReservesOne(), 18, limitsWide, price, time.Now().Unix()-10) require.Nil(t, outAmt) require.EqualError(t, err, ErrInsufficientMaxPrice.Error()) // when reserves limt is hit - outAmt, err = swapInAdjusted(true, big.NewInt(5e16), NewColReservesOne(), NewDebtReservesOne(), 18, limitsWide, time.Now().Unix()-10) + price, _ = getApproxCenterPriceIn(big.NewInt(5e16), true, NewColReservesOne(), NewDebtReservesOne()) + outAmt, err = swapInAdjusted(true, big.NewInt(5e16), NewColReservesOne(), NewDebtReservesOne(), 18, limitsWide, price, time.Now().Unix()-10) require.Nil(t, outAmt) require.EqualError(t, err, ErrInsufficientReserve.Error()) }) @@ -598,9 +751,10 @@ func TestPoolSimulator_swapInAdjusted(t *testing.T) { } amountIn := big.NewInt(1e12) - outAmt, _ := swapInAdjusted(true, amountIn, colReserves, debtReserves, 18, limitsWide, time.Now().Unix()-10) + price, _ := getApproxCenterPriceIn(amountIn, true, colReserves, debtReserves) + outAmt, _ := swapInAdjusted(true, amountIn, colReserves, debtReserves, 18, limitsWide, price, time.Now().Unix()-10) - require.Equal(t, expectedAmountOut, big.NewInt(0).Mul(outAmt, big.NewInt(1e6)).String()) + require.Equal(t, expectedAmountOut, new(big.Int).Mul(outAmt, big.NewInt(1e6)).String()) }) } @@ -618,21 +772,25 @@ func TestPoolSimulator_SwapOut(t *testing.T) { func TestPoolSimulator_SwapOutLimits(t *testing.T) { t.Run("TestPoolSimulator_SwapInLimits", func(t *testing.T) { // when limits hit - outAmt, err := swapOutAdjusted(true, big.NewInt(1e15), NewColReservesOne(), NewDebtReservesOne(), 18, limitsTight, time.Now().Unix()-10) + price, _ := getApproxCenterPriceOut(big.NewInt(1e15), true, NewColReservesOne(), NewDebtReservesOne()) + outAmt, err := swapOutAdjusted(true, big.NewInt(1e15), NewColReservesOne(), NewDebtReservesOne(), 18, limitsTight, price, time.Now().Unix()-10) require.Nil(t, outAmt) require.EqualError(t, err, ErrInsufficientBorrowable.Error()) // when expanded - outAmt, _ = swapOutAdjusted(true, big.NewInt(1e15), NewColReservesOne(), NewDebtReservesOne(), 18, limitsTight, time.Now().Unix()-6000) + price, _ = getApproxCenterPriceOut(big.NewInt(1e15), true, NewColReservesOne(), NewDebtReservesOne()) + outAmt, _ = swapOutAdjusted(true, big.NewInt(1e15), NewColReservesOne(), NewDebtReservesOne(), 18, limitsTight, price, time.Now().Unix()-6000) require.Equal(t, "1001743360284199", outAmt.String()) // when price diff hit - outAmt, err = swapOutAdjusted(true, big.NewInt(2e16), NewColReservesOne(), NewDebtReservesOne(), 18, limitsWide, time.Now().Unix()-10) + price, _ = getApproxCenterPriceOut(big.NewInt(2e16), true, NewColReservesOne(), NewDebtReservesOne()) + outAmt, err = swapOutAdjusted(true, big.NewInt(2e16), NewColReservesOne(), NewDebtReservesOne(), 18, limitsWide, price, time.Now().Unix()-10) require.Nil(t, outAmt) require.EqualError(t, err, ErrInsufficientMaxPrice.Error()) // when reserves limt is hit - outAmt, err = swapOutAdjusted(true, big.NewInt(3e16), NewColReservesOne(), NewDebtReservesOne(), 18, limitsWide, time.Now().Unix()-10) + price, _ = getApproxCenterPriceOut(big.NewInt(3e16), true, NewColReservesOne(), NewDebtReservesOne()) + outAmt, err = swapOutAdjusted(true, big.NewInt(3e16), NewColReservesOne(), NewDebtReservesOne(), 18, limitsWide, price, time.Now().Unix()-10) require.Nil(t, outAmt) require.EqualError(t, err, ErrInsufficientReserve.Error()) }) @@ -679,16 +837,16 @@ func NewVerifyRatioColReserves() CollateralReserves { return CollateralReserves{ Token0RealReserves: big.NewInt(2_000_000 * 1e6 * 1e6), // e.g. 2M USDC Token1RealReserves: big.NewInt(15_000 * 1e6 * 1e6), // e.g. 15 USDT - Token0ImaginaryReserves: big.NewInt(0), - Token1ImaginaryReserves: big.NewInt(0), + Token0ImaginaryReserves: new(big.Int), + Token1ImaginaryReserves: new(big.Int), } } func NewVerifyRatioDebtReserves() DebtReserves { return DebtReserves{ Token0RealReserves: big.NewInt(2_000_000 * 1e6 * 1e6), // e.g. 2M USDC Token1RealReserves: big.NewInt(15_000 * 1e6 * 1e6), // e.g. 15 USDT - Token0ImaginaryReserves: big.NewInt(0), - Token1ImaginaryReserves: big.NewInt(0), + Token0ImaginaryReserves: new(big.Int), + Token1ImaginaryReserves: new(big.Int), } } func TestSwapInVerifyReservesInRange(t *testing.T) { @@ -720,14 +878,16 @@ func TestSwapInVerifyReservesInRange(t *testing.T) { // expected required ratio: // token1Reserves must be > (token0Reserves * price) / (1e27 * MIN_SWAP_LIQUIDITY) - // so 2M / 6667, which is ~300 + // so 2M / 2e4, which is 100 - // Test for swap amount 14_705, revert should hit - swapAmount := big.NewInt(14_705 * 1e6 * 1e6) - result, _ := swapInAdjusted(true, swapAmount, colReserves, NewDebtReservesEmpty(), decimals, limitsWide, time.Now().Unix()-10) - require.Nil(t, result, "FAIL: reserves ratio verification revert NOT hit for col reserves when swap amount %d", 14_705) - result, _ = swapInAdjusted(true, swapAmount, NewColReservesEmpty(), debtReserves, decimals, limitsWide, time.Now().Unix()-10) - require.Nil(t, result, "FAIL: reserves ratio verification revert NOT hit for debt reserves when swap amount %d", 14_705) + // Test for swap amount 14_905, revert should hit + swapAmount := big.NewInt(14_905 * 1e6 * 1e6) + price, _ = getApproxCenterPriceIn(swapAmount, true, colReserves, NewDebtReservesEmpty()) + result, _ := swapInAdjusted(true, swapAmount, colReserves, NewDebtReservesEmpty(), decimals, limitsWide, price, time.Now().Unix()-10) + require.Nil(t, result, "FAIL: reserves ratio verification revert NOT hit for col reserves when swap amount %d", 14_905) + price, _ = getApproxCenterPriceIn(swapAmount, true, NewColReservesEmpty(), debtReserves) + result, _ = swapInAdjusted(true, swapAmount, NewColReservesEmpty(), debtReserves, decimals, limitsWide, price, time.Now().Unix()-10) + require.Nil(t, result, "FAIL: reserves ratio verification revert NOT hit for debt reserves when swap amount %d", 14_905) // refresh reserves colReserves = NewVerifyRatioColReserves() @@ -749,14 +909,16 @@ func TestSwapInVerifyReservesInRange(t *testing.T) { debtReserves.Token0ImaginaryReserves = new(big.Int).Add(reserveXOutside, debtReserves.Token0RealReserves) debtReserves.Token1ImaginaryReserves = new(big.Int).Add(reserveYOutside, debtReserves.Token1RealReserves) - // Test for swap amount 14_695, revert should NOT hit - swapAmount = big.NewInt(14_695 * 1e6 * 1e6) + // Test for swap amount 14_895, revert should NOT hit + swapAmount = big.NewInt(14_895 * 1e6 * 1e6) err := error(nil) - result, err = swapInAdjusted(true, swapAmount, colReserves, NewDebtReservesEmpty(), decimals, limitsWide, time.Now().Unix()-10) + price, _ = getApproxCenterPriceIn(swapAmount, true, colReserves, NewDebtReservesEmpty()) + result, err = swapInAdjusted(true, swapAmount, colReserves, NewDebtReservesEmpty(), decimals, limitsWide, price, time.Now().Unix()-10) require.NoError(t, err, "Error during swapInAdjusted for col reserves") - require.NotNil(t, result, "FAIL: reserves ratio verification revert hit for col reserves when swap amount %d", 14_695) - result, _ = swapInAdjusted(true, swapAmount, NewColReservesEmpty(), debtReserves, decimals, limitsWide, time.Now().Unix()-10) - require.NotNil(t, result, "FAIL: reserves ratio verification revert hit for debt reserves when swap amount %d", 14_695) + require.NotNil(t, result, "FAIL: reserves ratio verification revert hit for col reserves when swap amount %d", 14_895) + price, _ = getApproxCenterPriceIn(swapAmount, true, NewColReservesEmpty(), debtReserves) + result, _ = swapInAdjusted(true, swapAmount, NewColReservesEmpty(), debtReserves, decimals, limitsWide, price, time.Now().Unix()-10) + require.NotNil(t, result, "FAIL: reserves ratio verification revert hit for debt reserves when swap amount %d", 14_895) }) } @@ -764,16 +926,16 @@ func NewVerifyRatioColReservesSwapOut() CollateralReserves { return CollateralReserves{ Token0RealReserves: big.NewInt(15_000 * 1e6 * 1e6), // e.g. 15 USDT Token1RealReserves: big.NewInt(2_000_000 * 1e6 * 1e6), // e.g. 2M USDC - Token0ImaginaryReserves: big.NewInt(0), - Token1ImaginaryReserves: big.NewInt(0), + Token0ImaginaryReserves: new(big.Int), + Token1ImaginaryReserves: new(big.Int), } } func NewVerifyRatioDebtReservesSwapOut() DebtReserves { return DebtReserves{ Token0RealReserves: big.NewInt(15_000 * 1e6 * 1e6), // e.g. 15 USDT Token1RealReserves: big.NewInt(2_000_000 * 1e6 * 1e6), // e.g. 2M USDC - Token0ImaginaryReserves: big.NewInt(0), - Token1ImaginaryReserves: big.NewInt(0), + Token0ImaginaryReserves: new(big.Int), + Token1ImaginaryReserves: new(big.Int), } } @@ -806,14 +968,16 @@ func TestSwapOutVerifyReservesInRange(t *testing.T) { // expected required ratio: // token0Reserves >= (token1Reserves * 1e27) / (price * MIN_SWAP_LIQUIDITY) - // so 2M / 6667, which is ~300 + // so 2M / 2e4, which is 100 - // Test for swap amount 14_705, revert should hit - swapAmount := big.NewInt(14_705 * 1e6 * 1e6) - result, _ := swapOutAdjusted(false, swapAmount, colReserves, NewDebtReservesEmpty(), decimals, limitsWide, time.Now().Unix()-10) - require.Nil(t, result, "FAIL: reserves ratio verification revert NOT hit for col reserves when swap amount %d", 14_705) - result, _ = swapOutAdjusted(false, swapAmount, NewColReservesEmpty(), debtReserves, decimals, limitsWide, time.Now().Unix()-10) - require.Nil(t, result, "FAIL: reserves ratio verification revert NOT hit for debt reserves when swap amount %d", 14_705) + // Test for swap amount 14_905, revert should hit + swapAmount := big.NewInt(14_905 * 1e6 * 1e6) + price, _ = getApproxCenterPriceOut(swapAmount, false, colReserves, NewDebtReservesEmpty()) + result, _ := swapOutAdjusted(false, swapAmount, colReserves, NewDebtReservesEmpty(), decimals, limitsWide, price, time.Now().Unix()-10) + require.Nil(t, result, "FAIL: reserves ratio verification revert NOT hit for col reserves when swap amount %d", 14_905) + price, _ = getApproxCenterPriceOut(swapAmount, false, NewColReservesEmpty(), debtReserves) + result, _ = swapOutAdjusted(false, swapAmount, NewColReservesEmpty(), debtReserves, decimals, limitsWide, price, time.Now().Unix()-10) + require.Nil(t, result, "FAIL: reserves ratio verification revert NOT hit for debt reserves when swap amount %d", 14_905) // refresh reserves colReserves = NewVerifyRatioColReservesSwapOut() @@ -835,13 +999,15 @@ func TestSwapOutVerifyReservesInRange(t *testing.T) { debtReserves.Token0ImaginaryReserves = new(big.Int).Add(reserveXOutside, debtReserves.Token0RealReserves) debtReserves.Token1ImaginaryReserves = new(big.Int).Add(reserveYOutside, debtReserves.Token1RealReserves) - // Test for swap amount 14_695, revert should NOT hit - swapAmount = big.NewInt(14_695 * 1e6 * 1e6) + // Test for swap amount 14_895, revert should NOT hit + swapAmount = big.NewInt(14_895 * 1e6 * 1e6) err := error(nil) - result, err = swapOutAdjusted(false, swapAmount, colReserves, NewDebtReservesEmpty(), decimals, limitsWide, time.Now().Unix()-10) + price, _ = getApproxCenterPriceOut(swapAmount, false, colReserves, NewDebtReservesEmpty()) + result, err = swapOutAdjusted(false, swapAmount, colReserves, NewDebtReservesEmpty(), decimals, limitsWide, price, time.Now().Unix()-10) require.NoError(t, err, "Error during swapOutAdjusted for col reserves") - require.NotNil(t, result, "FAIL: reserves ratio verification revert hit for col reserves when swap amount %d", 14_695) - result, _ = swapOutAdjusted(false, swapAmount, NewColReservesEmpty(), debtReserves, decimals, limitsWide, time.Now().Unix()-10) - require.NotNil(t, result, "FAIL: reserves ratio verification revert hit for debt reserves when swap amount %d", 14_695) + require.NotNil(t, result, "FAIL: reserves ratio verification revert hit for col reserves when swap amount %d", 14_895) + price, _ = getApproxCenterPriceOut(swapAmount, false, NewColReservesEmpty(), debtReserves) + result, _ = swapOutAdjusted(false, swapAmount, NewColReservesEmpty(), debtReserves, decimals, limitsWide, price, time.Now().Unix()-10) + require.NotNil(t, result, "FAIL: reserves ratio verification revert hit for debt reserves when swap amount %d", 14_895) }) } diff --git a/pkg/liquidity-source/fluid/dex-t1/pool_tracker.go b/pkg/liquidity-source/fluid/dex-t1/pool_tracker.go index 005d135e2..adb9adc81 100644 --- a/pkg/liquidity-source/fluid/dex-t1/pool_tracker.go +++ b/pkg/liquidity-source/fluid/dex-t1/pool_tracker.go @@ -61,6 +61,7 @@ func (t *PoolTracker) getNewPoolState( DebtReserves: debtReserves, IsSwapAndArbitragePaused: isSwapAndArbitragePaused, DexLimits: poolReserves.Limits, + CenterPrice: poolReserves.CenterPrice, } extraBytes, err := json.Marshal(extra) @@ -69,7 +70,7 @@ func (t *PoolTracker) getNewPoolState( return p, err } - p.SwapFee = float64(poolReserves.Fee.Int64()) / float64(FeePercentPrecision) + p.SwapFee = float64(poolReserves.Fee.Int64()) / FeePercentPrecision p.Extra = string(extraBytes) p.BlockNumber = blockNumber p.Timestamp = time.Now().Unix() @@ -96,9 +97,9 @@ func (t *PoolTracker) getPoolReserves( poolAddress string, overrides map[common.Address]gethclient.OverrideAccount, ) (*PoolWithReserves, bool, uint64, error) { - pool := &PoolWithReserves{} + poolReserves := &PoolWithReserves{} - dexVariables2 := bignumber.ZeroBI + dexVariables2 := new(big.Int) req := t.ethrpcClient.R().SetContext(ctx) if overrides != nil { @@ -110,7 +111,7 @@ func (t *PoolTracker) getPoolReserves( Target: t.config.DexReservesResolver, Method: DRRMethodGetPoolReservesAdjusted, Params: []interface{}{common.HexToAddress(poolAddress)}, - }, []interface{}{&pool}) + }, []interface{}{&poolReserves}) req.AddCall(ðrpc.Call{ ABI: storageReadABI, @@ -129,9 +130,9 @@ func (t *PoolTracker) getPoolReserves( return nil, false, 0, err } - isSwapAndArbitragePaused := dexVariables2.Rsh(dexVariables2, 255).Cmp(bignumber.One) == 0 + isSwapAndArbitragePaused := dexVariables2.Bit(255) == 1 - return pool, isSwapAndArbitragePaused, resp.BlockNumber.Uint64(), nil + return poolReserves, isSwapAndArbitragePaused, resp.BlockNumber.Uint64(), nil } func getMaxReserves( @@ -147,9 +148,9 @@ func getMaxReserves( // if expandTo for borrowable and withdrawable match, that means they are a hard limit like liquidity layer balance // or utilization limit. In that case expandTo can not be summed up. Otherwise it's the case of expanding withdrawal // and borrow limits, for which we must sum up the max available reserve amount. - maxLimitReserves := new(big.Int).Add(borrowableLimit.ExpandsTo, withdrawableLimit.ExpandsTo) - if borrowableLimit.ExpandsTo.Cmp(withdrawableLimit.ExpandsTo) == 0 { - maxLimitReserves.Set(borrowableLimit.ExpandsTo) + maxLimitReserves := new(big.Int).Set(borrowableLimit.ExpandsTo) + if borrowableLimit.ExpandsTo.Cmp(withdrawableLimit.ExpandsTo) != 0 { + maxLimitReserves.Add(maxLimitReserves, withdrawableLimit.ExpandsTo) } maxRealReserves := new(big.Int).Add(realColReserves, realDebtReserves) @@ -159,10 +160,8 @@ func getMaxReserves( maxRealReserves.Div(maxRealReserves, bignumber.TenPowInt(DexAmountsDecimals-int8(decimals))) } - var maxReserve = maxLimitReserves if maxRealReserves.Cmp(maxLimitReserves) < 0 { - maxReserve = maxRealReserves + return maxRealReserves } - - return maxReserve + return maxLimitReserves } diff --git a/pkg/liquidity-source/fluid/dex-t1/pool_tracker_test.go b/pkg/liquidity-source/fluid/dex-t1/pool_tracker_test.go index 566e64f07..ff40c9e4e 100644 --- a/pkg/liquidity-source/fluid/dex-t1/pool_tracker_test.go +++ b/pkg/liquidity-source/fluid/dex-t1/pool_tracker_test.go @@ -7,13 +7,14 @@ import ( "testing" "github.com/KyberNetwork/ethrpc" - "github.com/KyberNetwork/kyberswap-dex-lib/pkg/entity" - "github.com/KyberNetwork/kyberswap-dex-lib/pkg/source/pool" - "github.com/KyberNetwork/kyberswap-dex-lib/pkg/valueobject" "github.com/KyberNetwork/logger" "github.com/ethereum/go-ethereum/common" "github.com/goccy/go-json" "github.com/stretchr/testify/require" + + "github.com/KyberNetwork/kyberswap-dex-lib/pkg/entity" + "github.com/KyberNetwork/kyberswap-dex-lib/pkg/source/pool" + "github.com/KyberNetwork/kyberswap-dex-lib/pkg/valueobject" ) func TestPoolTracker(t *testing.T) { @@ -25,7 +26,7 @@ func TestPoolTracker(t *testing.T) { var ( config = Config{ - DexReservesResolver: "0x45f4ad57e300da55c33dea579a40fcee000d7b94", + DexReservesResolver: "0xb387f9C2092cF7c4943F97842887eBff7AE96EB3", } ) @@ -85,22 +86,25 @@ func TestPoolTracker(t *testing.T) { reserve0, _ := new(big.Int).SetString(newPool.Reserves[0], 10) reserve1, _ := new(big.Int).SetString(newPool.Reserves[1], 10) - require.True(t, reserve0.Cmp(big.NewInt(0)) > 0) - require.True(t, reserve1.Cmp(big.NewInt(0)) > 0) + require.True(t, reserve0.Sign() > 0) + require.True(t, reserve1.Sign() > 0) - require.True(t, extra.CollateralReserves.Token0RealReserves.Cmp(big.NewInt(0)) > 0) - require.True(t, extra.CollateralReserves.Token1RealReserves.Cmp(big.NewInt(0)) > 0) - require.True(t, extra.CollateralReserves.Token0ImaginaryReserves.Cmp(big.NewInt(0)) > 0) - require.True(t, extra.CollateralReserves.Token1ImaginaryReserves.Cmp(big.NewInt(0)) > 0) - require.True(t, extra.DebtReserves.Token0Debt.Cmp(big.NewInt(0)) > 0) - require.True(t, extra.DebtReserves.Token1Debt.Cmp(big.NewInt(0)) > 0) - require.True(t, extra.DebtReserves.Token0RealReserves.Cmp(big.NewInt(0)) > 0) - require.True(t, extra.DebtReserves.Token1RealReserves.Cmp(big.NewInt(0)) > 0) - require.True(t, extra.DebtReserves.Token0ImaginaryReserves.Cmp(big.NewInt(0)) > 0) + require.True(t, extra.CollateralReserves.Token0RealReserves.Sign() > 0) + require.True(t, extra.CollateralReserves.Token1RealReserves.Sign() > 0) + require.True(t, extra.CollateralReserves.Token0ImaginaryReserves.Sign() > 0) + require.True(t, extra.CollateralReserves.Token1ImaginaryReserves.Sign() > 0) + require.True(t, extra.DebtReserves.Token0Debt.Sign() > 0) + require.True(t, extra.DebtReserves.Token1Debt.Sign() > 0) + require.True(t, extra.DebtReserves.Token0RealReserves.Sign() > 0) + require.True(t, extra.DebtReserves.Token1RealReserves.Sign() > 0) + require.True(t, extra.DebtReserves.Token0ImaginaryReserves.Sign() > 0) + require.True(t, extra.CenterPrice.Sign() > 0) logger.Debugf("Reserve0: %s", newPool.Reserves[0]) logger.Debugf("Reserve1: %s", newPool.Reserves[1]) + logger.Debugf("CenterPrice: %s", extra.CenterPrice.String()) + logger.Debugf("Debt Reserves: Token0Debt: %s", extra.DebtReserves.Token0Debt.String()) logger.Debugf("Debt Reserves: Token1Debt: %s", extra.DebtReserves.Token1Debt.String()) logger.Debugf("Debt Reserves: Token0RealReserves: %s", extra.DebtReserves.Token0RealReserves.String()) diff --git a/pkg/liquidity-source/fluid/dex-t1/types.go b/pkg/liquidity-source/fluid/dex-t1/types.go index 64d9a82be..7edff03b8 100644 --- a/pkg/liquidity-source/fluid/dex-t1/types.go +++ b/pkg/liquidity-source/fluid/dex-t1/types.go @@ -15,6 +15,7 @@ type PoolExtra struct { DebtReserves DebtReserves IsSwapAndArbitragePaused bool DexLimits DexLimits + CenterPrice *big.Int } type CollateralReserves struct { @@ -24,6 +25,15 @@ type CollateralReserves struct { Token1ImaginaryReserves *big.Int `json:"token1ImaginaryReserves"` } +func (r CollateralReserves) Clone() CollateralReserves { + return CollateralReserves{ + Token0RealReserves: new(big.Int).Set(r.Token0RealReserves), + Token1RealReserves: new(big.Int).Set(r.Token1RealReserves), + Token0ImaginaryReserves: new(big.Int).Set(r.Token0ImaginaryReserves), + Token1ImaginaryReserves: new(big.Int).Set(r.Token1ImaginaryReserves), + } +} + type DebtReserves struct { Token0Debt *big.Int `json:"token0Debt"` Token1Debt *big.Int `json:"token1Debt"` @@ -33,12 +43,31 @@ type DebtReserves struct { Token1ImaginaryReserves *big.Int `json:"token1ImaginaryReserves"` } +func (r DebtReserves) Clone() DebtReserves { + return DebtReserves{ + Token0Debt: new(big.Int).Set(r.Token0Debt), + Token1Debt: new(big.Int).Set(r.Token1Debt), + Token0RealReserves: new(big.Int).Set(r.Token0RealReserves), + Token1RealReserves: new(big.Int).Set(r.Token1RealReserves), + Token0ImaginaryReserves: new(big.Int).Set(r.Token0ImaginaryReserves), + Token1ImaginaryReserves: new(big.Int).Set(r.Token1ImaginaryReserves), + } +} + type TokenLimit struct { Available *big.Int `json:"available"` // maximum available swap amount ExpandsTo *big.Int `json:"expandsTo"` // maximum amount the available swap amount expands to ExpandDuration *big.Int `json:"expandDuration"` // duration for `available` to grow to `expandsTo` } +func (t TokenLimit) Clone() TokenLimit { + return TokenLimit{ + Available: new(big.Int).Set(t.Available), + ExpandsTo: new(big.Int).Set(t.ExpandsTo), + ExpandDuration: new(big.Int).Set(t.ExpandDuration), + } +} + type DexLimits struct { WithdrawableToken0 TokenLimit `json:"withdrawableToken0"` WithdrawableToken1 TokenLimit `json:"withdrawableToken1"` @@ -46,11 +75,21 @@ type DexLimits struct { BorrowableToken1 TokenLimit `json:"borrowableToken1"` } +func (d DexLimits) Clone() DexLimits { + return DexLimits{ + WithdrawableToken0: d.WithdrawableToken0.Clone(), + WithdrawableToken1: d.WithdrawableToken1.Clone(), + BorrowableToken0: d.BorrowableToken0.Clone(), + BorrowableToken1: d.BorrowableToken1.Clone(), + } +} + type PoolWithReserves struct { PoolAddress common.Address `json:"poolAddress"` Token0Address common.Address `json:"token0Address"` Token1Address common.Address `json:"token1Address"` Fee *big.Int `json:"fee"` + CenterPrice *big.Int `json:"centerPrice"` CollateralReserves CollateralReserves `json:"collateralReserves"` DebtReserves DebtReserves `json:"debtReserves"` Limits DexLimits `json:"limits"`