Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
github.com/KyberNetwork/kyber-trace-go v0.1.2
github.com/KyberNetwork/kyberswap-dex-lib v0.101.7
github.com/TheZeroSlave/zapsentry v1.23.0
github.com/deckarep/golang-set/v2 v2.8.0
github.com/duoxehyon/mev-share-go v0.3.0
github.com/ethereum/go-ethereum v1.15.10
github.com/flashbots/mev-share-node v0.0.0-20240517155750-67003f8e8700
Expand All @@ -22,6 +23,7 @@ require (
github.com/holiman/uint256 v1.3.2
github.com/jmoiron/sqlx v1.4.0
github.com/lib/pq v1.10.9
github.com/oleiade/lane/v2 v2.0.0
github.com/shopspring/decimal v1.4.0
github.com/sourcegraph/conc v0.3.0
github.com/stretchr/testify v1.10.0
Expand Down Expand Up @@ -56,10 +58,8 @@ require (
github.com/daoleno/uniswap-sdk-core v0.1.7 // indirect
github.com/daoleno/uniswapv3-sdk v0.4.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/deckarep/golang-set/v2 v2.8.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dmarkham/enumer v1.5.11 // indirect
github.com/ethereum/c-kzg-4844 v1.0.3 // indirect
github.com/ethereum/go-verkle v0.2.2 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
Expand Down Expand Up @@ -91,7 +91,6 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/orcaman/concurrent-map v1.0.0 // indirect
github.com/pascaldekloe/name v1.0.0 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pierrec/lz4/v3 v3.3.5 // indirect
github.com/pion/dtls/v2 v2.2.12 // indirect
Expand Down Expand Up @@ -131,13 +130,11 @@ require (
golang.org/x/arch v0.16.0 // indirect
golang.org/x/crypto v0.37.0 // indirect
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/net v0.39.0 // indirect
golang.org/x/sync v0.13.0 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.org/x/text v0.24.0 // indirect
golang.org/x/time v0.11.0 // indirect
golang.org/x/tools v0.32.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 // indirect
google.golang.org/grpc v1.72.0 // indirect
Expand Down
10 changes: 2 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,6 @@ github.com/dhui/dktest v0.4.5 h1:uUfYBIVREmj/Rw6MvgmqNAYzTiKOHJak+enB5Di73MM=
github.com/dhui/dktest v0.4.5/go.mod h1:tmcyeHDKagvlDrz7gDKq4UAJOLIfVZYkfD5OnHDwcCo=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/dmarkham/enumer v1.5.11 h1:quorLCaEfzjJ23Pf7PB9lyyaHseh91YfTM/sAD/4Mbo=
github.com/dmarkham/enumer v1.5.11/go.mod h1:yixql+kDDQRYqcuBM2n9Vlt7NoT9ixgXhaXry8vmRg8=
github.com/docker/docker v27.2.0+incompatible h1:Rk9nIVdfH3+Vz4cyI/uhbINhEZ/oLmc+CBXmH6fbNk4=
github.com/docker/docker v27.2.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
Expand Down Expand Up @@ -386,6 +384,8 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oleiade/lane/v2 v2.0.0 h1:XW/ex/Inr+bPkLd3O240xrFOhUkTd4Wy176+Gv0E3Qw=
github.com/oleiade/lane/v2 v2.0.0/go.mod h1:i5FBPFAYSWCgLh58UkUGCChjcCzef/MI7PlQm2TKCeg=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
Expand All @@ -410,8 +410,6 @@ github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsq
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/orcaman/concurrent-map v1.0.0 h1:I/2A2XPCb4IuQWcQhBhSwGfiuybl/J0ev9HDbW65HOY=
github.com/orcaman/concurrent-map v1.0.0/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI=
github.com/pascaldekloe/name v1.0.0 h1:n7LKFgHixETzxpRv2R77YgPUFo85QHGZKrdaYm7eY5U=
github.com/pascaldekloe/name v1.0.0/go.mod h1:Z//MfYJnH4jVpQ9wkclwu2I2MkHmXTlT9wR5UZScttM=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
Expand Down Expand Up @@ -618,8 +616,6 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
Expand Down Expand Up @@ -713,8 +709,6 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
69 changes: 69 additions & 0 deletions pkg/finderengine/engine.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package finderengine

import (
dexlibPool "github.com/KyberNetwork/kyberswap-dex-lib/pkg/source/pool"
"github.com/KyberNetwork/tradinglib/pkg/finderengine/entity"
)

type Finder struct {
MaxHop uint64
DistributionPercent uint64
NumPathSplits uint64
NumHopSplits uint64
findHops FindHopFunc
}

func (f *Finder) Find(params entity.FinderParams) (*entity.BestRouteResult, error) {
if err := f.validateParameters(params); err != nil {
return nil, err
}

edges := make(map[string]map[string][]dexlibPool.IPoolSimulator)
for i := range params.Pools {
pool := params.Pools[i]
tokens := pool.GetTokens()
for i := range tokens {
if edges[tokens[i]] == nil {
edges[tokens[i]] = make(map[string][]dexlibPool.IPoolSimulator)
}
for j := range tokens {
if i == j {
continue
}
if edges[tokens[i]][tokens[j]] == nil {
edges[tokens[i]][tokens[j]] = make([]dexlibPool.IPoolSimulator, 0)
}
edges[tokens[i]][tokens[j]] = append(edges[tokens[i]][tokens[j]], pool)
}
}
}

minHops := f.minHopsToTokenOut(params.TokenIn, params.TokenOut, edges, params.WhitelistHopTokens)
_ = f.findBestPathsOptimized(&params, minHops, edges)
// Optimize Route: TODO

return nil, nil

Check failure on line 45 in pkg/finderengine/engine.go

View workflow job for this annotation

GitHub Actions / Run golangci-lint

return both a `nil` error and an invalid value: use a sentinel error instead (nilnil)
}

func (f *Finder) validateParameters(params entity.FinderParams) error {
if _, exist := params.Tokens[params.TokenIn]; !exist {
return ErrTokenInNotFound
}
if _, exist := params.Tokens[params.TokenOut]; !exist {
return ErrTokenOutNotFound
}

if params.GasIncluded {
if params.GasToken == "" {
return ErrGasTokenRequired
}
if params.GasPrice == nil {
return ErrGasPriceRequired
}
if _, exist := params.Tokens[params.GasToken]; !exist {
return ErrGasTokenNotFound
}
}

return nil
}
95 changes: 95 additions & 0 deletions pkg/finderengine/entity/entity.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package entity

import (
"math/big"

dexlibPool "github.com/KyberNetwork/kyberswap-dex-lib/pkg/source/pool"
)

type Token struct {
Address string `json:"address"`
Symbol string `json:"symbol"`
Name string `json:"name"`
Decimals uint8 `json:"decimals"`
}

func (t Token) GetAddress() string {
return t.Address
}

type SimplifiedToken struct {
Address string `json:"address"`
Decimals uint8 `json:"decimals"`
}

func (t SimplifiedToken) GetAddress() string {
return t.Address
}

type FinderParams struct {
// TokenIn is the token to be swapped
TokenIn string
// TokenOut is the token to be received
TokenOut string
// AmountIn is the amount of TokenIn to be swapped
AmountIn *big.Int

// WhitelistHopTokens is the list of tokens that can be used as intermediate tokens
// when finding the best route.
WhitelistHopTokens map[string]struct{}

// Pools is a mapping between pool address and its simulator.
// The pathfinder will use these pools to find the best route.
Pools map[string]dexlibPool.IPoolSimulator

// SwapLimits is a mapping between pool type and its swap limit (inventory).
// The pathfinder will use these limits to find the best route.
SwapLimits map[string]dexlibPool.SwapLimit

// Tokens is a mapping between token address and its information.
// TokenIn, TokenOut, WhitelistTokens (& GasToken if GasInclude = true)
// should be included in this map.
Tokens map[string]SimplifiedToken

// Prices is a mapping between token address and its price.
// The price can be USD price or Native price (from the On-chain price feed).
// If GasIncluded is true, the pathfinder will use the price information to find the best route.
Prices map[string]float64

// GasIncluded is the flag to indicate whether the gas fee is included in finding the best route or not.
// If true, the gas fee will be accounted for in the final result (the best route is the one with the
// highest price of TokenOut after deducting the gas fee).
// If false, the gas fee will be ignored (the best route is the one with the highest amount of TokenOut).
GasIncluded bool

// GasToken is the token used to pay for the gas fee. Required if GasIncluded is true.
GasToken string

// GasPrice is the gas price in WEI. Required if GasIncluded is true.
// This field should be differentiated from the price of the gas token:
// GasFee = GasPrice * GasUsed;
// GasFeePrice = GasFee * Price[GasToken] / 10^Tokens[GasToken].Decimals;
GasPrice *big.Int

// L1GasFeePriceOverhead estimated L1 gas fee for an empty route summary data (without a pool)
// in Price value (USD/Native).
L1GasFeePriceOverhead float64

// L1GasFeePricePerPool estimated L1 gas fee for each pool in Price value (USD/Native).
L1GasFeePricePerPool float64

// ClientId is the client ID used to identify the request.
ClientId string

// OnlySinglePath if enabled, the pathfinder will return route with only one path.
OnlySinglePath bool

// SkipMergeSwap if enabled, the pathfinder will skip the merge swap process.
SkipMergeSwap bool

// ReturnAMMBestPath if enabled, the pathfinder will return an extra route that contains only AMM swaps.
ReturnAMMBestPath bool

// EnableHillClimbForAlphaFee if enabled, we will run hill climbing for amm best route
EnableHillClimbForAlphaFee bool
}
23 changes: 23 additions & 0 deletions pkg/finderengine/entity/hop.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package entity

import "math/big"

type HopSplit struct {
ID string
AmountIn *big.Int
AmountOut *big.Int
GasUsed *big.Int
GasFeePrice float64
L1GasFeePrice float64
}

type Hop struct {
TokenIn string
TokenOut string
AmountIn *big.Int
AmountOut *big.Int
GasUsed int64
GasFeePrice float64
L1GasFeePrice float64
Splits []*HopSplit
}
82 changes: 82 additions & 0 deletions pkg/finderengine/entity/path.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package entity

import (
"math/big"

"github.com/KyberNetwork/tradinglib/pkg/finderengine/utils"
)

type Path struct {
ID string
AmountIn *big.Int
AmountOut *big.Int
AmountOutPrice float64
GasUsed int64
GasFeePrice float64
L1GasFeePrice float64
TokenOrders []string
HopOrders []*Hop
}

func NewPath(amountIn *big.Int) *Path {
return &Path{
AmountIn: new(big.Int).Set(amountIn),
TokenOrders: []string{},
HopOrders: []*Hop{},
}
}

func (p *Path) AddToken(token string) *Path {
p.TokenOrders = append(p.TokenOrders, token)
return p
}

func (p *Path) AddHop(hop *Hop) *Path {
p.HopOrders = append(p.HopOrders, hop)
return p
}

func (p *Path) SetAmountOutAndPrice(
amountOut *big.Int,
decimals uint8,
price float64,
) *Path {
p.AmountOut.Set(amountOut)
p.AmountOutPrice = utils.CalcAmountPrice(amountOut, decimals, price)

return p
}

func (p *Path) SetGasUsedAndPrice(
gasUsed int64,
gasPrice *big.Int,
gasTokenDecimals uint8,
gasTokenPrice float64,
l1GasFeePrice float64,
) *Path {
p.GasUsed = gasUsed

var gasFee big.Int
gasFee.SetInt64(gasUsed)
gasFee.Mul(&gasFee, gasPrice)

p.GasFeePrice = utils.CalcAmountPrice(&gasFee, gasTokenDecimals, gasTokenPrice)

p.L1GasFeePrice = l1GasFeePrice

return p
}

func (p *Path) Clone() *Path {
return &Path{
ID: p.ID,
AmountIn: new(big.Int).Set(p.AmountIn),
AmountOut: new(big.Int).Set(p.AmountOut),
AmountOutPrice: p.AmountOutPrice,
GasUsed: p.GasUsed,
GasFeePrice: p.GasFeePrice,
L1GasFeePrice: p.L1GasFeePrice,
HopOrders: append([]*Hop{}, p.HopOrders...),
TokenOrders: append([]string{}, p.TokenOrders...),
}
}
Loading
Loading