From 21101c9444288187348599347f00abc1b5e68fd6 Mon Sep 17 00:00:00 2001 From: Dario Gabriel Lipicar Date: Wed, 10 Jul 2024 18:06:56 -0300 Subject: [PATCH] feat(wallet)!: return routerV2 suggested routes whenever available, on top of error if the best route doesn't pass all checks --- services/wallet/router/router_v2.go | 34 +- services/wallet/router/router_v2_test.go | 3234 +---------------- services/wallet/router/router_v2_test_data.go | 3163 ++++++++++++++++ 3 files changed, 3286 insertions(+), 3145 deletions(-) create mode 100644 services/wallet/router/router_v2_test_data.go diff --git a/services/wallet/router/router_v2.go b/services/wallet/router/router_v2.go index 6aa37f60f..89e4df94d 100644 --- a/services/wallet/router/router_v2.go +++ b/services/wallet/router/router_v2.go @@ -133,9 +133,13 @@ type SuggestedRoutesV2 struct { NativeChainTokenPrice float64 } -type ErrorResponseWithUUID struct { - Uuid string - ErrorResponse error +type SuggestedRoutesV2Response struct { + Uuid string `json:"Uuid"` + Best []*PathV2 `json:"Best,omitempty"` + Candidates []*PathV2 `json:"Candidates,omitempty"` + TokenPrice *float64 `json:"TokenPrice,omitempty"` + NativeChainTokenPrice *float64 `json:"NativeChainTokenPrice,omitempty"` + ErrorResponse *errors.ErrorResponse `json:"ErrorResponse,omitempty"` } type GraphV2 []*NodeV2 @@ -449,15 +453,23 @@ func (r *Router) SuggestedRoutesV2Async(input *RouteInputParams) { r.scheduler.Enqueue(routerTask, func(ctx context.Context) (interface{}, error) { return r.SuggestedRoutesV2(ctx, input) }, func(result interface{}, taskType async.TaskType, err error) { - if err != nil { - errResponse := &ErrorResponseWithUUID{ - Uuid: input.Uuid, - ErrorResponse: errors.CreateErrorResponseFromError(err), - } - signal.SendWalletEvent(signal.SuggestedRoutes, errResponse) - return + routesResponse := SuggestedRoutesV2Response{ + Uuid: input.Uuid, } - signal.SendWalletEvent(signal.SuggestedRoutes, result) + + if err != nil { + errorResponse := errors.CreateErrorResponseFromError(err) + routesResponse.ErrorResponse = errorResponse.(*errors.ErrorResponse) + } + + if suggestedRoutes, ok := result.(*SuggestedRoutesV2); ok && suggestedRoutes != nil { + routesResponse.Best = suggestedRoutes.Best + routesResponse.Candidates = suggestedRoutes.Candidates + routesResponse.TokenPrice = &suggestedRoutes.TokenPrice + routesResponse.NativeChainTokenPrice = &suggestedRoutes.NativeChainTokenPrice + } + + signal.SendWalletEvent(signal.SuggestedRoutes, routesResponse) }) } diff --git a/services/wallet/router/router_v2_test.go b/services/wallet/router/router_v2_test.go index fde18c6d5..cec978fb5 100644 --- a/services/wallet/router/router_v2_test.go +++ b/services/wallet/router/router_v2_test.go @@ -3,207 +3,21 @@ package router import ( "context" "database/sql" - "math/big" + "encoding/json" "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" + "time" "github.com/status-im/status-go/appdatabase" "github.com/status-im/status-go/params" "github.com/status-im/status-go/rpc" - walletCommon "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/token" + "github.com/status-im/status-go/signal" "github.com/status-im/status-go/t/helpers" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -const ( - testBaseFee = 50000000000 - testGasPrice = 10000000000 - testPriorityFeeLow = 1000000000 - testPriorityFeeMedium = 2000000000 - testPriorityFeeHigh = 3000000000 - testBonderFeeETH = 150000000000000 - testBonderFeeUSDC = 10000 - - testAmount0Point1ETHInWei = 100000000000000000 - testAmount0Point2ETHInWei = 200000000000000000 - testAmount0Point3ETHInWei = 300000000000000000 - testAmount0Point4ETHInWei = 400000000000000000 - testAmount0Point5ETHInWei = 500000000000000000 - testAmount0Point6ETHInWei = 600000000000000000 - testAmount0Point8ETHInWei = 800000000000000000 - testAmount1ETHInWei = 1000000000000000000 - testAmount2ETHInWei = 2000000000000000000 - testAmount3ETHInWei = 3000000000000000000 - testAmount5ETHInWei = 5000000000000000000 - - testAmount1USDC = 1000000 - testAmount100USDC = 100000000 - - testApprovalGasEstimation = 1000 - testApprovalL1Fee = 100000000000 -) - -var ( - testEstimationMap = map[string]uint64{ - pathprocessor.ProcessorTransferName: uint64(1000), - pathprocessor.ProcessorBridgeHopName: uint64(5000), - } - - testBbonderFeeMap = map[string]*big.Int{ - pathprocessor.EthSymbol: big.NewInt(testBonderFeeETH), - pathprocessor.UsdcSymbol: big.NewInt(testBonderFeeUSDC), - } - - testTokenPrices = map[string]float64{ - pathprocessor.EthSymbol: 2000, - pathprocessor.UsdcSymbol: 1, - } - - testSuggestedFees = &SuggestedFees{ - GasPrice: big.NewInt(testGasPrice), - BaseFee: big.NewInt(testBaseFee), - MaxPriorityFeePerGas: big.NewInt(testPriorityFeeLow), - MaxFeesLevels: &MaxFeesLevels{ - Low: (*hexutil.Big)(big.NewInt(testPriorityFeeLow)), - Medium: (*hexutil.Big)(big.NewInt(testPriorityFeeMedium)), - High: (*hexutil.Big)(big.NewInt(testPriorityFeeHigh)), - }, - EIP1559Enabled: false, - } - - testBalanceMapPerChain = map[string]*big.Int{ - makeBalanceKey(walletCommon.EthereumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount2ETHInWei), - makeBalanceKey(walletCommon.EthereumMainnet, pathprocessor.UsdcSymbol): big.NewInt(testAmount100USDC), - makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount2ETHInWei), - makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.UsdcSymbol): big.NewInt(testAmount100USDC), - makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount2ETHInWei), - makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.UsdcSymbol): big.NewInt(testAmount100USDC), - } -) - -var mainnet = params.Network{ - ChainID: walletCommon.EthereumMainnet, - ChainName: "Mainnet", - RPCURL: "https://eth-archival.rpc.grove.city/v1/", - FallbackURL: "https://mainnet.infura.io/v3/", - BlockExplorerURL: "https://etherscan.io/", - IconURL: "network/Network=Ethereum", - ChainColor: "#627EEA", - ShortName: "eth", - NativeCurrencyName: "Ether", - NativeCurrencySymbol: "ETH", - NativeCurrencyDecimals: 18, - IsTest: false, - Layer: 1, - Enabled: true, - RelatedChainID: walletCommon.EthereumMainnet, -} - -var sepolia = params.Network{ - ChainID: walletCommon.EthereumSepolia, - ChainName: "Mainnet", - RPCURL: "https://sepolia-archival.rpc.grove.city/v1/", - FallbackURL: "https://sepolia.infura.io/v3/", - BlockExplorerURL: "https://sepolia.etherscan.io/", - IconURL: "network/Network=Ethereum", - ChainColor: "#627EEA", - ShortName: "eth", - NativeCurrencyName: "Ether", - NativeCurrencySymbol: "ETH", - NativeCurrencyDecimals: 18, - IsTest: true, - Layer: 1, - Enabled: true, - RelatedChainID: walletCommon.EthereumMainnet, -} - -var optimism = params.Network{ - ChainID: walletCommon.OptimismMainnet, - ChainName: "Optimism", - RPCURL: "https://optimism-mainnet.rpc.grove.city/v1/", - FallbackURL: "https://optimism-mainnet.infura.io/v3/", - BlockExplorerURL: "https://optimistic.etherscan.io", - IconURL: "network/Network=Optimism", - ChainColor: "#E90101", - ShortName: "oeth", - NativeCurrencyName: "Ether", - NativeCurrencySymbol: "ETH", - NativeCurrencyDecimals: 18, - IsTest: false, - Layer: 2, - Enabled: true, - RelatedChainID: walletCommon.OptimismMainnet, -} - -var optimismSepolia = params.Network{ - ChainID: walletCommon.OptimismSepolia, - ChainName: "Optimism", - RPCURL: "https://optimism-sepolia-archival.rpc.grove.city/v1/", - FallbackURL: "https://optimism-sepolia.infura.io/v3/", - BlockExplorerURL: "https://sepolia-optimism.etherscan.io/", - IconURL: "network/Network=Optimism", - ChainColor: "#E90101", - ShortName: "oeth", - NativeCurrencyName: "Ether", - NativeCurrencySymbol: "ETH", - NativeCurrencyDecimals: 18, - IsTest: true, - Layer: 2, - Enabled: false, - RelatedChainID: walletCommon.OptimismMainnet, -} - -var arbitrum = params.Network{ - ChainID: walletCommon.ArbitrumMainnet, - ChainName: "Arbitrum", - RPCURL: "https://arbitrum-one.rpc.grove.city/v1/", - FallbackURL: "https://arbitrum-mainnet.infura.io/v3/", - BlockExplorerURL: "https://arbiscan.io/", - IconURL: "network/Network=Arbitrum", - ChainColor: "#51D0F0", - ShortName: "arb1", - NativeCurrencyName: "Ether", - NativeCurrencySymbol: "ETH", - NativeCurrencyDecimals: 18, - IsTest: false, - Layer: 2, - Enabled: true, - RelatedChainID: walletCommon.ArbitrumMainnet, -} - -var arbitrumSepolia = params.Network{ - ChainID: walletCommon.ArbitrumSepolia, - ChainName: "Arbitrum", - RPCURL: "https://arbitrum-sepolia-archival.rpc.grove.city/v1/", - FallbackURL: "https://arbitrum-sepolia.infura.io/v3/", - BlockExplorerURL: "https://sepolia-explorer.arbitrum.io/", - IconURL: "network/Network=Arbitrum", - ChainColor: "#51D0F0", - ShortName: "arb1", - NativeCurrencyName: "Ether", - NativeCurrencySymbol: "ETH", - NativeCurrencyDecimals: 18, - IsTest: true, - Layer: 2, - Enabled: false, - RelatedChainID: walletCommon.ArbitrumMainnet, -} - -var defaultNetworks = []params.Network{ - mainnet, - sepolia, - optimism, - optimismSepolia, - arbitrum, - arbitrumSepolia, -} - func amountOptionEqual(a, b amountOption) bool { return a.amount.Cmp(b.amount) == 0 && a.locked == b.locked } @@ -244,6 +58,26 @@ func amountOptionsMapsEqual(map1, map2 map[uint64][]amountOption) bool { return true } +func assertPathsEqual(t *testing.T, expected, actual []*PathV2) { + assert.Equal(t, len(expected), len(actual)) + + for _, c := range actual { + found := false + for _, expC := range expected { + if c.ProcessorName == expC.ProcessorName && + c.FromChain.ChainID == expC.FromChain.ChainID && + c.ToChain.ChainID == expC.ToChain.ChainID && + c.ApprovalRequired == expC.ApprovalRequired && + (expC.AmountOut == nil || c.AmountOut.ToInt().Cmp(expC.AmountOut.ToInt()) == 0) { + found = true + break + } + } + + assert.True(t, found) + } +} + func setupTestNetworkDB(t *testing.T) (*sql.DB, func()) { db, cleanup, err := helpers.SetupTestSQLDB(appdatabase.DbInitializer{}, "wallet-router-tests") require.NoError(t, err) @@ -287,2524 +121,86 @@ func setupRouter(t *testing.T) (*Router, func()) { return router, cleanTmpDb } +type suggestedRoutesV2ResponseEnvelope struct { + Type string `json:"type"` + Routes SuggestedRoutesV2Response `json:"event"` +} + +func setupSignalHandler(t *testing.T) (chan SuggestedRoutesV2Response, func()) { + suggestedRoutesCh := make(chan SuggestedRoutesV2Response) + 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 suggestedRoutesV2ResponseEnvelope + err := json.Unmarshal(data, &response) + assert.NoError(t, err) + + suggestedRoutesCh <- response.Routes + } + }) + signal.SetMobileSignalHandler(signalHandler) + + closeFn := func() { + close(suggestedRoutesCh) + signal.SetMobileSignalHandler(nil) + } + + return suggestedRoutesCh, closeFn +} + func TestRouterV2(t *testing.T) { router, cleanTmpDb := setupRouter(t) defer cleanTmpDb() - tests := []struct { - name string - input *RouteInputParams - expectedCandidates []*PathV2 - expectedError error - }{ - { - name: "ETH transfer - No Specific FromChain - No Specific ToChain", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - TokenID: pathprocessor.EthSymbol, + suggestedRoutesCh, closeSignalHandler := setupSignalHandler(t) + defer closeSignalHandler() - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - tokenPrices: testTokenPrices, - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &mainnet, - ToChain: &mainnet, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &optimism, - ToChain: &optimism, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &arbitrum, - ToChain: &arbitrum, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &optimism, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &arbitrum, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &mainnet, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &arbitrum, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - ApprovalRequired: false, - }, - }, - }, - { - name: "ETH transfer - No Specific FromChain - Specific Single ToChain", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - TokenID: pathprocessor.EthSymbol, - DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &mainnet, - ToChain: &mainnet, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &mainnet, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: false, - }, - }, - }, - { - name: "ETH transfer - No Specific FromChain - Specific Multiple ToChain", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - TokenID: pathprocessor.EthSymbol, - DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &optimism, - ToChain: &optimism, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &arbitrum, - ToChain: &arbitrum, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &optimism, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &arbitrum, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &arbitrum, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - ApprovalRequired: false, - }, - }, - }, - { - name: "ETH transfer - Specific Single FromChain - No Specific ToChain", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - TokenID: pathprocessor.EthSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &arbitrum, - ToChain: &arbitrum, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - ApprovalRequired: false, - }, - }, - }, - { - name: "ETH transfer - Specific Multiple FromChain - No Specific ToChain", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - TokenID: pathprocessor.EthSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &optimism, - ToChain: &optimism, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &arbitrum, - ToChain: &arbitrum, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &mainnet, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &arbitrum, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - ApprovalRequired: false, - }, - }, - }, - { - name: "ETH transfer - Specific Single FromChain - Specific Single ToChain - Same Chains", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - TokenID: pathprocessor.EthSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &arbitrum, - ToChain: &arbitrum, - ApprovalRequired: false, - }, - }, - }, - { - name: "ETH transfer - Specific Single FromChain - Specific Single ToChain - Different Chains", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - TokenID: pathprocessor.EthSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: false, - }, - }, - }, - { - name: "ETH transfer - Specific Multiple FromChain - Specific Multiple ToChain - Single Common Chain", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - TokenID: pathprocessor.EthSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &arbitrum, - ToChain: &arbitrum, - ApprovalRequired: false, - }, - }, - }, - { - name: "ETH transfer - Specific Multiple FromChain - Specific Multiple ToChain - Multiple Common Chains", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - TokenID: pathprocessor.EthSymbol, - DisabledFromChainIDs: []uint64{walletCommon.OptimismMainnet}, - DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &mainnet, - ToChain: &mainnet, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &arbitrum, - ToChain: &arbitrum, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &arbitrum, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: false, - }, - }, - }, - { - name: "ETH transfer - Specific Multiple FromChain - Specific Multiple ToChain - No Common Chains", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - TokenID: pathprocessor.EthSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: false, - }, - }, - }, - { - name: "ETH transfer - All FromChains Disabled - All ToChains Disabled", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - TokenID: pathprocessor.EthSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, - DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{}, - }, - { - name: "ETH transfer - No Specific FromChain - No Specific ToChain - Single Chain LockedAmount", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - TokenID: pathprocessor.EthSymbol, - FromLockedAmount: map[uint64]*hexutil.Big{ - walletCommon.EthereumMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei)), - }, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &mainnet, - ToChain: &mainnet, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &optimism, - ToChain: &optimism, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point8ETHInWei)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &arbitrum, - ToChain: &arbitrum, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point8ETHInWei)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &optimism, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei - testBonderFeeETH)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &arbitrum, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei - testBonderFeeETH)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &mainnet, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point8ETHInWei - testBonderFeeETH)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &arbitrum, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point8ETHInWei - testBonderFeeETH)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point8ETHInWei - testBonderFeeETH)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point8ETHInWei - testBonderFeeETH)), - ApprovalRequired: false, - }, - }, - }, - { - name: "ETH transfer - No Specific FromChain - Specific ToChain - Single Chain LockedAmount", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - TokenID: pathprocessor.EthSymbol, - DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet}, - FromLockedAmount: map[uint64]*hexutil.Big{ - walletCommon.EthereumMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei)), - walletCommon.ArbitrumMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei)), - }, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &optimism, - ToChain: &optimism, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei - testAmount0Point2ETHInWei - testAmount0Point3ETHInWei)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &optimism, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei - testBonderFeeETH)), //(*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei)), //(big.NewInt(testAmount0Point2ETHInWei - testBonderFeeETH)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei - testBonderFeeETH)), //(*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei)), - ApprovalRequired: false, - }, - }, - }, - { - name: "ETH transfer - No Specific FromChain - No Specific ToChain - Multiple Chains LockedAmount", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - TokenID: pathprocessor.EthSymbol, - FromLockedAmount: map[uint64]*hexutil.Big{ - walletCommon.EthereumMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei)), - walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei)), - }, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &mainnet, - ToChain: &mainnet, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &optimism, - ToChain: &optimism, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &arbitrum, - ToChain: &arbitrum, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point5ETHInWei)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &optimism, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei - testBonderFeeETH)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &arbitrum, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei - testBonderFeeETH)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &mainnet, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei - testBonderFeeETH)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &arbitrum, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei - testBonderFeeETH)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point5ETHInWei - testBonderFeeETH)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point5ETHInWei - testBonderFeeETH)), - ApprovalRequired: false, - }, - }, - }, - { - name: "ETH transfer - No Specific FromChain - No Specific ToChain - All Chains LockedAmount", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - TokenID: pathprocessor.EthSymbol, - FromLockedAmount: map[uint64]*hexutil.Big{ - walletCommon.EthereumMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei)), - walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei)), - walletCommon.ArbitrumMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point5ETHInWei)), - }, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &mainnet, - ToChain: &mainnet, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &optimism, - ToChain: &optimism, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &arbitrum, - ToChain: &arbitrum, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point5ETHInWei)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &optimism, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei - testBonderFeeETH)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &arbitrum, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei - testBonderFeeETH)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &mainnet, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei - testBonderFeeETH)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &arbitrum, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei - testBonderFeeETH)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point5ETHInWei - testBonderFeeETH)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point5ETHInWei - testBonderFeeETH)), - ApprovalRequired: false, - }, - }, - }, - { - name: "ETH transfer - No Specific FromChain - No Specific ToChain - All Chains LockedAmount with insufficient amount", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - TokenID: pathprocessor.EthSymbol, - FromLockedAmount: map[uint64]*hexutil.Big{ - walletCommon.EthereumMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei)), - walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei)), - walletCommon.ArbitrumMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point4ETHInWei)), - }, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedError: ErrLockedAmountLessThanSendAmountAllNetworks, - expectedCandidates: []*PathV2{}, - }, - { - name: "ETH transfer - No Specific FromChain - No Specific ToChain - LockedAmount exceeds sending amount", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - TokenID: pathprocessor.EthSymbol, - FromLockedAmount: map[uint64]*hexutil.Big{ - walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei)), - walletCommon.ArbitrumMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point8ETHInWei)), - }, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedError: ErrLockedAmountExceedsTotalSendAmount, - expectedCandidates: []*PathV2{}, - }, - { - name: "ERC20 transfer - No Specific FromChain - No Specific ToChain", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &mainnet, - ToChain: &mainnet, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &optimism, - ToChain: &optimism, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &arbitrum, - ToChain: &arbitrum, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &optimism, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &arbitrum, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &mainnet, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &arbitrum, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - ApprovalRequired: true, - }, - }, - }, - { - name: "ERC20 transfer - No Specific FromChain - Specific Single ToChain", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &mainnet, - ToChain: &mainnet, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &mainnet, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: true, - }, - }, - }, - { - name: "ERC20 transfer - No Specific FromChain - Specific Multiple ToChain", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &optimism, - ToChain: &optimism, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &arbitrum, - ToChain: &arbitrum, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &optimism, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &arbitrum, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &arbitrum, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - ApprovalRequired: true, - }, - }, - }, - { - name: "ERC20 transfer - Specific Single FromChain - No Specific ToChain", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &arbitrum, - ToChain: &arbitrum, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - ApprovalRequired: true, - }, - }, - }, - { - name: "ERC20 transfer - Specific Multiple FromChain - No Specific ToChain", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &optimism, - ToChain: &optimism, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &arbitrum, - ToChain: &arbitrum, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &mainnet, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &arbitrum, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - ApprovalRequired: true, - }, - }, - }, - { - name: "ERC20 transfer - Specific Single FromChain - Specific Single ToChain - Same Chains", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &arbitrum, - ToChain: &arbitrum, - ApprovalRequired: false, - }, - }, - }, - { - name: "ERC20 transfer - Specific Single FromChain - Specific Single ToChain - Different Chains", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: true, - }, - }, - }, - { - name: "ERC20 transfer - Specific Multiple FromChain - Specific Multiple ToChain - Single Common Chain", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &arbitrum, - ToChain: &arbitrum, - ApprovalRequired: false, - }, - }, - }, - { - name: "ERC20 transfer - Specific Multiple FromChain - Specific Multiple ToChain - Multiple Common Chains", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledFromChainIDs: []uint64{walletCommon.OptimismMainnet}, - DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &mainnet, - ToChain: &mainnet, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &arbitrum, - ToChain: &arbitrum, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &arbitrum, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: true, - }, - }, - }, - { - name: "ERC20 transfer - Specific Multiple FromChain - Specific Multiple ToChain - No Common Chains", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: true, - }, - }, - }, - { - name: "ERC20 transfer - All FromChains Disabled - All ToChains Disabled", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, - DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{}, - }, - { - name: "ERC20 transfer - All FromChains - No Locked Amount - Enough Token Balance Across All Chains", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(2.5 * testAmount100USDC)), - TokenID: pathprocessor.UsdcSymbol, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &mainnet, - ToChain: &mainnet, - AmountOut: (*hexutil.Big)(big.NewInt(2.5 * testAmount100USDC)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &mainnet, - ToChain: &mainnet, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount100USDC)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &optimism, - AmountOut: (*hexutil.Big)(big.NewInt(2.5*testAmount100USDC - testBonderFeeUSDC)), - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &optimism, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount100USDC - testBonderFeeUSDC)), - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &arbitrum, - AmountOut: (*hexutil.Big)(big.NewInt(2.5*testAmount100USDC - testBonderFeeUSDC)), - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &arbitrum, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount100USDC - testBonderFeeUSDC)), - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &optimism, - ToChain: &optimism, - AmountOut: (*hexutil.Big)(big.NewInt(0.5 * testAmount100USDC)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &optimism, - ToChain: &optimism, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount100USDC)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &optimism, - ToChain: &optimism, - AmountOut: (*hexutil.Big)(big.NewInt(2.5 * testAmount100USDC)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &mainnet, - AmountOut: (*hexutil.Big)(big.NewInt(0.5*testAmount100USDC - testBonderFeeUSDC)), - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &mainnet, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount100USDC - testBonderFeeUSDC)), - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &mainnet, - AmountOut: (*hexutil.Big)(big.NewInt(2.5*testAmount100USDC - testBonderFeeUSDC)), - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &arbitrum, - AmountOut: (*hexutil.Big)(big.NewInt(0.5*testAmount100USDC - testBonderFeeUSDC)), - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &arbitrum, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount100USDC - testBonderFeeUSDC)), - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &arbitrum, - AmountOut: (*hexutil.Big)(big.NewInt(2.5*testAmount100USDC - testBonderFeeUSDC)), - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &arbitrum, - ToChain: &arbitrum, - AmountOut: (*hexutil.Big)(big.NewInt(0.5 * testAmount100USDC)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &arbitrum, - ToChain: &arbitrum, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount100USDC)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &arbitrum, - ToChain: &arbitrum, - AmountOut: (*hexutil.Big)(big.NewInt(2.5 * testAmount100USDC)), - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - AmountOut: (*hexutil.Big)(big.NewInt(0.5*testAmount100USDC - testBonderFeeUSDC)), - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount100USDC - testBonderFeeUSDC)), - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - AmountOut: (*hexutil.Big)(big.NewInt(2.5*testAmount100USDC - testBonderFeeUSDC)), - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - AmountOut: (*hexutil.Big)(big.NewInt(0.5*testAmount100USDC - testBonderFeeUSDC)), - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - AmountOut: (*hexutil.Big)(big.NewInt(testAmount100USDC - testBonderFeeUSDC)), - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - AmountOut: (*hexutil.Big)(big.NewInt(2.5*testAmount100USDC - testBonderFeeUSDC)), - ApprovalRequired: true, - }, - }, - }, - { - name: "Bridge - No Specific FromChain - No Specific ToChain", - input: &RouteInputParams{ - testnetMode: false, - SendType: Bridge, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &optimism, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &arbitrum, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &mainnet, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &arbitrum, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - ApprovalRequired: true, - }, - }, - }, - { - name: "Bridge - No Specific FromChain - Specific Single ToChain", - input: &RouteInputParams{ - testnetMode: false, - SendType: Bridge, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &mainnet, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: true, - }, - }, - }, - { - name: "Bridge - No Specific FromChain - Specific Multiple ToChain", - input: &RouteInputParams{ - testnetMode: false, - SendType: Bridge, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &optimism, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &arbitrum, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &arbitrum, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - ApprovalRequired: true, - }, - }, - }, - { - name: "Bridge - Specific Single FromChain - No Specific ToChain", - input: &RouteInputParams{ - testnetMode: false, - SendType: Bridge, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - ApprovalRequired: true, - }, - }, - }, - { - name: "Bridge - Specific Multiple FromChain - No Specific ToChain", - input: &RouteInputParams{ - testnetMode: false, - SendType: Bridge, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &mainnet, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &optimism, - ToChain: &arbitrum, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - ApprovalRequired: true, - }, - }, - }, - { - name: "Bridge - Specific Single FromChain - Specific Single ToChain - Same Chains", - input: &RouteInputParams{ - testnetMode: false, - SendType: Bridge, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{}, - }, - { - name: "Bridge - Specific Single FromChain - Specific Single ToChain - Different Chains", - input: &RouteInputParams{ - testnetMode: false, - SendType: Bridge, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: true, - }, - }, - }, - { - name: "Bridge - Specific Multiple FromChain - Specific Multiple ToChain - Single Common Chain", - input: &RouteInputParams{ - testnetMode: false, - SendType: Bridge, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{}, - }, - { - name: "Bridge - Specific Multiple FromChain - Specific Multiple ToChain - Multiple Common Chains", - input: &RouteInputParams{ - testnetMode: false, - SendType: Bridge, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledFromChainIDs: []uint64{walletCommon.OptimismMainnet}, - DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &arbitrum, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: true, - }, - }, - }, - { - name: "Bridge - Specific Multiple FromChain - Specific Multiple ToChain - No Common Chains", - input: &RouteInputParams{ - testnetMode: false, - SendType: Bridge, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, - DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &mainnet, - ApprovalRequired: true, - }, - }, - }, - { - name: "Bridge - All FromChains Disabled - All ToChains Disabled", - input: &RouteInputParams{ - testnetMode: false, - SendType: Bridge, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, - DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - baseFee: big.NewInt(testBaseFee), - suggestedFees: testSuggestedFees, - balanceMap: testBalanceMapPerChain, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{}, - }, - } + tests := getNormalTestParamsList() + // Test blocking endpoints for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - routes, err := router.SuggestedRoutesV2(context.Background(), tt.input) if tt.expectedError != nil { assert.Error(t, err) - assert.Equal(t, tt.expectedError, err) + assert.Equal(t, tt.expectedError.Error(), err.Error()) assert.Nil(t, routes) } else { assert.NoError(t, err) - assert.Equal(t, len(tt.expectedCandidates), len(routes.Candidates)) - - for _, c := range routes.Candidates { - found := false - for _, expC := range tt.expectedCandidates { - if c.ProcessorName == expC.ProcessorName && - c.FromChain.ChainID == expC.FromChain.ChainID && - c.ToChain.ChainID == expC.ToChain.ChainID && - c.ApprovalRequired == expC.ApprovalRequired && - (expC.AmountOut == nil || c.AmountOut.ToInt().Cmp(expC.AmountOut.ToInt()) == 0) { - found = true - break - } - } - - assert.True(t, found) - } + assertPathsEqual(t, tt.expectedCandidates, routes.Candidates) } }) } + + // Test async endpoints + for _, tt := range tests { + router.SuggestedRoutesV2Async(tt.input) + + select { + case asyncRoutes := <-suggestedRoutesCh: + assert.Equal(t, tt.input.Uuid, asyncRoutes.Uuid) + assert.Equal(t, tt.expectedError, asyncRoutes.ErrorResponse) + assertPathsEqual(t, tt.expectedCandidates, asyncRoutes.Candidates) + break + case <-time.After(10 * time.Second): + t.FailNow() + } + } } func TestNoBalanceForTheBestRouteRouterV2(t *testing.T) { router, cleanTmpDb := setupRouter(t) defer cleanTmpDb() - tests := []struct { - name string - input *RouteInputParams - expectedCandidates []*PathV2 - expectedBest []*PathV2 - expectedError error - }{ - { - name: "ERC20 transfer - Specific FromChain - Specific ToChain - Not Enough Token Balance", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount100USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet}, - DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet}, + suggestedRoutesCh, closeSignalHandler := setupSignalHandler(t) + defer closeSignalHandler() - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - suggestedFees: testSuggestedFees, - balanceMap: map[string]*big.Int{ - makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.UsdcSymbol): big.NewInt(0), - }, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedError: ErrNotEnoughTokenBalance, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &optimism, - ToChain: &optimism, - ApprovalRequired: false, - requiredTokenBalance: big.NewInt(testAmount100USDC), - requiredNativeBalance: big.NewInt((testBaseFee + testPriorityFeeLow) * testApprovalGasEstimation), - }, - }, - }, - { - name: "ERC20 transfer - Specific FromChain - Specific ToChain - Not Enough Native Balance", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount100USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet}, - DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - suggestedFees: testSuggestedFees, - balanceMap: map[string]*big.Int{ - makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.UsdcSymbol): big.NewInt(testAmount100USDC), - makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.EthSymbol): big.NewInt(0), - }, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedError: ErrNotEnoughNativeBalance, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &optimism, - ToChain: &optimism, - ApprovalRequired: false, - requiredTokenBalance: big.NewInt(testAmount100USDC), - requiredNativeBalance: big.NewInt((testBaseFee + testPriorityFeeLow) * testApprovalGasEstimation), - }, - }, - }, - { - name: "ERC20 transfer - No Specific FromChain - Specific ToChain - Not Enough Token Balance Across All Chains", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount100USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - suggestedFees: testSuggestedFees, - balanceMap: map[string]*big.Int{ - makeBalanceKey(walletCommon.EthereumMainnet, pathprocessor.UsdcSymbol): big.NewInt(0), - makeBalanceKey(walletCommon.EthereumMainnet, pathprocessor.EthSymbol): big.NewInt(0), - makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.UsdcSymbol): big.NewInt(0), - makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.EthSymbol): big.NewInt(0), - makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.UsdcSymbol): big.NewInt(0), - makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.EthSymbol): big.NewInt(0), - }, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedError: ErrNotEnoughTokenBalance, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &optimism, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &optimism, - ToChain: &optimism, - ApprovalRequired: false, - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - ApprovalRequired: true, - }, - }, - }, - { - name: "ERC20 transfer - No Specific FromChain - Specific ToChain - Enough Token Balance On Arbitrum Chain But Not Enough Native Balance", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount100USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - suggestedFees: testSuggestedFees, - balanceMap: map[string]*big.Int{ - makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.UsdcSymbol): big.NewInt(testAmount100USDC + testAmount100USDC), - makeBalanceKey(walletCommon.EthereumMainnet, pathprocessor.UsdcSymbol): big.NewInt(testAmount100USDC + testAmount100USDC), - makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.UsdcSymbol): big.NewInt(testAmount100USDC + testAmount100USDC), - makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.EthSymbol): big.NewInt(0), - makeBalanceKey(walletCommon.EthereumMainnet, pathprocessor.EthSymbol): big.NewInt(0), - makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.EthSymbol): big.NewInt(0), - }, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedError: ErrNotEnoughNativeBalance, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &optimism, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &optimism, - ToChain: &optimism, - ApprovalRequired: false, - requiredTokenBalance: big.NewInt(testAmount100USDC), - requiredNativeBalance: big.NewInt((testBaseFee + testPriorityFeeLow) * testApprovalGasEstimation), - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - ApprovalRequired: true, - }, - }, - }, - { - name: "ERC20 transfer - No Specific FromChain - Specific ToChain - Enough Token Balance On Arbitrum Chain And Enough Native Balance On Arbitrum Chain", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AddrFrom: common.HexToAddress("0x1"), - AddrTo: common.HexToAddress("0x2"), - AmountIn: (*hexutil.Big)(big.NewInt(testAmount100USDC)), - TokenID: pathprocessor.UsdcSymbol, - DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.UsdcSymbol, - Decimals: 6, - }, - tokenPrices: testTokenPrices, - suggestedFees: testSuggestedFees, - balanceMap: map[string]*big.Int{ - makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.UsdcSymbol): big.NewInt(testAmount100USDC + testAmount100USDC), - makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount1ETHInWei), - }, - estimationMap: testEstimationMap, - bonderFeeMap: testBbonderFeeMap, - approvalGasEstimation: testApprovalGasEstimation, - approvalL1Fee: testApprovalL1Fee, - }, - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &mainnet, - ToChain: &optimism, - ApprovalRequired: true, - }, - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &optimism, - ToChain: &optimism, - ApprovalRequired: false, - requiredTokenBalance: big.NewInt(testAmount100USDC), - requiredNativeBalance: big.NewInt((testBaseFee + testPriorityFeeLow) * testApprovalGasEstimation), - }, - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - ApprovalRequired: true, - }, - }, - expectedBest: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorBridgeHopName, - FromChain: &arbitrum, - ToChain: &optimism, - ApprovalRequired: true, - }, - }, - }, - } + tests := getNoBalanceTestParamsList() + // Test blocking endpoints for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -2812,473 +208,43 @@ func TestNoBalanceForTheBestRouteRouterV2(t *testing.T) { if tt.expectedError != nil { assert.Error(t, err) - assert.Equal(t, tt.expectedError, err) + assert.Equal(t, tt.expectedError.Error(), err.Error()) assert.NotNil(t, routes) - assert.Equal(t, len(tt.expectedCandidates), len(routes.Candidates)) + assertPathsEqual(t, tt.expectedCandidates, routes.Candidates) } else { assert.NoError(t, err) assert.Equal(t, len(tt.expectedCandidates), len(routes.Candidates)) assert.Equal(t, len(tt.expectedBest), len(routes.Best)) - - for _, c := range routes.Candidates { - found := false - for _, expC := range tt.expectedCandidates { - if c.ProcessorName == expC.ProcessorName && - c.FromChain.ChainID == expC.FromChain.ChainID && - c.ToChain.ChainID == expC.ToChain.ChainID && - c.ApprovalRequired == expC.ApprovalRequired && - (expC.AmountOut == nil || c.AmountOut.ToInt().Cmp(expC.AmountOut.ToInt()) == 0) { - found = true - break - } - } - - assert.True(t, found) - } - - for _, c := range routes.Best { - found := false - for _, expC := range tt.expectedBest { - if c.ProcessorName == expC.ProcessorName && - c.FromChain.ChainID == expC.FromChain.ChainID && - c.ToChain.ChainID == expC.ToChain.ChainID && - c.ApprovalRequired == expC.ApprovalRequired && - (expC.AmountOut == nil || c.AmountOut.ToInt().Cmp(expC.AmountOut.ToInt()) == 0) { - found = true - break - } - } - - assert.True(t, found) - } + assertPathsEqual(t, tt.expectedCandidates, routes.Candidates) + assertPathsEqual(t, tt.expectedBest, routes.Best) } }) } + + // Test async endpoints + for _, tt := range tests { + router.SuggestedRoutesV2Async(tt.input) + + select { + case asyncRoutes := <-suggestedRoutesCh: + assert.Equal(t, tt.input.Uuid, asyncRoutes.Uuid) + assert.Equal(t, tt.expectedError, asyncRoutes.ErrorResponse) + assertPathsEqual(t, tt.expectedCandidates, asyncRoutes.Candidates) + if tt.expectedError == nil { + assertPathsEqual(t, tt.expectedBest, asyncRoutes.Best) + } + break + case <-time.After(10 * time.Second): + t.FailNow() + } + } } func TestAmountOptions(t *testing.T) { router, cleanTmpDb := setupRouter(t) defer cleanTmpDb() - tests := []struct { - name string - input *RouteInputParams - expectedAmountOptions map[uint64][]amountOption - }{ - { - name: "Transfer - Single From Chain - No Locked Amount", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - TokenID: pathprocessor.EthSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet}, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - balanceMap: map[string]*big.Int{}, - }, - }, - expectedAmountOptions: map[uint64][]amountOption{ - walletCommon.OptimismMainnet: { - { - amount: big.NewInt(testAmount1ETHInWei), - locked: false, - }, - }, - }, - }, - { - name: "Transfer - Single From Chain - Locked Amount To Single Chain Equal Total Amount", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - TokenID: pathprocessor.EthSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet}, - FromLockedAmount: map[uint64]*hexutil.Big{ - walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - }, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - balanceMap: map[string]*big.Int{}, - }, - }, - expectedAmountOptions: map[uint64][]amountOption{ - walletCommon.OptimismMainnet: { - { - amount: big.NewInt(testAmount1ETHInWei), - locked: true, - }, - }, - }, - }, - { - name: "Transfer - Multiple From Chains - Locked Amount To Single Chain Is Less Than Total Amount", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AmountIn: (*hexutil.Big)(big.NewInt(testAmount2ETHInWei)), - TokenID: pathprocessor.EthSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet}, - FromLockedAmount: map[uint64]*hexutil.Big{ - walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - }, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - balanceMap: map[string]*big.Int{}, - }, - }, - expectedAmountOptions: map[uint64][]amountOption{ - walletCommon.OptimismMainnet: { - { - amount: big.NewInt(testAmount1ETHInWei), - locked: true, - }, - }, - walletCommon.ArbitrumMainnet: { - { - amount: big.NewInt(testAmount1ETHInWei), - locked: false, - }, - }, - }, - }, - { - name: "Transfer - Multiple From Chains - Locked Amount To Multiple Chains", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AmountIn: (*hexutil.Big)(big.NewInt(testAmount2ETHInWei)), - TokenID: pathprocessor.EthSymbol, - DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet}, - FromLockedAmount: map[uint64]*hexutil.Big{ - walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - walletCommon.ArbitrumMainnet: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - }, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - balanceMap: map[string]*big.Int{}, - }, - }, - expectedAmountOptions: map[uint64][]amountOption{ - walletCommon.OptimismMainnet: { - { - amount: big.NewInt(testAmount1ETHInWei), - locked: true, - }, - }, - walletCommon.ArbitrumMainnet: { - { - amount: big.NewInt(testAmount1ETHInWei), - locked: true, - }, - }, - }, - }, - { - name: "Transfer - All From Chains - Locked Amount To Multiple Chains Equal Total Amount", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AmountIn: (*hexutil.Big)(big.NewInt(testAmount2ETHInWei)), - TokenID: pathprocessor.EthSymbol, - FromLockedAmount: map[uint64]*hexutil.Big{ - walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - walletCommon.ArbitrumMainnet: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - }, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - balanceMap: map[string]*big.Int{}, - }, - }, - expectedAmountOptions: map[uint64][]amountOption{ - walletCommon.OptimismMainnet: { - { - amount: big.NewInt(testAmount1ETHInWei), - locked: true, - }, - }, - walletCommon.ArbitrumMainnet: { - { - amount: big.NewInt(testAmount1ETHInWei), - locked: true, - }, - }, - }, - }, - { - name: "Transfer - All From Chains - Locked Amount To Multiple Chains Is Less Than Total Amount", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AmountIn: (*hexutil.Big)(big.NewInt(testAmount5ETHInWei)), - TokenID: pathprocessor.EthSymbol, - FromLockedAmount: map[uint64]*hexutil.Big{ - walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - walletCommon.ArbitrumMainnet: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - }, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - balanceMap: map[string]*big.Int{}, - }, - }, - expectedAmountOptions: map[uint64][]amountOption{ - walletCommon.OptimismMainnet: { - { - amount: big.NewInt(testAmount1ETHInWei), - locked: true, - }, - }, - walletCommon.ArbitrumMainnet: { - { - amount: big.NewInt(testAmount1ETHInWei), - locked: true, - }, - }, - walletCommon.EthereumMainnet: { - { - amount: big.NewInt(testAmount3ETHInWei), - locked: false, - }, - }, - }, - }, - { - name: "Transfer - All From Chain - No Locked Amount - Enough Token Balance If All Chains Are Used", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AmountIn: (*hexutil.Big)(big.NewInt(testAmount3ETHInWei)), - TokenID: pathprocessor.EthSymbol, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - balanceMap: map[string]*big.Int{ - makeBalanceKey(walletCommon.EthereumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount1ETHInWei), - makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount1ETHInWei), - makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount1ETHInWei), - }, - }, - }, - expectedAmountOptions: map[uint64][]amountOption{ - walletCommon.OptimismMainnet: { - { - amount: big.NewInt(testAmount3ETHInWei), - locked: false, - }, - { - amount: big.NewInt(testAmount1ETHInWei), - locked: false, - }, - }, - walletCommon.ArbitrumMainnet: { - { - amount: big.NewInt(testAmount3ETHInWei), - locked: false, - }, - { - amount: big.NewInt(testAmount1ETHInWei), - locked: false, - }, - }, - walletCommon.EthereumMainnet: { - { - amount: big.NewInt(testAmount3ETHInWei), - locked: false, - }, - { - amount: big.NewInt(testAmount1ETHInWei), - locked: false, - }, - }, - }, - }, - { - name: "Transfer - All From Chain - Locked Amount To Single Chain - Enough Token Balance If All Chains Are Used", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AmountIn: (*hexutil.Big)(big.NewInt(testAmount3ETHInWei)), - TokenID: pathprocessor.EthSymbol, - FromLockedAmount: map[uint64]*hexutil.Big{ - walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point5ETHInWei)), - }, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - balanceMap: map[string]*big.Int{ - makeBalanceKey(walletCommon.EthereumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount2ETHInWei), - makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount1ETHInWei), - makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount3ETHInWei), - }, - }, - }, - expectedAmountOptions: map[uint64][]amountOption{ - walletCommon.OptimismMainnet: { - { - amount: big.NewInt(testAmount0Point5ETHInWei), - locked: true, - }, - }, - walletCommon.ArbitrumMainnet: { - { - amount: big.NewInt(testAmount2ETHInWei + testAmount0Point5ETHInWei), - locked: false, - }, - { - amount: big.NewInt(testAmount0Point5ETHInWei), - locked: false, - }, - }, - walletCommon.EthereumMainnet: { - { - amount: big.NewInt(testAmount2ETHInWei + testAmount0Point5ETHInWei), - locked: false, - }, - { - amount: big.NewInt(testAmount2ETHInWei), - locked: false, - }, - }, - }, - }, - { - name: "Transfer - All From Chain - Locked Amount To Multiple Chains - Enough Token Balance If All Chains Are Used", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AmountIn: (*hexutil.Big)(big.NewInt(testAmount3ETHInWei)), - TokenID: pathprocessor.EthSymbol, - FromLockedAmount: map[uint64]*hexutil.Big{ - walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point5ETHInWei)), - walletCommon.EthereumMainnet: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), - }, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - balanceMap: map[string]*big.Int{ - makeBalanceKey(walletCommon.EthereumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount2ETHInWei), - makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount1ETHInWei), - makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount3ETHInWei), - }, - }, - }, - expectedAmountOptions: map[uint64][]amountOption{ - walletCommon.OptimismMainnet: { - { - amount: big.NewInt(testAmount0Point5ETHInWei), - locked: true, - }, - }, - walletCommon.ArbitrumMainnet: { - { - amount: big.NewInt(testAmount1ETHInWei + testAmount0Point5ETHInWei), - locked: false, - }, - }, - walletCommon.EthereumMainnet: { - { - amount: big.NewInt(testAmount1ETHInWei), - locked: true, - }, - }, - }, - }, - { - name: "Transfer - All From Chain - No Locked Amount - Not Enough Token Balance", - input: &RouteInputParams{ - testnetMode: false, - SendType: Transfer, - AmountIn: (*hexutil.Big)(big.NewInt(testAmount5ETHInWei)), - TokenID: pathprocessor.EthSymbol, - - testsMode: true, - testParams: &routerTestParams{ - tokenFrom: &token.Token{ - ChainID: 1, - Symbol: pathprocessor.EthSymbol, - Decimals: 18, - }, - balanceMap: map[string]*big.Int{ - makeBalanceKey(walletCommon.EthereumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount1ETHInWei), - makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount1ETHInWei), - makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount1ETHInWei), - }, - }, - }, - expectedAmountOptions: map[uint64][]amountOption{ - walletCommon.OptimismMainnet: { - { - amount: big.NewInt(testAmount5ETHInWei), - locked: false, - }, - }, - walletCommon.ArbitrumMainnet: { - { - amount: big.NewInt(testAmount5ETHInWei), - locked: false, - }, - }, - walletCommon.EthereumMainnet: { - { - amount: big.NewInt(testAmount5ETHInWei), - locked: false, - }, - }, - }, - }, - } + tests := getAmountOptionsTestParamsList() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/services/wallet/router/router_v2_test_data.go b/services/wallet/router/router_v2_test_data.go new file mode 100644 index 000000000..9a84901d7 --- /dev/null +++ b/services/wallet/router/router_v2_test_data.go @@ -0,0 +1,3163 @@ +package router + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + + "github.com/google/uuid" + + "github.com/status-im/status-go/errors" + "github.com/status-im/status-go/params" + walletCommon "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/token" +) + +const ( + testBaseFee = 50000000000 + testGasPrice = 10000000000 + testPriorityFeeLow = 1000000000 + testPriorityFeeMedium = 2000000000 + testPriorityFeeHigh = 3000000000 + testBonderFeeETH = 150000000000000 + testBonderFeeUSDC = 10000 + + testAmount0Point1ETHInWei = 100000000000000000 + testAmount0Point2ETHInWei = 200000000000000000 + testAmount0Point3ETHInWei = 300000000000000000 + testAmount0Point4ETHInWei = 400000000000000000 + testAmount0Point5ETHInWei = 500000000000000000 + testAmount0Point6ETHInWei = 600000000000000000 + testAmount0Point8ETHInWei = 800000000000000000 + testAmount1ETHInWei = 1000000000000000000 + testAmount2ETHInWei = 2000000000000000000 + testAmount3ETHInWei = 3000000000000000000 + testAmount5ETHInWei = 5000000000000000000 + + testAmount1USDC = 1000000 + testAmount100USDC = 100000000 + + testApprovalGasEstimation = 1000 + testApprovalL1Fee = 100000000000 +) + +var ( + testEstimationMap = map[string]uint64{ + pathprocessor.ProcessorTransferName: uint64(1000), + pathprocessor.ProcessorBridgeHopName: uint64(5000), + } + + testBbonderFeeMap = map[string]*big.Int{ + pathprocessor.EthSymbol: big.NewInt(testBonderFeeETH), + pathprocessor.UsdcSymbol: big.NewInt(testBonderFeeUSDC), + } + + testTokenPrices = map[string]float64{ + pathprocessor.EthSymbol: 2000, + pathprocessor.UsdcSymbol: 1, + } + + testSuggestedFees = &SuggestedFees{ + GasPrice: big.NewInt(testGasPrice), + BaseFee: big.NewInt(testBaseFee), + MaxPriorityFeePerGas: big.NewInt(testPriorityFeeLow), + MaxFeesLevels: &MaxFeesLevels{ + Low: (*hexutil.Big)(big.NewInt(testPriorityFeeLow)), + Medium: (*hexutil.Big)(big.NewInt(testPriorityFeeMedium)), + High: (*hexutil.Big)(big.NewInt(testPriorityFeeHigh)), + }, + EIP1559Enabled: false, + } + + testBalanceMapPerChain = map[string]*big.Int{ + makeBalanceKey(walletCommon.EthereumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount2ETHInWei), + makeBalanceKey(walletCommon.EthereumMainnet, pathprocessor.UsdcSymbol): big.NewInt(testAmount100USDC), + makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount2ETHInWei), + makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.UsdcSymbol): big.NewInt(testAmount100USDC), + makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount2ETHInWei), + makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.UsdcSymbol): big.NewInt(testAmount100USDC), + } +) + +var mainnet = params.Network{ + ChainID: walletCommon.EthereumMainnet, + ChainName: "Mainnet", + RPCURL: "https://eth-archival.rpc.grove.city/v1/", + FallbackURL: "https://mainnet.infura.io/v3/", + BlockExplorerURL: "https://etherscan.io/", + IconURL: "network/Network=Ethereum", + ChainColor: "#627EEA", + ShortName: "eth", + NativeCurrencyName: "Ether", + NativeCurrencySymbol: "ETH", + NativeCurrencyDecimals: 18, + IsTest: false, + Layer: 1, + Enabled: true, + RelatedChainID: walletCommon.EthereumMainnet, +} + +var sepolia = params.Network{ + ChainID: walletCommon.EthereumSepolia, + ChainName: "Mainnet", + RPCURL: "https://sepolia-archival.rpc.grove.city/v1/", + FallbackURL: "https://sepolia.infura.io/v3/", + BlockExplorerURL: "https://sepolia.etherscan.io/", + IconURL: "network/Network=Ethereum", + ChainColor: "#627EEA", + ShortName: "eth", + NativeCurrencyName: "Ether", + NativeCurrencySymbol: "ETH", + NativeCurrencyDecimals: 18, + IsTest: true, + Layer: 1, + Enabled: true, + RelatedChainID: walletCommon.EthereumMainnet, +} + +var optimism = params.Network{ + ChainID: walletCommon.OptimismMainnet, + ChainName: "Optimism", + RPCURL: "https://optimism-mainnet.rpc.grove.city/v1/", + FallbackURL: "https://optimism-mainnet.infura.io/v3/", + BlockExplorerURL: "https://optimistic.etherscan.io", + IconURL: "network/Network=Optimism", + ChainColor: "#E90101", + ShortName: "oeth", + NativeCurrencyName: "Ether", + NativeCurrencySymbol: "ETH", + NativeCurrencyDecimals: 18, + IsTest: false, + Layer: 2, + Enabled: true, + RelatedChainID: walletCommon.OptimismMainnet, +} + +var optimismSepolia = params.Network{ + ChainID: walletCommon.OptimismSepolia, + ChainName: "Optimism", + RPCURL: "https://optimism-sepolia-archival.rpc.grove.city/v1/", + FallbackURL: "https://optimism-sepolia.infura.io/v3/", + BlockExplorerURL: "https://sepolia-optimism.etherscan.io/", + IconURL: "network/Network=Optimism", + ChainColor: "#E90101", + ShortName: "oeth", + NativeCurrencyName: "Ether", + NativeCurrencySymbol: "ETH", + NativeCurrencyDecimals: 18, + IsTest: true, + Layer: 2, + Enabled: false, + RelatedChainID: walletCommon.OptimismMainnet, +} + +var arbitrum = params.Network{ + ChainID: walletCommon.ArbitrumMainnet, + ChainName: "Arbitrum", + RPCURL: "https://arbitrum-one.rpc.grove.city/v1/", + FallbackURL: "https://arbitrum-mainnet.infura.io/v3/", + BlockExplorerURL: "https://arbiscan.io/", + IconURL: "network/Network=Arbitrum", + ChainColor: "#51D0F0", + ShortName: "arb1", + NativeCurrencyName: "Ether", + NativeCurrencySymbol: "ETH", + NativeCurrencyDecimals: 18, + IsTest: false, + Layer: 2, + Enabled: true, + RelatedChainID: walletCommon.ArbitrumMainnet, +} + +var arbitrumSepolia = params.Network{ + ChainID: walletCommon.ArbitrumSepolia, + ChainName: "Arbitrum", + RPCURL: "https://arbitrum-sepolia-archival.rpc.grove.city/v1/", + FallbackURL: "https://arbitrum-sepolia.infura.io/v3/", + BlockExplorerURL: "https://sepolia-explorer.arbitrum.io/", + IconURL: "network/Network=Arbitrum", + ChainColor: "#51D0F0", + ShortName: "arb1", + NativeCurrencyName: "Ether", + NativeCurrencySymbol: "ETH", + NativeCurrencyDecimals: 18, + IsTest: true, + Layer: 2, + Enabled: false, + RelatedChainID: walletCommon.ArbitrumMainnet, +} + +var defaultNetworks = []params.Network{ + mainnet, + sepolia, + optimism, + optimismSepolia, + arbitrum, + arbitrumSepolia, +} + +type normalTestParams struct { + name string + input *RouteInputParams + expectedCandidates []*PathV2 + expectedError *errors.ErrorResponse +} + +func getNormalTestParamsList() []normalTestParams { + return []normalTestParams{ + { + name: "ETH transfer - No Specific FromChain - No Specific ToChain", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + TokenID: pathprocessor.EthSymbol, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + tokenPrices: testTokenPrices, + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &mainnet, + ToChain: &mainnet, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &optimism, + ToChain: &optimism, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &arbitrum, + ToChain: &arbitrum, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &optimism, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &arbitrum, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &mainnet, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &arbitrum, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + ApprovalRequired: false, + }, + }, + }, + { + name: "ETH transfer - No Specific FromChain - Specific Single ToChain", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + TokenID: pathprocessor.EthSymbol, + DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &mainnet, + ToChain: &mainnet, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &mainnet, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: false, + }, + }, + }, + { + name: "ETH transfer - No Specific FromChain - Specific Multiple ToChain", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + TokenID: pathprocessor.EthSymbol, + DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &optimism, + ToChain: &optimism, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &arbitrum, + ToChain: &arbitrum, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &optimism, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &arbitrum, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &arbitrum, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + ApprovalRequired: false, + }, + }, + }, + { + name: "ETH transfer - Specific Single FromChain - No Specific ToChain", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + TokenID: pathprocessor.EthSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &arbitrum, + ToChain: &arbitrum, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + ApprovalRequired: false, + }, + }, + }, + { + name: "ETH transfer - Specific Multiple FromChain - No Specific ToChain", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + TokenID: pathprocessor.EthSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &optimism, + ToChain: &optimism, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &arbitrum, + ToChain: &arbitrum, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &mainnet, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &arbitrum, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + ApprovalRequired: false, + }, + }, + }, + { + name: "ETH transfer - Specific Single FromChain - Specific Single ToChain - Same Chains", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + TokenID: pathprocessor.EthSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &arbitrum, + ToChain: &arbitrum, + ApprovalRequired: false, + }, + }, + }, + { + name: "ETH transfer - Specific Single FromChain - Specific Single ToChain - Different Chains", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + TokenID: pathprocessor.EthSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: false, + }, + }, + }, + { + name: "ETH transfer - Specific Multiple FromChain - Specific Multiple ToChain - Single Common Chain", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + TokenID: pathprocessor.EthSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &arbitrum, + ToChain: &arbitrum, + ApprovalRequired: false, + }, + }, + }, + { + name: "ETH transfer - Specific Multiple FromChain - Specific Multiple ToChain - Multiple Common Chains", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + TokenID: pathprocessor.EthSymbol, + DisabledFromChainIDs: []uint64{walletCommon.OptimismMainnet}, + DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &mainnet, + ToChain: &mainnet, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &arbitrum, + ToChain: &arbitrum, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &arbitrum, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: false, + }, + }, + }, + { + name: "ETH transfer - Specific Multiple FromChain - Specific Multiple ToChain - No Common Chains", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + TokenID: pathprocessor.EthSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: false, + }, + }, + }, + { + name: "ETH transfer - All FromChains Disabled - All ToChains Disabled", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + TokenID: pathprocessor.EthSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, + DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{}, + }, + { + name: "ETH transfer - No Specific FromChain - No Specific ToChain - Single Chain LockedAmount", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + TokenID: pathprocessor.EthSymbol, + FromLockedAmount: map[uint64]*hexutil.Big{ + walletCommon.EthereumMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei)), + }, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &mainnet, + ToChain: &mainnet, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &optimism, + ToChain: &optimism, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point8ETHInWei)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &arbitrum, + ToChain: &arbitrum, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point8ETHInWei)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &optimism, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei - testBonderFeeETH)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &arbitrum, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei - testBonderFeeETH)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &mainnet, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point8ETHInWei - testBonderFeeETH)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &arbitrum, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point8ETHInWei - testBonderFeeETH)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point8ETHInWei - testBonderFeeETH)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point8ETHInWei - testBonderFeeETH)), + ApprovalRequired: false, + }, + }, + }, + { + name: "ETH transfer - No Specific FromChain - Specific ToChain - Single Chain LockedAmount", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + TokenID: pathprocessor.EthSymbol, + DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet}, + FromLockedAmount: map[uint64]*hexutil.Big{ + walletCommon.EthereumMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei)), + walletCommon.ArbitrumMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei)), + }, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &optimism, + ToChain: &optimism, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei - testAmount0Point2ETHInWei - testAmount0Point3ETHInWei)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &optimism, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei - testBonderFeeETH)), //(*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei)), //(big.NewInt(testAmount0Point2ETHInWei - testBonderFeeETH)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei - testBonderFeeETH)), //(*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei)), + ApprovalRequired: false, + }, + }, + }, + { + name: "ETH transfer - No Specific FromChain - No Specific ToChain - Multiple Chains LockedAmount", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + TokenID: pathprocessor.EthSymbol, + FromLockedAmount: map[uint64]*hexutil.Big{ + walletCommon.EthereumMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei)), + walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei)), + }, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &mainnet, + ToChain: &mainnet, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &optimism, + ToChain: &optimism, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &arbitrum, + ToChain: &arbitrum, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point5ETHInWei)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &optimism, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei - testBonderFeeETH)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &arbitrum, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei - testBonderFeeETH)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &mainnet, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei - testBonderFeeETH)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &arbitrum, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei - testBonderFeeETH)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point5ETHInWei - testBonderFeeETH)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point5ETHInWei - testBonderFeeETH)), + ApprovalRequired: false, + }, + }, + }, + { + name: "ETH transfer - No Specific FromChain - No Specific ToChain - All Chains LockedAmount", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + TokenID: pathprocessor.EthSymbol, + FromLockedAmount: map[uint64]*hexutil.Big{ + walletCommon.EthereumMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei)), + walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei)), + walletCommon.ArbitrumMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point5ETHInWei)), + }, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &mainnet, + ToChain: &mainnet, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &optimism, + ToChain: &optimism, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &arbitrum, + ToChain: &arbitrum, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point5ETHInWei)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &optimism, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei - testBonderFeeETH)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &arbitrum, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei - testBonderFeeETH)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &mainnet, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei - testBonderFeeETH)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &arbitrum, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei - testBonderFeeETH)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point5ETHInWei - testBonderFeeETH)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount0Point5ETHInWei - testBonderFeeETH)), + ApprovalRequired: false, + }, + }, + }, + { + name: "ETH transfer - No Specific FromChain - No Specific ToChain - All Chains LockedAmount with insufficient amount", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + TokenID: pathprocessor.EthSymbol, + FromLockedAmount: map[uint64]*hexutil.Big{ + walletCommon.EthereumMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point2ETHInWei)), + walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei)), + walletCommon.ArbitrumMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point4ETHInWei)), + }, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedError: ErrLockedAmountLessThanSendAmountAllNetworks, + expectedCandidates: []*PathV2{}, + }, + { + name: "ETH transfer - No Specific FromChain - No Specific ToChain - LockedAmount exceeds sending amount", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + TokenID: pathprocessor.EthSymbol, + FromLockedAmount: map[uint64]*hexutil.Big{ + walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point3ETHInWei)), + walletCommon.ArbitrumMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point8ETHInWei)), + }, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedError: ErrLockedAmountExceedsTotalSendAmount, + expectedCandidates: []*PathV2{}, + }, + { + name: "ERC20 transfer - No Specific FromChain - No Specific ToChain", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &mainnet, + ToChain: &mainnet, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &optimism, + ToChain: &optimism, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &arbitrum, + ToChain: &arbitrum, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &optimism, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &arbitrum, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &mainnet, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &arbitrum, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + ApprovalRequired: true, + }, + }, + }, + { + name: "ERC20 transfer - No Specific FromChain - Specific Single ToChain", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &mainnet, + ToChain: &mainnet, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &mainnet, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: true, + }, + }, + }, + { + name: "ERC20 transfer - No Specific FromChain - Specific Multiple ToChain", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &optimism, + ToChain: &optimism, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &arbitrum, + ToChain: &arbitrum, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &optimism, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &arbitrum, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &arbitrum, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + ApprovalRequired: true, + }, + }, + }, + { + name: "ERC20 transfer - Specific Single FromChain - No Specific ToChain", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &arbitrum, + ToChain: &arbitrum, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + ApprovalRequired: true, + }, + }, + }, + { + name: "ERC20 transfer - Specific Multiple FromChain - No Specific ToChain", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &optimism, + ToChain: &optimism, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &arbitrum, + ToChain: &arbitrum, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &mainnet, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &arbitrum, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + ApprovalRequired: true, + }, + }, + }, + { + name: "ERC20 transfer - Specific Single FromChain - Specific Single ToChain - Same Chains", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &arbitrum, + ToChain: &arbitrum, + ApprovalRequired: false, + }, + }, + }, + { + name: "ERC20 transfer - Specific Single FromChain - Specific Single ToChain - Different Chains", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: true, + }, + }, + }, + { + name: "ERC20 transfer - Specific Multiple FromChain - Specific Multiple ToChain - Single Common Chain", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &arbitrum, + ToChain: &arbitrum, + ApprovalRequired: false, + }, + }, + }, + { + name: "ERC20 transfer - Specific Multiple FromChain - Specific Multiple ToChain - Multiple Common Chains", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledFromChainIDs: []uint64{walletCommon.OptimismMainnet}, + DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &mainnet, + ToChain: &mainnet, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &arbitrum, + ToChain: &arbitrum, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &arbitrum, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: true, + }, + }, + }, + { + name: "ERC20 transfer - Specific Multiple FromChain - Specific Multiple ToChain - No Common Chains", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: true, + }, + }, + }, + { + name: "ERC20 transfer - All FromChains Disabled - All ToChains Disabled", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, + DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{}, + }, + { + name: "ERC20 transfer - All FromChains - No Locked Amount - Enough Token Balance Across All Chains", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(2.5 * testAmount100USDC)), + TokenID: pathprocessor.UsdcSymbol, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &mainnet, + ToChain: &mainnet, + AmountOut: (*hexutil.Big)(big.NewInt(2.5 * testAmount100USDC)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &mainnet, + ToChain: &mainnet, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount100USDC)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &optimism, + AmountOut: (*hexutil.Big)(big.NewInt(2.5*testAmount100USDC - testBonderFeeUSDC)), + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &optimism, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount100USDC - testBonderFeeUSDC)), + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &arbitrum, + AmountOut: (*hexutil.Big)(big.NewInt(2.5*testAmount100USDC - testBonderFeeUSDC)), + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &arbitrum, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount100USDC - testBonderFeeUSDC)), + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &optimism, + ToChain: &optimism, + AmountOut: (*hexutil.Big)(big.NewInt(0.5 * testAmount100USDC)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &optimism, + ToChain: &optimism, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount100USDC)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &optimism, + ToChain: &optimism, + AmountOut: (*hexutil.Big)(big.NewInt(2.5 * testAmount100USDC)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &mainnet, + AmountOut: (*hexutil.Big)(big.NewInt(0.5*testAmount100USDC - testBonderFeeUSDC)), + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &mainnet, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount100USDC - testBonderFeeUSDC)), + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &mainnet, + AmountOut: (*hexutil.Big)(big.NewInt(2.5*testAmount100USDC - testBonderFeeUSDC)), + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &arbitrum, + AmountOut: (*hexutil.Big)(big.NewInt(0.5*testAmount100USDC - testBonderFeeUSDC)), + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &arbitrum, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount100USDC - testBonderFeeUSDC)), + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &arbitrum, + AmountOut: (*hexutil.Big)(big.NewInt(2.5*testAmount100USDC - testBonderFeeUSDC)), + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &arbitrum, + ToChain: &arbitrum, + AmountOut: (*hexutil.Big)(big.NewInt(0.5 * testAmount100USDC)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &arbitrum, + ToChain: &arbitrum, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount100USDC)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &arbitrum, + ToChain: &arbitrum, + AmountOut: (*hexutil.Big)(big.NewInt(2.5 * testAmount100USDC)), + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + AmountOut: (*hexutil.Big)(big.NewInt(0.5*testAmount100USDC - testBonderFeeUSDC)), + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount100USDC - testBonderFeeUSDC)), + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + AmountOut: (*hexutil.Big)(big.NewInt(2.5*testAmount100USDC - testBonderFeeUSDC)), + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + AmountOut: (*hexutil.Big)(big.NewInt(0.5*testAmount100USDC - testBonderFeeUSDC)), + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + AmountOut: (*hexutil.Big)(big.NewInt(testAmount100USDC - testBonderFeeUSDC)), + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + AmountOut: (*hexutil.Big)(big.NewInt(2.5*testAmount100USDC - testBonderFeeUSDC)), + ApprovalRequired: true, + }, + }, + }, + { + name: "Bridge - No Specific FromChain - No Specific ToChain", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Bridge, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &optimism, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &arbitrum, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &mainnet, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &arbitrum, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + ApprovalRequired: true, + }, + }, + }, + { + name: "Bridge - No Specific FromChain - Specific Single ToChain", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Bridge, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &mainnet, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: true, + }, + }, + }, + { + name: "Bridge - No Specific FromChain - Specific Multiple ToChain", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Bridge, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &optimism, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &arbitrum, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &arbitrum, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + ApprovalRequired: true, + }, + }, + }, + { + name: "Bridge - Specific Single FromChain - No Specific ToChain", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Bridge, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + ApprovalRequired: true, + }, + }, + }, + { + name: "Bridge - Specific Multiple FromChain - No Specific ToChain", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Bridge, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &mainnet, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &optimism, + ToChain: &arbitrum, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + ApprovalRequired: true, + }, + }, + }, + { + name: "Bridge - Specific Single FromChain - Specific Single ToChain - Same Chains", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Bridge, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{}, + }, + { + name: "Bridge - Specific Single FromChain - Specific Single ToChain - Different Chains", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Bridge, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: true, + }, + }, + }, + { + name: "Bridge - Specific Multiple FromChain - Specific Multiple ToChain - Single Common Chain", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Bridge, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{}, + }, + { + name: "Bridge - Specific Multiple FromChain - Specific Multiple ToChain - Multiple Common Chains", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Bridge, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledFromChainIDs: []uint64{walletCommon.OptimismMainnet}, + DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &arbitrum, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: true, + }, + }, + }, + { + name: "Bridge - Specific Multiple FromChain - Specific Multiple ToChain - No Common Chains", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Bridge, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet}, + DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &mainnet, + ApprovalRequired: true, + }, + }, + }, + { + name: "Bridge - All FromChains Disabled - All ToChains Disabled", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Bridge, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, + DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + baseFee: big.NewInt(testBaseFee), + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{}, + }, + } +} + +type noBalanceTestParams struct { + name string + input *RouteInputParams + expectedCandidates []*PathV2 + expectedBest []*PathV2 + expectedError *errors.ErrorResponse +} + +func getNoBalanceTestParamsList() []noBalanceTestParams { + return []noBalanceTestParams{ + { + name: "ERC20 transfer - Specific FromChain - Specific ToChain - Not Enough Token Balance", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount100USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet}, + DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + suggestedFees: testSuggestedFees, + balanceMap: map[string]*big.Int{ + makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.UsdcSymbol): big.NewInt(0), + }, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedError: ErrNotEnoughTokenBalance, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &optimism, + ToChain: &optimism, + ApprovalRequired: false, + requiredTokenBalance: big.NewInt(testAmount100USDC), + requiredNativeBalance: big.NewInt((testBaseFee + testPriorityFeeLow) * testApprovalGasEstimation), + }, + }, + }, + { + name: "ERC20 transfer - Specific FromChain - Specific ToChain - Not Enough Native Balance", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount100USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet}, + DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + suggestedFees: testSuggestedFees, + balanceMap: map[string]*big.Int{ + makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.UsdcSymbol): big.NewInt(testAmount100USDC), + makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.EthSymbol): big.NewInt(0), + }, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedError: ErrNotEnoughNativeBalance, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &optimism, + ToChain: &optimism, + ApprovalRequired: false, + requiredTokenBalance: big.NewInt(testAmount100USDC), + requiredNativeBalance: big.NewInt((testBaseFee + testPriorityFeeLow) * testApprovalGasEstimation), + }, + }, + }, + { + name: "ERC20 transfer - No Specific FromChain - Specific ToChain - Not Enough Token Balance Across All Chains", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount100USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + suggestedFees: testSuggestedFees, + balanceMap: map[string]*big.Int{ + makeBalanceKey(walletCommon.EthereumMainnet, pathprocessor.UsdcSymbol): big.NewInt(0), + makeBalanceKey(walletCommon.EthereumMainnet, pathprocessor.EthSymbol): big.NewInt(0), + makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.UsdcSymbol): big.NewInt(0), + makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.EthSymbol): big.NewInt(0), + makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.UsdcSymbol): big.NewInt(0), + makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.EthSymbol): big.NewInt(0), + }, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedError: ErrNotEnoughTokenBalance, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &optimism, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &optimism, + ToChain: &optimism, + ApprovalRequired: false, + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + ApprovalRequired: true, + }, + }, + }, + { + name: "ERC20 transfer - No Specific FromChain - Specific ToChain - Enough Token Balance On Arbitrum Chain But Not Enough Native Balance", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount100USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + suggestedFees: testSuggestedFees, + balanceMap: map[string]*big.Int{ + makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.UsdcSymbol): big.NewInt(testAmount100USDC + testAmount100USDC), + makeBalanceKey(walletCommon.EthereumMainnet, pathprocessor.UsdcSymbol): big.NewInt(testAmount100USDC + testAmount100USDC), + makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.UsdcSymbol): big.NewInt(testAmount100USDC + testAmount100USDC), + makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.EthSymbol): big.NewInt(0), + makeBalanceKey(walletCommon.EthereumMainnet, pathprocessor.EthSymbol): big.NewInt(0), + makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.EthSymbol): big.NewInt(0), + }, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedError: ErrNotEnoughNativeBalance, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &optimism, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &optimism, + ToChain: &optimism, + ApprovalRequired: false, + requiredTokenBalance: big.NewInt(testAmount100USDC), + requiredNativeBalance: big.NewInt((testBaseFee + testPriorityFeeLow) * testApprovalGasEstimation), + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + ApprovalRequired: true, + }, + }, + }, + { + name: "ERC20 transfer - No Specific FromChain - Specific ToChain - Enough Token Balance On Arbitrum Chain And Enough Native Balance On Arbitrum Chain", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AddrFrom: common.HexToAddress("0x1"), + AddrTo: common.HexToAddress("0x2"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount100USDC)), + TokenID: pathprocessor.UsdcSymbol, + DisabledToChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.UsdcSymbol, + Decimals: 6, + }, + tokenPrices: testTokenPrices, + suggestedFees: testSuggestedFees, + balanceMap: map[string]*big.Int{ + makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.UsdcSymbol): big.NewInt(testAmount100USDC + testAmount100USDC), + makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount1ETHInWei), + }, + estimationMap: testEstimationMap, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedCandidates: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &mainnet, + ToChain: &optimism, + ApprovalRequired: true, + }, + { + ProcessorName: pathprocessor.ProcessorTransferName, + FromChain: &optimism, + ToChain: &optimism, + ApprovalRequired: false, + requiredTokenBalance: big.NewInt(testAmount100USDC), + requiredNativeBalance: big.NewInt((testBaseFee + testPriorityFeeLow) * testApprovalGasEstimation), + }, + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + ApprovalRequired: true, + }, + }, + expectedBest: []*PathV2{ + { + ProcessorName: pathprocessor.ProcessorBridgeHopName, + FromChain: &arbitrum, + ToChain: &optimism, + ApprovalRequired: true, + }, + }, + }, + } +} + +type amountOptionsTestParams struct { + name string + input *RouteInputParams + expectedAmountOptions map[uint64][]amountOption +} + +func getAmountOptionsTestParamsList() []amountOptionsTestParams { + return []amountOptionsTestParams{ + { + name: "Transfer - Single From Chain - No Locked Amount", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + TokenID: pathprocessor.EthSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + balanceMap: map[string]*big.Int{}, + }, + }, + expectedAmountOptions: map[uint64][]amountOption{ + walletCommon.OptimismMainnet: { + { + amount: big.NewInt(testAmount1ETHInWei), + locked: false, + }, + }, + }, + }, + { + name: "Transfer - Single From Chain - Locked Amount To Single Chain Equal Total Amount", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AmountIn: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + TokenID: pathprocessor.EthSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet}, + FromLockedAmount: map[uint64]*hexutil.Big{ + walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + }, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + balanceMap: map[string]*big.Int{}, + }, + }, + expectedAmountOptions: map[uint64][]amountOption{ + walletCommon.OptimismMainnet: { + { + amount: big.NewInt(testAmount1ETHInWei), + locked: true, + }, + }, + }, + }, + { + name: "Transfer - Multiple From Chains - Locked Amount To Single Chain Is Less Than Total Amount", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AmountIn: (*hexutil.Big)(big.NewInt(testAmount2ETHInWei)), + TokenID: pathprocessor.EthSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet}, + FromLockedAmount: map[uint64]*hexutil.Big{ + walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + }, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + balanceMap: map[string]*big.Int{}, + }, + }, + expectedAmountOptions: map[uint64][]amountOption{ + walletCommon.OptimismMainnet: { + { + amount: big.NewInt(testAmount1ETHInWei), + locked: true, + }, + }, + walletCommon.ArbitrumMainnet: { + { + amount: big.NewInt(testAmount1ETHInWei), + locked: false, + }, + }, + }, + }, + { + name: "Transfer - Multiple From Chains - Locked Amount To Multiple Chains", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AmountIn: (*hexutil.Big)(big.NewInt(testAmount2ETHInWei)), + TokenID: pathprocessor.EthSymbol, + DisabledFromChainIDs: []uint64{walletCommon.EthereumMainnet}, + FromLockedAmount: map[uint64]*hexutil.Big{ + walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + walletCommon.ArbitrumMainnet: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + }, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + balanceMap: map[string]*big.Int{}, + }, + }, + expectedAmountOptions: map[uint64][]amountOption{ + walletCommon.OptimismMainnet: { + { + amount: big.NewInt(testAmount1ETHInWei), + locked: true, + }, + }, + walletCommon.ArbitrumMainnet: { + { + amount: big.NewInt(testAmount1ETHInWei), + locked: true, + }, + }, + }, + }, + { + name: "Transfer - All From Chains - Locked Amount To Multiple Chains Equal Total Amount", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AmountIn: (*hexutil.Big)(big.NewInt(testAmount2ETHInWei)), + TokenID: pathprocessor.EthSymbol, + FromLockedAmount: map[uint64]*hexutil.Big{ + walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + walletCommon.ArbitrumMainnet: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + }, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + balanceMap: map[string]*big.Int{}, + }, + }, + expectedAmountOptions: map[uint64][]amountOption{ + walletCommon.OptimismMainnet: { + { + amount: big.NewInt(testAmount1ETHInWei), + locked: true, + }, + }, + walletCommon.ArbitrumMainnet: { + { + amount: big.NewInt(testAmount1ETHInWei), + locked: true, + }, + }, + }, + }, + { + name: "Transfer - All From Chains - Locked Amount To Multiple Chains Is Less Than Total Amount", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AmountIn: (*hexutil.Big)(big.NewInt(testAmount5ETHInWei)), + TokenID: pathprocessor.EthSymbol, + FromLockedAmount: map[uint64]*hexutil.Big{ + walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + walletCommon.ArbitrumMainnet: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + }, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + balanceMap: map[string]*big.Int{}, + }, + }, + expectedAmountOptions: map[uint64][]amountOption{ + walletCommon.OptimismMainnet: { + { + amount: big.NewInt(testAmount1ETHInWei), + locked: true, + }, + }, + walletCommon.ArbitrumMainnet: { + { + amount: big.NewInt(testAmount1ETHInWei), + locked: true, + }, + }, + walletCommon.EthereumMainnet: { + { + amount: big.NewInt(testAmount3ETHInWei), + locked: false, + }, + }, + }, + }, + { + name: "Transfer - All From Chain - No Locked Amount - Enough Token Balance If All Chains Are Used", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AmountIn: (*hexutil.Big)(big.NewInt(testAmount3ETHInWei)), + TokenID: pathprocessor.EthSymbol, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + balanceMap: map[string]*big.Int{ + makeBalanceKey(walletCommon.EthereumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount1ETHInWei), + makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount1ETHInWei), + makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount1ETHInWei), + }, + }, + }, + expectedAmountOptions: map[uint64][]amountOption{ + walletCommon.OptimismMainnet: { + { + amount: big.NewInt(testAmount3ETHInWei), + locked: false, + }, + { + amount: big.NewInt(testAmount1ETHInWei), + locked: false, + }, + }, + walletCommon.ArbitrumMainnet: { + { + amount: big.NewInt(testAmount3ETHInWei), + locked: false, + }, + { + amount: big.NewInt(testAmount1ETHInWei), + locked: false, + }, + }, + walletCommon.EthereumMainnet: { + { + amount: big.NewInt(testAmount3ETHInWei), + locked: false, + }, + { + amount: big.NewInt(testAmount1ETHInWei), + locked: false, + }, + }, + }, + }, + { + name: "Transfer - All From Chain - Locked Amount To Single Chain - Enough Token Balance If All Chains Are Used", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AmountIn: (*hexutil.Big)(big.NewInt(testAmount3ETHInWei)), + TokenID: pathprocessor.EthSymbol, + FromLockedAmount: map[uint64]*hexutil.Big{ + walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point5ETHInWei)), + }, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + balanceMap: map[string]*big.Int{ + makeBalanceKey(walletCommon.EthereumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount2ETHInWei), + makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount1ETHInWei), + makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount3ETHInWei), + }, + }, + }, + expectedAmountOptions: map[uint64][]amountOption{ + walletCommon.OptimismMainnet: { + { + amount: big.NewInt(testAmount0Point5ETHInWei), + locked: true, + }, + }, + walletCommon.ArbitrumMainnet: { + { + amount: big.NewInt(testAmount2ETHInWei + testAmount0Point5ETHInWei), + locked: false, + }, + { + amount: big.NewInt(testAmount0Point5ETHInWei), + locked: false, + }, + }, + walletCommon.EthereumMainnet: { + { + amount: big.NewInt(testAmount2ETHInWei + testAmount0Point5ETHInWei), + locked: false, + }, + { + amount: big.NewInt(testAmount2ETHInWei), + locked: false, + }, + }, + }, + }, + { + name: "Transfer - All From Chain - Locked Amount To Multiple Chains - Enough Token Balance If All Chains Are Used", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AmountIn: (*hexutil.Big)(big.NewInt(testAmount3ETHInWei)), + TokenID: pathprocessor.EthSymbol, + FromLockedAmount: map[uint64]*hexutil.Big{ + walletCommon.OptimismMainnet: (*hexutil.Big)(big.NewInt(testAmount0Point5ETHInWei)), + walletCommon.EthereumMainnet: (*hexutil.Big)(big.NewInt(testAmount1ETHInWei)), + }, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + balanceMap: map[string]*big.Int{ + makeBalanceKey(walletCommon.EthereumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount2ETHInWei), + makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount1ETHInWei), + makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount3ETHInWei), + }, + }, + }, + expectedAmountOptions: map[uint64][]amountOption{ + walletCommon.OptimismMainnet: { + { + amount: big.NewInt(testAmount0Point5ETHInWei), + locked: true, + }, + }, + walletCommon.ArbitrumMainnet: { + { + amount: big.NewInt(testAmount1ETHInWei + testAmount0Point5ETHInWei), + locked: false, + }, + }, + walletCommon.EthereumMainnet: { + { + amount: big.NewInt(testAmount1ETHInWei), + locked: true, + }, + }, + }, + }, + { + name: "Transfer - All From Chain - No Locked Amount - Not Enough Token Balance", + input: &RouteInputParams{ + testnetMode: false, + Uuid: uuid.NewString(), + SendType: Transfer, + AmountIn: (*hexutil.Big)(big.NewInt(testAmount5ETHInWei)), + TokenID: pathprocessor.EthSymbol, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + balanceMap: map[string]*big.Int{ + makeBalanceKey(walletCommon.EthereumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount1ETHInWei), + makeBalanceKey(walletCommon.OptimismMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount1ETHInWei), + makeBalanceKey(walletCommon.ArbitrumMainnet, pathprocessor.EthSymbol): big.NewInt(testAmount1ETHInWei), + }, + }, + }, + expectedAmountOptions: map[uint64][]amountOption{ + walletCommon.OptimismMainnet: { + { + amount: big.NewInt(testAmount5ETHInWei), + locked: false, + }, + }, + walletCommon.ArbitrumMainnet: { + { + amount: big.NewInt(testAmount5ETHInWei), + locked: false, + }, + }, + walletCommon.EthereumMainnet: { + { + amount: big.NewInt(testAmount5ETHInWei), + locked: false, + }, + }, + }, + }, + } +}