chore_: router response moved to wallet responses location
Following the approach we did for keeping requests at the same location, these changes introduce new location for responses. `SuggestedRoutesResponse` is moved there and renamed to `RouterSuggestedRoutes` and code is updated accordingly. New type `Route` defined (since a single route is composed of zero or more paths). Types `Route`, `Path`, `Graph` and `Node` belong to a new `routs` package now.
This commit is contained in:
parent
00559692bc
commit
1bb9cbc573
|
@ -0,0 +1,15 @@
|
|||
package responses
|
||||
|
||||
import (
|
||||
"github.com/status-im/status-go/errors"
|
||||
"github.com/status-im/status-go/services/wallet/router/routes"
|
||||
)
|
||||
|
||||
type RouterSuggestedRoutes struct {
|
||||
Uuid string `json:"Uuid"`
|
||||
Best routes.Route `json:"Best,omitempty"`
|
||||
Candidates routes.Route `json:"Candidates,omitempty"`
|
||||
TokenPrice *float64 `json:"TokenPrice,omitempty"`
|
||||
NativeChainTokenPrice *float64 `json:"NativeChainTokenPrice,omitempty"`
|
||||
ErrorResponse *errors.ErrorResponse `json:"ErrorResponse,omitempty"`
|
||||
}
|
|
@ -2,9 +2,10 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/status-im/status-go/services/wallet/common"
|
||||
"github.com/status-im/status-go/services/wallet/router/routes"
|
||||
)
|
||||
|
||||
func removeBestRouteFromAllRouters(allRoutes [][]*Path, best []*Path) [][]*Path {
|
||||
func removeBestRouteFromAllRouters(allRoutes []routes.Route, best routes.Route) []routes.Route {
|
||||
for i := len(allRoutes) - 1; i >= 0; i-- {
|
||||
route := allRoutes[i]
|
||||
routeFound := true
|
||||
|
@ -45,7 +46,7 @@ func getChainPriority(chainID uint64) int {
|
|||
}
|
||||
}
|
||||
|
||||
func getRoutePriority(route []*Path) int {
|
||||
func getRoutePriority(route routes.Route) int {
|
||||
priority := 0
|
||||
for _, path := range route {
|
||||
priority += getChainPriority(path.FromChain.ChainID)
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/status-im/status-go/services/wallet/common"
|
||||
"github.com/status-im/status-go/services/wallet/router/pathprocessor"
|
||||
"github.com/status-im/status-go/services/wallet/router/routes"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
@ -20,7 +21,7 @@ func init() {
|
|||
}
|
||||
}
|
||||
|
||||
func filterRoutes(routes [][]*Path, amountIn *big.Int, fromLockedAmount map[uint64]*hexutil.Big) [][]*Path {
|
||||
func filterRoutes(routes []routes.Route, amountIn *big.Int, fromLockedAmount map[uint64]*hexutil.Big) []routes.Route {
|
||||
for i := len(routes) - 1; i >= 0; i-- {
|
||||
routeAmount := big.NewInt(0)
|
||||
for _, p := range routes[i] {
|
||||
|
@ -43,15 +44,15 @@ func filterRoutes(routes [][]*Path, amountIn *big.Int, fromLockedAmount map[uint
|
|||
}
|
||||
|
||||
// filterNetworkCompliance performs the first level of filtering based on network inclusion/exclusion criteria.
|
||||
func filterNetworkCompliance(routes [][]*Path, fromLockedAmount map[uint64]*hexutil.Big) [][]*Path {
|
||||
filteredRoutes := make([][]*Path, 0)
|
||||
if routes == nil || fromLockedAmount == nil {
|
||||
func filterNetworkCompliance(allRoutes []routes.Route, fromLockedAmount map[uint64]*hexutil.Big) []routes.Route {
|
||||
filteredRoutes := make([]routes.Route, 0)
|
||||
if allRoutes == nil || fromLockedAmount == nil {
|
||||
return filteredRoutes
|
||||
}
|
||||
|
||||
fromIncluded, fromExcluded := setupRouteValidationMaps(fromLockedAmount)
|
||||
|
||||
for _, route := range routes {
|
||||
for _, route := range allRoutes {
|
||||
if route == nil {
|
||||
continue
|
||||
}
|
||||
|
@ -65,7 +66,7 @@ func filterNetworkCompliance(routes [][]*Path, fromLockedAmount map[uint64]*hexu
|
|||
}
|
||||
|
||||
// isValidForNetworkCompliance checks if a route complies with network inclusion/exclusion criteria.
|
||||
func isValidForNetworkCompliance(route []*Path, fromIncluded, fromExcluded map[uint64]bool) bool {
|
||||
func isValidForNetworkCompliance(route routes.Route, fromIncluded, fromExcluded map[uint64]bool) bool {
|
||||
logger.Debug("Initial inclusion/exclusion maps",
|
||||
zap.Any("fromIncluded", fromIncluded),
|
||||
zap.Any("fromExcluded", fromExcluded),
|
||||
|
@ -117,10 +118,10 @@ func setupRouteValidationMaps(fromLockedAmount map[uint64]*hexutil.Big) (map[uin
|
|||
}
|
||||
|
||||
// filterCapacityValidation performs the second level of filtering based on amount and capacity validation.
|
||||
func filterCapacityValidation(routes [][]*Path, amountIn *big.Int, fromLockedAmount map[uint64]*hexutil.Big) [][]*Path {
|
||||
filteredRoutes := make([][]*Path, 0)
|
||||
func filterCapacityValidation(allRoutes []routes.Route, amountIn *big.Int, fromLockedAmount map[uint64]*hexutil.Big) []routes.Route {
|
||||
filteredRoutes := make([]routes.Route, 0)
|
||||
|
||||
for _, route := range routes {
|
||||
for _, route := range allRoutes {
|
||||
if hasSufficientCapacity(route, amountIn, fromLockedAmount) {
|
||||
filteredRoutes = append(filteredRoutes, route)
|
||||
}
|
||||
|
@ -129,7 +130,7 @@ func filterCapacityValidation(routes [][]*Path, amountIn *big.Int, fromLockedAmo
|
|||
}
|
||||
|
||||
// hasSufficientCapacity checks if a route has sufficient capacity to handle the required amount.
|
||||
func hasSufficientCapacity(route []*Path, amountIn *big.Int, fromLockedAmount map[uint64]*hexutil.Big) bool {
|
||||
func hasSufficientCapacity(route routes.Route, amountIn *big.Int, fromLockedAmount map[uint64]*hexutil.Big) bool {
|
||||
for _, path := range route {
|
||||
if amount, ok := fromLockedAmount[path.FromChain.ChainID]; ok {
|
||||
if path.AmountIn.ToInt().Cmp(amount.ToInt()) != 0 {
|
||||
|
@ -153,7 +154,7 @@ func hasSufficientCapacity(route []*Path, amountIn *big.Int, fromLockedAmount ma
|
|||
}
|
||||
|
||||
// calculateRestAmountIn calculates the remaining amount in for the route excluding the specified path
|
||||
func calculateRestAmountIn(route []*Path, excludePath *Path) *big.Int {
|
||||
func calculateRestAmountIn(route routes.Route, excludePath *routes.Path) *big.Int {
|
||||
restAmountIn := big.NewInt(0)
|
||||
for _, path := range route {
|
||||
if path != excludePath {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/status-im/status-go/params"
|
||||
"github.com/status-im/status-go/services/wallet/router/pathprocessor"
|
||||
"github.com/status-im/status-go/services/wallet/router/routes"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -26,24 +27,24 @@ var (
|
|||
amount4 = hexutil.Big(*big.NewInt(400))
|
||||
amount5 = hexutil.Big(*big.NewInt(500))
|
||||
|
||||
path0 = &Path{FromChain: network4, AmountIn: &amount0}
|
||||
path0 = &routes.Path{FromChain: network4, AmountIn: &amount0}
|
||||
|
||||
pathC1A1 = &Path{FromChain: network1, AmountIn: &amount1}
|
||||
pathC1A1 = &routes.Path{FromChain: network1, AmountIn: &amount1}
|
||||
|
||||
pathC2A1 = &Path{FromChain: network2, AmountIn: &amount1}
|
||||
pathC2A2 = &Path{FromChain: network2, AmountIn: &amount2}
|
||||
pathC2A1 = &routes.Path{FromChain: network2, AmountIn: &amount1}
|
||||
pathC2A2 = &routes.Path{FromChain: network2, AmountIn: &amount2}
|
||||
|
||||
pathC3A1 = &Path{FromChain: network3, AmountIn: &amount1}
|
||||
pathC3A2 = &Path{FromChain: network3, AmountIn: &amount2}
|
||||
pathC3A3 = &Path{FromChain: network3, AmountIn: &amount3}
|
||||
pathC3A1 = &routes.Path{FromChain: network3, AmountIn: &amount1}
|
||||
pathC3A2 = &routes.Path{FromChain: network3, AmountIn: &amount2}
|
||||
pathC3A3 = &routes.Path{FromChain: network3, AmountIn: &amount3}
|
||||
|
||||
pathC4A1 = &Path{FromChain: network4, AmountIn: &amount1}
|
||||
pathC4A4 = &Path{FromChain: network4, AmountIn: &amount4}
|
||||
pathC4A1 = &routes.Path{FromChain: network4, AmountIn: &amount1}
|
||||
pathC4A4 = &routes.Path{FromChain: network4, AmountIn: &amount4}
|
||||
|
||||
pathC5A5 = &Path{FromChain: network5, AmountIn: &amount5}
|
||||
pathC5A5 = &routes.Path{FromChain: network5, AmountIn: &amount5}
|
||||
)
|
||||
|
||||
func routesEqual(t *testing.T, expected, actual [][]*Path) bool {
|
||||
func routesEqual(t *testing.T, expected, actual []routes.Route) bool {
|
||||
if len(expected) != len(actual) {
|
||||
return false
|
||||
}
|
||||
|
@ -55,7 +56,7 @@ func routesEqual(t *testing.T, expected, actual [][]*Path) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func pathsEqual(t *testing.T, expected, actual []*Path) bool {
|
||||
func pathsEqual(t *testing.T, expected, actual routes.Route) bool {
|
||||
if len(expected) != len(actual) {
|
||||
return false
|
||||
}
|
||||
|
@ -67,7 +68,7 @@ func pathsEqual(t *testing.T, expected, actual []*Path) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func pathEqual(t *testing.T, expected, actual *Path) bool {
|
||||
func pathEqual(t *testing.T, expected, actual *routes.Path) bool {
|
||||
if expected.FromChain.ChainID != actual.FromChain.ChainID {
|
||||
t.Logf("expected chain ID '%d' , actual chain ID '%d'", expected.FromChain.ChainID, actual.FromChain.ChainID)
|
||||
return false
|
||||
|
@ -171,43 +172,43 @@ func TestSetupRouteValidationMaps(t *testing.T) {
|
|||
func TestCalculateRestAmountIn(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
route []*Path
|
||||
excludePath *Path
|
||||
route routes.Route
|
||||
excludePath *routes.Path
|
||||
expected *big.Int
|
||||
}{
|
||||
{
|
||||
name: "Exclude pathC1A1",
|
||||
route: []*Path{pathC1A1, pathC2A2, pathC3A3},
|
||||
route: routes.Route{pathC1A1, pathC2A2, pathC3A3},
|
||||
excludePath: pathC1A1,
|
||||
expected: big.NewInt(500), // 200 + 300
|
||||
},
|
||||
{
|
||||
name: "Exclude pathC2A2",
|
||||
route: []*Path{pathC1A1, pathC2A2, pathC3A3},
|
||||
route: routes.Route{pathC1A1, pathC2A2, pathC3A3},
|
||||
excludePath: pathC2A2,
|
||||
expected: big.NewInt(400), // 100 + 300
|
||||
},
|
||||
{
|
||||
name: "Exclude pathC3A3",
|
||||
route: []*Path{pathC1A1, pathC2A2, pathC3A3},
|
||||
route: routes.Route{pathC1A1, pathC2A2, pathC3A3},
|
||||
excludePath: pathC3A3,
|
||||
expected: big.NewInt(300), // 100 + 200
|
||||
},
|
||||
{
|
||||
name: "Single path, exclude that path",
|
||||
route: []*Path{pathC1A1},
|
||||
route: routes.Route{pathC1A1},
|
||||
excludePath: pathC1A1,
|
||||
expected: big.NewInt(0), // No other paths
|
||||
},
|
||||
{
|
||||
name: "Empty route",
|
||||
route: []*Path{},
|
||||
route: routes.Route{},
|
||||
excludePath: pathC1A1,
|
||||
expected: big.NewInt(0), // No paths
|
||||
},
|
||||
{
|
||||
name: "Empty route, with nil exclude",
|
||||
route: []*Path{},
|
||||
route: routes.Route{},
|
||||
excludePath: nil,
|
||||
expected: big.NewInt(0), // No paths
|
||||
},
|
||||
|
@ -224,56 +225,56 @@ func TestCalculateRestAmountIn(t *testing.T) {
|
|||
func TestIsValidForNetworkCompliance(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
route []*Path
|
||||
route routes.Route
|
||||
fromIncluded map[uint64]bool
|
||||
fromExcluded map[uint64]bool
|
||||
expectedResult bool
|
||||
}{
|
||||
{
|
||||
name: "Route with all included chain IDs",
|
||||
route: []*Path{pathC1A1, pathC2A2},
|
||||
route: routes.Route{pathC1A1, pathC2A2},
|
||||
fromIncluded: map[uint64]bool{1: true, 2: true},
|
||||
fromExcluded: map[uint64]bool{},
|
||||
expectedResult: true,
|
||||
},
|
||||
{
|
||||
name: "Route with fromExcluded only",
|
||||
route: []*Path{pathC1A1, pathC2A2},
|
||||
route: routes.Route{pathC1A1, pathC2A2},
|
||||
fromIncluded: map[uint64]bool{},
|
||||
fromExcluded: map[uint64]bool{3: false, 4: false},
|
||||
expectedResult: true,
|
||||
},
|
||||
{
|
||||
name: "Route without excluded chain IDs",
|
||||
route: []*Path{pathC1A1, pathC2A2},
|
||||
route: routes.Route{pathC1A1, pathC2A2},
|
||||
fromIncluded: map[uint64]bool{1: false, 2: false},
|
||||
fromExcluded: map[uint64]bool{3: false, 4: false},
|
||||
expectedResult: true,
|
||||
},
|
||||
{
|
||||
name: "Route with an excluded chain ID",
|
||||
route: []*Path{pathC1A1, pathC3A3},
|
||||
route: routes.Route{pathC1A1, pathC3A3},
|
||||
fromIncluded: map[uint64]bool{1: false, 2: false},
|
||||
fromExcluded: map[uint64]bool{3: false, 4: false},
|
||||
expectedResult: false,
|
||||
},
|
||||
{
|
||||
name: "Route missing one included chain ID",
|
||||
route: []*Path{pathC1A1},
|
||||
route: routes.Route{pathC1A1},
|
||||
fromIncluded: map[uint64]bool{1: false, 2: false},
|
||||
fromExcluded: map[uint64]bool{},
|
||||
expectedResult: false,
|
||||
},
|
||||
{
|
||||
name: "Route with no fromIncluded or fromExcluded",
|
||||
route: []*Path{pathC1A1, pathC2A2},
|
||||
route: routes.Route{pathC1A1, pathC2A2},
|
||||
fromIncluded: map[uint64]bool{},
|
||||
fromExcluded: map[uint64]bool{},
|
||||
expectedResult: true,
|
||||
},
|
||||
{
|
||||
name: "Empty route",
|
||||
route: []*Path{},
|
||||
route: routes.Route{},
|
||||
fromIncluded: map[uint64]bool{1: false, 2: false},
|
||||
fromExcluded: map[uint64]bool{3: false, 4: false},
|
||||
expectedResult: false,
|
||||
|
@ -291,14 +292,14 @@ func TestIsValidForNetworkCompliance(t *testing.T) {
|
|||
func TestHasSufficientCapacity(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
route []*Path
|
||||
route routes.Route
|
||||
amountIn *big.Int
|
||||
fromLockedAmount map[uint64]*hexutil.Big
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "All paths meet required amount",
|
||||
route: []*Path{pathC1A1, pathC2A2, pathC3A3},
|
||||
route: routes.Route{pathC1A1, pathC2A2, pathC3A3},
|
||||
amountIn: big.NewInt(600),
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{1: &amount1, 2: &amount2, 3: &amount3},
|
||||
expected: true,
|
||||
|
@ -308,7 +309,7 @@ func TestHasSufficientCapacity(t *testing.T) {
|
|||
/*
|
||||
{
|
||||
name: "A path does not meet required amount",
|
||||
route: []*Path{pathC1A1, pathC2A2, pathC3A3},
|
||||
route: routes.Route{pathC1A1, pathC2A2, pathC3A3},
|
||||
amountIn: big.NewInt(600),
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{1: &amount1, 2: &amount2, 4: &amount4},
|
||||
expected: false,
|
||||
|
@ -316,42 +317,42 @@ func TestHasSufficientCapacity(t *testing.T) {
|
|||
*/
|
||||
{
|
||||
name: "No fromLockedAmount",
|
||||
route: []*Path{pathC1A1, pathC2A2, pathC3A3},
|
||||
route: routes.Route{pathC1A1, pathC2A2, pathC3A3},
|
||||
amountIn: big.NewInt(600),
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "Single path meets required amount",
|
||||
route: []*Path{pathC1A1},
|
||||
route: routes.Route{pathC1A1},
|
||||
amountIn: big.NewInt(100),
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{1: &amount1},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "Single path does not meet required amount",
|
||||
route: []*Path{pathC1A1},
|
||||
route: routes.Route{pathC1A1},
|
||||
amountIn: big.NewInt(200),
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{1: &amount1},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Path meets required amount with excess",
|
||||
route: []*Path{pathC1A1, pathC2A2},
|
||||
route: routes.Route{pathC1A1, pathC2A2},
|
||||
amountIn: big.NewInt(250),
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{1: &amount1, 2: &amount2},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "Path does not meet required amount due to insufficient rest",
|
||||
route: []*Path{pathC1A1, pathC2A2, pathC4A4},
|
||||
route: routes.Route{pathC1A1, pathC2A2, pathC4A4},
|
||||
amountIn: big.NewInt(800),
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{1: &amount1, 4: &amount4},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Empty route",
|
||||
route: []*Path{},
|
||||
route: routes.Route{},
|
||||
amountIn: big.NewInt(500),
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{1: &amount1, 2: &amount2},
|
||||
expected: true,
|
||||
|
@ -369,13 +370,13 @@ func TestHasSufficientCapacity(t *testing.T) {
|
|||
func TestFilterNetworkCompliance(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
routes [][]*Path
|
||||
routes []routes.Route
|
||||
fromLockedAmount map[uint64]*hexutil.Big
|
||||
expected [][]*Path
|
||||
expected []routes.Route
|
||||
}{
|
||||
{
|
||||
name: "Mixed routes with valid and invalid paths",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1},
|
||||
{FromChain: network3},
|
||||
|
@ -394,7 +395,7 @@ func TestFilterNetworkCompliance(t *testing.T) {
|
|||
1: (*hexutil.Big)(big.NewInt(100)),
|
||||
2: (*hexutil.Big)(big.NewInt(0)),
|
||||
},
|
||||
expected: [][]*Path{
|
||||
expected: []routes.Route{
|
||||
{
|
||||
{FromChain: network1},
|
||||
{FromChain: network3},
|
||||
|
@ -403,7 +404,7 @@ func TestFilterNetworkCompliance(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "All valid routes",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1},
|
||||
{FromChain: network3},
|
||||
|
@ -416,7 +417,7 @@ func TestFilterNetworkCompliance(t *testing.T) {
|
|||
fromLockedAmount: map[uint64]*hexutil.Big{
|
||||
1: (*hexutil.Big)(big.NewInt(100)),
|
||||
},
|
||||
expected: [][]*Path{
|
||||
expected: []routes.Route{
|
||||
{
|
||||
{FromChain: network1},
|
||||
{FromChain: network3},
|
||||
|
@ -429,7 +430,7 @@ func TestFilterNetworkCompliance(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "All invalid routes",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{
|
||||
{FromChain: network2},
|
||||
{FromChain: network3},
|
||||
|
@ -443,19 +444,19 @@ func TestFilterNetworkCompliance(t *testing.T) {
|
|||
1: (*hexutil.Big)(big.NewInt(100)),
|
||||
2: (*hexutil.Big)(big.NewInt(0)),
|
||||
},
|
||||
expected: [][]*Path{},
|
||||
expected: []routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "Empty routes",
|
||||
routes: [][]*Path{},
|
||||
routes: []routes.Route{},
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{
|
||||
1: (*hexutil.Big)(big.NewInt(100)),
|
||||
},
|
||||
expected: [][]*Path{},
|
||||
expected: []routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "No locked amounts",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1},
|
||||
{FromChain: network2},
|
||||
|
@ -466,7 +467,7 @@ func TestFilterNetworkCompliance(t *testing.T) {
|
|||
},
|
||||
},
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{},
|
||||
expected: [][]*Path{
|
||||
expected: []routes.Route{
|
||||
{
|
||||
{FromChain: network1},
|
||||
{FromChain: network2},
|
||||
|
@ -479,7 +480,7 @@ func TestFilterNetworkCompliance(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Single route with mixed valid and invalid paths",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1},
|
||||
{FromChain: network2},
|
||||
|
@ -490,11 +491,11 @@ func TestFilterNetworkCompliance(t *testing.T) {
|
|||
1: (*hexutil.Big)(big.NewInt(100)),
|
||||
2: (*hexutil.Big)(big.NewInt(0)),
|
||||
},
|
||||
expected: [][]*Path{},
|
||||
expected: []routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "Routes with duplicate chain IDs",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1},
|
||||
{FromChain: network1},
|
||||
|
@ -504,7 +505,7 @@ func TestFilterNetworkCompliance(t *testing.T) {
|
|||
fromLockedAmount: map[uint64]*hexutil.Big{
|
||||
1: (*hexutil.Big)(big.NewInt(100)),
|
||||
},
|
||||
expected: [][]*Path{
|
||||
expected: []routes.Route{
|
||||
{
|
||||
{FromChain: network1},
|
||||
{FromChain: network1},
|
||||
|
@ -514,7 +515,7 @@ func TestFilterNetworkCompliance(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Minimum and maximum chain IDs",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{
|
||||
{FromChain: ¶ms.Network{ChainID: 0}},
|
||||
{FromChain: ¶ms.Network{ChainID: ^uint64(0)}},
|
||||
|
@ -524,7 +525,7 @@ func TestFilterNetworkCompliance(t *testing.T) {
|
|||
0: (*hexutil.Big)(big.NewInt(100)),
|
||||
^uint64(0): (*hexutil.Big)(big.NewInt(100)),
|
||||
},
|
||||
expected: [][]*Path{
|
||||
expected: []routes.Route{
|
||||
{
|
||||
{FromChain: ¶ms.Network{ChainID: 0}},
|
||||
{FromChain: ¶ms.Network{ChainID: ^uint64(0)}},
|
||||
|
@ -533,34 +534,34 @@ func TestFilterNetworkCompliance(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Large number of routes",
|
||||
routes: func() [][]*Path {
|
||||
var routes [][]*Path
|
||||
routes: func() []routes.Route {
|
||||
var routes1 []routes.Route
|
||||
for i := 0; i < 1000; i++ {
|
||||
routes = append(routes, []*Path{
|
||||
routes1 = append(routes1, routes.Route{
|
||||
{FromChain: ¶ms.Network{ChainID: uint64(i + 1)}},
|
||||
{FromChain: ¶ms.Network{ChainID: uint64(i + 1001)}},
|
||||
})
|
||||
}
|
||||
return routes
|
||||
return routes1
|
||||
}(),
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{
|
||||
1: (*hexutil.Big)(big.NewInt(100)),
|
||||
1001: (*hexutil.Big)(big.NewInt(100)),
|
||||
},
|
||||
expected: func() [][]*Path {
|
||||
var routes [][]*Path
|
||||
expected: func() []routes.Route {
|
||||
var routes1 []routes.Route
|
||||
for i := 0; i < 1; i++ {
|
||||
routes = append(routes, []*Path{
|
||||
routes1 = append(routes1, routes.Route{
|
||||
{FromChain: ¶ms.Network{ChainID: uint64(i + 1)}},
|
||||
{FromChain: ¶ms.Network{ChainID: uint64(i + 1001)}},
|
||||
})
|
||||
}
|
||||
return routes
|
||||
return routes1
|
||||
}(),
|
||||
},
|
||||
{
|
||||
name: "Routes with missing data",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{
|
||||
{FromChain: nil},
|
||||
{FromChain: network2},
|
||||
|
@ -574,11 +575,11 @@ func TestFilterNetworkCompliance(t *testing.T) {
|
|||
1: (*hexutil.Big)(big.NewInt(100)),
|
||||
2: (*hexutil.Big)(big.NewInt(0)),
|
||||
},
|
||||
expected: [][]*Path{},
|
||||
expected: []routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "Consistency check",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1},
|
||||
{FromChain: network2},
|
||||
|
@ -591,7 +592,7 @@ func TestFilterNetworkCompliance(t *testing.T) {
|
|||
fromLockedAmount: map[uint64]*hexutil.Big{
|
||||
1: (*hexutil.Big)(big.NewInt(100)),
|
||||
},
|
||||
expected: [][]*Path{
|
||||
expected: []routes.Route{
|
||||
{
|
||||
{FromChain: network1},
|
||||
{FromChain: network2},
|
||||
|
@ -604,77 +605,77 @@ func TestFilterNetworkCompliance(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Routes without excluded chain IDs, missing included path",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{pathC1A1, pathC2A2},
|
||||
{pathC2A2, pathC3A3},
|
||||
},
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{1: &amount1, 2: &amount2},
|
||||
expected: [][]*Path{
|
||||
expected: []routes.Route{
|
||||
{pathC1A1, pathC2A2},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Routes with an excluded chain ID",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{pathC1A1, pathC2A2},
|
||||
{pathC2A2, pathC3A3, path0},
|
||||
},
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{1: &amount1, 2: &amount2, 4: &amount0},
|
||||
expected: [][]*Path{
|
||||
expected: []routes.Route{
|
||||
{pathC1A1, pathC2A2},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Routes with all included chain IDs",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{pathC1A1, pathC2A2, pathC3A3},
|
||||
},
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{1: &amount1, 2: &amount2, 3: &amount3},
|
||||
expected: [][]*Path{
|
||||
expected: []routes.Route{
|
||||
{pathC1A1, pathC2A2, pathC3A3},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Routes missing one included chain ID",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{pathC1A1, pathC2A2},
|
||||
{pathC1A1},
|
||||
},
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{1: &amount1, 2: &amount2, 3: &amount3},
|
||||
expected: [][]*Path{},
|
||||
expected: []routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "Routes with no fromLockedAmount",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{pathC1A1, pathC2A2},
|
||||
{pathC2A2, pathC3A3},
|
||||
},
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{},
|
||||
expected: [][]*Path{
|
||||
expected: []routes.Route{
|
||||
{pathC1A1, pathC2A2},
|
||||
{pathC2A2, pathC3A3},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Routes with fromExcluded only",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{pathC1A1, pathC2A2},
|
||||
{pathC2A2, pathC3A3},
|
||||
},
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{4: &amount0},
|
||||
expected: [][]*Path{
|
||||
expected: []routes.Route{
|
||||
{pathC1A1, pathC2A2},
|
||||
{pathC2A2, pathC3A3},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Routes with all excluded chain IDs",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{path0, pathC1A1},
|
||||
{path0, pathC2A2},
|
||||
},
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{1: &amount1, 2: &amount2, 3: &amount3, 4: &amount0},
|
||||
expected: [][]*Path{},
|
||||
expected: []routes.Route{},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -691,14 +692,14 @@ func TestFilterNetworkCompliance(t *testing.T) {
|
|||
func TestFilterCapacityValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
routes [][]*Path
|
||||
routes []routes.Route
|
||||
amountIn *big.Int
|
||||
fromLockedAmount map[uint64]*hexutil.Big
|
||||
expectedRoutes [][]*Path
|
||||
expectedRoutes []routes.Route
|
||||
}{
|
||||
{
|
||||
name: "Sufficient capacity with multiple paths",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1, AmountIn: (*hexutil.Big)(big.NewInt(50))},
|
||||
{FromChain: network2, AmountIn: (*hexutil.Big)(big.NewInt(100))},
|
||||
|
@ -717,7 +718,7 @@ func TestFilterCapacityValidation(t *testing.T) {
|
|||
fromLockedAmount: map[uint64]*hexutil.Big{
|
||||
1: (*hexutil.Big)(big.NewInt(50)),
|
||||
},
|
||||
expectedRoutes: [][]*Path{
|
||||
expectedRoutes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1, AmountIn: (*hexutil.Big)(big.NewInt(50))},
|
||||
{FromChain: network2, AmountIn: (*hexutil.Big)(big.NewInt(100))},
|
||||
|
@ -731,7 +732,7 @@ func TestFilterCapacityValidation(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Insufficient capacity",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1, AmountIn: (*hexutil.Big)(big.NewInt(100))},
|
||||
{FromChain: network2, AmountIn: (*hexutil.Big)(big.NewInt(50))},
|
||||
|
@ -742,11 +743,11 @@ func TestFilterCapacityValidation(t *testing.T) {
|
|||
1: (*hexutil.Big)(big.NewInt(50)),
|
||||
2: (*hexutil.Big)(big.NewInt(50)),
|
||||
},
|
||||
expectedRoutes: [][]*Path{},
|
||||
expectedRoutes: []routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "Exact capacity match",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1, AmountIn: (*hexutil.Big)(big.NewInt(100))},
|
||||
{FromChain: network2, AmountIn: (*hexutil.Big)(big.NewInt(50))},
|
||||
|
@ -757,7 +758,7 @@ func TestFilterCapacityValidation(t *testing.T) {
|
|||
1: (*hexutil.Big)(big.NewInt(100)),
|
||||
2: (*hexutil.Big)(big.NewInt(50)),
|
||||
},
|
||||
expectedRoutes: [][]*Path{
|
||||
expectedRoutes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1, AmountIn: (*hexutil.Big)(big.NewInt(100))},
|
||||
{FromChain: network2, AmountIn: (*hexutil.Big)(big.NewInt(50))},
|
||||
|
@ -766,7 +767,7 @@ func TestFilterCapacityValidation(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "No locked amounts",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1, AmountIn: (*hexutil.Big)(big.NewInt(100))},
|
||||
{FromChain: network2, AmountIn: (*hexutil.Big)(big.NewInt(50))},
|
||||
|
@ -774,7 +775,7 @@ func TestFilterCapacityValidation(t *testing.T) {
|
|||
},
|
||||
amountIn: big.NewInt(150),
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{},
|
||||
expectedRoutes: [][]*Path{
|
||||
expectedRoutes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1, AmountIn: (*hexutil.Big)(big.NewInt(100))},
|
||||
{FromChain: network2, AmountIn: (*hexutil.Big)(big.NewInt(50))},
|
||||
|
@ -783,7 +784,7 @@ func TestFilterCapacityValidation(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Single route with sufficient capacity",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1, AmountIn: (*hexutil.Big)(big.NewInt(50))},
|
||||
{FromChain: network2, AmountIn: (*hexutil.Big)(big.NewInt(100))},
|
||||
|
@ -793,7 +794,7 @@ func TestFilterCapacityValidation(t *testing.T) {
|
|||
fromLockedAmount: map[uint64]*hexutil.Big{
|
||||
1: (*hexutil.Big)(big.NewInt(50)),
|
||||
},
|
||||
expectedRoutes: [][]*Path{
|
||||
expectedRoutes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1, AmountIn: (*hexutil.Big)(big.NewInt(50))},
|
||||
{FromChain: network2, AmountIn: (*hexutil.Big)(big.NewInt(100))},
|
||||
|
@ -802,7 +803,7 @@ func TestFilterCapacityValidation(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Single route with inappropriately locked amount",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1, AmountIn: (*hexutil.Big)(big.NewInt(100))},
|
||||
},
|
||||
|
@ -811,11 +812,11 @@ func TestFilterCapacityValidation(t *testing.T) {
|
|||
fromLockedAmount: map[uint64]*hexutil.Big{
|
||||
1: (*hexutil.Big)(big.NewInt(50)),
|
||||
},
|
||||
expectedRoutes: [][]*Path{},
|
||||
expectedRoutes: []routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "Single route with insufficient capacity",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1, AmountIn: (*hexutil.Big)(big.NewInt(50))},
|
||||
},
|
||||
|
@ -824,20 +825,20 @@ func TestFilterCapacityValidation(t *testing.T) {
|
|||
fromLockedAmount: map[uint64]*hexutil.Big{
|
||||
1: (*hexutil.Big)(big.NewInt(50)),
|
||||
},
|
||||
expectedRoutes: [][]*Path{},
|
||||
expectedRoutes: []routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "Empty routes",
|
||||
routes: [][]*Path{},
|
||||
routes: []routes.Route{},
|
||||
amountIn: big.NewInt(150),
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{
|
||||
1: (*hexutil.Big)(big.NewInt(50)),
|
||||
},
|
||||
expectedRoutes: [][]*Path{},
|
||||
expectedRoutes: []routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "Partial locked amounts",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1, AmountIn: (*hexutil.Big)(big.NewInt(50))},
|
||||
{FromChain: network3, AmountIn: (*hexutil.Big)(big.NewInt(100))},
|
||||
|
@ -850,7 +851,7 @@ func TestFilterCapacityValidation(t *testing.T) {
|
|||
2: (*hexutil.Big)(big.NewInt(0)), // Excluded path
|
||||
3: (*hexutil.Big)(big.NewInt(100)),
|
||||
},
|
||||
expectedRoutes: [][]*Path{
|
||||
expectedRoutes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1, AmountIn: (*hexutil.Big)(big.NewInt(50))},
|
||||
{FromChain: network3, AmountIn: (*hexutil.Big)(big.NewInt(100))},
|
||||
|
@ -860,7 +861,7 @@ func TestFilterCapacityValidation(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Mixed networks with sufficient capacity",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1, AmountIn: (*hexutil.Big)(big.NewInt(100))},
|
||||
{FromChain: network3, AmountIn: (*hexutil.Big)(big.NewInt(200))},
|
||||
|
@ -871,7 +872,7 @@ func TestFilterCapacityValidation(t *testing.T) {
|
|||
1: (*hexutil.Big)(big.NewInt(100)),
|
||||
3: (*hexutil.Big)(big.NewInt(200)),
|
||||
},
|
||||
expectedRoutes: [][]*Path{
|
||||
expectedRoutes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1, AmountIn: (*hexutil.Big)(big.NewInt(100))},
|
||||
{FromChain: network3, AmountIn: (*hexutil.Big)(big.NewInt(200))},
|
||||
|
@ -880,7 +881,7 @@ func TestFilterCapacityValidation(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "Mixed networks with insufficient capacity",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{
|
||||
{FromChain: network1, AmountIn: (*hexutil.Big)(big.NewInt(100))},
|
||||
{FromChain: network3, AmountIn: (*hexutil.Big)(big.NewInt(100))},
|
||||
|
@ -891,7 +892,7 @@ func TestFilterCapacityValidation(t *testing.T) {
|
|||
1: (*hexutil.Big)(big.NewInt(50)),
|
||||
3: (*hexutil.Big)(big.NewInt(100)),
|
||||
},
|
||||
expectedRoutes: [][]*Path{},
|
||||
expectedRoutes: []routes.Route{},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -908,50 +909,50 @@ func TestFilterCapacityValidation(t *testing.T) {
|
|||
func TestFilterRoutes(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
routes [][]*Path
|
||||
routes []routes.Route
|
||||
amountIn *big.Int
|
||||
fromLockedAmount map[uint64]*hexutil.Big
|
||||
expectedRoutes [][]*Path
|
||||
expectedRoutes []routes.Route
|
||||
}{
|
||||
{
|
||||
name: "Empty fromLockedAmount and routes don't match amountIn",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{pathC1A1, pathC2A2},
|
||||
{pathC3A3, pathC4A4},
|
||||
},
|
||||
amountIn: big.NewInt(150),
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{},
|
||||
expectedRoutes: [][]*Path{},
|
||||
expectedRoutes: []routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "Empty fromLockedAmount and sigle route match amountIn",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{pathC1A1, pathC2A2},
|
||||
{pathC3A3, pathC4A4},
|
||||
},
|
||||
amountIn: big.NewInt(300),
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{},
|
||||
expectedRoutes: [][]*Path{
|
||||
expectedRoutes: []routes.Route{
|
||||
{pathC1A1, pathC2A2},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Empty fromLockedAmount and more routes match amountIn",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{pathC1A1, pathC2A2},
|
||||
{pathC3A3, pathC4A4},
|
||||
{pathC1A1, pathC2A1, pathC3A1},
|
||||
},
|
||||
amountIn: big.NewInt(300),
|
||||
fromLockedAmount: map[uint64]*hexutil.Big{},
|
||||
expectedRoutes: [][]*Path{
|
||||
expectedRoutes: []routes.Route{
|
||||
{pathC1A1, pathC2A2},
|
||||
{pathC1A1, pathC2A1, pathC3A1},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "All paths appear in fromLockedAmount but not within a single route",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{pathC1A1, pathC3A3},
|
||||
{pathC2A2, pathC4A4},
|
||||
},
|
||||
|
@ -962,11 +963,11 @@ func TestFilterRoutes(t *testing.T) {
|
|||
3: &amount3,
|
||||
4: &amount4,
|
||||
},
|
||||
expectedRoutes: [][]*Path{},
|
||||
expectedRoutes: []routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "Mixed valid and invalid routes I",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{pathC1A1, pathC2A2},
|
||||
{pathC2A2, pathC3A3},
|
||||
{pathC1A1, pathC4A4},
|
||||
|
@ -977,13 +978,13 @@ func TestFilterRoutes(t *testing.T) {
|
|||
1: &amount1,
|
||||
2: &amount2,
|
||||
},
|
||||
expectedRoutes: [][]*Path{
|
||||
expectedRoutes: []routes.Route{
|
||||
{pathC1A1, pathC2A2},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Mixed valid and invalid routes II",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{pathC1A1, pathC2A2},
|
||||
{pathC2A2, pathC3A3},
|
||||
{pathC1A1, pathC4A4},
|
||||
|
@ -993,14 +994,14 @@ func TestFilterRoutes(t *testing.T) {
|
|||
fromLockedAmount: map[uint64]*hexutil.Big{
|
||||
1: &amount1,
|
||||
},
|
||||
expectedRoutes: [][]*Path{
|
||||
expectedRoutes: []routes.Route{
|
||||
{pathC1A1, pathC2A2},
|
||||
{pathC1A1, pathC2A1, pathC3A1},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "All invalid routes",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{pathC2A2, pathC3A3},
|
||||
{pathC4A4, pathC5A5},
|
||||
},
|
||||
|
@ -1008,11 +1009,11 @@ func TestFilterRoutes(t *testing.T) {
|
|||
fromLockedAmount: map[uint64]*hexutil.Big{
|
||||
1: &amount1,
|
||||
},
|
||||
expectedRoutes: [][]*Path{},
|
||||
expectedRoutes: []routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "Single valid route",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{pathC1A1, pathC3A3},
|
||||
{pathC2A2, pathC3A3},
|
||||
},
|
||||
|
@ -1021,13 +1022,13 @@ func TestFilterRoutes(t *testing.T) {
|
|||
1: &amount1,
|
||||
3: &amount3,
|
||||
},
|
||||
expectedRoutes: [][]*Path{
|
||||
expectedRoutes: []routes.Route{
|
||||
{pathC1A1, pathC3A3},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Route with mixed valid and invalid paths I",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{pathC1A1, pathC2A2, pathC3A3},
|
||||
},
|
||||
amountIn: big.NewInt(300),
|
||||
|
@ -1035,11 +1036,11 @@ func TestFilterRoutes(t *testing.T) {
|
|||
1: &amount1,
|
||||
2: &amount0, // This path should be filtered out due to being excluded via a zero amount
|
||||
},
|
||||
expectedRoutes: [][]*Path{},
|
||||
expectedRoutes: []routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "Route with mixed valid and invalid paths II",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{pathC1A1, pathC3A3},
|
||||
},
|
||||
amountIn: big.NewInt(400),
|
||||
|
@ -1047,13 +1048,13 @@ func TestFilterRoutes(t *testing.T) {
|
|||
1: &amount1,
|
||||
2: &amount0, // This path should be filtered out due to being excluded via a zero amount, 0 value locked means this chain is disabled
|
||||
},
|
||||
expectedRoutes: [][]*Path{
|
||||
expectedRoutes: []routes.Route{
|
||||
{pathC1A1, pathC3A3},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Route with mixed valid and invalid paths III",
|
||||
routes: [][]*Path{
|
||||
routes: []routes.Route{
|
||||
{pathC1A1, pathC3A3},
|
||||
{pathC1A1, pathC3A2, pathC4A1},
|
||||
},
|
||||
|
@ -1062,7 +1063,7 @@ func TestFilterRoutes(t *testing.T) {
|
|||
1: &amount1,
|
||||
2: &amount0, // This path should be filtered out due to being excluded via a zero amount, 0 value locked means this chain is disabled
|
||||
},
|
||||
expectedRoutes: [][]*Path{
|
||||
expectedRoutes: []routes.Route{
|
||||
{pathC1A1, pathC3A3},
|
||||
{pathC1A1, pathC3A2, pathC4A1},
|
||||
},
|
||||
|
|
|
@ -21,8 +21,10 @@ import (
|
|||
walletCommon "github.com/status-im/status-go/services/wallet/common"
|
||||
"github.com/status-im/status-go/services/wallet/market"
|
||||
"github.com/status-im/status-go/services/wallet/requests"
|
||||
"github.com/status-im/status-go/services/wallet/responses"
|
||||
"github.com/status-im/status-go/services/wallet/router/fees"
|
||||
"github.com/status-im/status-go/services/wallet/router/pathprocessor"
|
||||
"github.com/status-im/status-go/services/wallet/router/routes"
|
||||
"github.com/status-im/status-go/services/wallet/router/sendtype"
|
||||
"github.com/status-im/status-go/services/wallet/token"
|
||||
walletToken "github.com/status-im/status-go/services/wallet/token"
|
||||
|
@ -54,21 +56,12 @@ type ProcessorError struct {
|
|||
|
||||
type SuggestedRoutes struct {
|
||||
Uuid string
|
||||
Best []*Path
|
||||
Candidates []*Path
|
||||
Best routes.Route
|
||||
Candidates routes.Route
|
||||
TokenPrice float64
|
||||
NativeChainTokenPrice float64
|
||||
}
|
||||
|
||||
type SuggestedRoutesResponse struct {
|
||||
Uuid string `json:"Uuid"`
|
||||
Best []*Path `json:"Best,omitempty"`
|
||||
Candidates []*Path `json:"Candidates,omitempty"`
|
||||
TokenPrice *float64 `json:"TokenPrice,omitempty"`
|
||||
NativeChainTokenPrice *float64 `json:"NativeChainTokenPrice,omitempty"`
|
||||
ErrorResponse *errors.ErrorResponse `json:"ErrorResponse,omitempty"`
|
||||
}
|
||||
|
||||
type Router struct {
|
||||
rpcClient *rpc.Client
|
||||
tokenManager *token.Manager
|
||||
|
@ -121,11 +114,11 @@ func (r *Router) GetPathProcessors() map[string]pathprocessor.PathProcessor {
|
|||
func newSuggestedRoutes(
|
||||
uuid string,
|
||||
amountIn *big.Int,
|
||||
candidates []*Path,
|
||||
candidates routes.Route,
|
||||
fromLockedAmount map[uint64]*hexutil.Big,
|
||||
tokenPrice float64,
|
||||
nativeChainTokenPrice float64,
|
||||
) (*SuggestedRoutes, [][]*Path) {
|
||||
) (*SuggestedRoutes, []routes.Route) {
|
||||
suggestedRoutes := &SuggestedRoutes{
|
||||
Uuid: uuid,
|
||||
Candidates: candidates,
|
||||
|
@ -136,11 +129,11 @@ func newSuggestedRoutes(
|
|||
return suggestedRoutes, nil
|
||||
}
|
||||
|
||||
node := &Node{
|
||||
node := &routes.Node{
|
||||
Path: nil,
|
||||
Children: buildGraph(amountIn, candidates, 0, []uint64{}),
|
||||
Children: routes.BuildGraph(amountIn, candidates, 0, []uint64{}),
|
||||
}
|
||||
allRoutes := node.buildAllRoutes()
|
||||
allRoutes := node.BuildAllRoutes()
|
||||
allRoutes = filterRoutes(allRoutes, amountIn, fromLockedAmount)
|
||||
|
||||
if len(allRoutes) > 0 {
|
||||
|
@ -158,7 +151,7 @@ func (r *Router) SuggestedRoutesAsync(input *requests.RouteInputParams) {
|
|||
r.scheduler.Enqueue(routerTask, func(ctx context.Context) (interface{}, error) {
|
||||
return r.SuggestedRoutes(ctx, input)
|
||||
}, func(result interface{}, taskType async.TaskType, err error) {
|
||||
routesResponse := SuggestedRoutesResponse{
|
||||
routesResponse := responses.RouterSuggestedRoutes{
|
||||
Uuid: input.Uuid,
|
||||
}
|
||||
|
||||
|
@ -511,7 +504,7 @@ func (r *Router) getSelectedChains(input *requests.RouteInputParams) (selectedFr
|
|||
}
|
||||
|
||||
func (r *Router) resolveCandidates(ctx context.Context, input *requests.RouteInputParams, selectedFromChains []*params.Network,
|
||||
selectedToChains []*params.Network, balanceMap map[string]*big.Int) (candidates []*Path, processorErrors []*ProcessorError, err error) {
|
||||
selectedToChains []*params.Network, balanceMap map[string]*big.Int) (candidates routes.Route, processorErrors []*ProcessorError, err error) {
|
||||
var (
|
||||
testsMode = input.TestsMode && input.TestParams != nil
|
||||
group = async.NewAtomicGroup(ctx)
|
||||
|
@ -533,7 +526,7 @@ func (r *Router) resolveCandidates(ctx context.Context, input *requests.RouteInp
|
|||
})
|
||||
}
|
||||
|
||||
appendPathFn := func(path *Path) {
|
||||
appendPathFn := func(path *routes.Path) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
candidates = append(candidates, path)
|
||||
|
@ -731,7 +724,7 @@ func (r *Router) resolveCandidates(ctx context.Context, input *requests.RouteInp
|
|||
requiredNativeBalance.Add(requiredNativeBalance, ethTotalFees)
|
||||
}
|
||||
|
||||
appendPathFn(&Path{
|
||||
appendPathFn(&routes.Path{
|
||||
ProcessorName: pProcessor.Name(),
|
||||
FromChain: network,
|
||||
ToChain: dest,
|
||||
|
@ -767,9 +760,9 @@ func (r *Router) resolveCandidates(ctx context.Context, input *requests.RouteInp
|
|||
|
||||
EstimatedTime: estimatedTime,
|
||||
|
||||
subtractFees: amountOption.subtractFees,
|
||||
requiredTokenBalance: requiredTokenBalance,
|
||||
requiredNativeBalance: requiredNativeBalance,
|
||||
SubtractFees: amountOption.subtractFees,
|
||||
RequiredTokenBalance: requiredTokenBalance,
|
||||
RequiredNativeBalance: requiredNativeBalance,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -788,7 +781,7 @@ func (r *Router) resolveCandidates(ctx context.Context, input *requests.RouteInp
|
|||
return candidates, processorErrors, nil
|
||||
}
|
||||
|
||||
func (r *Router) checkBalancesForTheBestRoute(ctx context.Context, bestRoute []*Path, balanceMap map[string]*big.Int) (hasPositiveBalance bool, err error) {
|
||||
func (r *Router) checkBalancesForTheBestRoute(ctx context.Context, bestRoute routes.Route, balanceMap map[string]*big.Int) (hasPositiveBalance bool, err error) {
|
||||
balanceMapCopy := walletCommon.CopyMapGeneric(balanceMap, func(v interface{}) interface{} {
|
||||
return new(big.Int).Set(v.(*big.Int))
|
||||
}).(map[string]*big.Int)
|
||||
|
@ -811,16 +804,16 @@ func (r *Router) checkBalancesForTheBestRoute(ctx context.Context, bestRoute []*
|
|||
}
|
||||
}
|
||||
|
||||
if path.requiredTokenBalance != nil && path.requiredTokenBalance.Cmp(pathprocessor.ZeroBigIntValue) > 0 {
|
||||
if path.RequiredTokenBalance != nil && path.RequiredTokenBalance.Cmp(pathprocessor.ZeroBigIntValue) > 0 {
|
||||
if tokenBalance, ok := balanceMapCopy[tokenKey]; ok {
|
||||
if tokenBalance.Cmp(path.requiredTokenBalance) == -1 {
|
||||
if tokenBalance.Cmp(path.RequiredTokenBalance) == -1 {
|
||||
err := &errors.ErrorResponse{
|
||||
Code: ErrNotEnoughTokenBalance.Code,
|
||||
Details: fmt.Sprintf(ErrNotEnoughTokenBalance.Details, path.FromToken.Symbol, path.FromChain.ChainID),
|
||||
}
|
||||
return hasPositiveBalance, err
|
||||
}
|
||||
balanceMapCopy[tokenKey].Sub(tokenBalance, path.requiredTokenBalance)
|
||||
balanceMapCopy[tokenKey].Sub(tokenBalance, path.RequiredTokenBalance)
|
||||
} else {
|
||||
return hasPositiveBalance, ErrTokenNotFound
|
||||
}
|
||||
|
@ -828,14 +821,14 @@ func (r *Router) checkBalancesForTheBestRoute(ctx context.Context, bestRoute []*
|
|||
|
||||
ethKey := makeBalanceKey(path.FromChain.ChainID, pathprocessor.EthSymbol)
|
||||
if nativeBalance, ok := balanceMapCopy[ethKey]; ok {
|
||||
if nativeBalance.Cmp(path.requiredNativeBalance) == -1 {
|
||||
if nativeBalance.Cmp(path.RequiredNativeBalance) == -1 {
|
||||
err := &errors.ErrorResponse{
|
||||
Code: ErrNotEnoughNativeBalance.Code,
|
||||
Details: fmt.Sprintf(ErrNotEnoughNativeBalance.Details, pathprocessor.EthSymbol, path.FromChain.ChainID),
|
||||
}
|
||||
return hasPositiveBalance, err
|
||||
}
|
||||
balanceMapCopy[ethKey].Sub(nativeBalance, path.requiredNativeBalance)
|
||||
balanceMapCopy[ethKey].Sub(nativeBalance, path.RequiredNativeBalance)
|
||||
} else {
|
||||
return hasPositiveBalance, ErrNativeTokenNotFound
|
||||
}
|
||||
|
@ -844,7 +837,7 @@ func (r *Router) checkBalancesForTheBestRoute(ctx context.Context, bestRoute []*
|
|||
return hasPositiveBalance, nil
|
||||
}
|
||||
|
||||
func (r *Router) resolveRoutes(ctx context.Context, input *requests.RouteInputParams, candidates []*Path, balanceMap map[string]*big.Int) (suggestedRoutes *SuggestedRoutes, err error) {
|
||||
func (r *Router) resolveRoutes(ctx context.Context, input *requests.RouteInputParams, candidates routes.Route, balanceMap map[string]*big.Int) (suggestedRoutes *SuggestedRoutes, err error) {
|
||||
var prices map[string]float64
|
||||
if input.TestsMode {
|
||||
prices = input.TestParams.TokenPrices
|
||||
|
@ -858,7 +851,7 @@ func (r *Router) resolveRoutes(ctx context.Context, input *requests.RouteInputPa
|
|||
tokenPrice := prices[input.TokenID]
|
||||
nativeTokenPrice := prices[pathprocessor.EthSymbol]
|
||||
|
||||
var allRoutes [][]*Path
|
||||
var allRoutes []routes.Route
|
||||
suggestedRoutes, allRoutes = newSuggestedRoutes(input.Uuid, input.AmountIn.ToInt(), candidates, input.FromLockedAmount, tokenPrice, nativeTokenPrice)
|
||||
|
||||
defer func() {
|
||||
|
@ -872,13 +865,13 @@ func (r *Router) resolveRoutes(ctx context.Context, input *requests.RouteInputPa
|
|||
}()
|
||||
|
||||
var (
|
||||
bestRoute []*Path
|
||||
lastBestRouteWithPositiveBalance []*Path
|
||||
bestRoute routes.Route
|
||||
lastBestRouteWithPositiveBalance routes.Route
|
||||
lastBestRouteErr error
|
||||
)
|
||||
|
||||
for len(allRoutes) > 0 {
|
||||
bestRoute = findBest(allRoutes, tokenPrice, nativeTokenPrice)
|
||||
bestRoute = routes.FindBestRoute(allRoutes, tokenPrice, nativeTokenPrice)
|
||||
var hasPositiveBalance bool
|
||||
hasPositiveBalance, err = r.checkBalancesForTheBestRoute(ctx, bestRoute, balanceMap)
|
||||
|
||||
|
@ -913,7 +906,7 @@ func (r *Router) resolveRoutes(ctx context.Context, input *requests.RouteInputPa
|
|||
if len(bestRoute) > 0 {
|
||||
// At this point we have to do the final check and update the amountIn (subtracting fees) if complete balance is going to be sent for native token (ETH)
|
||||
for _, path := range bestRoute {
|
||||
if path.subtractFees && path.FromToken.IsNative() {
|
||||
if path.SubtractFees && path.FromToken.IsNative() {
|
||||
path.AmountIn.ToInt().Sub(path.AmountIn.ToInt(), path.TxFee.ToInt())
|
||||
if path.TxL1Fee.ToInt().Cmp(pathprocessor.ZeroBigIntValue) > 0 {
|
||||
path.AmountIn.ToInt().Sub(path.AmountIn.ToInt(), path.TxL1Fee.ToInt())
|
||||
|
|
|
@ -10,7 +10,9 @@ import (
|
|||
"github.com/status-im/status-go/appdatabase"
|
||||
"github.com/status-im/status-go/params"
|
||||
"github.com/status-im/status-go/rpc"
|
||||
"github.com/status-im/status-go/services/wallet/responses"
|
||||
"github.com/status-im/status-go/services/wallet/router/pathprocessor"
|
||||
"github.com/status-im/status-go/services/wallet/router/routes"
|
||||
"github.com/status-im/status-go/signal"
|
||||
"github.com/status-im/status-go/t/helpers"
|
||||
|
||||
|
@ -58,7 +60,7 @@ func amountOptionsMapsEqual(map1, map2 map[uint64][]amountOption) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func assertPathsEqual(t *testing.T, expected, actual []*Path) {
|
||||
func assertPathsEqual(t *testing.T, expected, actual routes.Route) {
|
||||
assert.Equal(t, len(expected), len(actual))
|
||||
if len(expected) == 0 {
|
||||
return
|
||||
|
@ -124,19 +126,19 @@ func setupRouter(t *testing.T) (*Router, func()) {
|
|||
return router, cleanTmpDb
|
||||
}
|
||||
|
||||
type suggestedRoutesResponseEnvelope struct {
|
||||
type routerSuggestedRoutesEnvelope struct {
|
||||
Type string `json:"type"`
|
||||
Routes SuggestedRoutesResponse `json:"event"`
|
||||
Routes responses.RouterSuggestedRoutes `json:"event"`
|
||||
}
|
||||
|
||||
func setupSignalHandler(t *testing.T) (chan SuggestedRoutesResponse, func()) {
|
||||
suggestedRoutesCh := make(chan SuggestedRoutesResponse)
|
||||
func setupSignalHandler(t *testing.T) (chan responses.RouterSuggestedRoutes, func()) {
|
||||
suggestedRoutesCh := make(chan responses.RouterSuggestedRoutes)
|
||||
signalHandler := signal.MobileSignalHandler(func(data []byte) {
|
||||
var envelope signal.Envelope
|
||||
err := json.Unmarshal(data, &envelope)
|
||||
assert.NoError(t, err)
|
||||
if envelope.Type == string(signal.SuggestedRoutes) {
|
||||
var response suggestedRoutesResponseEnvelope
|
||||
var response routerSuggestedRoutesEnvelope
|
||||
err := json.Unmarshal(data, &response)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/status-im/status-go/services/wallet/requests"
|
||||
"github.com/status-im/status-go/services/wallet/router/fees"
|
||||
"github.com/status-im/status-go/services/wallet/router/pathprocessor"
|
||||
"github.com/status-im/status-go/services/wallet/router/routes"
|
||||
"github.com/status-im/status-go/services/wallet/router/sendtype"
|
||||
"github.com/status-im/status-go/services/wallet/token"
|
||||
)
|
||||
|
@ -205,7 +206,7 @@ var defaultNetworks = []params.Network{
|
|||
type normalTestParams struct {
|
||||
name string
|
||||
input *requests.RouteInputParams
|
||||
expectedCandidates []*Path
|
||||
expectedCandidates routes.Route
|
||||
expectedError *errors.ErrorResponse
|
||||
}
|
||||
|
||||
|
@ -249,7 +250,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
Code: errors.GenericErrorCode,
|
||||
Details: fmt.Sprintf("failed with 50000000 gas: insufficient funds for gas * price + value: address %s", common.HexToAddress("0x1")),
|
||||
},
|
||||
expectedCandidates: []*Path{},
|
||||
expectedCandidates: routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "ETH transfer - No Specific FromChain - No Specific ToChain - 0 AmountIn",
|
||||
|
@ -278,7 +279,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &mainnet,
|
||||
|
@ -326,7 +327,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &mainnet,
|
||||
|
@ -412,7 +413,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &mainnet,
|
||||
|
@ -462,7 +463,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &optimism,
|
||||
|
@ -531,7 +532,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &arbitrum,
|
||||
|
@ -581,7 +582,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &optimism,
|
||||
|
@ -650,7 +651,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &arbitrum,
|
||||
|
@ -689,7 +690,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorBridgeHopName,
|
||||
FromChain: &arbitrum,
|
||||
|
@ -728,7 +729,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &arbitrum,
|
||||
|
@ -767,7 +768,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &mainnet,
|
||||
|
@ -824,7 +825,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorBridgeHopName,
|
||||
FromChain: &arbitrum,
|
||||
|
@ -865,7 +866,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
},
|
||||
},
|
||||
expectedError: ErrNoBestRouteFound,
|
||||
expectedCandidates: []*Path{},
|
||||
expectedCandidates: routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "ETH transfer - No Specific FromChain - No Specific ToChain - Single Chain LockedAmount",
|
||||
|
@ -898,7 +899,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &mainnet,
|
||||
|
@ -997,7 +998,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &optimism,
|
||||
|
@ -1053,7 +1054,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &mainnet,
|
||||
|
@ -1152,7 +1153,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &mainnet,
|
||||
|
@ -1252,7 +1253,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
},
|
||||
},
|
||||
expectedError: requests.ErrLockedAmountLessThanSendAmountAllNetworks,
|
||||
expectedCandidates: []*Path{},
|
||||
expectedCandidates: routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "ETH transfer - No Specific FromChain - No Specific ToChain - LockedAmount exceeds sending amount",
|
||||
|
@ -1287,7 +1288,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
},
|
||||
},
|
||||
expectedError: requests.ErrLockedAmountExceedsTotalSendAmount,
|
||||
expectedCandidates: []*Path{},
|
||||
expectedCandidates: routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "ERC20 transfer - No Specific FromChain - No Specific ToChain",
|
||||
|
@ -1317,7 +1318,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &mainnet,
|
||||
|
@ -1403,7 +1404,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &mainnet,
|
||||
|
@ -1453,7 +1454,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &optimism,
|
||||
|
@ -1521,7 +1522,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &arbitrum,
|
||||
|
@ -1571,7 +1572,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &optimism,
|
||||
|
@ -1640,7 +1641,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &arbitrum,
|
||||
|
@ -1679,7 +1680,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorBridgeHopName,
|
||||
FromChain: &arbitrum,
|
||||
|
@ -1718,7 +1719,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &arbitrum,
|
||||
|
@ -1757,7 +1758,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &mainnet,
|
||||
|
@ -1814,7 +1815,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorBridgeHopName,
|
||||
FromChain: &arbitrum,
|
||||
|
@ -1854,7 +1855,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
},
|
||||
},
|
||||
expectedError: ErrNoBestRouteFound,
|
||||
expectedCandidates: []*Path{},
|
||||
expectedCandidates: routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "ERC20 transfer - All FromChains - No Locked Amount - Enough Token Balance Across All Chains",
|
||||
|
@ -1884,7 +1885,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &mainnet,
|
||||
|
@ -2083,7 +2084,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorBridgeHopName,
|
||||
FromChain: &mainnet,
|
||||
|
@ -2151,7 +2152,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorBridgeHopName,
|
||||
FromChain: &optimism,
|
||||
|
@ -2195,7 +2196,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorBridgeHopName,
|
||||
FromChain: &mainnet,
|
||||
|
@ -2251,7 +2252,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorBridgeHopName,
|
||||
FromChain: &arbitrum,
|
||||
|
@ -2295,7 +2296,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorBridgeHopName,
|
||||
FromChain: &optimism,
|
||||
|
@ -2353,7 +2354,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
},
|
||||
},
|
||||
expectedError: ErrNoBestRouteFound,
|
||||
expectedCandidates: []*Path{},
|
||||
expectedCandidates: routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "Bridge - Specific Single FromChain - Specific Single ToChain - Different Chains",
|
||||
|
@ -2385,7 +2386,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorBridgeHopName,
|
||||
FromChain: &arbitrum,
|
||||
|
@ -2425,7 +2426,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
},
|
||||
},
|
||||
expectedError: ErrNoBestRouteFound,
|
||||
expectedCandidates: []*Path{},
|
||||
expectedCandidates: routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "Bridge - Specific Multiple FromChain - Specific Multiple ToChain - Multiple Common Chains",
|
||||
|
@ -2457,7 +2458,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorBridgeHopName,
|
||||
FromChain: &mainnet,
|
||||
|
@ -2502,7 +2503,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorBridgeHopName,
|
||||
FromChain: &arbitrum,
|
||||
|
@ -2542,7 +2543,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
},
|
||||
},
|
||||
expectedError: ErrNoBestRouteFound,
|
||||
expectedCandidates: []*Path{},
|
||||
expectedCandidates: routes.Route{},
|
||||
},
|
||||
{
|
||||
name: "ETH transfer - Not Enough Native Balance",
|
||||
|
@ -2577,7 +2578,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
Code: ErrNotEnoughNativeBalance.Code,
|
||||
Details: fmt.Sprintf(ErrNotEnoughNativeBalance.Details, pathprocessor.EthSymbol, walletCommon.EthereumMainnet),
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorBridgeHopName,
|
||||
FromChain: &mainnet,
|
||||
|
@ -2619,7 +2620,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
Code: ErrNotEnoughTokenBalance.Code,
|
||||
Details: fmt.Sprintf(ErrNotEnoughTokenBalance.Details, pathprocessor.UsdcSymbol, walletCommon.EthereumMainnet),
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorBridgeHopName,
|
||||
FromChain: &mainnet,
|
||||
|
@ -2659,7 +2660,7 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
},
|
||||
},
|
||||
expectedError: ErrLowAmountInForHopBridge,
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorBridgeHopName,
|
||||
FromChain: &arbitrum,
|
||||
|
@ -2674,8 +2675,8 @@ func getNormalTestParamsList() []normalTestParams {
|
|||
type noBalanceTestParams struct {
|
||||
name string
|
||||
input *requests.RouteInputParams
|
||||
expectedCandidates []*Path
|
||||
expectedBest []*Path
|
||||
expectedCandidates routes.Route
|
||||
expectedBest routes.Route
|
||||
expectedError *errors.ErrorResponse
|
||||
}
|
||||
|
||||
|
@ -2750,14 +2751,14 @@ func getNoBalanceTestParamsList() []noBalanceTestParams {
|
|||
Code: ErrNotEnoughNativeBalance.Code,
|
||||
Details: fmt.Sprintf(ErrNotEnoughNativeBalance.Details, pathprocessor.EthSymbol, walletCommon.OptimismMainnet),
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorTransferName,
|
||||
FromChain: &optimism,
|
||||
ToChain: &optimism,
|
||||
ApprovalRequired: false,
|
||||
requiredTokenBalance: big.NewInt(testAmount100USDC),
|
||||
requiredNativeBalance: big.NewInt((testBaseFee + testPriorityFeeLow) * testApprovalGasEstimation),
|
||||
RequiredTokenBalance: big.NewInt(testAmount100USDC),
|
||||
RequiredNativeBalance: big.NewInt((testBaseFee + testPriorityFeeLow) * testApprovalGasEstimation),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -2837,7 +2838,7 @@ func getNoBalanceTestParamsList() []noBalanceTestParams {
|
|||
Code: ErrNotEnoughNativeBalance.Code,
|
||||
Details: fmt.Sprintf(ErrNotEnoughNativeBalance.Details, pathprocessor.EthSymbol, walletCommon.ArbitrumMainnet),
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorBridgeHopName,
|
||||
FromChain: &mainnet,
|
||||
|
@ -2849,8 +2850,8 @@ func getNoBalanceTestParamsList() []noBalanceTestParams {
|
|||
FromChain: &optimism,
|
||||
ToChain: &optimism,
|
||||
ApprovalRequired: false,
|
||||
requiredTokenBalance: big.NewInt(testAmount100USDC),
|
||||
requiredNativeBalance: big.NewInt((testBaseFee + testPriorityFeeLow) * testApprovalGasEstimation),
|
||||
RequiredTokenBalance: big.NewInt(testAmount100USDC),
|
||||
RequiredNativeBalance: big.NewInt((testBaseFee + testPriorityFeeLow) * testApprovalGasEstimation),
|
||||
},
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorBridgeHopName,
|
||||
|
@ -2891,7 +2892,7 @@ func getNoBalanceTestParamsList() []noBalanceTestParams {
|
|||
ApprovalL1Fee: testApprovalL1Fee,
|
||||
},
|
||||
},
|
||||
expectedCandidates: []*Path{
|
||||
expectedCandidates: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorBridgeHopName,
|
||||
FromChain: &mainnet,
|
||||
|
@ -2903,8 +2904,8 @@ func getNoBalanceTestParamsList() []noBalanceTestParams {
|
|||
FromChain: &optimism,
|
||||
ToChain: &optimism,
|
||||
ApprovalRequired: false,
|
||||
requiredTokenBalance: big.NewInt(testAmount100USDC),
|
||||
requiredNativeBalance: big.NewInt((testBaseFee + testPriorityFeeLow) * testApprovalGasEstimation),
|
||||
RequiredTokenBalance: big.NewInt(testAmount100USDC),
|
||||
RequiredNativeBalance: big.NewInt((testBaseFee + testPriorityFeeLow) * testApprovalGasEstimation),
|
||||
},
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorBridgeHopName,
|
||||
|
@ -2913,7 +2914,7 @@ func getNoBalanceTestParamsList() []noBalanceTestParams {
|
|||
ApprovalRequired: true,
|
||||
},
|
||||
},
|
||||
expectedBest: []*Path{
|
||||
expectedBest: routes.Route{
|
||||
{
|
||||
ProcessorName: pathprocessor.ProcessorBridgeHopName,
|
||||
FromChain: &arbitrum,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package router
|
||||
package routes
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
@ -8,80 +8,10 @@ import (
|
|||
"github.com/status-im/status-go/services/wallet/router/pathprocessor"
|
||||
)
|
||||
|
||||
type Graph []*Node
|
||||
type Route []*Path
|
||||
|
||||
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
|
||||
func FindBestRoute(routes []Route, tokenPrice float64, nativeTokenPrice float64) Route {
|
||||
var best Route
|
||||
bestCost := big.NewFloat(math.Inf(1))
|
||||
for _, route := range routes {
|
||||
currentCost := big.NewFloat(0)
|
|
@ -0,0 +1,77 @@
|
|||
package routes
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
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, route Route, level int, sourceChainIDs []uint64) Graph {
|
||||
graph := make(Graph, 0)
|
||||
for _, path := range route {
|
||||
found := false
|
||||
for _, chainID := range sourceChainIDs {
|
||||
if chainID == path.FromChain.ChainID {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if found {
|
||||
continue
|
||||
}
|
||||
node := newNode(path)
|
||||
|
||||
newRoute := make(Route, 0)
|
||||
for _, p := range route {
|
||||
if path.Equal(p) {
|
||||
continue
|
||||
}
|
||||
newRoute = append(newRoute, p)
|
||||
}
|
||||
|
||||
newAmountIn := new(big.Int).Sub(AmountIn, path.AmountIn.ToInt())
|
||||
if newAmountIn.Sign() > 0 {
|
||||
newSourceChainIDs := make([]uint64, len(sourceChainIDs))
|
||||
copy(newSourceChainIDs, sourceChainIDs)
|
||||
newSourceChainIDs = append(newSourceChainIDs, path.FromChain.ChainID)
|
||||
node.Children = BuildGraph(newAmountIn, newRoute, level+1, newSourceChainIDs)
|
||||
|
||||
if len(node.Children) == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
graph = append(graph, node)
|
||||
}
|
||||
|
||||
return graph
|
||||
}
|
||||
|
||||
func (n Node) BuildAllRoutes() []Route {
|
||||
res := make([]Route, 0)
|
||||
|
||||
if len(n.Children) == 0 && n.Path != nil {
|
||||
res = append(res, Route{n.Path})
|
||||
}
|
||||
|
||||
for _, node := range n.Children {
|
||||
for _, route := range node.BuildAllRoutes() {
|
||||
extendedRoute := route
|
||||
if n.Path != nil {
|
||||
extendedRoute = append(Route{n.Path}, route...)
|
||||
}
|
||||
res = append(res, extendedRoute)
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package router
|
||||
package routes
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
@ -46,9 +46,9 @@ type Path struct {
|
|||
|
||||
EstimatedTime fees.TransactionEstimation
|
||||
|
||||
requiredTokenBalance *big.Int // (in selected token)
|
||||
requiredNativeBalance *big.Int // (in ETH WEI)
|
||||
subtractFees bool
|
||||
RequiredTokenBalance *big.Int // (in selected token)
|
||||
RequiredNativeBalance *big.Int // (in ETH WEI)
|
||||
SubtractFees bool
|
||||
}
|
||||
|
||||
func (p *Path) Equal(o *Path) bool {
|
Loading…
Reference in New Issue