feat_: the router - add candidates, as potential paths, by taking the max amount on enabled chains
This commit is contained in:
parent
4b19845592
commit
378e5741b9
|
@ -27,4 +27,5 @@ var (
|
|||
ErrDisabledChainFoundAmongLockedNetworks = &errors.ErrorResponse{Code: errors.ErrorCode("WR-019"), Details: "disabled chain found among locked networks"}
|
||||
ErrENSSetPubKeyInvalidUsername = &errors.ErrorResponse{Code: errors.ErrorCode("WR-020"), Details: "a valid username, ending in '.eth', is required for ENSSetPubKey"}
|
||||
ErrLockedAmountExcludesAllSupported = &errors.ErrorResponse{Code: errors.ErrorCode("WR-021"), Details: "all supported chains are excluded, routing impossible"}
|
||||
ErrTokenNotFound = &errors.ErrorResponse{Code: errors.ErrorCode("WR-022"), Details: "token not found"}
|
||||
)
|
||||
|
|
|
@ -414,8 +414,8 @@ func (r *Router) requireApproval(ctx context.Context, sendType SendType, approva
|
|||
return true, params.AmountIn, estimate, l1Fee, nil
|
||||
}
|
||||
|
||||
func (r *Router) getBalance(ctx context.Context, network *params.Network, token *token.Token, account common.Address) (*big.Int, error) {
|
||||
client, err := r.rpcClient.EthClient(network.ChainID)
|
||||
func (r *Router) getBalance(ctx context.Context, chainID uint64, token *token.Token, account common.Address) (*big.Int, error) {
|
||||
client, err := r.rpcClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -521,7 +521,7 @@ func (r *Router) SuggestedRoutes(
|
|||
return err
|
||||
}
|
||||
} else if sendType != ERC721Transfer {
|
||||
balance, err = r.getBalance(ctx, network, token, addrFrom)
|
||||
balance, err = r.getBalance(ctx, network.ChainID, token, addrFrom)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -535,7 +535,7 @@ func (r *Router) SuggestedRoutes(
|
|||
maxAmountIn = amount
|
||||
}
|
||||
|
||||
nativeBalance, err := r.getBalance(ctx, network, nativeToken, addrFrom)
|
||||
nativeBalance, err := r.getBalance(ctx, network.ChainID, nativeToken, addrFrom)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -79,15 +79,13 @@ type routerTestParams struct {
|
|||
approvalL1Fee uint64
|
||||
}
|
||||
|
||||
func makeTestBalanceKey(chainID uint64, symbol string) string {
|
||||
return fmt.Sprintf("%d-%s", chainID, symbol)
|
||||
type amountOption struct {
|
||||
amount *big.Int
|
||||
locked bool
|
||||
}
|
||||
|
||||
func (rt routerTestParams) getTestBalance(chainID uint64, symbol string) *big.Int {
|
||||
if val, ok := rt.balanceMap[makeTestBalanceKey(chainID, symbol)]; ok {
|
||||
return val
|
||||
}
|
||||
return big.NewInt(0)
|
||||
func makeBalanceKey(chainID uint64, symbol string) string {
|
||||
return fmt.Sprintf("%d-%s", chainID, symbol)
|
||||
}
|
||||
|
||||
type PathV2 struct {
|
||||
|
@ -487,40 +485,246 @@ func (r *Router) SuggestedRoutesV2(ctx context.Context, input *RouteInputParams)
|
|||
return nil, errors.CreateErrorResponseFromError(err)
|
||||
}
|
||||
|
||||
candidates, err := r.resolveCandidates(ctx, input)
|
||||
selectedFromChains, selectedTohains, err := r.getSelectedChains(input)
|
||||
if err != nil {
|
||||
return nil, errors.CreateErrorResponseFromError(err)
|
||||
}
|
||||
|
||||
return r.resolveRoutes(ctx, input, candidates)
|
||||
balanceMap, err := r.getBalanceMapForTokenOnChains(ctx, input, selectedFromChains)
|
||||
if err != nil {
|
||||
return nil, errors.CreateErrorResponseFromError(err)
|
||||
}
|
||||
|
||||
candidates, err := r.resolveCandidates(ctx, input, selectedFromChains, selectedTohains, balanceMap)
|
||||
if err != nil {
|
||||
return nil, errors.CreateErrorResponseFromError(err)
|
||||
}
|
||||
|
||||
return r.resolveRoutes(ctx, input, candidates, balanceMap)
|
||||
}
|
||||
|
||||
func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams) (candidates []*PathV2, err error) {
|
||||
var (
|
||||
testsMode = input.testsMode && input.testParams != nil
|
||||
networks []*params.Network
|
||||
)
|
||||
// getBalanceMapForTokenOnChains returns the balance map for passed address, where the key is in format "chainID-tokenSymbol" and
|
||||
// value is the balance of the token. Native token (EHT) is always added to the balance map.
|
||||
func (r *Router) getBalanceMapForTokenOnChains(ctx context.Context, input *RouteInputParams, selectedFromChains []*params.Network) (balanceMap map[string]*big.Int, err error) {
|
||||
if input.testsMode {
|
||||
return input.testParams.balanceMap, nil
|
||||
}
|
||||
|
||||
networks, err = r.rpcClient.NetworkManager.Get(false)
|
||||
balanceMap = make(map[string]*big.Int)
|
||||
|
||||
for _, chain := range selectedFromChains {
|
||||
token := input.SendType.FindToken(r.tokenManager, r.collectiblesService, input.AddrFrom, chain, input.TokenID)
|
||||
if token == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// add token balance for the chain
|
||||
tokenBalance := big.NewInt(1)
|
||||
if input.SendType == ERC1155Transfer {
|
||||
tokenBalance, err = r.getERC1155Balance(ctx, chain, token, input.AddrFrom)
|
||||
if err != nil {
|
||||
return nil, errors.CreateErrorResponseFromError(err)
|
||||
}
|
||||
} else if input.SendType != ERC721Transfer {
|
||||
tokenBalance, err = r.getBalance(ctx, chain.ChainID, token, input.AddrFrom)
|
||||
if err != nil {
|
||||
return nil, errors.CreateErrorResponseFromError(err)
|
||||
}
|
||||
}
|
||||
balanceMap[makeBalanceKey(chain.ChainID, token.Symbol)] = tokenBalance
|
||||
|
||||
// add native token balance for the chain
|
||||
nativeToken := r.tokenManager.FindToken(chain, chain.NativeCurrencySymbol)
|
||||
if nativeToken == nil {
|
||||
return nil, ErrNativeTokenNotFound
|
||||
}
|
||||
|
||||
nativeBalance, err := r.getBalance(ctx, chain.ChainID, nativeToken, input.AddrFrom)
|
||||
if err != nil {
|
||||
return nil, errors.CreateErrorResponseFromError(err)
|
||||
}
|
||||
balanceMap[makeBalanceKey(chain.ChainID, nativeToken.Symbol)] = nativeBalance
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *Router) getSelectedUnlockedChains(input *RouteInputParams, processingChain *params.Network, selectedFromChains []*params.Network) []*params.Network {
|
||||
selectedButNotLockedChains := []*params.Network{processingChain} // always add the processing chain at the beginning
|
||||
for _, net := range selectedFromChains {
|
||||
if net.ChainID == processingChain.ChainID {
|
||||
continue
|
||||
}
|
||||
if _, ok := input.FromLockedAmount[net.ChainID]; !ok {
|
||||
selectedButNotLockedChains = append(selectedButNotLockedChains, net)
|
||||
}
|
||||
}
|
||||
return selectedButNotLockedChains
|
||||
}
|
||||
|
||||
func (r *Router) getOptionsForAmoutToSplitAccrossChainsForProcessingChain(input *RouteInputParams, amountToSplit *big.Int, processingChain *params.Network,
|
||||
selectedFromChains []*params.Network, balanceMap map[string]*big.Int) map[uint64][]amountOption {
|
||||
selectedButNotLockedChains := r.getSelectedUnlockedChains(input, processingChain, selectedFromChains)
|
||||
|
||||
crossChainAmountOptions := make(map[uint64][]amountOption)
|
||||
for _, chain := range selectedButNotLockedChains {
|
||||
var (
|
||||
group = async.NewAtomicGroup(ctx)
|
||||
mu sync.Mutex
|
||||
ok bool
|
||||
tokenBalance *big.Int
|
||||
)
|
||||
|
||||
for networkIdx := range networks {
|
||||
network := networks[networkIdx]
|
||||
if tokenBalance, ok = balanceMap[makeBalanceKey(chain.ChainID, input.TokenID)]; !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if tokenBalance.Cmp(pathprocessor.ZeroBigIntValue) > 0 {
|
||||
if tokenBalance.Cmp(amountToSplit) <= 0 {
|
||||
crossChainAmountOptions[chain.ChainID] = append(crossChainAmountOptions[chain.ChainID], amountOption{
|
||||
amount: tokenBalance,
|
||||
locked: false,
|
||||
})
|
||||
amountToSplit = new(big.Int).Sub(amountToSplit, tokenBalance)
|
||||
} else if amountToSplit.Cmp(pathprocessor.ZeroBigIntValue) > 0 {
|
||||
crossChainAmountOptions[chain.ChainID] = append(crossChainAmountOptions[chain.ChainID], amountOption{
|
||||
amount: amountToSplit,
|
||||
locked: false,
|
||||
})
|
||||
// break since amountToSplit is fully addressed and the rest is 0
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return crossChainAmountOptions
|
||||
}
|
||||
|
||||
func (r *Router) getCrossChainsOptionsForSendingAmount(input *RouteInputParams, selectedFromChains []*params.Network,
|
||||
balanceMap map[string]*big.Int) map[uint64][]amountOption {
|
||||
// All we do in this block we're free to do, because of the validateInputData function which checks if the locked amount
|
||||
// was properly set and if there is something unexpected it will return an error and we will not reach this point
|
||||
finalCrossChainAmountOptions := make(map[uint64][]amountOption) // represents all possible amounts that can be sent from the "from" chain
|
||||
|
||||
for _, selectedFromChain := range selectedFromChains {
|
||||
|
||||
amountLocked := false
|
||||
amountToSend := input.AmountIn.ToInt()
|
||||
lockedAmount, fromChainLocked := input.FromLockedAmount[selectedFromChain.ChainID]
|
||||
if fromChainLocked {
|
||||
amountToSend = lockedAmount.ToInt()
|
||||
amountLocked = true
|
||||
} else if len(input.FromLockedAmount) > 0 {
|
||||
for chainID, lockedAmount := range input.FromLockedAmount {
|
||||
if chainID == selectedFromChain.ChainID {
|
||||
continue
|
||||
}
|
||||
amountToSend = new(big.Int).Sub(amountToSend, lockedAmount.ToInt())
|
||||
}
|
||||
}
|
||||
|
||||
if amountToSend.Cmp(pathprocessor.ZeroBigIntValue) > 0 {
|
||||
// add full amount always, cause we want to check for balance errors at the end of the routing algorithm
|
||||
// TODO: once we introduce bettwer error handling and start checking for the balance at the beginning of the routing algorithm
|
||||
// we can remove this line and optimize the routing algorithm more
|
||||
finalCrossChainAmountOptions[selectedFromChain.ChainID] = append(finalCrossChainAmountOptions[selectedFromChain.ChainID], amountOption{
|
||||
amount: amountToSend,
|
||||
locked: amountLocked,
|
||||
})
|
||||
|
||||
if amountLocked {
|
||||
continue
|
||||
}
|
||||
|
||||
// If the amount that need to be send is bigger than the balance on the chain, then we want to check options if that
|
||||
// amount can be splitted and sent across multiple chains.
|
||||
if input.SendType == Transfer && len(selectedFromChains) > 1 {
|
||||
// All we do in this block we're free to do, because of the validateInputData function which checks if the locked amount
|
||||
// was properly set and if there is something unexpected it will return an error and we will not reach this point
|
||||
amountToSplitAccrossChains := new(big.Int).Set(amountToSend)
|
||||
|
||||
crossChainAmountOptions := r.getOptionsForAmoutToSplitAccrossChainsForProcessingChain(input, amountToSend, selectedFromChain, selectedFromChains, balanceMap)
|
||||
|
||||
// sum up all the allocated amounts accorss all chains
|
||||
allocatedAmount := big.NewInt(0)
|
||||
for _, amountOptions := range crossChainAmountOptions {
|
||||
for _, amountOption := range amountOptions {
|
||||
allocatedAmount = new(big.Int).Add(allocatedAmount, amountOption.amount)
|
||||
}
|
||||
}
|
||||
|
||||
// if the allocated amount is the same as the amount that need to be sent, then we can add the options to the finalCrossChainAmountOptions
|
||||
if allocatedAmount.Cmp(amountToSplitAccrossChains) == 0 {
|
||||
for cID, amountOptions := range crossChainAmountOptions {
|
||||
finalCrossChainAmountOptions[cID] = append(finalCrossChainAmountOptions[cID], amountOptions...)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return finalCrossChainAmountOptions
|
||||
}
|
||||
|
||||
func (r *Router) findOptionsForSendingAmount(input *RouteInputParams, selectedFromChains []*params.Network,
|
||||
balanceMap map[string]*big.Int) (map[uint64][]amountOption, error) {
|
||||
|
||||
crossChainAmountOptions := r.getCrossChainsOptionsForSendingAmount(input, selectedFromChains, balanceMap)
|
||||
|
||||
// filter out duplicates values for the same chain
|
||||
for chainID, amountOptions := range crossChainAmountOptions {
|
||||
uniqueAmountOptions := make(map[string]amountOption)
|
||||
for _, amountOption := range amountOptions {
|
||||
uniqueAmountOptions[amountOption.amount.String()] = amountOption
|
||||
}
|
||||
|
||||
crossChainAmountOptions[chainID] = make([]amountOption, 0)
|
||||
for _, amountOption := range uniqueAmountOptions {
|
||||
crossChainAmountOptions[chainID] = append(crossChainAmountOptions[chainID], amountOption)
|
||||
}
|
||||
}
|
||||
|
||||
return crossChainAmountOptions, nil
|
||||
}
|
||||
|
||||
func (r *Router) getSelectedChains(input *RouteInputParams) (selectedFromChains []*params.Network, selectedTohains []*params.Network, err error) {
|
||||
var networks []*params.Network
|
||||
networks, err = r.rpcClient.NetworkManager.Get(false)
|
||||
if err != nil {
|
||||
return nil, nil, errors.CreateErrorResponseFromError(err)
|
||||
}
|
||||
|
||||
for _, network := range networks {
|
||||
if network.IsTest != input.testnetMode {
|
||||
continue
|
||||
}
|
||||
|
||||
if containsNetworkChainID(network.ChainID, input.DisabledFromChainIDs) {
|
||||
continue
|
||||
if !containsNetworkChainID(network.ChainID, input.DisabledFromChainIDs) {
|
||||
selectedFromChains = append(selectedFromChains, network)
|
||||
}
|
||||
|
||||
if !containsNetworkChainID(network.ChainID, input.DisabledToChainIDs) {
|
||||
selectedTohains = append(selectedTohains, network)
|
||||
}
|
||||
}
|
||||
|
||||
return selectedFromChains, selectedTohains, nil
|
||||
}
|
||||
|
||||
func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams, selectedFromChains []*params.Network,
|
||||
selectedTohains []*params.Network, balanceMap map[string]*big.Int) (candidates []*PathV2, err error) {
|
||||
var (
|
||||
testsMode = input.testsMode && input.testParams != nil
|
||||
group = async.NewAtomicGroup(ctx)
|
||||
mu sync.Mutex
|
||||
)
|
||||
|
||||
crossChainAmountOptions, err := r.findOptionsForSendingAmount(input, selectedFromChains, balanceMap)
|
||||
if err != nil {
|
||||
return nil, errors.CreateErrorResponseFromError(err)
|
||||
}
|
||||
|
||||
for networkIdx := range selectedFromChains {
|
||||
network := selectedFromChains[networkIdx]
|
||||
|
||||
if !input.SendType.isAvailableFor(network) {
|
||||
continue
|
||||
}
|
||||
|
@ -543,20 +747,6 @@ func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams)
|
|||
toToken = input.SendType.FindToken(r.tokenManager, r.collectiblesService, common.Address{}, network, input.ToTokenID)
|
||||
}
|
||||
|
||||
amountLocked := false
|
||||
amountToSend := input.AmountIn.ToInt()
|
||||
if lockedAmount, ok := input.FromLockedAmount[network.ChainID]; ok {
|
||||
amountToSend = lockedAmount.ToInt()
|
||||
amountLocked = true
|
||||
} else if len(input.FromLockedAmount) > 0 {
|
||||
for chainID, lockedAmount := range input.FromLockedAmount {
|
||||
if chainID == network.ChainID {
|
||||
continue
|
||||
}
|
||||
amountToSend = new(big.Int).Sub(amountToSend, lockedAmount.ToInt())
|
||||
}
|
||||
}
|
||||
|
||||
var fees *SuggestedFees
|
||||
if testsMode {
|
||||
fees = input.testParams.suggestedFees
|
||||
|
@ -568,6 +758,7 @@ func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams)
|
|||
}
|
||||
|
||||
group.Add(func(c context.Context) error {
|
||||
for _, amountOption := range crossChainAmountOptions[network.ChainID] {
|
||||
for _, pProcessor := range r.pathProcessors {
|
||||
// With the condition below we're eliminating `Swap` as potential path that can participate in calculating the best route
|
||||
// once we decide to inlcude `Swap` in the calculation we need to update `canUseProcessor` function.
|
||||
|
@ -589,10 +780,7 @@ func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams)
|
|||
continue
|
||||
}
|
||||
|
||||
for _, dest := range networks {
|
||||
if dest.IsTest != input.testnetMode {
|
||||
continue
|
||||
}
|
||||
for _, dest := range selectedTohains {
|
||||
|
||||
if !input.SendType.isAvailableFor(network) {
|
||||
continue
|
||||
|
@ -602,10 +790,6 @@ func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams)
|
|||
continue
|
||||
}
|
||||
|
||||
if containsNetworkChainID(dest.ChainID, input.DisabledToChainIDs) {
|
||||
continue
|
||||
}
|
||||
|
||||
processorInputParams := pathprocessor.ProcessorInputParams{
|
||||
FromChain: network,
|
||||
ToChain: dest,
|
||||
|
@ -613,7 +797,7 @@ func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams)
|
|||
ToToken: toToken,
|
||||
ToAddr: input.AddrTo,
|
||||
FromAddr: input.AddrFrom,
|
||||
AmountIn: amountToSend,
|
||||
AmountIn: amountOption.amount,
|
||||
AmountOut: input.AmountOut.ToInt(),
|
||||
|
||||
Username: input.Username,
|
||||
|
@ -682,8 +866,8 @@ func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams)
|
|||
ToChain: dest,
|
||||
FromToken: token,
|
||||
ToToken: toToken,
|
||||
AmountIn: (*hexutil.Big)(amountToSend),
|
||||
AmountInLocked: amountLocked,
|
||||
AmountIn: (*hexutil.Big)(amountOption.amount),
|
||||
AmountInLocked: amountOption.locked,
|
||||
AmountOut: (*hexutil.Big)(amountOut),
|
||||
|
||||
SuggestedLevelsForMaxFeesPerGas: fees.MaxFeesLevels,
|
||||
|
@ -708,6 +892,7 @@ func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams)
|
|||
mu.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
@ -716,50 +901,26 @@ func (r *Router) resolveCandidates(ctx context.Context, input *RouteInputParams)
|
|||
return candidates, nil
|
||||
}
|
||||
|
||||
func (r *Router) checkBalancesForTheBestRoute(ctx context.Context, bestRoute []*PathV2, input *RouteInputParams) (err error) {
|
||||
func (r *Router) checkBalancesForTheBestRoute(ctx context.Context, bestRoute []*PathV2, input *RouteInputParams, balanceMap map[string]*big.Int) (err error) {
|
||||
// check the best route for the required balances
|
||||
for _, path := range bestRoute {
|
||||
if path.requiredTokenBalance != nil && path.requiredTokenBalance.Cmp(pathprocessor.ZeroBigIntValue) > 0 {
|
||||
tokenBalance := big.NewInt(1)
|
||||
if input.testsMode {
|
||||
tokenBalance = input.testParams.getTestBalance(path.FromChain.ChainID, path.FromToken.Symbol)
|
||||
} else {
|
||||
if input.SendType == ERC1155Transfer {
|
||||
tokenBalance, err = r.getERC1155Balance(ctx, path.FromChain, path.FromToken, input.AddrFrom)
|
||||
if err != nil {
|
||||
return errors.CreateErrorResponseFromError(err)
|
||||
}
|
||||
} else if input.SendType != ERC721Transfer {
|
||||
tokenBalance, err = r.getBalance(ctx, path.FromChain, path.FromToken, input.AddrFrom)
|
||||
if err != nil {
|
||||
return errors.CreateErrorResponseFromError(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if tokenBalance, ok := balanceMap[makeBalanceKey(path.FromChain.ChainID, path.FromToken.Symbol)]; ok {
|
||||
if tokenBalance.Cmp(path.requiredTokenBalance) == -1 {
|
||||
return ErrNotEnoughTokenBalance
|
||||
}
|
||||
}
|
||||
|
||||
var nativeBalance *big.Int
|
||||
if input.testsMode {
|
||||
nativeBalance = input.testParams.getTestBalance(path.FromChain.ChainID, pathprocessor.EthSymbol)
|
||||
} else {
|
||||
nativeToken := r.tokenManager.FindToken(path.FromChain, path.FromChain.NativeCurrencySymbol)
|
||||
if nativeToken == nil {
|
||||
return ErrNativeTokenNotFound
|
||||
}
|
||||
|
||||
nativeBalance, err = r.getBalance(ctx, path.FromChain, nativeToken, input.AddrFrom)
|
||||
if err != nil {
|
||||
return errors.CreateErrorResponseFromError(err)
|
||||
return ErrTokenNotFound
|
||||
}
|
||||
}
|
||||
|
||||
if nativeBalance, ok := balanceMap[makeBalanceKey(path.FromChain.ChainID, pathprocessor.EthSymbol)]; ok {
|
||||
if nativeBalance.Cmp(path.requiredNativeBalance) == -1 {
|
||||
return ErrNotEnoughNativeBalance
|
||||
}
|
||||
} else {
|
||||
return ErrNativeTokenNotFound
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -792,7 +953,7 @@ func removeBestRouteFromAllRouters(allRoutes [][]*PathV2, best []*PathV2) [][]*P
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) resolveRoutes(ctx context.Context, input *RouteInputParams, candidates []*PathV2) (suggestedRoutes *SuggestedRoutesV2, err error) {
|
||||
func (r *Router) resolveRoutes(ctx context.Context, input *RouteInputParams, candidates []*PathV2, balanceMap map[string]*big.Int) (suggestedRoutes *SuggestedRoutesV2, err error) {
|
||||
var prices map[string]float64
|
||||
if input.testsMode {
|
||||
prices = input.testParams.tokenPrices
|
||||
|
@ -812,7 +973,7 @@ func (r *Router) resolveRoutes(ctx context.Context, input *RouteInputParams, can
|
|||
for len(allRoutes) > 0 {
|
||||
best := findBestV2(allRoutes, tokenPrice, nativeChainTokenPrice)
|
||||
|
||||
err := r.checkBalancesForTheBestRoute(ctx, best, input)
|
||||
err := r.checkBalancesForTheBestRoute(ctx, best, input, 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
|
||||
// we shold check other routes even though there are not the cheapest ones
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue