diff --git a/errors/errors.go b/errors/errors.go index bc4e4020f..9619905ff 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -27,6 +27,28 @@ func IsErrorResponse(err error) bool { return ok } +// ErrorCodeFromError returns the ErrorCode from an error. +func ErrorCodeFromError(err error) ErrorCode { + if err == nil { + return GenericErrorCode + } + if errResp, ok := err.(*ErrorResponse); ok { + return errResp.Code + } + return GenericErrorCode +} + +// DetailsFromError returns the details from an error. +func DetailsFromError(err error) string { + if err == nil { + return "" + } + if errResp, ok := err.(*ErrorResponse); ok { + return errResp.Details + } + return err.Error() +} + // CreateErrorResponseFromError creates an ErrorResponse from a generic error. func CreateErrorResponseFromError(err error) error { if err == nil { diff --git a/services/wallet/router/errors.go b/services/wallet/router/errors.go index 65397047f..a2886b44d 100644 --- a/services/wallet/router/errors.go +++ b/services/wallet/router/errors.go @@ -32,4 +32,5 @@ var ( ErrCannotCheckBalance = &errors.ErrorResponse{Code: errors.ErrorCode("WR-024"), Details: "cannot check balance"} ErrCannotCheckLockedAmounts = &errors.ErrorResponse{Code: errors.ErrorCode("WR-025"), Details: "cannot check locked amounts"} ErrLowAmountInForHopBridge = &errors.ErrorResponse{Code: errors.ErrorCode("WR-026"), Details: "bonder fee greater than estimated received, a higher amount is needed to cover fees"} + ErrNoPositiveBalance = &errors.ErrorResponse{Code: errors.ErrorCode("WR-027"), Details: "no positive balance"} ) diff --git a/services/wallet/router/pathprocessor/processor.go b/services/wallet/router/pathprocessor/processor.go index d337439b4..b9e539f91 100644 --- a/services/wallet/router/pathprocessor/processor.go +++ b/services/wallet/router/pathprocessor/processor.go @@ -56,8 +56,13 @@ type ProcessorInputParams struct { // for testing purposes TestsMode bool - TestEstimationMap map[string]uint64 // [brifge-name, estimated-value] - TestBonderFeeMap map[string]*big.Int // [token-symbol, bonder-fee] + TestEstimationMap map[string]Estimation // [bridge-name, estimation] + TestBonderFeeMap map[string]*big.Int // [token-symbol, bonder-fee] TestApprovalGasEstimation uint64 TestApprovalL1Fee uint64 } + +type Estimation struct { + Value uint64 + Err error +} diff --git a/services/wallet/router/pathprocessor/processor_bridge_celar.go b/services/wallet/router/pathprocessor/processor_bridge_celar.go index 1b11513d1..c1dc85201 100644 --- a/services/wallet/router/pathprocessor/processor_bridge_celar.go +++ b/services/wallet/router/pathprocessor/processor_bridge_celar.go @@ -236,7 +236,7 @@ func (s *CelerBridgeProcessor) EstimateGas(params ProcessorInputParams) (uint64, if params.TestsMode { if params.TestEstimationMap != nil { if val, ok := params.TestEstimationMap[s.Name()]; ok { - return val, nil + return val.Value, val.Err } } return 0, ErrNoEstimationFound diff --git a/services/wallet/router/pathprocessor/processor_bridge_hop.go b/services/wallet/router/pathprocessor/processor_bridge_hop.go index 6c28e26e3..7fe327b06 100644 --- a/services/wallet/router/pathprocessor/processor_bridge_hop.go +++ b/services/wallet/router/pathprocessor/processor_bridge_hop.go @@ -228,7 +228,7 @@ func (h *HopBridgeProcessor) EstimateGas(params ProcessorInputParams) (uint64, e if params.TestsMode { if params.TestEstimationMap != nil { if val, ok := params.TestEstimationMap[h.Name()]; ok { - return val, nil + return val.Value, val.Err } } return 0, ErrNoEstimationFound diff --git a/services/wallet/router/pathprocessor/processor_ens_public_key.go b/services/wallet/router/pathprocessor/processor_ens_public_key.go index 71913bc33..781727835 100644 --- a/services/wallet/router/pathprocessor/processor_ens_public_key.go +++ b/services/wallet/router/pathprocessor/processor_ens_public_key.go @@ -65,7 +65,7 @@ func (s *ENSPublicKeyProcessor) EstimateGas(params ProcessorInputParams) (uint64 if params.TestsMode { if params.TestEstimationMap != nil { if val, ok := params.TestEstimationMap[s.Name()]; ok { - return val, nil + return val.Value, val.Err } } return 0, ErrNoEstimationFound diff --git a/services/wallet/router/pathprocessor/processor_ens_register.go b/services/wallet/router/pathprocessor/processor_ens_register.go index 2eed73c2c..29ec6bfca 100644 --- a/services/wallet/router/pathprocessor/processor_ens_register.go +++ b/services/wallet/router/pathprocessor/processor_ens_register.go @@ -101,7 +101,7 @@ func (s *ENSRegisterProcessor) EstimateGas(params ProcessorInputParams) (uint64, if params.TestsMode { if params.TestEstimationMap != nil { if val, ok := params.TestEstimationMap[s.Name()]; ok { - return val, nil + return val.Value, val.Err } } return 0, ErrNoEstimationFound diff --git a/services/wallet/router/pathprocessor/processor_ens_release.go b/services/wallet/router/pathprocessor/processor_ens_release.go index 70772b8f6..3e9f5943b 100644 --- a/services/wallet/router/pathprocessor/processor_ens_release.go +++ b/services/wallet/router/pathprocessor/processor_ens_release.go @@ -64,7 +64,7 @@ func (s *ENSReleaseProcessor) EstimateGas(params ProcessorInputParams) (uint64, if params.TestsMode { if params.TestEstimationMap != nil { if val, ok := params.TestEstimationMap[s.Name()]; ok { - return val, nil + return val.Value, val.Err } } return 0, ErrNoEstimationFound diff --git a/services/wallet/router/pathprocessor/processor_erc1155.go b/services/wallet/router/pathprocessor/processor_erc1155.go index b4e68710c..02d50a688 100644 --- a/services/wallet/router/pathprocessor/processor_erc1155.go +++ b/services/wallet/router/pathprocessor/processor_erc1155.go @@ -75,7 +75,7 @@ func (s *ERC1155Processor) EstimateGas(params ProcessorInputParams) (uint64, err if params.TestsMode { if params.TestEstimationMap != nil { if val, ok := params.TestEstimationMap[s.Name()]; ok { - return val, nil + return val.Value, val.Err } } return 0, ErrNoEstimationFound diff --git a/services/wallet/router/pathprocessor/processor_erc721.go b/services/wallet/router/pathprocessor/processor_erc721.go index 0f98d93da..35f5814a4 100644 --- a/services/wallet/router/pathprocessor/processor_erc721.go +++ b/services/wallet/router/pathprocessor/processor_erc721.go @@ -112,7 +112,7 @@ func (s *ERC721Processor) EstimateGas(params ProcessorInputParams) (uint64, erro if params.TestsMode { if params.TestEstimationMap != nil { if val, ok := params.TestEstimationMap[s.Name()]; ok { - return val, nil + return val.Value, val.Err } } return 0, ErrNoEstimationFound diff --git a/services/wallet/router/pathprocessor/processor_stickers_buy.go b/services/wallet/router/pathprocessor/processor_stickers_buy.go index 540ad3b6e..5db9d9628 100644 --- a/services/wallet/router/pathprocessor/processor_stickers_buy.go +++ b/services/wallet/router/pathprocessor/processor_stickers_buy.go @@ -93,7 +93,7 @@ func (s *StickersBuyProcessor) EstimateGas(params ProcessorInputParams) (uint64, if params.TestsMode { if params.TestEstimationMap != nil { if val, ok := params.TestEstimationMap[s.Name()]; ok { - return val, nil + return val.Value, val.Err } } return 0, ErrNoEstimationFound diff --git a/services/wallet/router/pathprocessor/processor_swap_paraswap.go b/services/wallet/router/pathprocessor/processor_swap_paraswap.go index 649e02ac6..2759b5dd4 100644 --- a/services/wallet/router/pathprocessor/processor_swap_paraswap.go +++ b/services/wallet/router/pathprocessor/processor_swap_paraswap.go @@ -173,7 +173,7 @@ func (s *SwapParaswapProcessor) EstimateGas(params ProcessorInputParams) (uint64 if params.TestsMode { if params.TestEstimationMap != nil { if val, ok := params.TestEstimationMap[s.Name()]; ok { - return val, nil + return val.Value, val.Err } } return 0, ErrNoEstimationFound diff --git a/services/wallet/router/pathprocessor/processor_test.go b/services/wallet/router/pathprocessor/processor_test.go index 5cd560a4c..242157b24 100644 --- a/services/wallet/router/pathprocessor/processor_test.go +++ b/services/wallet/router/pathprocessor/processor_test.go @@ -47,10 +47,10 @@ var optimism = params.Network{ RelatedChainID: walletCommon.OptimismMainnet, } -var testEstimationMap = map[string]uint64{ - ProcessorTransferName: uint64(1000), - ProcessorBridgeHopName: uint64(5000), - ProcessorSwapParaswapName: uint64(2000), +var testEstimationMap = map[string]Estimation{ + ProcessorTransferName: {uint64(1000), nil}, + ProcessorBridgeHopName: {uint64(5000), nil}, + ProcessorSwapParaswapName: {uint64(2000), nil}, } type expectedResult struct { @@ -329,17 +329,17 @@ func TestPathProcessors(t *testing.T) { assert.Greater(t, estimatedGas, uint64(0)) input := tt.input - input.TestEstimationMap = map[string]uint64{ - "randomName": 10000, + input.TestEstimationMap = map[string]Estimation{ + "randomName": {10000, nil}, } estimatedGas, err = processor.EstimateGas(input) assert.Error(t, err) - assert.Equal(t, err, ErrNoEstimationFound) + assert.Equal(t, ErrNoEstimationFound, err) assert.Equal(t, uint64(0), estimatedGas) } else { estimatedGas, err := processor.EstimateGas(tt.input) assert.Error(t, err) - assert.Equal(t, err, ErrNoEstimationFound) + assert.Equal(t, ErrNoEstimationFound, err) assert.Equal(t, uint64(0), estimatedGas) } }) diff --git a/services/wallet/router/pathprocessor/processor_transfer.go b/services/wallet/router/pathprocessor/processor_transfer.go index 33baf256b..a6a3e3781 100644 --- a/services/wallet/router/pathprocessor/processor_transfer.go +++ b/services/wallet/router/pathprocessor/processor_transfer.go @@ -69,7 +69,7 @@ func (s *TransferProcessor) EstimateGas(params ProcessorInputParams) (uint64, er if params.TestsMode { if params.TestEstimationMap != nil { if val, ok := params.TestEstimationMap[s.Name()]; ok { - return val, nil + return val.Value, val.Err } } return 0, ErrNoEstimationFound diff --git a/services/wallet/router/router.go b/services/wallet/router/router.go index e0693d55e..b46cd33bf 100644 --- a/services/wallet/router/router.go +++ b/services/wallet/router/router.go @@ -308,16 +308,35 @@ func (r *Router) GetPathProcessors() map[string]pathprocessor.PathProcessor { return r.pathProcessors } -func containsNetworkChainID(chainID uint64, chainIDs []uint64) bool { - for _, cID := range chainIDs { - if cID == chainID { +func arrayContainsElement[T comparable](el T, arr []T) bool { + for _, e := range arr { + if e == el { return true } } - return false } +func arraysWithSameElements[T comparable](ar1 []T, ar2 []T, isEqual func(T, T) bool) bool { + if len(ar1) != len(ar2) { + return false + } + for _, el := range ar1 { + if !arrayContainsElement(el, ar2) { + return false + } + } + return true +} + +func sameSingleChainTransfer(fromChains []*params.Network, toChains []*params.Network) bool { + return len(fromChains) == 1 && + len(toChains) == 1 && + arraysWithSameElements(fromChains, toChains, func(a, b *params.Network) bool { + return a.ChainID == b.ChainID + }) +} + type Router struct { rpcClient *rpc.Client tokenManager *token.Manager @@ -484,7 +503,7 @@ func (r *Router) SuggestedRoutes( continue } - if containsNetworkChainID(network.ChainID, disabledFromChainIDs) { + if arrayContainsElement(network.ChainID, disabledFromChainIDs) { continue } @@ -568,10 +587,10 @@ func (r *Router) SuggestedRoutes( continue } - if len(preferedChainIDs) > 0 && !containsNetworkChainID(dest.ChainID, preferedChainIDs) { + if len(preferedChainIDs) > 0 && !arrayContainsElement(dest.ChainID, preferedChainIDs) { continue } - if containsNetworkChainID(dest.ChainID, disabledToChainIDs) { + if arrayContainsElement(dest.ChainID, disabledToChainIDs) { continue } diff --git a/services/wallet/router/router_send_type.go b/services/wallet/router/router_send_type.go index 4a4f1fc85..14f6fef99 100644 --- a/services/wallet/router/router_send_type.go +++ b/services/wallet/router/router_send_type.go @@ -133,6 +133,10 @@ func (s SendType) canUseProcessor(p pathprocessor.PathProcessor) bool { } } +func (s SendType) simpleTransfer(p pathprocessor.PathProcessor) bool { + return s == Transfer && p.Name() == pathprocessor.ProcessorTransferName +} + func (s SendType) processZeroAmountInProcessor(amountIn *big.Int, amountOut *big.Int, processorName string) bool { if amountIn.Cmp(pathprocessor.ZeroBigIntValue) == 0 { if s == Transfer { diff --git a/services/wallet/router/router_v2.go b/services/wallet/router/router_v2.go index 10f2d33f3..de99965bd 100644 --- a/services/wallet/router/router_v2.go +++ b/services/wallet/router/router_v2.go @@ -6,6 +6,7 @@ import ( "math" "math/big" "sort" + "strings" "sync" "github.com/ethereum/go-ethereum/common" @@ -21,6 +22,10 @@ import ( "github.com/status-im/status-go/signal" ) +const ( + hexAddressLength = 42 +) + var ( routerTask = async.TaskType{ ID: 1, @@ -71,8 +76,8 @@ type RouteInputParams struct { type routerTestParams struct { tokenFrom *walletToken.Token tokenPrices map[string]float64 - estimationMap map[string]uint64 // [processor-name, estimated-value] - bonderFeeMap map[string]*big.Int // [token-symbol, bonder-fee] + estimationMap map[string]pathprocessor.Estimation // [processor-name, estimation] + bonderFeeMap map[string]*big.Int // [token-symbol, bonder-fee] suggestedFees *SuggestedFees baseFee *big.Int balanceMap map[string]*big.Int // [token-symbol, balance] @@ -407,7 +412,7 @@ func validateFromLockedAmount(input *RouteInputParams) error { excludedChainCount := 0 for chainID, amount := range input.FromLockedAmount { - if containsNetworkChainID(chainID, input.DisabledFromChainIDs) { + if arrayContainsElement(chainID, input.DisabledFromChainIDs) { return ErrDisabledChainFoundAmongLockedNetworks } @@ -500,8 +505,21 @@ func (r *Router) SuggestedRoutesV2(ctx context.Context, input *RouteInputParams) balanceMap, err := r.getBalanceMapForTokenOnChains(ctx, input, selectedFromChains) // return only if there are no balances, otherwise try to resolve the candidates for chains we know the balances for - if len(balanceMap) == 0 && err != nil { - return nil, errors.CreateErrorResponseFromError(err) + if len(balanceMap) == 0 { + if err != nil { + return nil, errors.CreateErrorResponseFromError(err) + } + } else { + noBalanceOnAnyChain := true + for _, value := range balanceMap { + if value.Cmp(pathprocessor.ZeroBigIntValue) > 0 { + noBalanceOnAnyChain = false + break + } + } + if noBalanceOnAnyChain { + return nil, ErrNoPositiveBalance + } } candidates, processorErrors, err := r.resolveCandidates(ctx, input, selectedFromChains, selectedToChains, balanceMap) @@ -530,7 +548,23 @@ func (r *Router) SuggestedRoutesV2(ctx context.Context, input *RouteInputParams) } } - return suggestedRoutes, err + mapError := func(err error) error { + if err == nil { + return nil + } + pattern := "insufficient funds for gas * price + value: address " + addressIndex := strings.Index(errors.DetailsFromError(err), pattern) + if addressIndex != -1 { + addressIndex += len(pattern) + hexAddressLength + return errors.CreateErrorResponseFromError(&errors.ErrorResponse{ + Code: errors.ErrorCodeFromError(err), + Details: errors.DetailsFromError(err)[:addressIndex], + }) + } + return err + } + // map some errors to more user-friendly messages + return suggestedRoutes, mapError(err) } // getBalanceMapForTokenOnChains returns the balance map for passed address, where the key is in format "chainID-tokenSymbol" and @@ -584,6 +618,10 @@ func (r *Router) getBalanceMapForTokenOnChains(ctx context.Context, input *Route balanceMap[makeBalanceKey(chain.ChainID, token.Symbol)] = tokenBalance } + if token.IsNative() { + continue + } + // add native token balance for the chain nativeBalance, err := r.getBalance(ctx, chain.ChainID, nativeToken, input.AddrFrom) if err != nil { @@ -756,11 +794,11 @@ func (r *Router) getSelectedChains(input *RouteInputParams) (selectedFromChains continue } - if !containsNetworkChainID(network.ChainID, input.DisabledFromChainIDs) { + if !arrayContainsElement(network.ChainID, input.DisabledFromChainIDs) { selectedFromChains = append(selectedFromChains, network) } - if !containsNetworkChainID(network.ChainID, input.DisabledToChainIDs) { + if !arrayContainsElement(network.ChainID, input.DisabledToChainIDs) { selectedToChains = append(selectedToChains, network) } } @@ -781,8 +819,8 @@ func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams, return nil, nil, errors.CreateErrorResponseFromError(err) } - appendProcessorErrorFn := func(processorName string, err error) { - log.Error("routerv2.resolveCandidates error", "processor", processorName, "err", err) + appendProcessorErrorFn := func(processorName string, sendType SendType, fromChainID uint64, toChainID uint64, amount *big.Int, err error) { + log.Error("routerv2.resolveCandidates error", "processor", processorName, "sendType", sendType, "fromChainId: ", fromChainID, "toChainId", toChainID, "amount", amount, "err", err) mu.Lock() defer mu.Unlock() processorErrors = append(processorErrors, &ProcessorError{ @@ -855,6 +893,11 @@ func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams, continue } + // if just a single from and to chain is selected for transfer, we can skip the bridge as potential path + if !input.SendType.simpleTransfer(pProcessor) && sameSingleChainTransfer(selectedFromChains, selectedToChains) { + continue + } + if !input.SendType.processZeroAmountInProcessor(amountOption.amount, input.AmountOut.ToInt(), pProcessor.Name()) { continue } @@ -893,7 +936,7 @@ func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams, can, err := pProcessor.AvailableFor(processorInputParams) if err != nil { - appendProcessorErrorFn(pProcessor.Name(), err) + appendProcessorErrorFn(pProcessor.Name(), input.SendType, processorInputParams.FromChain.ChainID, processorInputParams.ToChain.ChainID, processorInputParams.AmountIn, err) continue } if !can { @@ -902,24 +945,24 @@ func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams, bonderFees, tokenFees, err := pProcessor.CalculateFees(processorInputParams) if err != nil { - appendProcessorErrorFn(pProcessor.Name(), err) + appendProcessorErrorFn(pProcessor.Name(), input.SendType, processorInputParams.FromChain.ChainID, processorInputParams.ToChain.ChainID, processorInputParams.AmountIn, err) continue } gasLimit, err := pProcessor.EstimateGas(processorInputParams) if err != nil { - appendProcessorErrorFn(pProcessor.Name(), err) + appendProcessorErrorFn(pProcessor.Name(), input.SendType, processorInputParams.FromChain.ChainID, processorInputParams.ToChain.ChainID, processorInputParams.AmountIn, err) continue } approvalContractAddress, err := pProcessor.GetContractAddress(processorInputParams) if err != nil { - appendProcessorErrorFn(pProcessor.Name(), err) + appendProcessorErrorFn(pProcessor.Name(), input.SendType, processorInputParams.FromChain.ChainID, processorInputParams.ToChain.ChainID, processorInputParams.AmountIn, err) continue } approvalRequired, approvalAmountRequired, approvalGasLimit, l1ApprovalFee, err := r.requireApproval(ctx, input.SendType, &approvalContractAddress, processorInputParams) if err != nil { - appendProcessorErrorFn(pProcessor.Name(), err) + appendProcessorErrorFn(pProcessor.Name(), input.SendType, processorInputParams.FromChain.ChainID, processorInputParams.ToChain.ChainID, processorInputParams.AmountIn, err) continue } @@ -936,7 +979,7 @@ func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams, amountOut, err := pProcessor.CalculateAmountOut(processorInputParams) if err != nil { - appendProcessorErrorFn(pProcessor.Name(), err) + appendProcessorErrorFn(pProcessor.Name(), input.SendType, processorInputParams.FromChain.ChainID, processorInputParams.ToChain.ChainID, processorInputParams.AmountIn, err) continue } @@ -1041,7 +1084,7 @@ func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams, return candidates, processorErrors, nil } -func (r *Router) checkBalancesForTheBestRoute(ctx context.Context, bestRoute []*PathV2, input *RouteInputParams, balanceMap map[string]*big.Int) (hasPositiveBalance bool, err error) { +func (r *Router) checkBalancesForTheBestRoute(ctx context.Context, bestRoute []*PathV2, balanceMap map[string]*big.Int) (hasPositiveBalance bool, err error) { balanceMapCopy := copyMapGeneric(balanceMap, func(v interface{}) interface{} { return new(big.Int).Set(v.(*big.Int)) }).(map[string]*big.Int) @@ -1182,7 +1225,7 @@ func (r *Router) resolveRoutes(ctx context.Context, input *RouteInputParams, can for len(allRoutes) > 0 { bestRoute = findBestV2(allRoutes, tokenPrice, nativeTokenPrice) var hasPositiveBalance bool - hasPositiveBalance, err = r.checkBalancesForTheBestRoute(ctx, bestRoute, input, balanceMap) + hasPositiveBalance, err = r.checkBalancesForTheBestRoute(ctx, bestRoute, balanceMap) if err != nil { // If it's about transfer or bridge and there is more routes, but on the best (cheapest) one there is not enugh balance diff --git a/services/wallet/router/router_v2_test.go b/services/wallet/router/router_v2_test.go index 214981883..170d84eca 100644 --- a/services/wallet/router/router_v2_test.go +++ b/services/wallet/router/router_v2_test.go @@ -216,8 +216,12 @@ func TestNoBalanceForTheBestRouteRouterV2(t *testing.T) { if tt.expectedError != nil { assert.Error(t, err) assert.Equal(t, tt.expectedError.Error(), err.Error()) - assert.NotNil(t, routes) - assertPathsEqual(t, tt.expectedCandidates, routes.Candidates) + if tt.expectedError == ErrNoPositiveBalance { + assert.Nil(t, routes) + } else { + assert.NotNil(t, routes) + assertPathsEqual(t, tt.expectedCandidates, routes.Candidates) + } } else { assert.NoError(t, err) assert.Equal(t, len(tt.expectedCandidates), len(routes.Candidates)) diff --git a/services/wallet/router/router_v2_test_data.go b/services/wallet/router/router_v2_test_data.go index d53b86263..b177c6d48 100644 --- a/services/wallet/router/router_v2_test_data.go +++ b/services/wallet/router/router_v2_test_data.go @@ -45,9 +45,9 @@ const ( ) var ( - testEstimationMap = map[string]uint64{ - pathprocessor.ProcessorTransferName: uint64(1000), - pathprocessor.ProcessorBridgeHopName: uint64(5000), + testEstimationMap = map[string]pathprocessor.Estimation{ + pathprocessor.ProcessorTransferName: {Value: uint64(1000), Err: nil}, + pathprocessor.ProcessorBridgeHopName: {Value: uint64(5000), Err: nil}, } testBbonderFeeMap = map[string]*big.Int{ @@ -208,6 +208,46 @@ type normalTestParams struct { func getNormalTestParamsList() []normalTestParams { return []normalTestParams{ + { + name: "ETH transfer - Insufficient Funds", + 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, walletCommon.ArbitrumMainnet}, + DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, + + testsMode: true, + testParams: &routerTestParams{ + tokenFrom: &token.Token{ + ChainID: 1, + Symbol: pathprocessor.EthSymbol, + Decimals: 18, + }, + tokenPrices: testTokenPrices, + suggestedFees: testSuggestedFees, + balanceMap: testBalanceMapPerChain, + estimationMap: map[string]pathprocessor.Estimation{ + pathprocessor.ProcessorTransferName: { + Value: uint64(0), + Err: fmt.Errorf("failed with 50000000 gas: insufficient funds for gas * price + value: address %s have 68251537427723 want 100000000000000", common.HexToAddress("0x1")), + }, + }, + bonderFeeMap: testBbonderFeeMap, + approvalGasEstimation: testApprovalGasEstimation, + approvalL1Fee: testApprovalL1Fee, + }, + }, + expectedError: &errors.ErrorResponse{ + Code: errors.GenericErrorCode, + Details: fmt.Sprintf("failed with 50000000 gas: insufficient funds for gas * price + value: address %s", common.HexToAddress("0x1")), + }, + expectedCandidates: []*PathV2{}, + }, { name: "ETH transfer - No Specific FromChain - No Specific ToChain - 0 AmountIn", input: &RouteInputParams{ @@ -2669,20 +2709,7 @@ func getNoBalanceTestParamsList() []noBalanceTestParams { approvalL1Fee: testApprovalL1Fee, }, }, - expectedError: &errors.ErrorResponse{ - Code: ErrNotEnoughTokenBalance.Code, - Details: fmt.Sprintf(ErrNotEnoughTokenBalance.Details, pathprocessor.UsdcSymbol, walletCommon.OptimismMainnet), - }, - expectedCandidates: []*PathV2{ - { - ProcessorName: pathprocessor.ProcessorTransferName, - FromChain: &optimism, - ToChain: &optimism, - ApprovalRequired: false, - requiredTokenBalance: big.NewInt(testAmount100USDC), - requiredNativeBalance: big.NewInt((testBaseFee + testPriorityFeeLow) * testApprovalGasEstimation), - }, - }, + expectedError: ErrNoPositiveBalance, }, { name: "ERC20 transfer - Specific FromChain - Specific ToChain - Not Enough Native Balance", @@ -2766,30 +2793,7 @@ func getNoBalanceTestParamsList() []noBalanceTestParams { approvalL1Fee: testApprovalL1Fee, }, }, - expectedError: &errors.ErrorResponse{ - Code: ErrNotEnoughTokenBalance.Code, - Details: fmt.Sprintf(ErrNotEnoughTokenBalance.Details, pathprocessor.UsdcSymbol, walletCommon.ArbitrumMainnet), - }, - 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, - }, - }, + expectedError: ErrNoPositiveBalance, }, { name: "ERC20 transfer - No Specific FromChain - Specific ToChain - Enough Token Balance On Arbitrum Chain But Not Enough Native Balance",