From 75b94f2ee0a2e2470c18ffe8b452212cf9e02779 Mon Sep 17 00:00:00 2001 From: Phu Ngo <12547020+NgoKimPhu@users.noreply.github.com> Date: Thu, 23 Jan 2025 01:40:45 +0700 Subject: [PATCH] fix: algebra-integral for thena-fusion-v3 (#705) - fetch s_priceChangeFactor and s_baseFee instead of hardcoding - fetch feeType for plugin switch - fix wrong 2<<96 vs 1<<(2*96) - sliding fee config should modify from existing one, not a constant one - wrong static extra field use - adjustedFee should become 1, not max, if 0 - wrong cross tick due to same targetPrice and currentPrice pointer, changed to use Clone --- .../algebra/integral/constant.go | 16 ++++---- .../algebra/integral/plugin.go | 37 +++++++----------- .../algebra/integral/pool_simulator.go | 39 +++++++++---------- .../algebra/integral/pool_simulator_test.go | 24 ++++++++++++ .../algebra/integral/pool_tracker.go | 39 ++++++++++--------- .../algebra/integral/pool_tracker_test.go | 35 +++++++++++++++++ pkg/liquidity-source/algebra/integral/type.go | 5 ++- 7 files changed, 124 insertions(+), 71 deletions(-) create mode 100644 pkg/liquidity-source/algebra/integral/pool_tracker_test.go diff --git a/pkg/liquidity-source/algebra/integral/constant.go b/pkg/liquidity-source/algebra/integral/constant.go index 40eb199fd..e7682bbd6 100644 --- a/pkg/liquidity-source/algebra/integral/constant.go +++ b/pkg/liquidity-source/algebra/integral/constant.go @@ -32,23 +32,23 @@ const ( dynamicFeeManagerPluginFeeConfigMethod = "feeConfig" - slidingFeePluginFeeFactorsMethod = "s_feeFactors" + slidingFeePluginFeeFactorsMethod = "s_feeFactors" + slidingFeePluginPriceChangeFactorMethod = "s_priceChangeFactor" + slidingFeePluginBaseFeeMethod = "s_baseFee" + slidingFeePluginFeeTypeMethod = "feeType" erc20BalanceOfMethod = "balanceOf" BEFORE_SWAP_FLAG = 1 RESOLUTION = 96 - s_priceChangeFactor = 1000 - s_baseFee = 500 - - FACTOR_DENOMINATOR = 1000 - FEE_FACTOR_SHIFT = 96 + FEE_FACTOR_SHIFT = 96 ) var ( FEE_DENOMINATOR = uint256.NewInt(1e6) COMMUNITY_FEE_DENOMINATOR = uint256.NewInt(1e3) + FACTOR_DENOMINATOR = uint256.NewInt(1e3) uZERO = uint256.NewInt(0) uONE = uint256.NewInt(1) @@ -62,8 +62,8 @@ var ( Q96 = new(uint256.Int).Lsh(uONE, 96) // 1 << 96 - BASE_FEE_MULTIPLIER = new(uint256.Int).Lsh(uONE, FEE_FACTOR_SHIFT) // 1 << 96 - DOUBLE_FEE_MULTIPLIER = new(uint256.Int).Lsh(uONE, 2*FEE_FACTOR_SHIFT) // 1 << 2*96 + FEE_FACTOR_MULTIPLIER = new(uint256.Int).Lsh(uONE, FEE_FACTOR_SHIFT) // 1 << 96 + DOUBLE_FEE_MULTIPLIER = new(uint256.Int).Lsh(uTWO, FEE_FACTOR_SHIFT) // 2 << 96 // Predefined e values multiplied by 10^20 as constants CLOSEST_VALUE_0, _ = uint256.FromDecimal("100000000000000000000") // 1 diff --git a/pkg/liquidity-source/algebra/integral/plugin.go b/pkg/liquidity-source/algebra/integral/plugin.go index 357031854..aa3ce7a21 100644 --- a/pkg/liquidity-source/algebra/integral/plugin.go +++ b/pkg/liquidity-source/algebra/integral/plugin.go @@ -4,10 +4,9 @@ import ( "sync" "github.com/KyberNetwork/elastic-go-sdk/v2/utils" - "github.com/samber/lo" - v3Utils "github.com/KyberNetwork/uniswapv3-sdk-uint256/utils" "github.com/holiman/uint256" + "github.com/samber/lo" ) type TimepointStorage struct { @@ -414,7 +413,7 @@ func (s *TimepointStorage) binarySearchInternal(currentTime, target, left, right } } -func calculateFeeFactors(currentTick, lastTick int32, priceChangeFactor uint16) (*SlidingFeeConfig, error) { +func (p *PoolSimulator) calculateFeeFactors(currentTick, lastTick int32, priceChangeFactor uint16) (*SlidingFeeConfig, error) { tickDelta := lo.Clamp(currentTick-lastTick, utils.MinTick, utils.MaxTick) var sqrtPriceDelta v3Utils.Uint160 @@ -423,37 +422,27 @@ func calculateFeeFactors(currentTick, lastTick int32, priceChangeFactor uint16) return nil, err } - priceRatioSquared, err := v3Utils.MulDiv(&sqrtPriceDelta, &sqrtPriceDelta, DOUBLE_FEE_MULTIPLIER) + priceRatioSquared, err := v3Utils.MulDiv(&sqrtPriceDelta, &sqrtPriceDelta, FEE_FACTOR_MULTIPLIER) if err != nil { return nil, err } - - priceChangeRatio := priceRatioSquared.Sub(priceRatioSquared, BASE_FEE_MULTIPLIER) + priceChangeRatio := priceRatioSquared.Sub(priceRatioSquared, FEE_FACTOR_MULTIPLIER) factor := uint256.NewInt(uint64(priceChangeFactor)) - feeFactorImpact := priceChangeRatio.Div(priceChangeRatio.Mul(priceChangeRatio, factor), - uint256.NewInt(FACTOR_DENOMINATOR)) + feeFactorImpact := priceChangeRatio.Mul(priceChangeRatio, factor).Div(priceChangeRatio, FACTOR_DENOMINATOR) - feeFactors := &SlidingFeeConfig{ - ZeroToOneFeeFactor: BASE_FEE_MULTIPLIER, - OneToZeroFeeFactor: BASE_FEE_MULTIPLIER, - } - - newZeroToOneFeeFactor := new(uint256.Int).Sub(feeFactors.ZeroToOneFeeFactor, feeFactorImpact) - - twoShift := DOUBLE_FEE_MULTIPLIER - - if newZeroToOneFeeFactor.Sign() > 0 && newZeroToOneFeeFactor.Cmp(twoShift) < 0 { + feeFactors := p.slidingFee + newZeroToOneFeeFactor := feeFactors.ZeroToOneFeeFactor.Sub(feeFactors.ZeroToOneFeeFactor, feeFactorImpact) + if 0 < newZeroToOneFeeFactor.Sign() && newZeroToOneFeeFactor.Cmp(DOUBLE_FEE_MULTIPLIER) < 0 { feeFactors.ZeroToOneFeeFactor = newZeroToOneFeeFactor - feeFactors.OneToZeroFeeFactor = new(uint256.Int).Add(feeFactors.OneToZeroFeeFactor, feeFactorImpact) + feeFactors.OneToZeroFeeFactor.Add(feeFactors.OneToZeroFeeFactor, feeFactorImpact) } else if newZeroToOneFeeFactor.Sign() <= 0 { - feeFactors.ZeroToOneFeeFactor = uZERO - feeFactors.OneToZeroFeeFactor = twoShift + feeFactors.ZeroToOneFeeFactor.Clear() + feeFactors.OneToZeroFeeFactor.Set(DOUBLE_FEE_MULTIPLIER) } else { - feeFactors.ZeroToOneFeeFactor = twoShift - feeFactors.OneToZeroFeeFactor = uZERO + feeFactors.ZeroToOneFeeFactor.Set(DOUBLE_FEE_MULTIPLIER) + feeFactors.OneToZeroFeeFactor.Clear() } - return feeFactors, nil } diff --git a/pkg/liquidity-source/algebra/integral/pool_simulator.go b/pkg/liquidity-source/algebra/integral/pool_simulator.go index 860b00475..a32597450 100644 --- a/pkg/liquidity-source/algebra/integral/pool_simulator.go +++ b/pkg/liquidity-source/algebra/integral/pool_simulator.go @@ -49,7 +49,7 @@ func NewPoolSimulator(entityPool entity.Pool, defaultGas int64) (*PoolSimulator, } var staticExtra StaticExtra - if err := json.Unmarshal([]byte(entityPool.StaticExtra), &extra); err != nil { + if err := json.Unmarshal([]byte(entityPool.StaticExtra), &staticExtra); err != nil { return nil, err } @@ -187,7 +187,8 @@ func (p *PoolSimulator) swap(tokenIn, tokenOut string, amtRequired *uint256.Int) } zeroForOne := tokenInIndex == 0 - overrideFee, pluginFee, err := lo.Ternary(p.useBasePluginV2, p.beforeSwapV2, p.beforeSwapV1)(zeroForOne) + overrideFee, pluginFee, err := lo.Ternary(p.useBasePluginV2 && p.slidingFee.FeeType, + p.beforeSwapV2, p.beforeSwapV1)(zeroForOne) if err != nil { return } @@ -263,6 +264,8 @@ func (p *PoolSimulator) getSqrtPriceLimit(zeroForOne bool) (*uint256.Int, error) return &sqrtPriceX96Limit, nil } +var blockTimestamp = func() uint32 { return uint32(time.Now().Unix()) } + // writeTimepoint locks and writes timepoint only once, triggering onWrite only if said write happened. // By right we should re-update the timepoint every new second, but the difference should be small enough, and // new pool should have already been created and used in replacement of this pool. @@ -273,7 +276,7 @@ func (p *PoolSimulator) writeTimepoint(onWrite func() error) (err error) { } p.writeTimePointOnce.Do(func() { - volatilityOracle.LastTimepointTimestamp = uint32(time.Now().Unix()) + volatilityOracle.LastTimepointTimestamp = blockTimestamp() volatilityOracle.TimepointIndex, _, err = p.timepoints.write( volatilityOracle.TimepointIndex, volatilityOracle.LastTimepointTimestamp, p.globalState.Tick) if err != nil || onWrite == nil { @@ -325,7 +328,7 @@ func (p *PoolSimulator) getFeeAndUpdateFactors(zeroToOne bool, currentTick, last if currentTick != lastTick { var err error - currentFeeFactors, err = calculateFeeFactors(currentTick, lastTick, s_priceChangeFactor) + currentFeeFactors, err = p.calculateFeeFactors(currentTick, lastTick, p.slidingFee.PriceChangeFactor) if err != nil { return 0, err } @@ -335,19 +338,19 @@ func (p *PoolSimulator) getFeeAndUpdateFactors(zeroToOne bool, currentTick, last currentFeeFactors = p.slidingFee } - var adjustedFee *uint256.Int - baseFeeBig := uint256.NewInt(s_baseFee) - adjustedFee = baseFeeBig.Rsh( - baseFeeBig.Mul(baseFeeBig, + adjustedFee := uint256.NewInt(uint64(p.slidingFee.BaseFee)) + adjustedFee = adjustedFee.Rsh( + adjustedFee.Mul(adjustedFee, lo.Ternary(zeroToOne, currentFeeFactors.ZeroToOneFeeFactor, currentFeeFactors.OneToZeroFeeFactor), ), FEE_FACTOR_SHIFT, ) - if adjustedFee.BitLen() > 15 || adjustedFee.IsZero() { - adjustedFee.SetUint64(math.MaxUint16) + if adjustedFee.BitLen() > 16 { + return math.MaxUint16, nil + } else if adjustedFee.IsZero() { + return 1, nil } - return uint16(adjustedFee.Uint64()), nil } @@ -397,13 +400,9 @@ func (p *PoolSimulator) calculateSwap(overrideFee, pluginFee uint32, zeroToOne b if pluginFee > 0 { cache.pluginFee = uint256.NewInt(uint64(pluginFee)) } - if overrideFee != 0 { - cache.fee = uint64(overrideFee + pluginFee) - } else if fee := uint32(p.globalState.LastFee) + pluginFee; fee != 0 { - if fee >= 1e6 { - return nil, nil, nil, 0, nil, FeesAmount{}, ErrIncorrectPluginFee - } - cache.fee = uint64(fee) + cache.fee = uint64(lo.Ternary(overrideFee != 0, overrideFee, uint32(p.globalState.LastFee)) + pluginFee) + if cache.fee >= 1e6 { + return nil, nil, nil, 0, nil, FeesAmount{}, ErrIncorrectPluginFee } feeU := uint256.NewInt(cache.fee) cache.communityFee = uint256.NewInt(uint64(p.globalState.CommunityFee)) @@ -545,7 +544,7 @@ func movePriceTowardsTarget(zeroToOne bool, currentPrice, targetPrice, liquidity } if amountAvailableAfterFee.Cmp(input) >= 0 { - resultPrice = targetPrice + resultPrice = targetPrice.Clone() feeAmount, err = v3Utils.MulDivRoundingUp(input, uint256.NewInt(fee), feeDenoMinusFee) if err != nil { return nil, nil, nil, nil, err @@ -585,7 +584,7 @@ func movePriceTowardsTarget(zeroToOne bool, currentPrice, targetPrice, liquidity } if amountAvailable.Cmp(output) >= 0 { - resultPrice = targetPrice + resultPrice = targetPrice.Clone() } else { resultPrice, err = getNewPriceAfterOutput(currentPrice, liquidity, amountAvailable, zeroToOne) if err != nil { diff --git a/pkg/liquidity-source/algebra/integral/pool_simulator_test.go b/pkg/liquidity-source/algebra/integral/pool_simulator_test.go index 0bcfe2bfb..940d194ce 100644 --- a/pkg/liquidity-source/algebra/integral/pool_simulator_test.go +++ b/pkg/liquidity-source/algebra/integral/pool_simulator_test.go @@ -500,6 +500,30 @@ func TestCalcAmountOut_FromPool(t *testing.T) { assert.Equal(t, big.NewInt(25555842204), res.TokenAmountOut.Amount) } +var ( + thenaEp entity.Pool + _ = lo.Must(0, + json.Unmarshal([]byte(`{"address":"0x9ea0f51fd2133d995cf00229bc523737415ad318","exchange":"thena-fusion-v3","type":"algebra-integral","timestamp":1737562946,"reserves":["18414865277861570689","35620318087431674"],"tokens":[{"address":"0x55d398326f99059ff775485246999027b3197955","name":"Tether USD","symbol":"USDT","decimals":18,"weight":50,"swappable":true},{"address":"0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c","name":"Wrapped BNB","symbol":"WBNB","decimals":18,"weight":50,"swappable":true}],"extra":"{\"liq\":\"7454466039228971588\",\"gS\":{\"price\":\"3013079375406544485683250193\",\"tick\":-65391,\"lF\":840,\"pC\":195,\"cF\":900,\"un\":true},\"ticks\":[{\"Index\":-887220,\"LiquidityGross\":\"54665134789121271\",\"LiquidityNet\":\"54665134789121271\"},{\"Index\":-604800,\"LiquidityGross\":\"378334690498943168\",\"LiquidityNet\":\"378334690498943168\"},{\"Index\":-83460,\"LiquidityGross\":\"114198463289361161\",\"LiquidityNet\":\"114198463289361161\"},{\"Index\":-81360,\"LiquidityGross\":\"1028162166888171618\",\"LiquidityNet\":\"1028162166888171618\"},{\"Index\":-74460,\"LiquidityGross\":\"114198463289361161\",\"LiquidityNet\":\"-114198463289361161\"},{\"Index\":-72360,\"LiquidityGross\":\"1028162166888171618\",\"LiquidityNet\":\"-1028162166888171618\"},{\"Index\":-67440,\"LiquidityGross\":\"30061094172819371\",\"LiquidityNet\":\"30061094172819371\"},{\"Index\":-66900,\"LiquidityGross\":\"516014702169853064\",\"LiquidityNet\":\"516014702169853064\"},{\"Index\":-66240,\"LiquidityGross\":\"369944374456874395\",\"LiquidityNet\":\"369944374456874395\"},{\"Index\":-66060,\"LiquidityGross\":\"2161245792615067038\",\"LiquidityNet\":\"2161245792615067038\"},{\"Index\":-65940,\"LiquidityGross\":\"443254816312717934\",\"LiquidityNet\":\"443254816312717934\"},{\"Index\":-65820,\"LiquidityGross\":\"1262134329124297016\",\"LiquidityNet\":\"1262134329124297016\"},{\"Index\":-65640,\"LiquidityGross\":\"1408506298369874820\",\"LiquidityNet\":\"1408506298369874820\"},{\"Index\":-65460,\"LiquidityGross\":\"830304806719403511\",\"LiquidityNet\":\"830304806719403511\"},{\"Index\":-65340,\"LiquidityGross\":\"72467299639106158\",\"LiquidityNet\":\"64833397926204928\"},{\"Index\":-65280,\"LiquidityGross\":\"2161245792615067038\",\"LiquidityNet\":\"-2161245792615067038\"},{\"Index\":-65040,\"LiquidityGross\":\"1262134329124297016\",\"LiquidityNet\":\"-1262134329124297016\"},{\"Index\":-64920,\"LiquidityGross\":\"1477156647152530363\",\"LiquidityNet\":\"-1477156647152530363\"},{\"Index\":-64860,\"LiquidityGross\":\"516014702169853064\",\"LiquidityNet\":\"-516014702169853064\"},{\"Index\":-64740,\"LiquidityGross\":\"585016684454068041\",\"LiquidityNet\":\"-585016684454068041\"},{\"Index\":-64200,\"LiquidityGross\":\"369944374456874395\",\"LiquidityNet\":\"-369944374456874395\"},{\"Index\":-63360,\"LiquidityGross\":\"30061094172819371\",\"LiquidityNet\":\"-30061094172819371\"},{\"Index\":-63060,\"LiquidityGross\":\"688542938578053404\",\"LiquidityNet\":\"-688542938578053404\"},{\"Index\":-55260,\"LiquidityGross\":\"453104336449262994\",\"LiquidityNet\":\"453104336449262994\"},{\"Index\":-52260,\"LiquidityGross\":\"453104336449262994\",\"LiquidityNet\":\"-453104336449262994\"},{\"Index\":-50520,\"LiquidityGross\":\"2670414588260124137\",\"LiquidityNet\":\"2670414588260124137\"},{\"Index\":-50460,\"LiquidityGross\":\"2670414588260124137\",\"LiquidityNet\":\"-2670414588260124137\"},{\"Index\":604800,\"LiquidityGross\":\"378334690498943168\",\"LiquidityNet\":\"-378334690498943168\"},{\"Index\":887220,\"LiquidityGross\":\"50848183932670656\",\"LiquidityNet\":\"-50848183932670656\"}],\"tS\":60,\"tP\":{\"0\":{\"init\":true,\"ts\":1737324773,\"vo\":\"0\",\"tick\":-65495,\"avgT\":-65495},\"54\":{\"init\":true,\"ts\":1737458202,\"cum\":-8719633295,\"vo\":\"1348335241\",\"tick\":-65324,\"avgT\":-65323,\"wsI\":32},\"55\":{\"init\":true,\"ts\":1737477357,\"cum\":-9971048600,\"vo\":\"1356463794\",\"tick\":-65331,\"avgT\":-65300,\"wsI\":39},\"56\":{\"init\":true,\"ts\":1737477411,\"cum\":-9974578742,\"vo\":\"1356751560\",\"tick\":-65373,\"avgT\":-65300,\"wsI\":39},\"57\":{\"init\":true,\"ts\":1737505454,\"cum\":-11808983544,\"vo\":\"1649854548\",\"tick\":-65414,\"avgT\":-65324,\"wsI\":44},\"58\":{\"init\":true,\"ts\":1737505604,\"cum\":-11818784394,\"vo\":\"1649888298\",\"tick\":-65339,\"avgT\":-65324,\"wsI\":44},\"59\":{\"init\":true,\"ts\":1737505976,\"cum\":-11843086410,\"vo\":\"1649892882\",\"tick\":-65328,\"avgT\":-65325,\"wsI\":44},\"60\":{\"init\":true,\"ts\":1737506084,\"cum\":-11850139566,\"vo\":\"1649927874\",\"tick\":-65307,\"avgT\":-65325,\"wsI\":44},\"61\":{\"init\":true,\"ts\":1737506432,\"cum\":-11872863270,\"vo\":\"1650181566\",\"tick\":-65298,\"avgT\":-65325,\"wsI\":44},\"62\":{\"init\":true,\"ts\":1737506573,\"cum\":-11882072544,\"vo\":\"1650198627\",\"tick\":-65314,\"avgT\":-65325,\"wsI\":44},\"63\":{\"init\":true,\"ts\":1737513536,\"cum\":-12337390077,\"vo\":\"1676165365\",\"tick\":-65391,\"avgT\":-65335,\"wsI\":44},\"64\":{\"init\":true,\"ts\":1737528797,\"cum\":-13335352650,\"vo\":\"1710491407\",\"tick\":-65393,\"avgT\":-65357,\"wsI\":45},\"65\":{\"init\":true,\"ts\":1737528803,\"cum\":-13335744780,\"vo\":\"1710491431\",\"tick\":-65355,\"avgT\":-65357,\"wsI\":45},\"66\":{\"init\":true,\"ts\":1737533351,\"cum\":-13632979320,\"vo\":\"1710618805\",\"tick\":-65355,\"avgT\":-65363,\"wsI\":45},\"67\":{\"init\":true,\"ts\":1737537416,\"cum\":-13899005115,\"vo\":\"1734424264\",\"tick\":-65443,\"avgT\":-65370,\"wsI\":46},\"68\":{\"init\":true,\"ts\":1737543071,\"cum\":-14269266240,\"vo\":\"1787219588\",\"tick\":-65475,\"avgT\":-65387,\"wsI\":50},\"69\":{\"init\":true,\"ts\":1737546995,\"cum\":-14526158748,\"vo\":\"1809904932\",\"tick\":-65467,\"avgT\":-65395,\"wsI\":54},\"70\":{\"init\":true,\"ts\":1737548408,\"cum\":-14618737095,\"vo\":\"1831109455\",\"tick\":-65519,\"avgT\":-65398,\"wsI\":54},\"71\":{\"init\":true,\"ts\":1737553181,\"cum\":-14931402006,\"vo\":\"1882772958\",\"tick\":-65507,\"avgT\":-65408,\"wsI\":54},\"72\":{\"init\":true,\"ts\":1737553955,\"cum\":-14982078882,\"vo\":\"1886093610\",\"tick\":-65474,\"avgT\":-65409,\"wsI\":54},\"73\":{\"init\":true,\"ts\":1737557573,\"cum\":-15218815476,\"vo\":\"1887773460\",\"tick\":-65433,\"avgT\":-65414,\"wsI\":54},\"74\":{\"init\":true,\"ts\":1737562367,\"cum\":-15532443750,\"vo\":\"1887880503\",\"tick\":-65421,\"avgT\":-65419,\"wsI\":54},\"75\":{\"init\":true,\"ts\":1737562850,\"cum\":-15564033882,\"vo\":\"1887989178\",\"tick\":-65404,\"avgT\":-65419,\"wsI\":54},\"76\":{\"vo\":\"0\"},\"77\":{\"vo\":\"0\"}},\"vo\":{\"tpIdx\":75,\"lastTs\":1737562850,\"init\":true},\"dF\":{\"a1\":500,\"a2\":200,\"b1\":360,\"b2\":60000,\"g1\":59,\"g2\":8500,\"bF\":490},\"sF\":{\"0to1fF\":\"79228162514264337593543950336\",\"1to0fF\":\"79228162514264337593543950336\",\"pCF\":1000,\"bF\":3000,\"feeType\":false}}","staticExtra":"{\"pluginV2\":true}"}`), + &thenaEp)) + thenaPS = lo.Must(NewPoolSimulator(thenaEp, 280000)) +) + +func TestCalcAmountOut_Ver_1_2(t *testing.T) { + blockTimestamp = func() uint32 { return 1737563754 } + res, err := testutil.MustConcurrentSafe(t, func() (*pool.CalcAmountOutResult, error) { + return thenaPS.CalcAmountOut(pool.CalcAmountOutParams{ + TokenAmountIn: pool.TokenAmount{ + Token: "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c", + Amount: big.NewInt(1e16), + }, + TokenOut: "0x55d398326f99059ff775485246999027b3197955", + }) + }) + + require.NoError(t, err) + assert.Equal(t, big.NewInt(6427705112340899769), res.TokenAmountOut.Amount) +} + func TestPoolSimulator_CalcAmountIn(t *testing.T) { for i := 0; i < 64; i++ { tokenIn := p.Tokens[i%2].Address diff --git a/pkg/liquidity-source/algebra/integral/pool_tracker.go b/pkg/liquidity-source/algebra/integral/pool_tracker.go index 495be3b0b..d68a35ce0 100644 --- a/pkg/liquidity-source/algebra/integral/pool_tracker.go +++ b/pkg/liquidity-source/algebra/integral/pool_tracker.go @@ -181,7 +181,6 @@ func (d *PoolTracker) fetchRPCData(ctx context.Context, p entity.Pool, blockNumb ABI: algebraIntegralPoolABI, Target: p.Address, Method: poolLiquidityMethod, - Params: nil, }, []interface{}{&res.Liquidity}) rpcState := &GlobalStateFromRPC{} @@ -189,14 +188,12 @@ func (d *PoolTracker) fetchRPCData(ctx context.Context, p entity.Pool, blockNumb ABI: algebraIntegralPoolABI, Target: p.Address, Method: poolGlobalStateMethod, - Params: nil, }, []interface{}{rpcState}) req.AddCall(ðrpc.Call{ ABI: algebraIntegralPoolABI, Target: p.Address, Method: poolTickSpacingMethod, - Params: nil, }, []interface{}{&res.TickSpacing}) if len(p.Tokens) == 2 { @@ -269,7 +266,6 @@ func (d *PoolTracker) getPluginData(ctx context.Context, poolAddress string, blo ABI: algebraIntegralPoolABI, Target: poolAddress, Method: poolPluginMethod, - Params: nil, }, []interface{}{&plugin}) _, err := req.Call() @@ -331,19 +327,16 @@ func (d *PoolTracker) getVolatilityOracleData(ctx context.Context, pluginAddress ABI: algebraBasePluginV2ABI, Target: pluginAddress, Method: votalityOraclePluginIsInitializedMethod, - Params: nil, }, []interface{}{&result.IsInitialized}) req.AddCall(ðrpc.Call{ ABI: algebraBasePluginV2ABI, Target: pluginAddress, Method: votalityOraclePluginLastTimepointTimestampMethod, - Params: nil, }, []interface{}{&result.LastTimepointTimestamp}) req.AddCall(ðrpc.Call{ ABI: algebraBasePluginV2ABI, Target: pluginAddress, Method: votalityOraclePluginTimepointIndexMethod, - Params: nil, }, []interface{}{&result.TimepointIndex}) _, err := req.Aggregate() @@ -355,30 +348,41 @@ func (d *PoolTracker) getVolatilityOracleData(ctx context.Context, pluginAddress } func (d *PoolTracker) getSlidingFeeData(ctx context.Context, pluginAddress string, - blockNumber *big.Int) (SlidingFeeConfig, error) { - var result SlidingFeeConfigRPC - + blockNumber *big.Int) (cfg SlidingFeeConfig, err error) { req := d.ethrpcClient.NewRequest().SetContext(ctx) if blockNumber != nil && blockNumber.Sign() > 0 { req.SetBlockNumber(blockNumber) } + var result SlidingFeeConfigRPC req.AddCall(ðrpc.Call{ ABI: algebraBasePluginV2ABI, Target: pluginAddress, Method: slidingFeePluginFeeFactorsMethod, - Params: nil, }, []interface{}{&result}) + req.AddCall(ðrpc.Call{ + ABI: algebraBasePluginV2ABI, + Target: pluginAddress, + Method: slidingFeePluginPriceChangeFactorMethod, + }, []interface{}{&cfg.PriceChangeFactor}) + req.AddCall(ðrpc.Call{ + ABI: algebraBasePluginV2ABI, + Target: pluginAddress, + Method: slidingFeePluginBaseFeeMethod, + }, []interface{}{&cfg.BaseFee}) + req.AddCall(ðrpc.Call{ + ABI: algebraBasePluginV2ABI, + Target: pluginAddress, + Method: slidingFeePluginFeeTypeMethod, + }, []interface{}{&cfg.FeeType}) - _, err := req.Call() - if err != nil { + if _, err = req.Call(); err != nil { return SlidingFeeConfig{}, err } - return SlidingFeeConfig{ - ZeroToOneFeeFactor: uint256.MustFromBig(result.OneToZeroFeeFactor), - OneToZeroFeeFactor: uint256.MustFromBig(result.ZeroToOneFeeFactor), - }, nil + cfg.ZeroToOneFeeFactor = uint256.MustFromBig(result.OneToZeroFeeFactor) + cfg.OneToZeroFeeFactor = uint256.MustFromBig(result.ZeroToOneFeeFactor) + return cfg, nil } func (d *PoolTracker) getDynamicFeeData(ctx context.Context, pluginAddress string, @@ -394,7 +398,6 @@ func (d *PoolTracker) getDynamicFeeData(ctx context.Context, pluginAddress strin ABI: algebraBasePluginV2ABI, Target: pluginAddress, Method: dynamicFeeManagerPluginFeeConfigMethod, - Params: nil, }, []interface{}{&result}) _, err := req.Call() diff --git a/pkg/liquidity-source/algebra/integral/pool_tracker_test.go b/pkg/liquidity-source/algebra/integral/pool_tracker_test.go new file mode 100644 index 000000000..06d6f9761 --- /dev/null +++ b/pkg/liquidity-source/algebra/integral/pool_tracker_test.go @@ -0,0 +1,35 @@ +package integral + +import ( + "context" + "testing" + + "github.com/KyberNetwork/ethrpc" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/goccy/go-json" + "github.com/samber/lo" + "github.com/stretchr/testify/require" + + "github.com/KyberNetwork/kyberswap-dex-lib/pkg/source/pool" + graphqlpkg "github.com/KyberNetwork/kyberswap-dex-lib/pkg/util/graphql" + "github.com/KyberNetwork/kyberswap-dex-lib/pkg/valueobject" +) + +func TestPoolTracker_GetNewPoolState(t *testing.T) { + // t.Skip() + + d := &PoolTracker{ + config: &Config{ + DexID: string(valueobject.ExchangeThenaFusionV3), + AllowSubgraphError: true, + UseBasePluginV2: true, + }, + ethrpcClient: ethrpc.NewWithClient(lo.Must(ethclient.Dial("https://bsc.kyberengineering.io"))). + SetMulticallContract(common.HexToAddress("0xcA11bde05977b3631167028862bE2a173976CA11")), + graphqlClient: graphqlpkg.NewClient("https://thegraph.com/explorer/api/playground/QmWSzHwZY9ZMNYMVbQLyL276V1toR3iZsnYMfQut166yit"), + } + got, err := d.GetNewPoolState(context.Background(), thenaEp, pool.GetNewPoolStateParams{}) + require.NoError(t, err) + t.Log(string(lo.Must(json.Marshal(got)))) +} diff --git a/pkg/liquidity-source/algebra/integral/type.go b/pkg/liquidity-source/algebra/integral/type.go index 71d1d44e2..081f7f1b7 100644 --- a/pkg/liquidity-source/algebra/integral/type.go +++ b/pkg/liquidity-source/algebra/integral/type.go @@ -160,6 +160,9 @@ type DynamicFeeConfig struct { type SlidingFeeConfig struct { ZeroToOneFeeFactor *uint256.Int `json:"0to1fF,omitempty"` OneToZeroFeeFactor *uint256.Int `json:"1to0fF,omitempty"` + PriceChangeFactor uint16 `json:"pCF,omitempty"` + BaseFee uint16 `json:"bF,omitempty"` + FeeType bool `json:"feeType,omitempty"` // false = v1, true = v2 - used by thena fusion v3 } type SlidingFeeConfigRPC struct { @@ -206,7 +209,7 @@ type SwapCalculationCache struct { amountCalculated *uint256.Int // The additive amount of total output/input calculated through the swap pluginFee *uint256.Int // The plugin fee communityFee *uint256.Int // The community fee of the selling token, uint256 to minimize casts - fee uint64 // The current fee value in hundredths of a bip, i.e. 1e-6 + fee uint64 // The current fee value in hundredths of a bip, i.e. 1e-6 exactInput bool // Whether the exact input or output is specified }