Skip to content

Commit 3f3b27a

Browse files
authored
[wildcat] track rate by multiple amountIn (#1244)
* track rate by multiple amountIn * . * bin search
1 parent 7b5af21 commit 3f3b27a

File tree

6 files changed

+46
-25
lines changed

6 files changed

+46
-25
lines changed

pkg/liquidity-source/wildcat/constant.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import "errors"
55
const (
66
DexType = "wildcat"
77
defaultGas = 10000
8+
sampleSize = 15
89
)
910

1011
var (

pkg/liquidity-source/wildcat/pool_list_updater.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,9 @@ func (u *PoolsListUpdater) GetNewPools(ctx context.Context, metadataBytes []byte
100100
p.Extra = string(extraBytes)
101101
return p
102102
})
103-
if _, err := TrackPools(ctx, pools, u.ethrpcClient, u.config); err != nil {
104-
return nil, metadataBytes, err
105-
}
103+
// if _, err := TrackPools(ctx, pools, u.ethrpcClient, u.config); err != nil {
104+
// return nil, metadataBytes, err
105+
// }
106106

107107
newMetadataBytes, err := u.newMetadata(offset + len(pairs))
108108
if err != nil {

pkg/liquidity-source/wildcat/pool_simulator.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/json"
55
"math/big"
66
"slices"
7+
"sort"
78

89
"github.com/samber/lo"
910

@@ -51,11 +52,17 @@ func (s *PoolSimulator) CalcAmountOut(params pool.CalcAmountOutParams) (*pool.Ca
5152
return nil, ErrInvalidToken
5253
}
5354

54-
amountOut := big.NewInt(0)
55-
if s.Rates[indexIn].Sign() >= 0 {
56-
bignumber.MulDivDown(amountOut, tokenAmountIn.Amount, s.Info.Reserves[indexOut], s.Rates[indexIn])
55+
if len(s.Samples[indexIn]) == 0 {
56+
return nil, ErrInsufficientLiquidity
5757
}
5858

59+
samples := s.Samples[indexIn]
60+
idx := sort.Search(len(samples), func(i int) bool {
61+
return samples[i][0].Cmp(tokenAmountIn.Amount) > 0
62+
})
63+
sampleIndex := max(idx-1, 0)
64+
amountOut := bignumber.MulDivDown(big.NewInt(0), tokenAmountIn.Amount, samples[sampleIndex][1], samples[sampleIndex][0])
65+
5966
if amountOut.Cmp(s.Info.Reserves[indexOut]) >= 0 {
6067
return nil, ErrInsufficientLiquidity
6168
}

pkg/liquidity-source/wildcat/pool_simulator_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212

1313
var (
1414
entityPool entity.Pool
15-
_ = json.Unmarshal([]byte(`{"address":"0x4ec0cb2ef6c438f1c1634212377abdc9f2b0b20d","exchange":"wildcat","type":"wildcat","timestamp":1765885780,"reserves":["118004000000000000000","999930756215080"],"tokens":[{"address":"0x6a5e34ea281b25a860517077a7a942e95ec31154","symbol":"ETH","decimals":18,"swappable":true},{"address":"0xb2b18b723f6d0df5be06e245f6eebf8a43d85151","symbol":"USDC","decimals":6,"swappable":true}],"extra":"{\"rates\":[332665881250712632291671,355429528951],\"isNative\":[false,false]}"}`),
15+
_ = json.Unmarshal([]byte(`{"address":"0xcc8e05f2d5e28b70214d3d384bada2bd0ae99cda","exchange":"wildcat","type":"wildcat","timestamp":1767595770,"reserves":["30699993136664026623","31490510717"],"tokens":[{"address":"0x4200000000000000000000000000000000000006","symbol":"WETH","decimals":18,"swappable":true},{"address":"0x833589fcd6edb6e08f4c7c32d4f71b54bda02913","symbol":"USDC","decimals":6,"swappable":true}],"extra":"{\"rates\":[18332721688954665668,70366686069],\"isNative\":[true,false],\"samples\":[[[1000000000000000,3154701],[10000000000000000,31547016],[100000000000000000,315470163],[1000000000000000000,3154701633],[10000000000000000000,0],[100000000000000000000,0],[1000000000000000000000,0]],[[1000,0],[10000,0],[100000,31698338375796],[1000000,316983383757966],[10000000,3169833837579669],[100000000,31698338375796699],[1000000000,316983383757966994]]]}"}`),
1616
&entityPool)
1717
poolSim = lo.Must(NewPoolSimulator(entityPool))
1818
)
@@ -22,12 +22,12 @@ func TestPoolSimulator_CalcAmountOut(t *testing.T) {
2222
testutil.TestCalcAmountOut(t, poolSim, map[int]map[int]map[string]string{
2323
1: {
2424
0: {
25-
"3005810": "997940729029576",
25+
"3005810": "952791824733531",
2626
},
2727
},
2828
0: {
2929
1: {
30-
"1000000000000000": "3005810",
30+
"1000000000000000": "3154701",
3131
},
3232
},
3333
})

pkg/liquidity-source/wildcat/pool_tracker.go

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ import (
99
"github.com/KyberNetwork/ethrpc"
1010
"github.com/ethereum/go-ethereum/common"
1111
"github.com/ethereum/go-ethereum/ethclient/gethclient"
12+
"github.com/samber/lo"
1213

1314
"github.com/KyberNetwork/kyberswap-dex-lib/pkg/entity"
1415
"github.com/KyberNetwork/kyberswap-dex-lib/pkg/source/pool"
1516
pooltrack "github.com/KyberNetwork/kyberswap-dex-lib/pkg/source/pool/tracker"
17+
"github.com/KyberNetwork/kyberswap-dex-lib/pkg/util/bignumber"
1618
)
1719

1820
type PoolTracker struct {
@@ -63,7 +65,6 @@ func (t *PoolTracker) getNewPoolState(
6365

6466
func TrackPools(ctx context.Context, pools []entity.Pool, rpcClient *ethrpc.Client, cfg *Config) ([]entity.Pool, error) {
6567
req := rpcClient.NewRequest().SetContext(ctx)
66-
rates := make([][]*big.Int, len(pools))
6768
reserves := make([][]*big.Int, len(pools))
6869
extras := make([]Extra, len(pools))
6970
for i, pool := range pools {
@@ -96,29 +97,40 @@ func TrackPools(ctx context.Context, pools []entity.Pool, rpcClient *ethrpc.Clie
9697
}
9798

9899
req = rpcClient.NewRequest().SetContext(ctx)
100+
samples := make([][][][2]*big.Int, len(pools))
99101
for i, pool := range pools {
100-
rates[i] = make([]*big.Int, 2)
102+
samples[i] = make([][][2]*big.Int, len(pool.Tokens))
101103
for j := range pool.Tokens {
102-
if reserves[i][(j+1)%2].Sign() == 0 {
103-
rates[i][j] = big.NewInt(0)
104-
continue
104+
samples[i][j] = make([][2]*big.Int, sampleSize)
105+
start := lo.Ternary(pool.Tokens[j].Decimals < sampleSize/2, 0, pool.Tokens[j].Decimals-sampleSize/2)
106+
end := pool.Tokens[j].Decimals + sampleSize/2
107+
index := 0
108+
for k := start; k <= end; k++ {
109+
samples[i][j][index] = [2]*big.Int{bignumber.TenPowInt(k), big.NewInt(0)}
110+
req.AddCall(&ethrpc.Call{
111+
ABI: pairABI,
112+
Target: pool.Address,
113+
Method: "getAmountOut",
114+
Params: []any{j == 0, samples[i][j][index][0]}, // true = 0->1 (getAmountIn(zero_for_one, amount_out))
115+
}, []any{&samples[i][j][index][1]})
116+
index++
105117
}
106-
req.AddCall(&ethrpc.Call{
107-
ABI: pairABI,
108-
Target: pool.Address,
109-
Method: "getAmountIn",
110-
Params: []any{j == 0, reserves[i][(j+1)%2]}, // true = 0->1 (getAmountIn(zero_for_one, amount_out))
111-
}, []any{&rates[i][j]})
112118
}
113119
}
114-
_, err = req.Aggregate()
120+
_, err = req.TryAggregate()
115121
if err != nil {
116122
return nil, err
117123
}
118-
124+
for i := range samples {
125+
for j := range samples[i] {
126+
samples[i][j] = lo.Filter(samples[i][j], func(sample [2]*big.Int, _ int) bool {
127+
return sample[0] != nil && sample[1] != nil
128+
})
129+
}
130+
}
119131
for i := range pools {
120132
pools[i].Reserves = []string{reserves[i][0].String(), reserves[i][1].String()}
121-
extras[i].Rates = rates[i]
133+
extras[i].Samples = samples[i]
122134
extraBytes, err := json.Marshal(extras[i])
123135
if err != nil {
124136
return nil, err

pkg/liquidity-source/wildcat/types.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ package wildcat
33
import "math/big"
44

55
type Extra struct {
6-
Rates []*big.Int `json:"rates"`
7-
IsNative []bool `json:"isNative"`
6+
Rates []*big.Int `json:"rates"`
7+
IsNative []bool `json:"isNative"`
8+
Samples [][][2]*big.Int `json:"samples"` // [2]*big.Int = [amountIn, amountOut]
89
}
910

1011
type PoolExtra struct {

0 commit comments

Comments
 (0)