feat: route-send-collectible
This commit is contained in:
parent
195214765b
commit
01babe3632
|
@ -445,7 +445,7 @@ func (api *API) GetSuggestedRoutes(
|
||||||
sendType SendType,
|
sendType SendType,
|
||||||
account common.Address,
|
account common.Address,
|
||||||
amountIn *hexutil.Big,
|
amountIn *hexutil.Big,
|
||||||
tokenSymbol string,
|
tokenID string,
|
||||||
disabledFromChainIDs,
|
disabledFromChainIDs,
|
||||||
disabledToChaindIDs,
|
disabledToChaindIDs,
|
||||||
preferedChainIDs []uint64,
|
preferedChainIDs []uint64,
|
||||||
|
@ -453,7 +453,7 @@ func (api *API) GetSuggestedRoutes(
|
||||||
fromLockedAmount map[uint64]*hexutil.Big,
|
fromLockedAmount map[uint64]*hexutil.Big,
|
||||||
) (*SuggestedRoutes, error) {
|
) (*SuggestedRoutes, error) {
|
||||||
log.Debug("call to GetSuggestedRoutes")
|
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)
|
// Generates addresses for the provided paths, response doesn't include `HasActivity` value (if you need it check `GetAddressDetails` function)
|
||||||
|
|
|
@ -24,54 +24,63 @@ func getSigner(chainID uint64, from types.Address, verifiedAccount *account.Sele
|
||||||
type TransactionBridge struct {
|
type TransactionBridge struct {
|
||||||
BridgeName string
|
BridgeName string
|
||||||
ChainID uint64
|
ChainID uint64
|
||||||
SimpleTx *transactions.SendTxArgs
|
TransferTx *transactions.SendTxArgs
|
||||||
HopTx *HopTxArgs
|
HopTx *HopTxArgs
|
||||||
CbridgeTx *CBridgeTxArgs
|
CbridgeTx *CBridgeTxArgs
|
||||||
|
ERC721TransferTx *ERC721TransferTxArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TransactionBridge) Value() *big.Int {
|
func (t *TransactionBridge) Value() *big.Int {
|
||||||
if t.SimpleTx != nil && t.SimpleTx.To != nil {
|
if t.TransferTx != nil && t.TransferTx.To != nil {
|
||||||
return t.SimpleTx.Value.ToInt()
|
return t.TransferTx.Value.ToInt()
|
||||||
} else if t.HopTx != nil {
|
} else if t.HopTx != nil {
|
||||||
return t.HopTx.Amount.ToInt()
|
return t.HopTx.Amount.ToInt()
|
||||||
} else if t.CbridgeTx != nil {
|
} else if t.CbridgeTx != nil {
|
||||||
return t.CbridgeTx.Amount.ToInt()
|
return t.CbridgeTx.Amount.ToInt()
|
||||||
|
} else if t.ERC721TransferTx != nil {
|
||||||
|
return big.NewInt(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return big.NewInt(0)
|
return big.NewInt(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TransactionBridge) From() types.Address {
|
func (t *TransactionBridge) From() types.Address {
|
||||||
if t.SimpleTx != nil && t.SimpleTx.To != nil {
|
if t.TransferTx != nil && t.TransferTx.To != nil {
|
||||||
return t.SimpleTx.From
|
return t.TransferTx.From
|
||||||
} else if t.HopTx != nil {
|
} else if t.HopTx != nil {
|
||||||
return t.HopTx.From
|
return t.HopTx.From
|
||||||
} else if t.CbridgeTx != nil {
|
} else if t.CbridgeTx != nil {
|
||||||
return t.CbridgeTx.From
|
return t.CbridgeTx.From
|
||||||
|
} else if t.ERC721TransferTx != nil {
|
||||||
|
return t.ERC721TransferTx.From
|
||||||
}
|
}
|
||||||
|
|
||||||
return types.HexToAddress("0x0")
|
return types.HexToAddress("0x0")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TransactionBridge) To() types.Address {
|
func (t *TransactionBridge) To() types.Address {
|
||||||
if t.SimpleTx != nil && t.SimpleTx.To != nil {
|
if t.TransferTx != nil && t.TransferTx.To != nil {
|
||||||
return *t.SimpleTx.To
|
return *t.TransferTx.To
|
||||||
} else if t.HopTx != nil {
|
} else if t.HopTx != nil {
|
||||||
return types.Address(t.HopTx.Recipient)
|
return types.Address(t.HopTx.Recipient)
|
||||||
} else if t.CbridgeTx != nil {
|
} else if t.CbridgeTx != nil {
|
||||||
return types.Address(t.HopTx.Recipient)
|
return types.Address(t.HopTx.Recipient)
|
||||||
|
} else if t.ERC721TransferTx != nil {
|
||||||
|
return types.Address(t.ERC721TransferTx.Recipient)
|
||||||
}
|
}
|
||||||
|
|
||||||
return types.HexToAddress("0x0")
|
return types.HexToAddress("0x0")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TransactionBridge) Data() types.HexBytes {
|
func (t *TransactionBridge) Data() types.HexBytes {
|
||||||
if t.SimpleTx != nil && t.SimpleTx.To != nil {
|
if t.TransferTx != nil && t.TransferTx.To != nil {
|
||||||
return t.SimpleTx.Data
|
return t.TransferTx.Data
|
||||||
} else if t.HopTx != nil {
|
} else if t.HopTx != nil {
|
||||||
return types.HexBytes("")
|
return types.HexBytes("")
|
||||||
} else if t.CbridgeTx != nil {
|
} else if t.CbridgeTx != nil {
|
||||||
return types.HexBytes("")
|
return types.HexBytes("")
|
||||||
|
} else if t.ERC721TransferTx != nil {
|
||||||
|
return types.HexBytes("")
|
||||||
}
|
}
|
||||||
|
|
||||||
return types.HexBytes("")
|
return types.HexBytes("")
|
||||||
|
@ -81,7 +90,7 @@ type Bridge interface {
|
||||||
Name() string
|
Name() string
|
||||||
Can(from *params.Network, to *params.Network, token *token.Token, balance *big.Int) (bool, error)
|
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)
|
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)
|
CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error)
|
||||||
Send(sendArgs *TransactionBridge, verifiedAccount *account.SelectedExtKey) (types.Hash, error)
|
Send(sendArgs *TransactionBridge, verifiedAccount *account.SelectedExtKey) (types.Hash, error)
|
||||||
GetContractAddress(network *params.Network, token *token.Token) *common.Address
|
GetContractAddress(network *params.Network, token *token.Token) *common.Address
|
||||||
|
|
|
@ -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
|
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
|
// TODO: replace by estimate function
|
||||||
if token.IsNative() {
|
if token.IsNative() {
|
||||||
return 22000, nil // default gas limit for eth transaction
|
return 22000, nil // default gas limit for eth transaction
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -125,7 +125,7 @@ func (h *HopBridge) Can(from, to *params.Network, token *token.Token, balance *b
|
||||||
return true, nil
|
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
|
// TODO: find why this doesn't work
|
||||||
// ethClient, err := s.contractMaker.RPCClient.EthClient(from.ChainID)
|
// ethClient, err := s.contractMaker.RPCClient.EthClient(from.ChainID)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
||||||
|
}
|
|
@ -134,3 +134,32 @@ func (o *OwnershipDB) GetOwnedCollectibles(chainIDs []w_common.ChainID, ownerAdd
|
||||||
|
|
||||||
return rowsToCollectibles(rows)
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
@ -265,3 +266,7 @@ func (s *Service) GetOwnedCollectibles(chainIDs []walletCommon.ChainID, owners [
|
||||||
|
|
||||||
return ids, hasMore, nil
|
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)
|
||||||
|
}
|
||||||
|
|
|
@ -23,10 +23,15 @@ import (
|
||||||
"github.com/status-im/status-go/services/wallet/async"
|
"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/bigint"
|
||||||
"github.com/status-im/status-go/services/wallet/bridge"
|
"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/services/wallet/token"
|
||||||
"github.com/status-im/status-go/transactions"
|
"github.com/status-im/status-go/transactions"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const EstimateUsername = "RandomUsername"
|
||||||
|
const EstimatePubKey = "0x04bb2024ce5d72e45d4a4f8589ae657ef9745855006996115a23a1af88d536cf02c0524a585fce7bfa79d6a9669af735eda6205d6c7e5b3cdc2b8ff7b2fa1f0b56"
|
||||||
|
const ERC721TransferString = "ERC721Transfer"
|
||||||
|
|
||||||
type SendType int
|
type SendType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -36,20 +41,79 @@ const (
|
||||||
ENSSetPubKey
|
ENSSetPubKey
|
||||||
StickersBuy
|
StickersBuy
|
||||||
Bridge
|
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 {
|
func (s SendType) isTransfer() bool {
|
||||||
return s == Transfer
|
return s == Transfer || s == ERC721Transfer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s SendType) isAvailableBetween(from, to *params.Network) bool {
|
func (s SendType) isAvailableBetween(from, to *params.Network) bool {
|
||||||
if s != Bridge {
|
if s == ERC721Transfer {
|
||||||
|
return from.ChainID == to.ChainID
|
||||||
|
}
|
||||||
|
|
||||||
|
if s == Bridge {
|
||||||
|
return from.ChainID != to.ChainID
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return from.ChainID != to.ChainID
|
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 {
|
func (s SendType) isAvailableFor(network *params.Network) bool {
|
||||||
|
@ -64,10 +128,9 @@ func (s SendType) isAvailableFor(network *params.Network) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s SendType) EstimateGas(service *Service, network *params.Network) uint64 {
|
func (s SendType) EstimateGas(service *Service, network *params.Network, from common.Address, tokenID string) uint64 {
|
||||||
from := types.Address(common.HexToAddress("0x5ffa75ce51c3a7ebe23bde37b5e3a0143dfbcee0"))
|
|
||||||
tx := transactions.SendTxArgs{
|
tx := transactions.SendTxArgs{
|
||||||
From: from,
|
From: (types.Address)(from),
|
||||||
Value: (*hexutil.Big)(zero),
|
Value: (*hexutil.Big)(zero),
|
||||||
}
|
}
|
||||||
if s == ENSRegister {
|
if s == ENSRegister {
|
||||||
|
@ -96,7 +159,7 @@ func (s SendType) EstimateGas(service *Service, network *params.Network) uint64
|
||||||
|
|
||||||
if s == StickersBuy {
|
if s == StickersBuy {
|
||||||
packID := &bigint.BigInt{Int: big.NewInt(2)}
|
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 {
|
if err != nil {
|
||||||
return 400000
|
return 400000
|
||||||
}
|
}
|
||||||
|
@ -343,10 +406,12 @@ func newSuggestedRoutes(
|
||||||
|
|
||||||
func NewRouter(s *Service) *Router {
|
func NewRouter(s *Service) *Router {
|
||||||
bridges := make(map[string]bridge.Bridge)
|
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)
|
cbridge := bridge.NewCbridge(s.rpcClient, s.transactor, s.tokenManager)
|
||||||
hop := bridge.NewHopBridge(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[hop.Name()] = hop
|
||||||
bridges[cbridge.Name()] = cbridge
|
bridges[cbridge.Name()] = cbridge
|
||||||
|
|
||||||
|
@ -369,7 +434,11 @@ type Router struct {
|
||||||
rpcClient *rpc.Client
|
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() {
|
if token.IsNative() {
|
||||||
return false, nil, 0, nil, nil
|
return false, nil, 0, nil, nil
|
||||||
}
|
}
|
||||||
|
@ -443,7 +512,7 @@ func (r *Router) suggestedRoutes(
|
||||||
sendType SendType,
|
sendType SendType,
|
||||||
account common.Address,
|
account common.Address,
|
||||||
amountIn *big.Int,
|
amountIn *big.Int,
|
||||||
tokenSymbol string,
|
tokenID string,
|
||||||
disabledFromChainIDs,
|
disabledFromChainIDs,
|
||||||
disabledToChaindIDs,
|
disabledToChaindIDs,
|
||||||
preferedChainIDs []uint64,
|
preferedChainIDs []uint64,
|
||||||
|
@ -460,14 +529,10 @@ func (r *Router) suggestedRoutes(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pricesMap, err := r.s.marketManager.FetchPrices([]string{"ETH", tokenSymbol}, []string{"USD"})
|
prices, err := sendType.FetchPrices(r.s, tokenID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
prices := make(map[string]float64, 0)
|
|
||||||
for symbol, pricePerCurrency := range pricesMap {
|
|
||||||
prices[symbol] = pricePerCurrency["USD"]
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
group = async.NewAtomicGroup(ctx)
|
group = async.NewAtomicGroup(ctx)
|
||||||
|
@ -486,7 +551,8 @@ func (r *Router) suggestedRoutes(
|
||||||
if !sendType.isAvailableFor(network) {
|
if !sendType.isAvailableFor(network) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
token := r.s.tokenManager.FindToken(network, tokenSymbol)
|
|
||||||
|
token := sendType.FindToken(r.s, account, network, tokenID)
|
||||||
if token == nil {
|
if token == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -500,10 +566,14 @@ func (r *Router) suggestedRoutes(
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
balance, err := r.getBalance(ctx, network, token, account)
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
maxAmountIn := (*hexutil.Big)(balance)
|
maxAmountIn := (*hexutil.Big)(balance)
|
||||||
if amount, ok := fromLockedAmount[network.ChainID]; ok {
|
if amount, ok := fromLockedAmount[network.ChainID]; ok {
|
||||||
|
@ -522,6 +592,10 @@ func (r *Router) suggestedRoutes(
|
||||||
estimatedTime := r.s.feesManager.transactionEstimatedTime(ctx, network.ChainID, maxFees)
|
estimatedTime := r.s.feesManager.transactionEstimatedTime(ctx, network.ChainID, maxFees)
|
||||||
|
|
||||||
for _, bridge := range r.bridges {
|
for _, bridge := range r.bridges {
|
||||||
|
if !sendType.canUseBridge(bridge) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
for _, dest := range networks {
|
for _, dest := range networks {
|
||||||
if dest.IsTest != areTestNetworksEnabled {
|
if dest.IsTest != areTestNetworksEnabled {
|
||||||
continue
|
continue
|
||||||
|
@ -547,12 +621,10 @@ func (r *Router) suggestedRoutes(
|
||||||
if err != nil || !can {
|
if err != nil || !can {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
bonderFees, tokenFees, err := bridge.CalculateFees(network, dest, token, amountIn, prices["ETH"], prices[tokenID], gasFees.GasPrice)
|
||||||
bonderFees, tokenFees, err := bridge.CalculateFees(network, dest, token, amountIn, prices["ETH"], prices[tokenSymbol], gasFees.GasPrice)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if maxAmountIn.ToInt().Cmp(amountIn) >= 0 {
|
if maxAmountIn.ToInt().Cmp(amountIn) >= 0 {
|
||||||
if bonderFees.Cmp(amountIn) >= 0 {
|
if bonderFees.Cmp(amountIn) >= 0 {
|
||||||
continue
|
continue
|
||||||
|
@ -562,28 +634,24 @@ func (r *Router) suggestedRoutes(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gasLimit := uint64(0)
|
gasLimit := uint64(0)
|
||||||
if sendType.isTransfer() {
|
if sendType.isTransfer() {
|
||||||
gasLimit, err = bridge.EstimateGas(network, dest, token, amountIn)
|
gasLimit, err = bridge.EstimateGas(network, dest, account, token, amountIn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
} else {
|
} 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)))
|
requiredNativeBalance := new(big.Int).Mul(gweiToWei(maxFees), big.NewInt(int64(gasLimit)))
|
||||||
|
|
||||||
// Removed the required fees from maxAMount in case of native token tx
|
// Removed the required fees from maxAMount in case of native token tx
|
||||||
if token.IsNative() {
|
if token.IsNative() {
|
||||||
maxAmountIn = (*hexutil.Big)(new(big.Int).Sub(maxAmountIn.ToInt(), requiredNativeBalance))
|
maxAmountIn = (*hexutil.Big)(new(big.Int).Sub(maxAmountIn.ToInt(), requiredNativeBalance))
|
||||||
}
|
}
|
||||||
|
|
||||||
if nativeBalance.Cmp(requiredNativeBalance) <= 0 {
|
if nativeBalance.Cmp(requiredNativeBalance) <= 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
approvalRequired, approvalAmountRequired, approvalGasLimit, approvalContractAddress, err := r.requireApproval(ctx, sendType, bridge, account, network, token, amountIn)
|
||||||
approvalRequired, approvalAmountRequired, approvalGasLimit, approvalContractAddress, err := r.requireApproval(ctx, bridge, account, network, token, amountIn)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -606,12 +674,11 @@ func (r *Router) suggestedRoutes(
|
||||||
big.NewFloat(math.Pow(10, float64(token.Decimals))),
|
big.NewFloat(math.Pow(10, float64(token.Decimals))),
|
||||||
)
|
)
|
||||||
tokenCost := new(big.Float)
|
tokenCost := new(big.Float)
|
||||||
tokenCost.Mul(tokenFeesAsFloat, big.NewFloat(prices[tokenSymbol]))
|
tokenCost.Mul(tokenFeesAsFloat, big.NewFloat(prices[tokenID]))
|
||||||
|
|
||||||
cost := new(big.Float)
|
cost := new(big.Float)
|
||||||
cost.Add(tokenCost, gasCost)
|
cost.Add(tokenCost, gasCost)
|
||||||
cost.Add(cost, approvalGasCost)
|
cost.Add(cost, approvalGasCost)
|
||||||
|
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
candidates = append(candidates, &Path{
|
candidates = append(candidates, &Path{
|
||||||
BridgeName: bridge.Name(),
|
BridgeName: bridge.Name(),
|
||||||
|
@ -641,14 +708,15 @@ func (r *Router) suggestedRoutes(
|
||||||
group.Wait()
|
group.Wait()
|
||||||
|
|
||||||
suggestedRoutes := newSuggestedRoutes(amountIn, candidates, fromLockedAmount)
|
suggestedRoutes := newSuggestedRoutes(amountIn, candidates, fromLockedAmount)
|
||||||
suggestedRoutes.TokenPrice = prices[tokenSymbol]
|
suggestedRoutes.TokenPrice = prices[tokenID]
|
||||||
suggestedRoutes.NativeChainTokenPrice = prices["ETH"]
|
suggestedRoutes.NativeChainTokenPrice = prices["ETH"]
|
||||||
for _, path := range suggestedRoutes.Best {
|
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 {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
path.AmountOut = (*hexutil.Big)(amountOut)
|
path.AmountOut = (*hexutil.Big)(amountOut)
|
||||||
}
|
}
|
||||||
|
|
||||||
return suggestedRoutes, nil
|
return suggestedRoutes, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue