status-go/services/wallet/router/router_graph.go

138 lines
3.7 KiB
Go
Raw Normal View History

chore!: router code organization improvements It's a breaking change due to errors' changes, the list of mapped old error codes: - `"WR-001"` is now `"WRR-001"` - `"WR-002"` is now `"WRR-002"` - `"WR-003"` is now `"WRR-003"` - `"WR-004"` is now `"WRR-004"` - `"WR-005"` is now `"WRR-005"` - `"WR-006"` is now `"WRR-006"` - `"WR-007"` is now `"WRR-007"` - `"WR-008"` is now `"WRR-008"` - `"WR-009"` is now `"WRR-009"` - `"WR-010"` is now `"WRR-010"` - `"WR-011"` is now `"WRR-011"` - `"WR-012"` is now `"WRR-012"` - `"WR-013"` is now `"WRR-013"` - `"WR-014"` is now `"WRR-014"` - `"WR-015"` is now `"WRR-015"` - `"WR-019"` is now `"WRR-016"` - `"WR-020"` is now `"WRR-017"` - `"WR-021"` is now `"WRR-018"` - `"WR-025"` is now `"WRR-019"` - `"WR-016"` is now `"WR-001"` - `"WR-017"` is now `"WR-002"` - `"WR-018"` is now `"WR-003"` - `"WR-022"` is now `"WR-004"` - `"WR-023"` is now `"WR-005"` - `"WR-024"` is now `"WR-006"` - `"WR-026"` is now `"WR-007"` - `"WR-027"` is now `"WR-008"` Other changes: - `RouteInputParams` type moved to `requests` package and code updated accordingly - `SuggestedFees` type moved to a new `fees` package and code updated accordingly - `SendType` type moved to a new `sendtype` package and code updated accordingly - the following functions moved to `common` package - `ArrayContainsElement` - `ArraysWithSameElements` - `SameSingleChainTransfer` - `CopyMapGeneric` - `GweiToEth` - `WeiToGwei` - the following consts moved to `common` package - `HexAddressLength` - `SupportedNetworks` - `SupportedTestNetworks`
2024-08-28 11:17:59 +00:00
package router
import (
"math"
"math/big"
"github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/router/pathprocessor"
)
type Graph []*Node
type Node struct {
Path *Path
Children Graph
}
func newNode(path *Path) *Node {
return &Node{Path: path, Children: make(Graph, 0)}
}
func buildGraph(AmountIn *big.Int, routes []*Path, level int, sourceChainIDs []uint64) Graph {
graph := make(Graph, 0)
for _, route := range routes {
found := false
for _, chainID := range sourceChainIDs {
if chainID == route.FromChain.ChainID {
found = true
break
}
}
if found {
continue
}
node := newNode(route)
newRoutes := make([]*Path, 0)
for _, r := range routes {
if route.Equal(r) {
continue
}
newRoutes = append(newRoutes, r)
}
newAmountIn := new(big.Int).Sub(AmountIn, route.AmountIn.ToInt())
if newAmountIn.Sign() > 0 {
newSourceChainIDs := make([]uint64, len(sourceChainIDs))
copy(newSourceChainIDs, sourceChainIDs)
newSourceChainIDs = append(newSourceChainIDs, route.FromChain.ChainID)
node.Children = buildGraph(newAmountIn, newRoutes, level+1, newSourceChainIDs)
if len(node.Children) == 0 {
continue
}
}
graph = append(graph, node)
}
return graph
}
func (n Node) buildAllRoutes() [][]*Path {
res := make([][]*Path, 0)
if len(n.Children) == 0 && n.Path != nil {
res = append(res, []*Path{n.Path})
}
for _, node := range n.Children {
for _, route := range node.buildAllRoutes() {
extendedRoute := route
if n.Path != nil {
extendedRoute = append([]*Path{n.Path}, route...)
}
res = append(res, extendedRoute)
}
}
return res
}
func findBest(routes [][]*Path, tokenPrice float64, nativeTokenPrice float64) []*Path {
var best []*Path
bestCost := big.NewFloat(math.Inf(1))
for _, route := range routes {
currentCost := big.NewFloat(0)
for _, path := range route {
tokenDenominator := big.NewFloat(math.Pow(10, float64(path.FromToken.Decimals)))
// calculate the cost of the path
nativeTokenPrice := new(big.Float).SetFloat64(nativeTokenPrice)
// tx fee
txFeeInEth := common.GweiToEth(common.WeiToGwei(path.TxFee.ToInt()))
pathCost := new(big.Float).Mul(txFeeInEth, nativeTokenPrice)
if path.TxL1Fee.ToInt().Cmp(pathprocessor.ZeroBigIntValue) > 0 {
txL1FeeInEth := common.GweiToEth(common.WeiToGwei(path.TxL1Fee.ToInt()))
pathCost.Add(pathCost, new(big.Float).Mul(txL1FeeInEth, nativeTokenPrice))
}
if path.TxBonderFees != nil && path.TxBonderFees.ToInt().Cmp(pathprocessor.ZeroBigIntValue) > 0 {
pathCost.Add(pathCost, new(big.Float).Mul(
new(big.Float).Quo(new(big.Float).SetInt(path.TxBonderFees.ToInt()), tokenDenominator),
new(big.Float).SetFloat64(tokenPrice)))
}
if path.TxTokenFees != nil && path.TxTokenFees.ToInt().Cmp(pathprocessor.ZeroBigIntValue) > 0 && path.FromToken != nil {
pathCost.Add(pathCost, new(big.Float).Mul(
new(big.Float).Quo(new(big.Float).SetInt(path.TxTokenFees.ToInt()), tokenDenominator),
new(big.Float).SetFloat64(tokenPrice)))
}
if path.ApprovalRequired {
// tx approval fee
approvalFeeInEth := common.GweiToEth(common.WeiToGwei(path.ApprovalFee.ToInt()))
pathCost.Add(pathCost, new(big.Float).Mul(approvalFeeInEth, nativeTokenPrice))
if path.ApprovalL1Fee.ToInt().Cmp(pathprocessor.ZeroBigIntValue) > 0 {
approvalL1FeeInEth := common.GweiToEth(common.WeiToGwei(path.ApprovalL1Fee.ToInt()))
pathCost.Add(pathCost, new(big.Float).Mul(approvalL1FeeInEth, nativeTokenPrice))
}
}
currentCost = new(big.Float).Add(currentCost, pathCost)
}
if currentCost.Cmp(bestCost) == -1 {
best = route
bestCost = currentCost
}
}
return best
}