-
Notifications
You must be signed in to change notification settings - Fork 9
feat: build pathfinding lib #159
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
1up1n
wants to merge
8
commits into
main
Choose a base branch
from
pathfinding-algorithm
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
c634e42
feat: build pathfinding lib
1up1n 297be78
fix lint
1up1n 8350fdc
feat: parallel add next token
1up1n 6509e24
fix: remove redundant code and add unit test
1up1n 6dac9b5
fix: change params
1up1n 706fee7
feat: add unit test and isolated pool
1up1n 08c6929
fix: update isolated pool clone
1up1n 07ed123
finalizer
1up1n File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package finderengine | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/KyberNetwork/tradinglib/pkg/finderengine/entity" | ||
"github.com/KyberNetwork/tradinglib/pkg/finderengine/finalizer" | ||
finderPkg "github.com/KyberNetwork/tradinglib/pkg/finderengine/finder" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
type PathFinderEngine struct { | ||
finder IFinder | ||
finalizer IFinalizer | ||
} | ||
|
||
func NewPathFinderEngine( | ||
finder IFinder, | ||
finalizer IFinalizer, | ||
) *PathFinderEngine { | ||
return &PathFinderEngine{ | ||
finder: finder, | ||
finalizer: finalizer, | ||
} | ||
} | ||
|
||
func (p *PathFinderEngine) Find(ctx context.Context, params entity.FinderParams) (*entity.FinalizedRoute, error) { | ||
bestRoute, err := p.finder.Find(params) | ||
if err != nil { | ||
if errors.Is(err, finderPkg.ErrRouteNotFound) { | ||
return nil, fmt.Errorf("not found") | ||
} | ||
|
||
return nil, fmt.Errorf("failed to find route, err: %w", err) | ||
} | ||
|
||
if bestRoute.AMMBestRoute == nil { | ||
return nil, fmt.Errorf("invalid swap") | ||
} | ||
|
||
var ammRoute *entity.FinalizedRoute | ||
ammRoute, _ = finalizer.NewFinalizer().Finalize(params, bestRoute.AMMBestRoute) | ||
|
||
return ammRoute, fmt.Errorf("inval") | ||
} | ||
|
||
func (p *PathFinderEngine) SetFinder(finder IFinder) { | ||
p.finder = finder | ||
} | ||
|
||
func (p *PathFinderEngine) GetFinder() IFinder { | ||
return p.finder | ||
} | ||
|
||
func (p *PathFinderEngine) SetFinalizer(finalizer IFinalizer) { | ||
p.finalizer = finalizer | ||
} | ||
|
||
func (p *PathFinderEngine) GetFinalizer() IFinalizer { | ||
return p.finalizer | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
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 | ||
TargetToken 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 | ||
|
||
MaxHop uint64 | ||
1up1n marked this conversation as resolved.
Show resolved
Hide resolved
|
||
NumPathSplits uint64 | ||
NumHopSplits uint64 | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package entity | ||
|
||
import "math/big" | ||
|
||
type HopSplit struct { | ||
ID string | ||
AmountIn *big.Int | ||
AmountOut *big.Int | ||
Fee *big.Int | ||
GasUsed int64 | ||
GasFeePrice float64 | ||
L1GasFeePrice float64 | ||
} | ||
|
||
type Hop struct { | ||
TokenIn string | ||
TokenOut string | ||
AmountIn *big.Int | ||
AmountOut *big.Int | ||
Fee *big.Int | ||
GasUsed int64 | ||
GasFeePrice float64 | ||
L1GasFeePrice float64 | ||
Splits []HopSplit | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
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), | ||
AmountOut: 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...), | ||
} | ||
} | ||
|
||
func (p *Path) Cmp(y *Path, gasIncluded bool) int { | ||
priceAvailable := p.AmountOutPrice != 0 || y.AmountOutPrice != 0 | ||
|
||
if gasIncluded && priceAvailable { | ||
xValue := p.AmountOutPrice - p.GasFeePrice - p.L1GasFeePrice | ||
yValue := y.AmountOutPrice - y.GasFeePrice - y.L1GasFeePrice | ||
|
||
if utils.AlmostEqual(xValue, yValue) { | ||
return p.AmountOut.Cmp(y.AmountOut) | ||
} | ||
|
||
if xValue < yValue { | ||
return -1 | ||
} else { | ||
return 1 | ||
} | ||
} | ||
|
||
return p.AmountOut.Cmp(y.AmountOut) | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.