diff --git a/pkg/liquidity-source/bebop/limit.go b/pkg/liquidity-source/bebop/limit.go new file mode 100644 index 000000000..63e02c4bf --- /dev/null +++ b/pkg/liquidity-source/bebop/limit.go @@ -0,0 +1,34 @@ +package bebop + +import ( + "math/big" + "sync/atomic" +) + +// Limit: limit 1 bebop swap per route +type Limit struct { + hasSwap *atomic.Bool +} + +func NewLimit(_ map[string]*big.Int) *Limit { + b := new(atomic.Bool) + return &Limit{ + hasSwap: b, + } +} + +func (l *Limit) GetLimit(key string) *big.Int { + if l.hasSwap.Load() { + return big.NewInt(0) + } + + return nil +} + +func (l *Limit) UpdateLimit( + _, _ string, _, _ *big.Int, +) (*big.Int, *big.Int, error) { + l.hasSwap.Store(true) + + return nil, nil, nil +} diff --git a/pkg/liquidity-source/bebop/pool_simulator.go b/pkg/liquidity-source/bebop/pool_simulator.go index ceed0f87b..2996a63cc 100644 --- a/pkg/liquidity-source/bebop/pool_simulator.go +++ b/pkg/liquidity-source/bebop/pool_simulator.go @@ -102,12 +102,17 @@ func NewPoolSimulator(entityPool entity.Pool) (*PoolSimulator, error) { } func (p *PoolSimulator) CalcAmountOut(params pool.CalcAmountOutParams) (*pool.CalcAmountOutResult, error) { + if params.Limit.GetLimit("") != nil { + return nil, pool.ErrNotEnoughInventory + } + if params.TokenAmountIn.Token == p.Info.Tokens[0] { return p.swap(params.TokenAmountIn.Amount, p.Token0, p.Token1, p.ZeroToOnePriceLevels) } else { return p.swap(params.TokenAmountIn.Amount, p.Token1, p.Token0, p.OneToZeroPriceLevels) } } + func (p *PoolSimulator) UpdateBalance(params pool.UpdateBalanceParams) { var amountInAfterDecimals, decimalsPow, amountInBF big.Float amountInBF.SetInt(params.TokenAmountIn.Amount) @@ -122,12 +127,40 @@ func (p *PoolSimulator) UpdateBalance(params pool.UpdateBalanceParams) { p.OneToZeroPriceLevels = getNewPriceLevelsState(&amountInAfterDecimals, p.OneToZeroPriceLevels) } + + // to handle the "top levels of orderbook" issue + // the swapLimit will be updated to 0, to limit using bebopRFQ once each route + // ref:https://team-kyber.slack.com/archives/C061UNZDUVC/p1728974288547259 + _, _, _ = params.SwapLimit.UpdateLimit( + "", "", + nil, nil, + ) } func (p *PoolSimulator) GetMetaInfo(_ string, _ string) interface{} { return nil } +func (p *PoolSimulator) CalculateLimit() map[string]*big.Int { + var pmmInventory = make(map[string]*big.Int, len(p.GetTokens())) + tokens := p.GetTokens() + rsv := p.GetReserves() + if len(tokens) != len(rsv) { + return pmmInventory + } + + for i, tok := range tokens { + // rsv of a token can be set to 1 wei to bypass the aggregator check + if rsv[i].Int64() == 1 { + continue + } + + pmmInventory[tok] = big.NewInt(0).Set(rsv[i]) //clone here. + } + + return pmmInventory +} + func (p *PoolSimulator) swap(amountIn *big.Int, baseToken, quoteToken entity.PoolToken, priceLevel []PriceLevel) (*pool.CalcAmountOutResult, error) { diff --git a/pkg/liquidity-source/bebop/pool_simulator_test.go b/pkg/liquidity-source/bebop/pool_simulator_test.go index 297ae2493..a8c6456c3 100644 --- a/pkg/liquidity-source/bebop/pool_simulator_test.go +++ b/pkg/liquidity-source/bebop/pool_simulator_test.go @@ -92,6 +92,7 @@ func TestPoolSimulator_GetAmountOut(t *testing.T) { Amount: tc.amountIn, }, TokenOut: "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270", + Limit: NewLimit(nil), } result, err := poolSimulator.CalcAmountOut(params) @@ -109,15 +110,24 @@ func TestPoolSimulator_GetAmountOut2(t *testing.T) { tests := []struct { name string + updateLimit bool amountIn *big.Int expectedAmountOut *big.Int expectedErr error }{ { name: "it should return correct amountOut when swap in levels", + updateLimit: false, amountIn: bigIntFromString("100000000000000000000"), expectedAmountOut: bigIntFromString("7595710"), }, + { + name: "it should return not enough inventory", + updateLimit: true, + amountIn: bigIntFromString("100000000000000000000"), + expectedAmountOut: bigIntFromString("7595710"), + expectedErr: pool.ErrNotEnoughInventory, + }, } for _, tc := range tests { @@ -129,6 +139,10 @@ func TestPoolSimulator_GetAmountOut2(t *testing.T) { Amount: tc.amountIn, }, TokenOut: "0xdac17f958d2ee523a2206206994597c13d831ec7", + Limit: NewLimit(nil), + } + if tc.updateLimit { + _, _, _ = params.Limit.UpdateLimit("", "", nil, nil) } result, err := poolSimulator.CalcAmountOut(params)