diff --git a/services/wallet/api.go b/services/wallet/api.go index 6e012c828..36324d48b 100644 --- a/services/wallet/api.go +++ b/services/wallet/api.go @@ -445,7 +445,7 @@ func (api *API) GetSuggestedRoutes( sendType SendType, account common.Address, amountIn *hexutil.Big, - tokenSymbol string, + tokenID string, disabledFromChainIDs, disabledToChaindIDs, preferedChainIDs []uint64, @@ -453,7 +453,7 @@ func (api *API) GetSuggestedRoutes( fromLockedAmount map[uint64]*hexutil.Big, ) (*SuggestedRoutes, error) { log.Debug("call to GetSuggestedRoutes") - return api.router.suggestedRoutes(ctx, sendType, account, amountIn.ToInt(), tokenSymbol, disabledFromChainIDs, disabledToChaindIDs, preferedChainIDs, gasFeeMode, fromLockedAmount) + return api.router.suggestedRoutes(ctx, sendType, account, amountIn.ToInt(), tokenID, disabledFromChainIDs, disabledToChaindIDs, preferedChainIDs, gasFeeMode, fromLockedAmount) } // Generates addresses for the provided paths, response doesn't include `HasActivity` value (if you need it check `GetAddressDetails` function) diff --git a/services/wallet/bridge/bridge.go b/services/wallet/bridge/bridge.go index 50a7e6d5c..961fa83b9 100644 --- a/services/wallet/bridge/bridge.go +++ b/services/wallet/bridge/bridge.go @@ -22,56 +22,65 @@ func getSigner(chainID uint64, from types.Address, verifiedAccount *account.Sele } type TransactionBridge struct { - BridgeName string - ChainID uint64 - SimpleTx *transactions.SendTxArgs - HopTx *HopTxArgs - CbridgeTx *CBridgeTxArgs + BridgeName string + ChainID uint64 + TransferTx *transactions.SendTxArgs + HopTx *HopTxArgs + CbridgeTx *CBridgeTxArgs + ERC721TransferTx *ERC721TransferTxArgs } func (t *TransactionBridge) Value() *big.Int { - if t.SimpleTx != nil && t.SimpleTx.To != nil { - return t.SimpleTx.Value.ToInt() + if t.TransferTx != nil && t.TransferTx.To != nil { + return t.TransferTx.Value.ToInt() } else if t.HopTx != nil { return t.HopTx.Amount.ToInt() } else if t.CbridgeTx != nil { return t.CbridgeTx.Amount.ToInt() + } else if t.ERC721TransferTx != nil { + return big.NewInt(1) } return big.NewInt(0) } func (t *TransactionBridge) From() types.Address { - if t.SimpleTx != nil && t.SimpleTx.To != nil { - return t.SimpleTx.From + if t.TransferTx != nil && t.TransferTx.To != nil { + return t.TransferTx.From } else if t.HopTx != nil { return t.HopTx.From } else if t.CbridgeTx != nil { return t.CbridgeTx.From + } else if t.ERC721TransferTx != nil { + return t.ERC721TransferTx.From } return types.HexToAddress("0x0") } func (t *TransactionBridge) To() types.Address { - if t.SimpleTx != nil && t.SimpleTx.To != nil { - return *t.SimpleTx.To + if t.TransferTx != nil && t.TransferTx.To != nil { + return *t.TransferTx.To } else if t.HopTx != nil { return types.Address(t.HopTx.Recipient) } else if t.CbridgeTx != nil { return types.Address(t.HopTx.Recipient) + } else if t.ERC721TransferTx != nil { + return types.Address(t.ERC721TransferTx.Recipient) } return types.HexToAddress("0x0") } func (t *TransactionBridge) Data() types.HexBytes { - if t.SimpleTx != nil && t.SimpleTx.To != nil { - return t.SimpleTx.Data + if t.TransferTx != nil && t.TransferTx.To != nil { + return t.TransferTx.Data } else if t.HopTx != nil { return types.HexBytes("") } else if t.CbridgeTx != nil { return types.HexBytes("") + } else if t.ERC721TransferTx != nil { + return types.HexBytes("") } return types.HexBytes("") @@ -81,7 +90,7 @@ type Bridge interface { Name() string Can(from *params.Network, to *params.Network, token *token.Token, balance *big.Int) (bool, error) CalculateFees(from, to *params.Network, token *token.Token, amountIn *big.Int, nativeTokenPrice, tokenPrice float64, gasPrice *big.Float) (*big.Int, *big.Int, error) - EstimateGas(from *params.Network, to *params.Network, token *token.Token, amountIn *big.Int) (uint64, error) + EstimateGas(from *params.Network, to *params.Network, account common.Address, token *token.Token, amountIn *big.Int) (uint64, error) CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error) Send(sendArgs *TransactionBridge, verifiedAccount *account.SelectedExtKey) (types.Hash, error) GetContractAddress(network *params.Network, token *token.Token) *common.Address diff --git a/services/wallet/bridge/cbridge.go b/services/wallet/bridge/cbridge.go index c305c3bee..0d10eac00 100644 --- a/services/wallet/bridge/cbridge.go +++ b/services/wallet/bridge/cbridge.go @@ -216,7 +216,7 @@ func (s *CBridge) CalculateFees(from, to *params.Network, token *token.Token, am return big.NewInt(0), new(big.Int).Add(baseFee, percFee), nil } -func (s *CBridge) EstimateGas(from, to *params.Network, token *token.Token, amountIn *big.Int) (uint64, error) { +func (s *CBridge) EstimateGas(from, to *params.Network, account common.Address, token *token.Token, amountIn *big.Int) (uint64, error) { // TODO: replace by estimate function if token.IsNative() { return 22000, nil // default gas limit for eth transaction diff --git a/services/wallet/bridge/erc721_transfer.go b/services/wallet/bridge/erc721_transfer.go new file mode 100644 index 000000000..80001d416 --- /dev/null +++ b/services/wallet/bridge/erc721_transfer.go @@ -0,0 +1,109 @@ +package bridge + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/status-im/status-go/account" + "github.com/status-im/status-go/contracts/community-tokens/collectibles" + "github.com/status-im/status-go/eth-node/types" + "github.com/status-im/status-go/params" + "github.com/status-im/status-go/rpc" + "github.com/status-im/status-go/services/wallet/token" + "github.com/status-im/status-go/transactions" +) + +type ERC721TransferTxArgs struct { + transactions.SendTxArgs + TokenID *hexutil.Big `json:"tokenId"` + Recipient common.Address `json:"recipient"` +} + +type ERC721TransferBridge struct { + rpcClient *rpc.Client + transactor *transactions.Transactor +} + +func NewERC721TransferBridge(rpcClient *rpc.Client, transactor *transactions.Transactor) *ERC721TransferBridge { + return &ERC721TransferBridge{rpcClient: rpcClient, transactor: transactor} +} + +func (s *ERC721TransferBridge) Name() string { + return "ERC721Transfer" +} + +func (s *ERC721TransferBridge) Can(from, to *params.Network, token *token.Token, balance *big.Int) (bool, error) { + return from.ChainID == to.ChainID, nil +} + +func (s *ERC721TransferBridge) CalculateFees(from, to *params.Network, token *token.Token, amountIn *big.Int, nativeTokenPrice, tokenPrice float64, gasPrice *big.Float) (*big.Int, *big.Int, error) { + return big.NewInt(0), big.NewInt(0), nil +} + +func (s *ERC721TransferBridge) EstimateGas(from, to *params.Network, account common.Address, token *token.Token, amountIn *big.Int) (uint64, error) { + // ethClient, err := s.rpcClient.EthClient(from.ChainID) + // if err != nil { + // return 0, err + // } + // collectiblesABI, err := abi.JSON(strings.NewReader(collectibles.CollectiblesABI)) + // if err != nil { + // return 0, err + // } + + // toAddress := common.HexToAddress("0x0") + // tokenID, success := new(big.Int).SetString(token.Symbol, 10) + // if !success { + // return 0, err + // } + + // data, err := collectiblesABI.Pack("safeTransferFrom", account, toAddress, tokenID) + // if err != nil { + // return 0, err + // } + // estimate, err := ethClient.EstimateGas(context.Background(), ethereum.CallMsg{ + // From: account, + // To: &toAddress, + // Value: big.NewInt(0), + // Data: data, + // }) + // if err != nil { + // return 0, err + // } + // return estimate + 1000, nil + return 80000, nil +} + +func (s *ERC721TransferBridge) Send(sendArgs *TransactionBridge, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) { + ethClient, err := s.rpcClient.EthClient(sendArgs.ChainID) + if err != nil { + return hash, err + } + contract, err := collectibles.NewCollectibles(common.Address(*sendArgs.ERC721TransferTx.To), ethClient) + if err != nil { + return hash, err + } + nonce, unlock, err := s.transactor.NextNonce(s.rpcClient, sendArgs.ChainID, sendArgs.ERC721TransferTx.From) + if err != nil { + return hash, err + } + defer func() { + unlock(err == nil, nonce) + }() + argNonce := hexutil.Uint64(nonce) + sendArgs.ERC721TransferTx.Nonce = &argNonce + txOpts := sendArgs.ERC721TransferTx.ToTransactOpts(getSigner(sendArgs.ChainID, sendArgs.ERC721TransferTx.From, verifiedAccount)) + tx, err := contract.SafeTransferFrom(txOpts, common.Address(sendArgs.ERC721TransferTx.From), sendArgs.ERC721TransferTx.Recipient, sendArgs.ERC721TransferTx.TokenID.ToInt()) + if err != nil { + return hash, err + } + return types.Hash(tx.Hash()), nil +} + +func (s *ERC721TransferBridge) CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error) { + return amountIn, nil +} + +func (s *ERC721TransferBridge) GetContractAddress(network *params.Network, token *token.Token) *common.Address { + return &token.Address +} diff --git a/services/wallet/bridge/hop.go b/services/wallet/bridge/hop.go index 8bcdc5941..0e5aeadfb 100644 --- a/services/wallet/bridge/hop.go +++ b/services/wallet/bridge/hop.go @@ -125,7 +125,7 @@ func (h *HopBridge) Can(from, to *params.Network, token *token.Token, balance *b return true, nil } -func (h *HopBridge) EstimateGas(from, to *params.Network, token *token.Token, amountIn *big.Int) (uint64, error) { +func (h *HopBridge) EstimateGas(from, to *params.Network, account common.Address, token *token.Token, amountIn *big.Int) (uint64, error) { // TODO: find why this doesn't work // ethClient, err := s.contractMaker.RPCClient.EthClient(from.ChainID) // if err != nil { diff --git a/services/wallet/bridge/simple.go b/services/wallet/bridge/simple.go deleted file mode 100644 index 78e42ecd2..000000000 --- a/services/wallet/bridge/simple.go +++ /dev/null @@ -1,53 +0,0 @@ -package bridge - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/status-im/status-go/account" - "github.com/status-im/status-go/eth-node/types" - "github.com/status-im/status-go/params" - "github.com/status-im/status-go/services/wallet/token" - "github.com/status-im/status-go/transactions" -) - -type SimpleBridge struct { - transactor *transactions.Transactor -} - -func NewSimpleBridge(transactor *transactions.Transactor) *SimpleBridge { - return &SimpleBridge{transactor: transactor} -} - -func (s *SimpleBridge) Name() string { - return "Simple" -} - -func (s *SimpleBridge) Can(from, to *params.Network, token *token.Token, balance *big.Int) (bool, error) { - return from.ChainID == to.ChainID, nil -} - -func (s *SimpleBridge) CalculateFees(from, to *params.Network, token *token.Token, amountIn *big.Int, nativeTokenPrice, tokenPrice float64, gasPrice *big.Float) (*big.Int, *big.Int, error) { - return big.NewInt(0), big.NewInt(0), nil -} - -func (s *SimpleBridge) EstimateGas(from, to *params.Network, token *token.Token, amountIn *big.Int) (uint64, error) { - // TODO: replace by estimate function - if token.IsNative() { - return 22000, nil // default gas limit for eth transaction - } - - return 200000, nil //default gas limit for erc20 transaction -} - -func (s *SimpleBridge) Send(sendArgs *TransactionBridge, verifiedAccount *account.SelectedExtKey) (types.Hash, error) { - return s.transactor.SendTransactionWithChainID(sendArgs.ChainID, *sendArgs.SimpleTx, verifiedAccount) -} - -func (s *SimpleBridge) CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error) { - return amountIn, nil -} - -func (s *SimpleBridge) GetContractAddress(network *params.Network, token *token.Token) *common.Address { - return nil -} diff --git a/services/wallet/bridge/transfer.go b/services/wallet/bridge/transfer.go new file mode 100644 index 000000000..107ca5813 --- /dev/null +++ b/services/wallet/bridge/transfer.go @@ -0,0 +1,53 @@ +package bridge + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/status-im/status-go/account" + "github.com/status-im/status-go/eth-node/types" + "github.com/status-im/status-go/params" + "github.com/status-im/status-go/services/wallet/token" + "github.com/status-im/status-go/transactions" +) + +type TransferBridge struct { + transactor *transactions.Transactor +} + +func NewTransferBridge(transactor *transactions.Transactor) *TransferBridge { + return &TransferBridge{transactor: transactor} +} + +func (s *TransferBridge) Name() string { + return "Transfer" +} + +func (s *TransferBridge) Can(from, to *params.Network, token *token.Token, balance *big.Int) (bool, error) { + return from.ChainID == to.ChainID, nil +} + +func (s *TransferBridge) CalculateFees(from, to *params.Network, token *token.Token, amountIn *big.Int, nativeTokenPrice, tokenPrice float64, gasPrice *big.Float) (*big.Int, *big.Int, error) { + return big.NewInt(0), big.NewInt(0), nil +} + +func (s *TransferBridge) EstimateGas(from, to *params.Network, account common.Address, token *token.Token, amountIn *big.Int) (uint64, error) { + // TODO: replace by estimate function + if token.IsNative() { + return 22000, nil // default gas limit for eth transaction + } + + return 200000, nil //default gas limit for erc20 transaction +} + +func (s *TransferBridge) Send(sendArgs *TransactionBridge, verifiedAccount *account.SelectedExtKey) (types.Hash, error) { + return s.transactor.SendTransactionWithChainID(sendArgs.ChainID, *sendArgs.TransferTx, verifiedAccount) +} + +func (s *TransferBridge) CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error) { + return amountIn, nil +} + +func (s *TransferBridge) GetContractAddress(network *params.Network, token *token.Token) *common.Address { + return nil +} diff --git a/services/wallet/collectibles/ownership_db.go b/services/wallet/collectibles/ownership_db.go index b4811d7b2..512f75e70 100644 --- a/services/wallet/collectibles/ownership_db.go +++ b/services/wallet/collectibles/ownership_db.go @@ -134,3 +134,32 @@ func (o *OwnershipDB) GetOwnedCollectibles(chainIDs []w_common.ChainID, ownerAdd return rowsToCollectibles(rows) } + +func (o *OwnershipDB) GetOwnedCollectible(chainID w_common.ChainID, ownerAddresses common.Address, contractAddress common.Address, tokenID *big.Int) (*thirdparty.CollectibleUniqueID, error) { + query := fmt.Sprintf(`SELECT %s + FROM collectibles_ownership_cache + WHERE chain_id = ? AND owner_address = ? AND contract_address = ? AND token_id = ?`, selectOwnershipColumns) + + stmt, err := o.db.Prepare(query) + if err != nil { + return nil, err + } + defer stmt.Close() + + rows, err := stmt.Query(chainID, ownerAddresses, contractAddress, (*bigint.SQLBigIntBytes)(tokenID)) + if err != nil { + return nil, err + } + defer rows.Close() + + ids, err := rowsToCollectibles(rows) + if err != nil { + return nil, err + } + + if len(ids) == 0 { + return nil, nil + } + + return &ids[0], nil +} diff --git a/services/wallet/collectibles/service.go b/services/wallet/collectibles/service.go index 843146901..51cd8e1df 100644 --- a/services/wallet/collectibles/service.go +++ b/services/wallet/collectibles/service.go @@ -5,6 +5,7 @@ import ( "database/sql" "encoding/json" "errors" + "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/event" @@ -265,3 +266,7 @@ func (s *Service) GetOwnedCollectibles(chainIDs []walletCommon.ChainID, owners [ return ids, hasMore, nil } + +func (s *Service) GetOwnedCollectible(chainID walletCommon.ChainID, owner common.Address, contractAddress common.Address, tokenID *big.Int) (*thirdparty.CollectibleUniqueID, error) { + return s.ownershipDB.GetOwnedCollectible(chainID, owner, contractAddress, tokenID) +} diff --git a/services/wallet/router.go b/services/wallet/router.go index 9a5719773..5e6617bdf 100644 --- a/services/wallet/router.go +++ b/services/wallet/router.go @@ -23,10 +23,15 @@ import ( "github.com/status-im/status-go/services/wallet/async" "github.com/status-im/status-go/services/wallet/bigint" "github.com/status-im/status-go/services/wallet/bridge" + walletCommon "github.com/status-im/status-go/services/wallet/common" "github.com/status-im/status-go/services/wallet/token" "github.com/status-im/status-go/transactions" ) +const EstimateUsername = "RandomUsername" +const EstimatePubKey = "0x04bb2024ce5d72e45d4a4f8589ae657ef9745855006996115a23a1af88d536cf02c0524a585fce7bfa79d6a9669af735eda6205d6c7e5b3cdc2b8ff7b2fa1f0b56" +const ERC721TransferString = "ERC721Transfer" + type SendType int const ( @@ -36,20 +41,79 @@ const ( ENSSetPubKey StickersBuy Bridge + ERC721Transfer ) -const EstimateUsername = "RandomUsername" -const EstimatePubKey = "0x04bb2024ce5d72e45d4a4f8589ae657ef9745855006996115a23a1af88d536cf02c0524a585fce7bfa79d6a9669af735eda6205d6c7e5b3cdc2b8ff7b2fa1f0b56" + +func (s SendType) FetchPrices(service *Service, tokenID string) (map[string]float64, error) { + symbols := []string{tokenID, "ETH"} + if s == ERC721Transfer { + symbols = []string{"ETH"} + } + + pricesMap, err := service.marketManager.FetchPrices(symbols, []string{"USD"}) + if err != nil { + return nil, err + } + prices := make(map[string]float64, 0) + for symbol, pricePerCurrency := range pricesMap { + prices[symbol] = pricePerCurrency["USD"] + } + if s == ERC721Transfer { + prices[tokenID] = 0 + } + return prices, nil +} + +func (s SendType) FindToken(service *Service, account common.Address, network *params.Network, tokenID string) *token.Token { + if s != ERC721Transfer { + return service.tokenManager.FindToken(network, tokenID) + } + + parts := strings.Split(tokenID, ":") + contractAddress := common.HexToAddress(parts[0]) + collectibleTokenID, success := new(big.Int).SetString(parts[1], 10) + if !success { + return nil + } + uniqueID, err := service.collectibles.GetOwnedCollectible(walletCommon.ChainID(network.ChainID), account, contractAddress, collectibleTokenID) + if err != nil || uniqueID == nil { + return nil + } + + return &token.Token{ + Address: contractAddress, + Symbol: collectibleTokenID.String(), + Decimals: 0, + ChainID: network.ChainID, + } +} func (s SendType) isTransfer() bool { - return s == Transfer + return s == Transfer || s == ERC721Transfer } func (s SendType) isAvailableBetween(from, to *params.Network) bool { - if s != Bridge { - return true + if s == ERC721Transfer { + return from.ChainID == to.ChainID } - return from.ChainID != to.ChainID + if s == Bridge { + return from.ChainID != to.ChainID + } + + return true +} + +func (s SendType) canUseBridge(b bridge.Bridge) bool { + if s == ERC721Transfer && b.Name() != ERC721TransferString { + return false + } + + if s != ERC721Transfer && b.Name() == ERC721TransferString { + return false + } + + return true } func (s SendType) isAvailableFor(network *params.Network) bool { @@ -64,10 +128,9 @@ func (s SendType) isAvailableFor(network *params.Network) bool { return false } -func (s SendType) EstimateGas(service *Service, network *params.Network) uint64 { - from := types.Address(common.HexToAddress("0x5ffa75ce51c3a7ebe23bde37b5e3a0143dfbcee0")) +func (s SendType) EstimateGas(service *Service, network *params.Network, from common.Address, tokenID string) uint64 { tx := transactions.SendTxArgs{ - From: from, + From: (types.Address)(from), Value: (*hexutil.Big)(zero), } if s == ENSRegister { @@ -96,7 +159,7 @@ func (s SendType) EstimateGas(service *Service, network *params.Network) uint64 if s == StickersBuy { packID := &bigint.BigInt{Int: big.NewInt(2)} - estimate, err := service.stickers.API().BuyEstimate(context.Background(), network.ChainID, from, packID) + estimate, err := service.stickers.API().BuyEstimate(context.Background(), network.ChainID, (types.Address)(from), packID) if err != nil { return 400000 } @@ -343,10 +406,12 @@ func newSuggestedRoutes( func NewRouter(s *Service) *Router { bridges := make(map[string]bridge.Bridge) - simple := bridge.NewSimpleBridge(s.transactor) + transfer := bridge.NewTransferBridge(s.transactor) + erc721Transfer := bridge.NewERC721TransferBridge(s.rpcClient, s.transactor) cbridge := bridge.NewCbridge(s.rpcClient, s.transactor, s.tokenManager) hop := bridge.NewHopBridge(s.rpcClient, s.transactor, s.tokenManager) - bridges[simple.Name()] = simple + bridges[transfer.Name()] = transfer + bridges[erc721Transfer.Name()] = erc721Transfer bridges[hop.Name()] = hop bridges[cbridge.Name()] = cbridge @@ -369,7 +434,11 @@ type Router struct { rpcClient *rpc.Client } -func (r *Router) requireApproval(ctx context.Context, bridge bridge.Bridge, account common.Address, network *params.Network, token *token.Token, amountIn *big.Int) (bool, *big.Int, uint64, *common.Address, error) { +func (r *Router) requireApproval(ctx context.Context, sendType SendType, bridge bridge.Bridge, account common.Address, network *params.Network, token *token.Token, amountIn *big.Int) (bool, *big.Int, uint64, *common.Address, error) { + if sendType == ERC721Transfer { + return false, nil, 0, nil, nil + } + if token.IsNative() { return false, nil, 0, nil, nil } @@ -443,7 +512,7 @@ func (r *Router) suggestedRoutes( sendType SendType, account common.Address, amountIn *big.Int, - tokenSymbol string, + tokenID string, disabledFromChainIDs, disabledToChaindIDs, preferedChainIDs []uint64, @@ -460,14 +529,10 @@ func (r *Router) suggestedRoutes( return nil, err } - pricesMap, err := r.s.marketManager.FetchPrices([]string{"ETH", tokenSymbol}, []string{"USD"}) + prices, err := sendType.FetchPrices(r.s, tokenID) if err != nil { return nil, err } - prices := make(map[string]float64, 0) - for symbol, pricePerCurrency := range pricesMap { - prices[symbol] = pricePerCurrency["USD"] - } var ( group = async.NewAtomicGroup(ctx) @@ -486,7 +551,8 @@ func (r *Router) suggestedRoutes( if !sendType.isAvailableFor(network) { continue } - token := r.s.tokenManager.FindToken(network, tokenSymbol) + + token := sendType.FindToken(r.s, account, network, tokenID) if token == nil { continue } @@ -500,9 +566,13 @@ func (r *Router) suggestedRoutes( return err } - balance, err := r.getBalance(ctx, network, token, account) - if err != nil { - return err + // Default value is 1 as in case of erc721 as we built the token we are sure the account owns it + balance := big.NewInt(1) + if sendType != ERC721Transfer { + balance, err = r.getBalance(ctx, network, token, account) + if err != nil { + return err + } } maxAmountIn := (*hexutil.Big)(balance) @@ -522,6 +592,10 @@ func (r *Router) suggestedRoutes( estimatedTime := r.s.feesManager.transactionEstimatedTime(ctx, network.ChainID, maxFees) for _, bridge := range r.bridges { + if !sendType.canUseBridge(bridge) { + continue + } + for _, dest := range networks { if dest.IsTest != areTestNetworksEnabled { continue @@ -547,12 +621,10 @@ func (r *Router) suggestedRoutes( if err != nil || !can { continue } - - bonderFees, tokenFees, err := bridge.CalculateFees(network, dest, token, amountIn, prices["ETH"], prices[tokenSymbol], gasFees.GasPrice) + bonderFees, tokenFees, err := bridge.CalculateFees(network, dest, token, amountIn, prices["ETH"], prices[tokenID], gasFees.GasPrice) if err != nil { continue } - if maxAmountIn.ToInt().Cmp(amountIn) >= 0 { if bonderFees.Cmp(amountIn) >= 0 { continue @@ -562,28 +634,24 @@ func (r *Router) suggestedRoutes( continue } } - gasLimit := uint64(0) if sendType.isTransfer() { - gasLimit, err = bridge.EstimateGas(network, dest, token, amountIn) + gasLimit, err = bridge.EstimateGas(network, dest, account, token, amountIn) if err != nil { continue } } else { - gasLimit = sendType.EstimateGas(r.s, network) + gasLimit = sendType.EstimateGas(r.s, network, account, tokenID) } requiredNativeBalance := new(big.Int).Mul(gweiToWei(maxFees), big.NewInt(int64(gasLimit))) - // Removed the required fees from maxAMount in case of native token tx if token.IsNative() { maxAmountIn = (*hexutil.Big)(new(big.Int).Sub(maxAmountIn.ToInt(), requiredNativeBalance)) } - if nativeBalance.Cmp(requiredNativeBalance) <= 0 { continue } - - approvalRequired, approvalAmountRequired, approvalGasLimit, approvalContractAddress, err := r.requireApproval(ctx, bridge, account, network, token, amountIn) + approvalRequired, approvalAmountRequired, approvalGasLimit, approvalContractAddress, err := r.requireApproval(ctx, sendType, bridge, account, network, token, amountIn) if err != nil { continue } @@ -606,12 +674,11 @@ func (r *Router) suggestedRoutes( big.NewFloat(math.Pow(10, float64(token.Decimals))), ) tokenCost := new(big.Float) - tokenCost.Mul(tokenFeesAsFloat, big.NewFloat(prices[tokenSymbol])) + tokenCost.Mul(tokenFeesAsFloat, big.NewFloat(prices[tokenID])) cost := new(big.Float) cost.Add(tokenCost, gasCost) cost.Add(cost, approvalGasCost) - mu.Lock() candidates = append(candidates, &Path{ BridgeName: bridge.Name(), @@ -641,14 +708,15 @@ func (r *Router) suggestedRoutes( group.Wait() suggestedRoutes := newSuggestedRoutes(amountIn, candidates, fromLockedAmount) - suggestedRoutes.TokenPrice = prices[tokenSymbol] + suggestedRoutes.TokenPrice = prices[tokenID] suggestedRoutes.NativeChainTokenPrice = prices["ETH"] for _, path := range suggestedRoutes.Best { - amountOut, err := r.bridges[path.BridgeName].CalculateAmountOut(path.From, path.To, (*big.Int)(path.AmountIn), tokenSymbol) + amountOut, err := r.bridges[path.BridgeName].CalculateAmountOut(path.From, path.To, (*big.Int)(path.AmountIn), tokenID) if err != nil { continue } path.AmountOut = (*hexutil.Big)(amountOut) } + return suggestedRoutes, nil }