chore_: ens register improvements

This commit is contained in:
Sale Djenic 2024-06-05 09:56:02 +02:00 committed by saledjenic
parent 2149035619
commit 11f83780d1
14 changed files with 630 additions and 302 deletions

View File

@ -1,6 +1,7 @@
package bridge
import (
"encoding/hex"
"math/big"
ethTypes "github.com/ethereum/go-ethereum/core/types"
@ -8,15 +9,33 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/status-im/status-go/account"
"github.com/status-im/status-go/eth-node/crypto"
"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"
)
var ZeroAddress = common.Address{}
var (
ZeroAddress = common.Address{}
ZeroBigIntValue = big.NewInt(0)
)
const IncreaseEstimatedGasFactor = 1.1
const (
IncreaseEstimatedGasFactor = 1.1
EthSymbol = "ETH"
SntSymbol = "SNT"
SttSymbol = "STT"
TransferName = "Transfer"
HopName = "Hop"
CBridgeName = "CBridge"
SwapParaswapName = "Paraswap"
ERC721TransferName = "ERC721Transfer"
ERC1155TransferName = "ERC1155Transfer"
ENSRegisterName = "ENSRegister"
)
func getSigner(chainID uint64, from types.Address, verifiedAccount *account.SelectedExtKey) bind.SignerFn {
return func(addr common.Address, tx *ethTypes.Transaction) (*ethTypes.Transaction, error) {
@ -100,19 +119,55 @@ func (t *TransactionBridge) Data() types.HexBytes {
return types.HexBytes("")
}
type BridgeParams struct {
FromChain *params.Network
ToChain *params.Network
FromAddr common.Address
ToAddr common.Address
FromToken *token.Token
ToToken *token.Token
AmountIn *big.Int
// extra params
BonderFee *big.Int
Username string
PublicKey string
}
type Bridge interface {
// returns the name of the bridge
Name() string
// checks if the bridge is available for the given networks/tokens
AvailableFor(from *params.Network, to *params.Network, token *token.Token, toToken *token.Token) (bool, error)
AvailableFor(params BridgeParams) (bool, error)
// calculates the fees for the bridge and returns the amount BonderFee and TokenFee (used for bridges)
CalculateFees(from, to *params.Network, token *token.Token, amountIn *big.Int) (*big.Int, *big.Int, error)
CalculateFees(params BridgeParams) (*big.Int, *big.Int, error)
// Pack the method for sending tx and method call's data
PackTxInputData(contractType string, fromNetwork *params.Network, toNetwork *params.Network, from common.Address, to common.Address, token *token.Token, amountIn *big.Int) ([]byte, error)
EstimateGas(fromNetwork *params.Network, toNetwork *params.Network, from common.Address, to common.Address, token *token.Token, toToken *token.Token, amountIn *big.Int) (uint64, error)
CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error)
PackTxInputData(params BridgeParams, contractType string) ([]byte, error)
EstimateGas(params BridgeParams) (uint64, error)
CalculateAmountOut(params BridgeParams) (*big.Int, error)
Send(sendArgs *TransactionBridge, verifiedAccount *account.SelectedExtKey) (types.Hash, error)
GetContractAddress(network *params.Network, token *token.Token) (common.Address, error)
GetContractAddress(params BridgeParams) (common.Address, error)
BuildTransaction(sendArgs *TransactionBridge) (*ethTypes.Transaction, error)
BuildTx(fromNetwork, toNetwork *params.Network, fromAddress common.Address, toAddress common.Address, token *token.Token, amountIn *big.Int, bonderFee *big.Int) (*ethTypes.Transaction, error)
BuildTx(params BridgeParams) (*ethTypes.Transaction, error)
}
func extractCoordinates(pubkey string) ([32]byte, [32]byte) {
x, _ := hex.DecodeString(pubkey[4:68])
y, _ := hex.DecodeString(pubkey[68:132])
var xByte [32]byte
copy(xByte[:], x)
var yByte [32]byte
copy(yByte[:], y)
return xByte, yByte
}
func usernameToLabel(username string) [32]byte {
usernameHashed := crypto.Keccak256([]byte(username))
var label [32]byte
copy(label[:], usernameHashed)
return label
}

View File

@ -34,7 +34,6 @@ const (
testBaseURL = "https://cbridge-v2-test.celer.network"
maxSlippage = uint32(1000)
ethSymbol = "ETH"
)
type CBridgeTxArgs struct {
@ -64,7 +63,7 @@ func NewCbridge(rpcClient *rpc.Client, transactor transactions.TransactorIface,
}
func (s *CBridge) Name() string {
return "CBridge"
return CBridgeName
}
func (s *CBridge) estimateAmt(from, to *params.Network, amountIn *big.Int, symbol string) (*cbridge.EstimateAmtResponse, error) {
@ -127,12 +126,12 @@ func (s *CBridge) getTransferConfig(isTest bool) (*cbridge.GetTransferConfigsRes
return &res, nil
}
func (s *CBridge) AvailableFor(from, to *params.Network, token *token.Token, toToken *token.Token) (bool, error) {
if from.ChainID == to.ChainID || toToken != nil {
func (s *CBridge) AvailableFor(params BridgeParams) (bool, error) {
if params.FromChain.ChainID == params.ToChain.ChainID || params.ToToken != nil {
return false, nil
}
transferConfig, err := s.getTransferConfig(from.IsTest)
transferConfig, err := s.getTransferConfig(params.FromChain.IsTest)
if err != nil {
return false, err
}
@ -143,11 +142,11 @@ func (s *CBridge) AvailableFor(from, to *params.Network, token *token.Token, toT
var fromAvailable *cbridge.Chain
var toAvailable *cbridge.Chain
for _, chain := range transferConfig.Chains {
if uint64(chain.GetId()) == from.ChainID && chain.GasTokenSymbol == ethSymbol {
if uint64(chain.GetId()) == params.FromChain.ChainID && chain.GasTokenSymbol == EthSymbol {
fromAvailable = chain
}
if uint64(chain.GetId()) == to.ChainID && chain.GasTokenSymbol == ethSymbol {
if uint64(chain.GetId()) == params.ToChain.ChainID && chain.GasTokenSymbol == EthSymbol {
toAvailable = chain
}
}
@ -162,7 +161,7 @@ func (s *CBridge) AvailableFor(from, to *params.Network, token *token.Token, toT
}
for _, tokenInfo := range transferConfig.ChainToken[fromAvailable.GetId()].Token {
if tokenInfo.Token.Symbol == token.Symbol {
if tokenInfo.Token.Symbol == params.FromToken.Symbol {
found = true
break
}
@ -173,19 +172,21 @@ func (s *CBridge) AvailableFor(from, to *params.Network, token *token.Token, toT
found = false
for _, tokenInfo := range transferConfig.ChainToken[toAvailable.GetId()].Token {
if tokenInfo.Token.Symbol == token.Symbol {
if tokenInfo.Token.Symbol == params.FromToken.Symbol {
found = true
break
}
}
if !found {
return false, nil
}
return true, nil
}
func (s *CBridge) CalculateFees(from, to *params.Network, token *token.Token, amountIn *big.Int) (*big.Int, *big.Int, error) {
amt, err := s.estimateAmt(from, to, amountIn, token.Symbol)
func (s *CBridge) CalculateFees(params BridgeParams) (*big.Int, *big.Int, error) {
amt, err := s.estimateAmt(params.FromChain, params.ToChain, params.AmountIn, params.FromToken.Symbol)
if err != nil {
return nil, nil, err
}
@ -201,46 +202,46 @@ func (s *CBridge) CalculateFees(from, to *params.Network, token *token.Token, am
return big.NewInt(0), new(big.Int).Add(baseFee, percFee), nil
}
func (c *CBridge) PackTxInputData(contractType string, fromNetwork *params.Network, toNetwork *params.Network, from common.Address, to common.Address, token *token.Token, amountIn *big.Int) ([]byte, error) {
func (c *CBridge) PackTxInputData(params BridgeParams, contractType string) ([]byte, error) {
abi, err := abi.JSON(strings.NewReader(celer.CelerABI))
if err != nil {
return []byte{}, err
}
if token.IsNative() {
if params.FromToken.IsNative() {
return abi.Pack("sendNative",
to,
amountIn,
toNetwork.ChainID,
params.ToAddr,
params.AmountIn,
params.ToChain.ChainID,
uint64(time.Now().UnixMilli()),
maxSlippage,
)
} else {
return abi.Pack("send",
to,
token.Address,
amountIn,
toNetwork.ChainID,
params.ToAddr,
params.FromToken.Address,
params.AmountIn,
params.ToChain.ChainID,
uint64(time.Now().UnixMilli()),
maxSlippage,
)
}
}
func (s *CBridge) EstimateGas(fromNetwork *params.Network, toNetwork *params.Network, from common.Address, to common.Address, token *token.Token, toToken *token.Token, amountIn *big.Int) (uint64, error) {
func (s *CBridge) EstimateGas(params BridgeParams) (uint64, error) {
value := new(big.Int)
input, err := s.PackTxInputData("", fromNetwork, toNetwork, from, to, token, amountIn)
input, err := s.PackTxInputData(params, "")
if err != nil {
return 0, err
}
contractAddress, err := s.GetContractAddress(fromNetwork, nil)
contractAddress, err := s.GetContractAddress(params)
if err != nil {
return 0, err
}
ethClient, err := s.rpcClient.EthClient(fromNetwork.ChainID)
ethClient, err := s.rpcClient.EthClient(params.FromChain.ChainID)
if err != nil {
return 0, err
}
@ -248,7 +249,7 @@ func (s *CBridge) EstimateGas(fromNetwork *params.Network, toNetwork *params.Net
ctx := context.Background()
msg := ethereum.CallMsg{
From: from,
From: params.FromAddr,
To: &contractAddress,
Value: value,
Data: input,
@ -256,7 +257,7 @@ func (s *CBridge) EstimateGas(fromNetwork *params.Network, toNetwork *params.Net
estimation, err := ethClient.EstimateGas(ctx, msg)
if err != nil {
if !token.IsNative() {
if !params.FromToken.IsNative() {
// TODO: this is a temporary solution until we find a better way to estimate the gas
// hardcoding the estimation for other than ETH, cause we cannot get a proper estimation without having an approval placed first
// this is an error we're facing otherwise: `execution reverted: ERC20: transfer amount exceeds allowance`
@ -269,29 +270,29 @@ func (s *CBridge) EstimateGas(fromNetwork *params.Network, toNetwork *params.Net
return uint64(increasedEstimation), nil
}
func (s *CBridge) BuildTx(fromNetwork, toNetwork *params.Network, fromAddress common.Address, toAddress common.Address, token *token.Token, amountIn *big.Int, bonderFee *big.Int) (*ethTypes.Transaction, error) {
toAddr := types.Address(toAddress)
func (s *CBridge) BuildTx(params BridgeParams) (*ethTypes.Transaction, error) {
toAddr := types.Address(params.ToAddr)
sendArgs := &TransactionBridge{
CbridgeTx: &CBridgeTxArgs{
SendTxArgs: transactions.SendTxArgs{
From: types.Address(fromAddress),
From: types.Address(params.FromAddr),
To: &toAddr,
Value: (*hexutil.Big)(amountIn),
Value: (*hexutil.Big)(params.AmountIn),
Data: types.HexBytes("0x0"),
},
ChainID: toNetwork.ChainID,
Symbol: token.Symbol,
Recipient: toAddress,
Amount: (*hexutil.Big)(amountIn),
ChainID: params.ToChain.ChainID,
Symbol: params.FromToken.Symbol,
Recipient: params.ToAddr,
Amount: (*hexutil.Big)(params.AmountIn),
},
ChainID: fromNetwork.ChainID,
ChainID: params.FromChain.ChainID,
}
return s.BuildTransaction(sendArgs)
}
func (s *CBridge) GetContractAddress(network *params.Network, token *token.Token) (common.Address, error) {
transferConfig, err := s.getTransferConfig(network.IsTest)
func (s *CBridge) GetContractAddress(params BridgeParams) (common.Address, error) {
transferConfig, err := s.getTransferConfig(params.FromChain.IsTest)
if err != nil {
return common.Address{}, err
}
@ -300,7 +301,7 @@ func (s *CBridge) GetContractAddress(network *params.Network, token *token.Token
}
for _, chain := range transferConfig.Chains {
if uint64(chain.Id) == network.ChainID {
if uint64(chain.Id) == params.FromChain.ChainID {
return common.HexToAddress(chain.ContractAddr), nil
}
}
@ -309,15 +310,17 @@ func (s *CBridge) GetContractAddress(network *params.Network, token *token.Token
}
func (s *CBridge) sendOrBuild(sendArgs *TransactionBridge, signerFn bind.SignerFn) (*ethTypes.Transaction, error) {
fromNetwork := s.rpcClient.NetworkManager.Find(sendArgs.ChainID)
if fromNetwork == nil {
fromChain := s.rpcClient.NetworkManager.Find(sendArgs.ChainID)
if fromChain == nil {
return nil, errors.New("network not found")
}
token := s.tokenManager.FindToken(fromNetwork, sendArgs.CbridgeTx.Symbol)
token := s.tokenManager.FindToken(fromChain, sendArgs.CbridgeTx.Symbol)
if token == nil {
return nil, errors.New("token not found")
}
addrs, err := s.GetContractAddress(fromNetwork, nil)
addrs, err := s.GetContractAddress(BridgeParams{
FromChain: fromChain,
})
if err != nil {
return nil, err
}
@ -367,8 +370,8 @@ func (s *CBridge) BuildTransaction(sendArgs *TransactionBridge) (*ethTypes.Trans
return s.sendOrBuild(sendArgs, nil)
}
func (s *CBridge) CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error) {
amt, err := s.estimateAmt(from, to, amountIn, symbol)
func (s *CBridge) CalculateAmountOut(params BridgeParams) (*big.Int, error) {
amt, err := s.estimateAmt(params.FromChain, params.ToChain, params.AmountIn, params.FromToken.Symbol)
if err != nil {
return nil, err
}

View File

@ -0,0 +1,165 @@
package bridge
import (
"context"
"math/big"
"strings"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethTypes "github.com/ethereum/go-ethereum/core/types"
"github.com/status-im/status-go/account"
"github.com/status-im/status-go/contracts"
"github.com/status-im/status-go/contracts/registrar"
"github.com/status-im/status-go/contracts/snt"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/rpc"
"github.com/status-im/status-go/services/ens"
walletCommon "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/transactions"
)
type ENSRegisterBridge struct {
contractMaker *contracts.ContractMaker
transactor transactions.TransactorIface
ensService *ens.Service
}
func NewENSRegisterBridge(rpcClient *rpc.Client, transactor transactions.TransactorIface, ensService *ens.Service) *ENSRegisterBridge {
return &ENSRegisterBridge{
contractMaker: &contracts.ContractMaker{
RPCClient: rpcClient,
},
// rpcClient: rpcClient,
transactor: transactor,
ensService: ensService,
}
}
func (s *ENSRegisterBridge) Name() string {
return ENSRegisterName
}
func (s *ENSRegisterBridge) GetPriceForRegisteringEnsName(chainID uint64) (*big.Int, error) {
registryAddr, err := s.ensService.API().GetRegistrarAddress(context.Background(), chainID)
if err != nil {
return nil, err
}
registrar, err := s.contractMaker.NewUsernameRegistrar(chainID, registryAddr)
if err != nil {
return nil, err
}
callOpts := &bind.CallOpts{Context: context.Background(), Pending: false}
return registrar.GetPrice(callOpts)
}
func (s *ENSRegisterBridge) AvailableFor(params BridgeParams) (bool, error) {
return params.FromChain.ChainID == walletCommon.EthereumMainnet || params.FromChain.ChainID == walletCommon.EthereumSepolia, nil
}
func (s *ENSRegisterBridge) CalculateFees(params BridgeParams) (*big.Int, *big.Int, error) {
return big.NewInt(0), big.NewInt(0), nil
}
func (s *ENSRegisterBridge) PackTxInputData(params BridgeParams, contractType string) ([]byte, error) {
price, err := s.GetPriceForRegisteringEnsName(params.FromChain.ChainID)
if err != nil {
return []byte{}, err
}
registrarABI, err := abi.JSON(strings.NewReader(registrar.UsernameRegistrarABI))
if err != nil {
return []byte{}, err
}
x, y := extractCoordinates(params.PublicKey)
extraData, err := registrarABI.Pack("register", usernameToLabel(params.Username), params.FromAddr, x, y)
if err != nil {
return []byte{}, err
}
sntABI, err := abi.JSON(strings.NewReader(snt.SNTABI))
if err != nil {
return []byte{}, err
}
registryAddr, err := s.ensService.API().GetRegistrarAddress(context.Background(), params.FromChain.ChainID)
if err != nil {
return []byte{}, err
}
return sntABI.Pack("approveAndCall", registryAddr, price, extraData)
}
func (s *ENSRegisterBridge) EstimateGas(params BridgeParams) (uint64, error) {
contractAddress, err := s.GetContractAddress(params)
if err != nil {
return 0, err
}
input, err := s.PackTxInputData(params, "")
if err != nil {
return 0, err
}
ethClient, err := s.contractMaker.RPCClient.EthClient(params.FromChain.ChainID)
if err != nil {
return 0, err
}
msg := ethereum.CallMsg{
From: params.FromAddr,
To: &contractAddress,
Value: big.NewInt(0),
Data: input,
}
estimation, err := ethClient.EstimateGas(context.Background(), msg)
if err != nil {
return 0, err
}
increasedEstimation := float64(estimation) * IncreaseEstimatedGasFactor
return uint64(increasedEstimation), nil
}
func (s *ENSRegisterBridge) BuildTx(params BridgeParams) (*ethTypes.Transaction, error) {
toAddr := types.Address(params.ToAddr)
inputData, err := s.PackTxInputData(params, "")
if err != nil {
return nil, err
}
sendArgs := &TransactionBridge{
TransferTx: &transactions.SendTxArgs{
From: types.Address(params.FromAddr),
To: &toAddr,
Value: (*hexutil.Big)(ZeroBigIntValue),
Data: inputData,
},
ChainID: params.FromChain.ChainID,
}
return s.BuildTransaction(sendArgs)
}
func (s *ENSRegisterBridge) Send(sendArgs *TransactionBridge, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) {
return s.transactor.SendTransactionWithChainID(sendArgs.ChainID, *sendArgs.TransferTx, verifiedAccount)
}
func (s *ENSRegisterBridge) BuildTransaction(sendArgs *TransactionBridge) (*ethTypes.Transaction, error) {
return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, *sendArgs.TransferTx)
}
func (s *ENSRegisterBridge) CalculateAmountOut(params BridgeParams) (*big.Int, error) {
return params.AmountIn, nil
}
func (s *ENSRegisterBridge) GetContractAddress(params BridgeParams) (common.Address, error) {
return snt.ContractAddress(params.FromChain.ChainID)
}

View File

@ -15,9 +15,7 @@ import (
"github.com/status-im/status-go/account"
"github.com/status-im/status-go/contracts/ierc1155"
"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"
)
@ -38,53 +36,53 @@ func NewERC1155TransferBridge(rpcClient *rpc.Client, transactor transactions.Tra
}
func (s *ERC1155TransferBridge) Name() string {
return "ERC1155Transfer"
return ERC1155TransferName
}
func (s *ERC1155TransferBridge) AvailableFor(from, to *params.Network, token *token.Token, toToken *token.Token) (bool, error) {
return from.ChainID == to.ChainID && toToken == nil, nil
func (s *ERC1155TransferBridge) AvailableFor(params BridgeParams) (bool, error) {
return params.FromChain.ChainID == params.ToChain.ChainID && params.ToToken == nil, nil
}
func (s *ERC1155TransferBridge) CalculateFees(from, to *params.Network, token *token.Token, amountIn *big.Int) (*big.Int, *big.Int, error) {
func (s *ERC1155TransferBridge) CalculateFees(params BridgeParams) (*big.Int, *big.Int, error) {
return big.NewInt(0), big.NewInt(0), nil
}
func (s *ERC1155TransferBridge) PackTxInputData(contractType string, fromNetwork *params.Network, toNetwork *params.Network, from common.Address, to common.Address, token *token.Token, amountIn *big.Int) ([]byte, error) {
func (s *ERC1155TransferBridge) PackTxInputData(params BridgeParams, contractType string) ([]byte, error) {
abi, err := abi.JSON(strings.NewReader(ierc1155.Ierc1155ABI))
if err != nil {
return []byte{}, err
}
id, success := big.NewInt(0).SetString(token.Symbol, 0)
id, success := big.NewInt(0).SetString(params.FromToken.Symbol, 0)
if !success {
return []byte{}, fmt.Errorf("failed to convert %s to big.Int", token.Symbol)
return []byte{}, fmt.Errorf("failed to convert %s to big.Int", params.FromToken.Symbol)
}
return abi.Pack("safeTransferFrom",
from,
to,
params.FromAddr,
params.ToAddr,
id,
amountIn,
params.AmountIn,
[]byte{},
)
}
func (s *ERC1155TransferBridge) EstimateGas(fromNetwork *params.Network, toNetwork *params.Network, from common.Address, to common.Address, token *token.Token, toToken *token.Token, amountIn *big.Int) (uint64, error) {
ethClient, err := s.rpcClient.EthClient(fromNetwork.ChainID)
func (s *ERC1155TransferBridge) EstimateGas(params BridgeParams) (uint64, error) {
ethClient, err := s.rpcClient.EthClient(params.FromChain.ChainID)
if err != nil {
return 0, err
}
value := new(big.Int)
input, err := s.PackTxInputData("", fromNetwork, toNetwork, from, to, token, amountIn)
input, err := s.PackTxInputData(params, "")
if err != nil {
return 0, err
}
msg := ethereum.CallMsg{
From: from,
To: &token.Address,
From: params.FromAddr,
To: &params.FromToken.Address,
Value: value,
Data: input,
}
@ -97,28 +95,28 @@ func (s *ERC1155TransferBridge) EstimateGas(fromNetwork *params.Network, toNetwo
return uint64(increasedEstimation), nil
}
func (s *ERC1155TransferBridge) BuildTx(network, _ *params.Network, fromAddress common.Address, toAddress common.Address, token *token.Token, amountIn *big.Int, _ *big.Int) (*ethTypes.Transaction, error) {
contractAddress := types.Address(token.Address)
func (s *ERC1155TransferBridge) BuildTx(params BridgeParams) (*ethTypes.Transaction, error) {
contractAddress := types.Address(params.FromToken.Address)
// We store ERC1155 Token ID using big.Int.String() in token.Symbol
tokenID, success := new(big.Int).SetString(token.Symbol, 10)
tokenID, success := new(big.Int).SetString(params.FromToken.Symbol, 10)
if !success {
return nil, fmt.Errorf("failed to convert ERC1155's Symbol %s to big.Int", token.Symbol)
return nil, fmt.Errorf("failed to convert ERC1155's Symbol %s to big.Int", params.FromToken.Symbol)
}
sendArgs := &TransactionBridge{
ERC1155TransferTx: &ERC1155TransferTxArgs{
SendTxArgs: transactions.SendTxArgs{
From: types.Address(fromAddress),
From: types.Address(params.FromAddr),
To: &contractAddress,
Value: (*hexutil.Big)(amountIn),
Value: (*hexutil.Big)(params.AmountIn),
Data: types.HexBytes("0x0"),
},
TokenID: (*hexutil.Big)(tokenID),
Recipient: toAddress,
Amount: (*hexutil.Big)(amountIn),
Recipient: params.ToAddr,
Amount: (*hexutil.Big)(params.AmountIn),
},
ChainID: network.ChainID,
ChainID: params.FromChain.ChainID,
}
return s.BuildTransaction(sendArgs)
@ -165,10 +163,10 @@ func (s *ERC1155TransferBridge) BuildTransaction(sendArgs *TransactionBridge) (*
return s.sendOrBuild(sendArgs, nil)
}
func (s *ERC1155TransferBridge) CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error) {
return amountIn, nil
func (s *ERC1155TransferBridge) CalculateAmountOut(params BridgeParams) (*big.Int, error) {
return params.AmountIn, nil
}
func (s *ERC1155TransferBridge) GetContractAddress(network *params.Network, token *token.Token) (common.Address, error) {
return token.Address, nil
func (s *ERC1155TransferBridge) GetContractAddress(params BridgeParams) (common.Address, error) {
return params.FromToken.Address, nil
}

View File

@ -15,9 +15,7 @@ import (
"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"
)
@ -37,51 +35,51 @@ func NewERC721TransferBridge(rpcClient *rpc.Client, transactor transactions.Tran
}
func (s *ERC721TransferBridge) Name() string {
return "ERC721Transfer"
return ERC721TransferName
}
func (s *ERC721TransferBridge) AvailableFor(from, to *params.Network, token *token.Token, toToken *token.Token) (bool, error) {
return from.ChainID == to.ChainID && toToken == nil, nil
func (s *ERC721TransferBridge) AvailableFor(params BridgeParams) (bool, error) {
return params.FromChain.ChainID == params.ToChain.ChainID && params.ToToken == nil, nil
}
func (s *ERC721TransferBridge) CalculateFees(from, to *params.Network, token *token.Token, amountIn *big.Int) (*big.Int, *big.Int, error) {
func (s *ERC721TransferBridge) CalculateFees(params BridgeParams) (*big.Int, *big.Int, error) {
return big.NewInt(0), big.NewInt(0), nil
}
func (s *ERC721TransferBridge) PackTxInputData(contractType string, fromNetwork *params.Network, toNetwork *params.Network, from common.Address, to common.Address, token *token.Token, amountIn *big.Int) ([]byte, error) {
func (s *ERC721TransferBridge) PackTxInputData(params BridgeParams, contractType string) ([]byte, error) {
abi, err := abi.JSON(strings.NewReader(collectibles.CollectiblesMetaData.ABI))
if err != nil {
return []byte{}, err
}
id, success := big.NewInt(0).SetString(token.Symbol, 0)
id, success := big.NewInt(0).SetString(params.FromToken.Symbol, 0)
if !success {
return []byte{}, fmt.Errorf("failed to convert %s to big.Int", token.Symbol)
return []byte{}, fmt.Errorf("failed to convert %s to big.Int", params.FromToken.Symbol)
}
return abi.Pack("safeTransferFrom",
from,
to,
params.FromAddr,
params.ToAddr,
id,
)
}
func (s *ERC721TransferBridge) EstimateGas(fromNetwork *params.Network, toNetwork *params.Network, from common.Address, to common.Address, token *token.Token, toToken *token.Token, amountIn *big.Int) (uint64, error) {
ethClient, err := s.rpcClient.EthClient(fromNetwork.ChainID)
func (s *ERC721TransferBridge) EstimateGas(params BridgeParams) (uint64, error) {
ethClient, err := s.rpcClient.EthClient(params.FromChain.ChainID)
if err != nil {
return 0, err
}
value := new(big.Int)
input, err := s.PackTxInputData("", fromNetwork, toNetwork, from, to, token, amountIn)
input, err := s.PackTxInputData(params, "")
if err != nil {
return 0, err
}
msg := ethereum.CallMsg{
From: from,
To: &token.Address,
From: params.FromAddr,
To: &params.FromToken.Address,
Value: value,
Data: input,
}
@ -90,31 +88,32 @@ func (s *ERC721TransferBridge) EstimateGas(fromNetwork *params.Network, toNetwor
if err != nil {
return 0, err
}
increasedEstimation := float64(estimation) * IncreaseEstimatedGasFactor
return uint64(increasedEstimation), nil
}
func (s *ERC721TransferBridge) BuildTx(network, _ *params.Network, fromAddress common.Address, toAddress common.Address, token *token.Token, amountIn *big.Int, _ *big.Int) (*ethTypes.Transaction, error) {
contractAddress := types.Address(token.Address)
func (s *ERC721TransferBridge) BuildTx(params BridgeParams) (*ethTypes.Transaction, error) {
contractAddress := types.Address(params.FromToken.Address)
// We store ERC721 Token ID using big.Int.String() in token.Symbol
tokenID, success := new(big.Int).SetString(token.Symbol, 10)
tokenID, success := new(big.Int).SetString(params.FromToken.Symbol, 10)
if !success {
return nil, fmt.Errorf("failed to convert ERC721's Symbol %s to big.Int", token.Symbol)
return nil, fmt.Errorf("failed to convert ERC721's Symbol %s to big.Int", params.FromToken.Symbol)
}
sendArgs := &TransactionBridge{
ERC721TransferTx: &ERC721TransferTxArgs{
SendTxArgs: transactions.SendTxArgs{
From: types.Address(fromAddress),
From: types.Address(params.FromAddr),
To: &contractAddress,
Value: (*hexutil.Big)(amountIn),
Value: (*hexutil.Big)(params.AmountIn),
Data: types.HexBytes("0x0"),
},
TokenID: (*hexutil.Big)(tokenID),
Recipient: toAddress,
Recipient: params.ToAddr,
},
ChainID: network.ChainID,
ChainID: params.FromChain.ChainID,
}
return s.BuildTransaction(sendArgs)
@ -139,6 +138,7 @@ func (s *ERC721TransferBridge) sendOrBuild(sendArgs *TransactionBridge, signerFn
argNonce := hexutil.Uint64(nonce)
sendArgs.ERC721TransferTx.Nonce = &argNonce
txOpts := sendArgs.ERC721TransferTx.ToTransactOpts(signerFn)
tx, err = contract.SafeTransferFrom(txOpts, common.Address(sendArgs.ERC721TransferTx.From),
sendArgs.ERC721TransferTx.Recipient,
sendArgs.ERC721TransferTx.TokenID.ToInt())
@ -157,10 +157,10 @@ func (s *ERC721TransferBridge) BuildTransaction(sendArgs *TransactionBridge) (*e
return s.sendOrBuild(sendArgs, nil)
}
func (s *ERC721TransferBridge) CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error) {
return amountIn, nil
func (s *ERC721TransferBridge) CalculateAmountOut(params BridgeParams) (*big.Int, error) {
return params.AmountIn, nil
}
func (s *ERC721TransferBridge) GetContractAddress(network *params.Network, token *token.Token) (common.Address, error) {
return token.Address, nil
func (s *ERC721TransferBridge) GetContractAddress(params BridgeParams) (common.Address, error) {
return params.FromToken.Address, nil
}

View File

@ -27,7 +27,6 @@ import (
hopL2CctpImplementation "github.com/status-im/status-go/contracts/hop/l2Contracts/l2CctpImplementation"
hopL2OptimismBridge "github.com/status-im/status-go/contracts/hop/l2Contracts/l2OptimismBridge"
"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/rpc/chain"
"github.com/status-im/status-go/services/wallet/bigint"
@ -124,14 +123,14 @@ func NewHopBridge(rpcClient *rpc.Client, transactor transactions.TransactorIface
}
func (h *HopBridge) Name() string {
return "Hop"
return HopName
}
func (h *HopBridge) AvailableFor(from, to *params.Network, token *token.Token, toToken *token.Token) (bool, error) {
func (h *HopBridge) AvailableFor(params BridgeParams) (bool, error) {
// We chcek if the contract is available on the network for the token
_, err := h.GetContractAddress(from, token)
_, err := h.GetContractAddress(params)
// toToken is not nil only if the send type is Swap
return err == nil && toToken == nil, nil
return err == nil && params.ToToken == nil, nil
}
func (c *HopBridge) getAppropriateABI(contractType string, chainID uint64, token *token.Token) (abi.ABI, error) {
@ -164,51 +163,51 @@ func (c *HopBridge) getAppropriateABI(contractType string, chainID uint64, token
return abi.ABI{}, errors.New("not available for contract type")
}
func (h *HopBridge) PackTxInputData(contractType string, fromNetwork *params.Network, toNetwork *params.Network, from common.Address, to common.Address, token *token.Token, amountIn *big.Int) ([]byte, error) {
abi, err := h.getAppropriateABI(contractType, fromNetwork.ChainID, token)
func (h *HopBridge) PackTxInputData(params BridgeParams, contractType string) ([]byte, error) {
abi, err := h.getAppropriateABI(contractType, params.FromChain.ChainID, params.FromToken)
if err != nil {
return []byte{}, err
}
switch contractType {
case hop.CctpL1Bridge:
return h.packCctpL1BridgeTx(abi, toNetwork.ChainID, to)
return h.packCctpL1BridgeTx(abi, params.ToChain.ChainID, params.ToAddr)
case hop.L1Bridge:
return h.packL1BridgeTx(abi, toNetwork.ChainID, to)
return h.packL1BridgeTx(abi, params.ToChain.ChainID, params.ToAddr)
case hop.L2AmmWrapper:
return h.packL2AmmWrapperTx(abi, toNetwork.ChainID, to)
return h.packL2AmmWrapperTx(abi, params.ToChain.ChainID, params.ToAddr)
case hop.CctpL2Bridge:
return h.packCctpL2BridgeTx(abi, toNetwork.ChainID, to)
return h.packCctpL2BridgeTx(abi, params.ToChain.ChainID, params.ToAddr)
case hop.L2Bridge:
return h.packL2BridgeTx(abi, toNetwork.ChainID, to)
return h.packL2BridgeTx(abi, params.ToChain.ChainID, params.ToAddr)
}
return []byte{}, errors.New("contract type not supported yet")
}
func (h *HopBridge) EstimateGas(fromNetwork *params.Network, toNetwork *params.Network, from common.Address, to common.Address, token *token.Token, toToken *token.Token, amountIn *big.Int) (uint64, error) {
func (h *HopBridge) EstimateGas(params BridgeParams) (uint64, error) {
value := big.NewInt(0)
if token.IsNative() {
value = amountIn
if params.FromToken.IsNative() {
value = params.AmountIn
}
contractAddress, contractType, err := hop.GetContractAddress(fromNetwork.ChainID, token.Symbol)
contractAddress, contractType, err := hop.GetContractAddress(params.FromChain.ChainID, params.FromToken.Symbol)
if err != nil {
return 0, err
}
input, err := h.PackTxInputData(contractType, fromNetwork, toNetwork, from, to, token, amountIn)
input, err := h.PackTxInputData(params, contractType)
if err != nil {
return 0, err
}
ethClient, err := h.contractMaker.RPCClient.EthClient(fromNetwork.ChainID)
ethClient, err := h.contractMaker.RPCClient.EthClient(params.FromChain.ChainID)
if err != nil {
return 0, err
}
msg := ethereum.CallMsg{
From: from,
From: params.FromAddr,
To: &contractAddress,
Value: value,
Data: input,
@ -216,7 +215,7 @@ func (h *HopBridge) EstimateGas(fromNetwork *params.Network, toNetwork *params.N
estimation, err := ethClient.EstimateGas(context.Background(), msg)
if err != nil {
if !token.IsNative() {
if !params.FromToken.IsNative() {
// TODO: this is a temporary solution until we find a better way to estimate the gas
// hardcoding the estimation for other than ETH, cause we cannot get a proper estimation without having an approval placed first
// this is an error we're facing otherwise: `execution reverted: ERC20: transfer amount exceeds allowance`
@ -230,42 +229,42 @@ func (h *HopBridge) EstimateGas(fromNetwork *params.Network, toNetwork *params.N
return uint64(increasedEstimation), nil
}
func (h *HopBridge) BuildTx(fromNetwork, toNetwork *params.Network, fromAddress common.Address, toAddress common.Address, token *token.Token, amountIn *big.Int, bonderFee *big.Int) (*ethTypes.Transaction, error) {
toAddr := types.Address(toAddress)
func (h *HopBridge) BuildTx(params BridgeParams) (*ethTypes.Transaction, error) {
toAddr := types.Address(params.ToAddr)
sendArgs := &TransactionBridge{
HopTx: &HopTxArgs{
SendTxArgs: transactions.SendTxArgs{
From: types.Address(fromAddress),
From: types.Address(params.FromAddr),
To: &toAddr,
Value: (*hexutil.Big)(amountIn),
Value: (*hexutil.Big)(params.AmountIn),
Data: types.HexBytes("0x0"),
},
Symbol: token.Symbol,
Recipient: toAddress,
Amount: (*hexutil.Big)(amountIn),
BonderFee: (*hexutil.Big)(bonderFee),
ChainID: toNetwork.ChainID,
Symbol: params.FromToken.Symbol,
Recipient: params.ToAddr,
Amount: (*hexutil.Big)(params.AmountIn),
BonderFee: (*hexutil.Big)(params.BonderFee),
ChainID: params.ToChain.ChainID,
},
ChainID: fromNetwork.ChainID,
ChainID: params.FromChain.ChainID,
}
return h.BuildTransaction(sendArgs)
}
func (h *HopBridge) GetContractAddress(network *params.Network, token *token.Token) (common.Address, error) {
address, _, err := hop.GetContractAddress(network.ChainID, token.Symbol)
func (h *HopBridge) GetContractAddress(params BridgeParams) (common.Address, error) {
address, _, err := hop.GetContractAddress(params.FromChain.ChainID, params.FromToken.Symbol)
return address, err
}
func (h *HopBridge) sendOrBuild(sendArgs *TransactionBridge, signerFn bind.SignerFn) (tx *ethTypes.Transaction, err error) {
fromNetwork := h.contractMaker.RPCClient.NetworkManager.Find(sendArgs.ChainID)
if fromNetwork == nil {
fromChain := h.contractMaker.RPCClient.NetworkManager.Find(sendArgs.ChainID)
if fromChain == nil {
return tx, fmt.Errorf("ChainID not supported %d", sendArgs.ChainID)
}
token := h.tokenManager.FindToken(fromNetwork, sendArgs.HopTx.Symbol)
token := h.tokenManager.FindToken(fromChain, sendArgs.HopTx.Symbol)
nonce, err := h.transactor.NextNonce(h.contractMaker.RPCClient, fromNetwork.ChainID, sendArgs.HopTx.From)
nonce, err := h.transactor.NextNonce(h.contractMaker.RPCClient, fromChain.ChainID, sendArgs.HopTx.From)
if err != nil {
return tx, err
}
@ -278,12 +277,12 @@ func (h *HopBridge) sendOrBuild(sendArgs *TransactionBridge, signerFn bind.Signe
txOpts.Value = (*big.Int)(sendArgs.HopTx.Amount)
}
ethClient, err := h.contractMaker.RPCClient.EthClient(fromNetwork.ChainID)
ethClient, err := h.contractMaker.RPCClient.EthClient(fromChain.ChainID)
if err != nil {
return tx, err
}
contractAddress, contractType, err := hop.GetContractAddress(fromNetwork.ChainID, sendArgs.HopTx.Symbol)
contractAddress, contractType, err := hop.GetContractAddress(fromChain.ChainID, sendArgs.HopTx.Symbol)
if err != nil {
return tx, err
}
@ -316,32 +315,32 @@ func (h *HopBridge) BuildTransaction(sendArgs *TransactionBridge) (*ethTypes.Tra
return h.sendOrBuild(sendArgs, nil)
}
func (h *HopBridge) CalculateFees(from, to *params.Network, token *token.Token, amountIn *big.Int) (*big.Int, *big.Int, error) {
func (h *HopBridge) CalculateFees(params BridgeParams) (*big.Int, *big.Int, error) {
hopChainsMap := map[uint64]string{
walletCommon.EthereumMainnet: "ethereum",
walletCommon.OptimismMainnet: "optimism",
walletCommon.ArbitrumMainnet: "arbitrum",
}
fromChainName, ok := hopChainsMap[from.ChainID]
fromChainName, ok := hopChainsMap[params.FromChain.ChainID]
if !ok {
return nil, nil, errors.New("from chain not supported")
}
toChainName, ok := hopChainsMap[to.ChainID]
toChainName, ok := hopChainsMap[params.ToChain.ChainID]
if !ok {
return nil, nil, errors.New("to chain not supported")
}
params := netUrl.Values{}
params.Add("amount", amountIn.String())
params.Add("token", token.Symbol)
params.Add("fromChain", fromChainName)
params.Add("toChain", toChainName)
params.Add("slippage", "0.5") // menas 0.5%
reqParams := netUrl.Values{}
reqParams.Add("amount", params.AmountIn.String())
reqParams.Add("token", params.FromToken.Symbol)
reqParams.Add("fromChain", fromChainName)
reqParams.Add("toChain", toChainName)
reqParams.Add("slippage", "0.5") // menas 0.5%
url := "https://api.hop.exchange/v1/quote"
response, err := h.httpClient.DoGetRequest(context.Background(), url, params)
response, err := h.httpClient.DoGetRequest(context.Background(), url, reqParams)
if err != nil {
return nil, nil, err
}
@ -360,7 +359,7 @@ func (h *HopBridge) CalculateFees(from, to *params.Network, token *token.Token,
return h.bonderFee.BonderFee.Int, tokenFee, nil
}
func (h *HopBridge) CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error) {
func (h *HopBridge) CalculateAmountOut(params BridgeParams) (*big.Int, error) {
return h.bonderFee.EstimatedRecieved.Int, nil
}

View File

@ -13,9 +13,7 @@ import (
gomock "github.com/golang/mock/gomock"
account "github.com/status-im/status-go/account"
types0 "github.com/status-im/status-go/eth-node/types"
params "github.com/status-im/status-go/params"
bridge "github.com/status-im/status-go/services/wallet/bridge"
token "github.com/status-im/status-go/services/wallet/token"
)
// MockBridge is a mock of Bridge interface.
@ -42,18 +40,18 @@ func (m *MockBridge) EXPECT() *MockBridgeMockRecorder {
}
// AvailableFor mocks base method.
func (m *MockBridge) AvailableFor(from, to *params.Network, token, toToken *token.Token) (bool, error) {
func (m *MockBridge) AvailableFor(params bridge.BridgeParams) (bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AvailableFor", from, to, token, toToken)
ret := m.ctrl.Call(m, "AvailableFor", params)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AvailableFor indicates an expected call of AvailableFor.
func (mr *MockBridgeMockRecorder) AvailableFor(from, to, token, toToken interface{}) *gomock.Call {
func (mr *MockBridgeMockRecorder) AvailableFor(params interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AvailableFor", reflect.TypeOf((*MockBridge)(nil).AvailableFor), from, to, token, toToken)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AvailableFor", reflect.TypeOf((*MockBridge)(nil).AvailableFor), params)
}
// BuildTransaction mocks base method.
@ -72,39 +70,39 @@ func (mr *MockBridgeMockRecorder) BuildTransaction(sendArgs interface{}) *gomock
}
// BuildTx mocks base method.
func (m *MockBridge) BuildTx(fromNetwork, toNetwork *params.Network, fromAddress, toAddress common.Address, token *token.Token, amountIn, bonderFee *big.Int) (*types.Transaction, error) {
func (m *MockBridge) BuildTx(params bridge.BridgeParams) (*types.Transaction, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BuildTx", fromNetwork, toNetwork, fromAddress, toAddress, token, amountIn, bonderFee)
ret := m.ctrl.Call(m, "BuildTx", params)
ret0, _ := ret[0].(*types.Transaction)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// BuildTx indicates an expected call of BuildTx.
func (mr *MockBridgeMockRecorder) BuildTx(fromNetwork, toNetwork, fromAddress, toAddress, token, amountIn, bonderFee interface{}) *gomock.Call {
func (mr *MockBridgeMockRecorder) BuildTx(params interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BuildTx", reflect.TypeOf((*MockBridge)(nil).BuildTx), fromNetwork, toNetwork, fromAddress, toAddress, token, amountIn, bonderFee)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BuildTx", reflect.TypeOf((*MockBridge)(nil).BuildTx), params)
}
// CalculateAmountOut mocks base method.
func (m *MockBridge) CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error) {
func (m *MockBridge) CalculateAmountOut(params bridge.BridgeParams) (*big.Int, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CalculateAmountOut", from, to, amountIn, symbol)
ret := m.ctrl.Call(m, "CalculateAmountOut", params)
ret0, _ := ret[0].(*big.Int)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// CalculateAmountOut indicates an expected call of CalculateAmountOut.
func (mr *MockBridgeMockRecorder) CalculateAmountOut(from, to, amountIn, symbol interface{}) *gomock.Call {
func (mr *MockBridgeMockRecorder) CalculateAmountOut(params interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CalculateAmountOut", reflect.TypeOf((*MockBridge)(nil).CalculateAmountOut), from, to, amountIn, symbol)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CalculateAmountOut", reflect.TypeOf((*MockBridge)(nil).CalculateAmountOut), params)
}
// CalculateFees mocks base method.
func (m *MockBridge) CalculateFees(from, to *params.Network, token *token.Token, amountIn *big.Int) (*big.Int, *big.Int, error) {
func (m *MockBridge) CalculateFees(params bridge.BridgeParams) (*big.Int, *big.Int, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CalculateFees", from, to, token, amountIn)
ret := m.ctrl.Call(m, "CalculateFees", params)
ret0, _ := ret[0].(*big.Int)
ret1, _ := ret[1].(*big.Int)
ret2, _ := ret[2].(error)
@ -112,39 +110,39 @@ func (m *MockBridge) CalculateFees(from, to *params.Network, token *token.Token,
}
// CalculateFees indicates an expected call of CalculateFees.
func (mr *MockBridgeMockRecorder) CalculateFees(from, to, token, amountIn interface{}) *gomock.Call {
func (mr *MockBridgeMockRecorder) CalculateFees(params interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CalculateFees", reflect.TypeOf((*MockBridge)(nil).CalculateFees), from, to, token, amountIn)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CalculateFees", reflect.TypeOf((*MockBridge)(nil).CalculateFees), params)
}
// EstimateGas mocks base method.
func (m *MockBridge) EstimateGas(fromNetwork, toNetwork *params.Network, from, to common.Address, token, toToken *token.Token, amountIn *big.Int) (uint64, error) {
func (m *MockBridge) EstimateGas(params bridge.BridgeParams) (uint64, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EstimateGas", fromNetwork, toNetwork, from, to, token, toToken, amountIn)
ret := m.ctrl.Call(m, "EstimateGas", params)
ret0, _ := ret[0].(uint64)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EstimateGas indicates an expected call of EstimateGas.
func (mr *MockBridgeMockRecorder) EstimateGas(fromNetwork, toNetwork, from, to, token, toToken, amountIn interface{}) *gomock.Call {
func (mr *MockBridgeMockRecorder) EstimateGas(params interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimateGas", reflect.TypeOf((*MockBridge)(nil).EstimateGas), fromNetwork, toNetwork, from, to, token, toToken, amountIn)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimateGas", reflect.TypeOf((*MockBridge)(nil).EstimateGas), params)
}
// GetContractAddress mocks base method.
func (m *MockBridge) GetContractAddress(network *params.Network, token *token.Token) (common.Address, error) {
func (m *MockBridge) GetContractAddress(params bridge.BridgeParams) (common.Address, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetContractAddress", network, token)
ret := m.ctrl.Call(m, "GetContractAddress", params)
ret0, _ := ret[0].(common.Address)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetContractAddress indicates an expected call of GetContractAddress.
func (mr *MockBridgeMockRecorder) GetContractAddress(network, token interface{}) *gomock.Call {
func (mr *MockBridgeMockRecorder) GetContractAddress(params interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetContractAddress", reflect.TypeOf((*MockBridge)(nil).GetContractAddress), network, token)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetContractAddress", reflect.TypeOf((*MockBridge)(nil).GetContractAddress), params)
}
// Name mocks base method.
@ -162,18 +160,18 @@ func (mr *MockBridgeMockRecorder) Name() *gomock.Call {
}
// PackTxInputData mocks base method.
func (m *MockBridge) PackTxInputData(contractType string, fromNetwork, toNetwork *params.Network, from, to common.Address, token *token.Token, amountIn *big.Int) ([]byte, error) {
func (m *MockBridge) PackTxInputData(params bridge.BridgeParams, contractType string) ([]byte, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PackTxInputData", contractType, fromNetwork, toNetwork, from, to, token, amountIn)
ret := m.ctrl.Call(m, "PackTxInputData", params, contractType)
ret0, _ := ret[0].([]byte)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// PackTxInputData indicates an expected call of PackTxInputData.
func (mr *MockBridgeMockRecorder) PackTxInputData(contractType, fromNetwork, toNetwork, from, to, token, amountIn interface{}) *gomock.Call {
func (mr *MockBridgeMockRecorder) PackTxInputData(params, contractType interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PackTxInputData", reflect.TypeOf((*MockBridge)(nil).PackTxInputData), contractType, fromNetwork, toNetwork, from, to, token, amountIn)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PackTxInputData", reflect.TypeOf((*MockBridge)(nil).PackTxInputData), params, contractType)
}
// Send mocks base method.

View File

@ -11,11 +11,9 @@ import (
ethTypes "github.com/ethereum/go-ethereum/core/types"
"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/rpc"
walletCommon "github.com/status-im/status-go/services/wallet/common"
"github.com/status-im/status-go/services/wallet/thirdparty/paraswap"
"github.com/status-im/status-go/services/wallet/token"
walletToken "github.com/status-im/status-go/services/wallet/token"
"github.com/status-im/status-go/transactions"
)
@ -39,22 +37,22 @@ func NewSwapParaswap(rpcClient *rpc.Client, transactor transactions.TransactorIf
}
func (s *SwapParaswap) Name() string {
return "Paraswap"
return SwapParaswapName
}
func (s *SwapParaswap) AvailableFor(from, to *params.Network, token *walletToken.Token, toToken *walletToken.Token) (bool, error) {
if token == nil || toToken == nil {
func (s *SwapParaswap) AvailableFor(params BridgeParams) (bool, error) {
if params.FromToken == nil || params.ToToken == nil {
return false, errors.New("token and toToken cannot be nil")
}
if from.ChainID != to.ChainID {
if params.FromChain.ChainID != params.ToChain.ChainID {
return false, nil
}
s.paraswapClient.SetChainID(from.ChainID)
s.paraswapClient.SetChainID(params.FromChain.ChainID)
searchForToken := token.Address == ZeroAddress
searchForToToken := toToken.Address == ZeroAddress
searchForToken := params.FromToken.Address == ZeroAddress
searchForToToken := params.ToToken.Address == ZeroAddress
if searchForToToken || searchForToken {
tokensList, err := s.paraswapClient.FetchTokensList(context.Background())
if err != nil {
@ -62,17 +60,17 @@ func (s *SwapParaswap) AvailableFor(from, to *params.Network, token *walletToken
}
for _, t := range tokensList {
if searchForToken && t.Symbol == token.Symbol {
token.Address = common.HexToAddress(t.Address)
token.Decimals = t.Decimals
if searchForToken && t.Symbol == params.FromToken.Symbol {
params.FromToken.Address = common.HexToAddress(t.Address)
params.FromToken.Decimals = t.Decimals
if !searchForToToken {
break
}
}
if searchForToToken && t.Symbol == toToken.Symbol {
toToken.Address = common.HexToAddress(t.Address)
toToken.Decimals = t.Decimals
if searchForToToken && t.Symbol == params.ToToken.Symbol {
params.ToToken.Address = common.HexToAddress(t.Address)
params.ToToken.Decimals = t.Decimals
if !searchForToken {
break
}
@ -80,24 +78,25 @@ func (s *SwapParaswap) AvailableFor(from, to *params.Network, token *walletToken
}
}
if token.Address == ZeroAddress || toToken.Address == ZeroAddress {
if params.FromToken.Address == ZeroAddress || params.ToToken.Address == ZeroAddress {
return false, errors.New("cannot resolve token/s")
}
return true, nil
}
func (s *SwapParaswap) CalculateFees(from, to *params.Network, token *token.Token, amountIn *big.Int) (*big.Int, *big.Int, error) {
func (s *SwapParaswap) CalculateFees(params BridgeParams) (*big.Int, *big.Int, error) {
return big.NewInt(0), big.NewInt(0), nil
}
func (s *SwapParaswap) PackTxInputData(contractType string, fromNetwork *params.Network, toNetwork *params.Network, from common.Address, to common.Address, token *token.Token, amountIn *big.Int) ([]byte, error) {
func (s *SwapParaswap) PackTxInputData(params BridgeParams, contractType string) ([]byte, error) {
// not sure what we can do here since we're using the api to build the transaction
return []byte{}, nil
}
func (s *SwapParaswap) EstimateGas(fromNetwork *params.Network, toNetwork *params.Network, from common.Address, to common.Address, token *token.Token, toToken *token.Token, amountIn *big.Int) (uint64, error) {
priceRoute, err := s.paraswapClient.FetchPriceRoute(context.Background(), token.Address, token.Decimals, toToken.Address, toToken.Decimals, amountIn, from, to)
func (s *SwapParaswap) EstimateGas(params BridgeParams) (uint64, error) {
priceRoute, err := s.paraswapClient.FetchPriceRoute(context.Background(), params.FromToken.Address, params.FromToken.Decimals,
params.ToToken.Address, params.ToToken.Decimals, params.AmountIn, params.FromAddr, params.ToAddr)
if err != nil {
return 0, err
}
@ -107,12 +106,12 @@ func (s *SwapParaswap) EstimateGas(fromNetwork *params.Network, toNetwork *param
return priceRoute.GasCost.Uint64(), nil
}
func (s *SwapParaswap) GetContractAddress(network *params.Network, token *token.Token) (address common.Address, err error) {
if network.ChainID == walletCommon.EthereumMainnet {
func (s *SwapParaswap) GetContractAddress(params BridgeParams) (address common.Address, err error) {
if params.FromChain.ChainID == walletCommon.EthereumMainnet {
address = common.HexToAddress("0x216b4b4ba9f3e719726886d34a177484278bfcae")
} else if network.ChainID == walletCommon.ArbitrumMainnet {
} else if params.FromChain.ChainID == walletCommon.ArbitrumMainnet {
address = common.HexToAddress("0x216b4b4ba9f3e719726886d34a177484278bfcae")
} else if network.ChainID == walletCommon.OptimismMainnet {
} else if params.FromChain.ChainID == walletCommon.OptimismMainnet {
address = common.HexToAddress("0x216b4b4ba9f3e719726886d34a177484278bfcae")
} else {
err = errors.New("unsupported network")
@ -120,18 +119,18 @@ func (s *SwapParaswap) GetContractAddress(network *params.Network, token *token.
return
}
func (s *SwapParaswap) BuildTx(network, _ *params.Network, fromAddress common.Address, toAddress common.Address, token *token.Token, amountIn *big.Int, _ *big.Int) (*ethTypes.Transaction, error) {
toAddr := types.Address(toAddress)
func (s *SwapParaswap) BuildTx(params BridgeParams) (*ethTypes.Transaction, error) {
toAddr := types.Address(params.ToAddr)
sendArgs := &TransactionBridge{
SwapTx: &SwapTxArgs{
SendTxArgs: transactions.SendTxArgs{
From: types.Address(fromAddress),
From: types.Address(params.FromAddr),
To: &toAddr,
Value: (*hexutil.Big)(amountIn),
Value: (*hexutil.Big)(params.AmountIn),
Data: types.HexBytes("0x0"),
Symbol: token.Symbol,
Symbol: params.FromToken.Symbol,
},
ChainID: network.ChainID,
ChainID: params.FromChain.ChainID,
},
}
@ -202,6 +201,6 @@ func (s *SwapParaswap) Send(sendArgs *TransactionBridge, verifiedAccount *accoun
return s.transactor.SendTransactionWithChainID(txBridgeArgs.ChainID, txBridgeArgs.SwapTx.SendTxArgs, verifiedAccount)
}
func (s *SwapParaswap) CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error) {
func (s *SwapParaswap) CalculateAmountOut(params BridgeParams) (*big.Int, error) {
return s.priceRoute.DestAmount.Int, nil
}

View File

@ -13,9 +13,7 @@ import (
"github.com/status-im/status-go/account"
"github.com/status-im/status-go/contracts/ierc20"
"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"
)
@ -29,19 +27,19 @@ func NewTransferBridge(rpcClient *rpc.Client, transactor transactions.Transactor
}
func (s *TransferBridge) Name() string {
return "Transfer"
return TransferName
}
func (s *TransferBridge) AvailableFor(from, to *params.Network, token *token.Token, toToken *token.Token) (bool, error) {
return from.ChainID == to.ChainID && token != nil && toToken == nil, nil
func (s *TransferBridge) AvailableFor(params BridgeParams) (bool, error) {
return params.FromChain.ChainID == params.ToChain.ChainID && params.FromToken != nil && params.ToToken == nil, nil
}
func (s *TransferBridge) CalculateFees(from, to *params.Network, token *token.Token, amountIn *big.Int) (*big.Int, *big.Int, error) {
func (s *TransferBridge) CalculateFees(params BridgeParams) (*big.Int, *big.Int, error) {
return big.NewInt(0), big.NewInt(0), nil
}
func (s *TransferBridge) PackTxInputData(contractType string, fromNetwork *params.Network, toNetwork *params.Network, from common.Address, to common.Address, token *token.Token, amountIn *big.Int) ([]byte, error) {
if token.IsNative() {
func (s *TransferBridge) PackTxInputData(params BridgeParams, contractType string) ([]byte, error) {
if params.FromToken.IsNative() {
return []byte("eth_sendRawTransaction"), nil
} else {
abi, err := abi.JSON(strings.NewReader(ierc20.IERC20ABI))
@ -49,28 +47,28 @@ func (s *TransferBridge) PackTxInputData(contractType string, fromNetwork *param
return []byte{}, err
}
return abi.Pack("transfer",
to,
amountIn,
params.ToAddr,
params.AmountIn,
)
}
}
func (s *TransferBridge) EstimateGas(fromNetwork *params.Network, toNetwork *params.Network, from common.Address, to common.Address, token *token.Token, toToken *token.Token, amountIn *big.Int) (uint64, error) {
func (s *TransferBridge) EstimateGas(params BridgeParams) (uint64, error) {
estimation := uint64(0)
var err error
input, err := s.PackTxInputData("", fromNetwork, toNetwork, from, to, token, amountIn)
input, err := s.PackTxInputData(params, "")
if err != nil {
return 0, err
}
if token.IsNative() {
estimation, err = s.transactor.EstimateGas(fromNetwork, from, to, amountIn, input)
if params.FromToken.IsNative() {
estimation, err = s.transactor.EstimateGas(params.FromChain, params.FromAddr, params.ToAddr, params.AmountIn, input)
if err != nil {
return 0, err
}
} else {
ethClient, err := s.rpcClient.EthClient(fromNetwork.ChainID)
ethClient, err := s.rpcClient.EthClient(params.FromChain.ChainID)
if err != nil {
return 0, err
}
@ -78,8 +76,8 @@ func (s *TransferBridge) EstimateGas(fromNetwork *params.Network, toNetwork *par
ctx := context.Background()
msg := ethereum.CallMsg{
From: from,
To: &token.Address,
From: params.FromAddr,
To: &params.FromToken.Address,
Data: input,
}
@ -94,17 +92,17 @@ func (s *TransferBridge) EstimateGas(fromNetwork *params.Network, toNetwork *par
return uint64(increasedEstimation), nil
}
func (s *TransferBridge) BuildTx(network, _ *params.Network, fromAddress common.Address, toAddress common.Address, token *token.Token, amountIn *big.Int, bonderFee *big.Int) (*ethTypes.Transaction, error) {
toAddr := types.Address(toAddress)
if token.IsNative() {
func (s *TransferBridge) BuildTx(params BridgeParams) (*ethTypes.Transaction, error) {
toAddr := types.Address(params.ToAddr)
if params.FromToken.IsNative() {
sendArgs := &TransactionBridge{
TransferTx: &transactions.SendTxArgs{
From: types.Address(fromAddress),
From: types.Address(params.FromAddr),
To: &toAddr,
Value: (*hexutil.Big)(amountIn),
Value: (*hexutil.Big)(params.AmountIn),
Data: types.HexBytes("0x0"),
},
ChainID: network.ChainID,
ChainID: params.FromChain.ChainID,
}
return s.BuildTransaction(sendArgs)
@ -114,20 +112,20 @@ func (s *TransferBridge) BuildTx(network, _ *params.Network, fromAddress common.
return nil, err
}
input, err := abi.Pack("transfer",
toAddress,
amountIn,
params.ToAddr,
params.AmountIn,
)
if err != nil {
return nil, err
}
sendArgs := &TransactionBridge{
TransferTx: &transactions.SendTxArgs{
From: types.Address(fromAddress),
From: types.Address(params.FromAddr),
To: &toAddr,
Value: (*hexutil.Big)(big.NewInt(0)),
Data: input,
},
ChainID: network.ChainID,
ChainID: params.FromChain.ChainID,
}
return s.BuildTransaction(sendArgs)
@ -141,10 +139,10 @@ func (s *TransferBridge) BuildTransaction(sendArgs *TransactionBridge) (*ethType
return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, *sendArgs.TransferTx)
}
func (s *TransferBridge) CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error) {
return amountIn, nil
func (s *TransferBridge) CalculateAmountOut(params BridgeParams) (*big.Int, error) {
return params.AmountIn, nil
}
func (s *TransferBridge) GetContractAddress(network *params.Network, token *token.Token) (common.Address, error) {
func (s *TransferBridge) GetContractAddress(params BridgeParams) (common.Address, error) {
return common.Address{}, nil
}

View File

@ -4,6 +4,7 @@ import (
"math/big"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/status-im/status-go/services/wallet/bridge"
"go.uber.org/zap"
)
@ -88,7 +89,7 @@ func setupRouteValidationMapsV2(fromLockedAmount map[uint64]*hexutil.Big) (map[u
fromExcluded := make(map[uint64]bool)
for chainID, amount := range fromLockedAmount {
if amount.ToInt().Cmp(zero) <= 0 {
if amount.ToInt().Cmp(bridge.ZeroBigIntValue) <= 0 {
fromExcluded[chainID] = false
} else {
fromIncluded[chainID] = false

View File

@ -7,6 +7,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/status-im/status-go/params"
"github.com/status-im/status-go/services/wallet/bridge"
"github.com/stretchr/testify/assert"
)
@ -83,9 +84,9 @@ func TestSetupRouteValidationMapsV2(t *testing.T) {
{
name: "Mixed zero and non-zero amounts",
fromLockedAmount: map[uint64]*hexutil.Big{
1: (*hexutil.Big)(zero),
1: (*hexutil.Big)(bridge.ZeroBigIntValue),
2: (*hexutil.Big)(big.NewInt(200)),
3: (*hexutil.Big)(zero),
3: (*hexutil.Big)(bridge.ZeroBigIntValue),
4: (*hexutil.Big)(big.NewInt(400)),
},
expectedIncluded: map[uint64]bool{
@ -112,8 +113,8 @@ func TestSetupRouteValidationMapsV2(t *testing.T) {
{
name: "All zero amounts",
fromLockedAmount: map[uint64]*hexutil.Big{
1: (*hexutil.Big)(zero),
2: (*hexutil.Big)(zero),
1: (*hexutil.Big)(bridge.ZeroBigIntValue),
2: (*hexutil.Big)(bridge.ZeroBigIntValue),
},
expectedIncluded: map[uint64]bool{},
expectedExcluded: map[uint64]bool{
@ -134,7 +135,7 @@ func TestSetupRouteValidationMapsV2(t *testing.T) {
{
name: "Single zero amount",
fromLockedAmount: map[uint64]*hexutil.Big{
1: (*hexutil.Big)(zero),
1: (*hexutil.Big)(bridge.ZeroBigIntValue),
},
expectedIncluded: map[uint64]bool{},
expectedExcluded: map[uint64]bool{

View File

@ -37,12 +37,9 @@ import (
// rename and make `router_v2.go` file the main and only file
// //////////////////////////////////////////////////////////////////////////////
// TODO: remove the following two consts once we fully move to routerV2
const EstimateUsername = "RandomUsername"
const EstimatePubKey = "0x04bb2024ce5d72e45d4a4f8589ae657ef9745855006996115a23a1af88d536cf02c0524a585fce7bfa79d6a9669af735eda6205d6c7e5b3cdc2b8ff7b2fa1f0b56"
const ERC721TransferString = "ERC721Transfer"
const ERC1155TransferString = "ERC1155Transfer"
var zero = big.NewInt(0)
type Path struct {
BridgeName string
@ -151,7 +148,7 @@ func filterRoutes(routes [][]*Path, amountIn *big.Int, fromLockedAmount map[uint
fromIncluded := make(map[uint64]bool)
fromExcluded := make(map[uint64]bool)
for chainID, amount := range fromLockedAmount {
if amount.ToInt().Cmp(zero) == 0 {
if amount.ToInt().Cmp(bridge.ZeroBigIntValue) == 0 {
fromExcluded[chainID] = false
} else {
fromIncluded[chainID] = false
@ -262,7 +259,7 @@ func newSuggestedRoutes(
rest := new(big.Int).Set(amountIn)
for _, path := range best {
diff := new(big.Int).Sub(rest, path.MaxAmountIn.ToInt())
if diff.Cmp(zero) >= 0 {
if diff.Cmp(bridge.ZeroBigIntValue) >= 0 {
path.AmountIn = (*hexutil.Big)(path.MaxAmountIn.ToInt())
} else {
path.AmountIn = (*hexutil.Big)(new(big.Int).Set(rest))
@ -286,12 +283,15 @@ func NewRouter(rpcClient *rpc.Client, transactor *transactions.Transactor, token
cbridge := bridge.NewCbridge(rpcClient, transactor, tokenManager)
hop := bridge.NewHopBridge(rpcClient, transactor, tokenManager)
paraswap := bridge.NewSwapParaswap(rpcClient, transactor, tokenManager)
ensRegister := bridge.NewENSRegisterBridge(rpcClient, transactor, ensService)
bridges[transfer.Name()] = transfer
bridges[erc721Transfer.Name()] = erc721Transfer
bridges[hop.Name()] = hop
bridges[cbridge.Name()] = cbridge
bridges[erc1155Transfer.Name()] = erc1155Transfer
bridges[paraswap.Name()] = paraswap
bridges[ensRegister.Name()] = ensRegister
return &Router{
rpcClient: rpcClient,
@ -338,7 +338,7 @@ type Router struct {
func (r *Router) requireApproval(ctx context.Context, sendType SendType, approvalContractAddress *common.Address, account common.Address, network *params.Network, token *token.Token, amountIn *big.Int) (
bool, *big.Int, uint64, uint64, error) {
if sendType.IsCollectiblesTransfer() {
if sendType.IsCollectiblesTransfer() || sendType.IsEnsTransfer() {
return false, nil, 0, 0, nil
}
@ -542,8 +542,13 @@ func (r *Router) SuggestedRoutes(
maxFees := gasFees.feeFor(gasFeeMode)
estimatedTime := r.feesManager.TransactionEstimatedTime(ctx, network.ChainID, maxFees)
for _, bridge := range r.bridges {
if !sendType.canUseBridge(bridge) {
for _, brdg := range r.bridges {
// Skip bridges that are added because of the Router V2, to not break the current functionality
if brdg.Name() == bridge.ENSRegisterName {
continue
}
if !sendType.canUseBridge(brdg) {
continue
}
@ -567,7 +572,17 @@ func (r *Router) SuggestedRoutes(
continue
}
can, err := bridge.AvailableFor(network, dest, token, toToken)
bridgeParams := bridge.BridgeParams{
FromChain: network,
ToChain: dest,
FromToken: token,
ToToken: toToken,
ToAddr: addrTo,
FromAddr: addrFrom,
AmountIn: amountIn,
}
can, err := brdg.AvailableFor(bridgeParams)
if err != nil || !can {
continue
}
@ -575,11 +590,11 @@ func (r *Router) SuggestedRoutes(
continue
}
bonderFees, tokenFees, err := bridge.CalculateFees(network, dest, token, amountIn)
bonderFees, tokenFees, err := brdg.CalculateFees(bridgeParams)
if err != nil {
continue
}
if bonderFees.Cmp(zero) != 0 {
if bonderFees.Cmp(bridge.ZeroBigIntValue) != 0 {
if maxAmountIn.ToInt().Cmp(amountIn) >= 0 {
if bonderFees.Cmp(amountIn) >= 0 {
continue
@ -592,7 +607,7 @@ func (r *Router) SuggestedRoutes(
}
gasLimit := uint64(0)
if sendType.isTransfer(false) {
gasLimit, err = bridge.EstimateGas(network, dest, addrFrom, addrTo, token, toToken, amountIn)
gasLimit, err = brdg.EstimateGas(bridgeParams)
if err != nil {
continue
}
@ -600,7 +615,7 @@ func (r *Router) SuggestedRoutes(
gasLimit = sendType.EstimateGas(r.ensService, r.stickersService, network, addrFrom, tokenID)
}
approvalContractAddress, err := bridge.GetContractAddress(network, token)
approvalContractAddress, err := brdg.GetContractAddress(bridgeParams)
if err != nil {
continue
}
@ -611,7 +626,7 @@ func (r *Router) SuggestedRoutes(
var l1GasFeeWei uint64
if sendType.needL1Fee() {
txInputData, err := bridge.PackTxInputData("", network, dest, addrFrom, addrTo, token, amountIn)
txInputData, err := brdg.PackTxInputData(bridgeParams, "")
if err != nil {
continue
}
@ -661,12 +676,12 @@ func (r *Router) SuggestedRoutes(
cost.Add(cost, l1GasCost)
mu.Lock()
candidates = append(candidates, &Path{
BridgeName: bridge.Name(),
BridgeName: brdg.Name(),
From: network,
To: dest,
MaxAmountIn: maxAmountIn,
AmountIn: (*hexutil.Big)(zero),
AmountOut: (*hexutil.Big)(zero),
AmountIn: (*hexutil.Big)(bridge.ZeroBigIntValue),
AmountOut: (*hexutil.Big)(bridge.ZeroBigIntValue),
GasAmount: gasLimit,
GasFees: gasFees,
BonderFees: (*hexutil.Big)(bonderFees),
@ -691,7 +706,16 @@ func (r *Router) SuggestedRoutes(
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), tokenID)
bridgeParams := bridge.BridgeParams{
FromChain: path.From,
ToChain: path.To,
AmountIn: path.AmountIn.ToInt(),
FromToken: &token.Token{
Symbol: tokenID,
},
}
amountOut, err := r.bridges[path.BridgeName].CalculateAmountOut(bridgeParams)
if err != nil {
continue
}

View File

@ -39,6 +39,10 @@ func (s SendType) IsCollectiblesTransfer() bool {
return s == ERC721Transfer || s == ERC1155Transfer
}
func (s SendType) IsEnsTransfer() bool {
return s == ENSRegister || s == ENSRelease || s == ENSSetPubKey
}
func (s SendType) FetchPrices(marketManager *market.Manager, tokenID string) (map[string]float64, error) {
symbols := []string{tokenID, "ETH"}
if s.IsCollectiblesTransfer() {
@ -83,6 +87,7 @@ func (s SendType) FindToken(tokenManager *token.Manager, collectibles *collectib
}
}
// TODO: remove this function once we fully move to routerV2
func (s SendType) isTransfer(routerV2Logic bool) bool {
return s == Transfer ||
s == Bridge && routerV2Logic ||
@ -98,16 +103,18 @@ func (s SendType) canUseBridge(b bridge.Bridge) bool {
bridgeName := b.Name()
switch s {
case ERC721Transfer:
return bridgeName == ERC721TransferString
return bridgeName == bridge.ERC721TransferName
case ERC1155Transfer:
return bridgeName == ERC1155TransferString
return bridgeName == bridge.ERC1155TransferName
case ENSRegister:
return bridgeName == bridge.ENSRegisterName
default:
return true
}
}
func (s SendType) isAvailableBetween(from, to *params.Network) bool {
if s.IsCollectiblesTransfer() {
if s.IsCollectiblesTransfer() || s.IsEnsTransfer() {
return from.ChainID == to.ChainID
}
@ -142,6 +149,10 @@ func (s SendType) isAvailableFor(network *params.Network) bool {
return swapAllowedNetworks[network.ChainID]
}
if s.IsEnsTransfer() {
return network.ChainID == walletCommon.EthereumMainnet || network.ChainID == walletCommon.EthereumSepolia
}
// Check for any SendType available for all networks
if s == Transfer || s == Bridge || s.IsCollectiblesTransfer() || allAllowedNetworks[network.ChainID] {
return true
@ -150,10 +161,11 @@ func (s SendType) isAvailableFor(network *params.Network) bool {
return false
}
// TODO: remove this function once we fully move to routerV2
func (s SendType) EstimateGas(ensService *ens.Service, stickersService *stickers.Service, network *params.Network, from common.Address, tokenID string) uint64 {
tx := transactions.SendTxArgs{
From: (types.Address)(from),
Value: (*hexutil.Big)(zero),
Value: (*hexutil.Big)(bridge.ZeroBigIntValue),
}
switch s {
case ENSRegister:

View File

@ -12,9 +12,25 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/status-im/status-go/params"
"github.com/status-im/status-go/services/wallet/async"
"github.com/status-im/status-go/services/wallet/bridge"
walletCommon "github.com/status-im/status-go/services/wallet/common"
walletToken "github.com/status-im/status-go/services/wallet/token"
)
var (
supportedNetworks = map[uint64]bool{
walletCommon.EthereumMainnet: true,
walletCommon.OptimismMainnet: true,
walletCommon.ArbitrumMainnet: true,
}
supportedTestNetworks = map[uint64]bool{
walletCommon.EthereumSepolia: true,
walletCommon.OptimismSepolia: true,
walletCommon.ArbitrumSepolia: true,
}
)
type RouteInputParams struct {
SendType SendType `json:"sendType" validate:"required"`
AddrFrom common.Address `json:"addrFrom" validate:"required"`
@ -28,6 +44,10 @@ type RouteInputParams struct {
GasFeeMode GasFeeMode `json:"gasFeeMode" validate:"required"`
FromLockedAmount map[uint64]*hexutil.Big `json:"fromLockedAmount"`
TestnetMode bool `json:"testnetMode"`
// For send types like EnsRegister, EnsRelease, EnsSetPubKey, StickersBuy
Username string `json:"username"`
PublicKey string `json:"publicKey"`
}
type PathV2 struct {
@ -112,7 +132,7 @@ func newSuggestedRoutesV2(
rest := new(big.Int).Set(amountIn)
for _, path := range best {
diff := new(big.Int).Sub(rest, path.AmountIn.ToInt())
if diff.Cmp(zero) >= 0 {
if diff.Cmp(bridge.ZeroBigIntValue) >= 0 {
path.AmountIn = (*hexutil.Big)(path.AmountIn.ToInt())
} else {
path.AmountIn = (*hexutil.Big)(new(big.Int).Set(rest))
@ -214,7 +234,7 @@ func findBestV2(routes [][]*PathV2, tokenPrice float64, nativeChainTokenPrice fl
pathCost = new(big.Float).Mul(txFeeInEth, nativeTokenPrice)
}
if path.TxBonderFees != nil && path.TxBonderFees.ToInt().Cmp(zero) > 0 {
if path.TxBonderFees != nil && path.TxBonderFees.ToInt().Cmp(bridge.ZeroBigIntValue) > 0 {
path.requiredTokenBalance.Add(path.requiredTokenBalance, path.TxBonderFees.ToInt())
pathCost.Add(pathCost, new(big.Float).Mul(
new(big.Float).Quo(new(big.Float).SetInt(path.TxBonderFees.ToInt()), tokenDenominator),
@ -222,7 +242,7 @@ func findBestV2(routes [][]*PathV2, tokenPrice float64, nativeChainTokenPrice fl
}
if path.TxL1Fee != nil && path.TxL1Fee.ToInt().Cmp(zero) > 0 {
if path.TxL1Fee != nil && path.TxL1Fee.ToInt().Cmp(bridge.ZeroBigIntValue) > 0 {
l1FeeInWei := path.TxL1Fee.ToInt()
l1FeeInEth := gweiToEth(weiToGwei(l1FeeInWei))
@ -230,7 +250,7 @@ func findBestV2(routes [][]*PathV2, tokenPrice float64, nativeChainTokenPrice fl
pathCost.Add(pathCost, new(big.Float).Mul(l1FeeInEth, nativeTokenPrice))
}
if path.TxTokenFees != nil && path.TxTokenFees.ToInt().Cmp(zero) > 0 && path.FromToken != nil {
if path.TxTokenFees != nil && path.TxTokenFees.ToInt().Cmp(bridge.ZeroBigIntValue) > 0 && path.FromToken != nil {
path.requiredTokenBalance.Add(path.requiredTokenBalance, path.TxTokenFees.ToInt())
pathCost.Add(pathCost, new(big.Float).Mul(
new(big.Float).Quo(new(big.Float).SetInt(path.TxTokenFees.ToInt()), tokenDenominator),
@ -268,7 +288,50 @@ func findBestV2(routes [][]*PathV2, tokenPrice float64, nativeChainTokenPrice fl
return best
}
func validateInputData(input *RouteInputParams) error {
if input.SendType == ENSRegister {
if input.Username == "" || input.PublicKey == "" {
return errors.New("username and public key are required for ENSRegister")
}
if input.TestnetMode {
if input.TokenID != bridge.SttSymbol {
return errors.New("only STT is supported for ENSRegister on testnet")
}
} else {
if input.TokenID != bridge.SntSymbol {
return errors.New("only SNT is supported for ENSRegister")
}
}
return nil
}
if input.FromLockedAmount != nil && len(input.FromLockedAmount) > 0 {
for chainID, amount := range input.FromLockedAmount {
if input.TestnetMode {
if !supportedTestNetworks[chainID] {
return errors.New("locked amount is not supported for the selected network")
}
} else {
if !supportedNetworks[chainID] {
return errors.New("locked amount is not supported for the selected network")
}
}
if amount == nil || amount.ToInt().Sign() < 0 {
return errors.New("locked amount must be positive")
}
}
}
return nil
}
func (r *Router) SuggestedRoutesV2(ctx context.Context, input *RouteInputParams) (*SuggestedRoutesV2, error) {
err := validateInputData(input)
if err != nil {
return nil, err
}
networks, err := r.rpcClient.NetworkManager.Get(false)
if err != nil {
return nil, err
@ -294,12 +357,16 @@ func (r *Router) SuggestedRoutesV2(ctx context.Context, input *RouteInputParams)
continue
}
token := input.SendType.FindToken(r.tokenManager, r.collectiblesService, input.AddrFrom, network, input.TokenID)
var (
token *walletToken.Token
toToken *walletToken.Token
)
token = input.SendType.FindToken(r.tokenManager, r.collectiblesService, input.AddrFrom, network, input.TokenID)
if token == nil {
continue
}
var toToken *walletToken.Token
if input.SendType == Swap {
toToken = input.SendType.FindToken(r.tokenManager, r.collectiblesService, common.Address{}, network, input.ToTokenID)
}
@ -325,8 +392,8 @@ func (r *Router) SuggestedRoutesV2(ctx context.Context, input *RouteInputParams)
return err
}
for _, bridge := range r.bridges {
if !input.SendType.canUseBridge(bridge) {
for _, brdg := range r.bridges {
if !input.SendType.canUseBridge(brdg) {
continue
}
@ -351,27 +418,35 @@ func (r *Router) SuggestedRoutesV2(ctx context.Context, input *RouteInputParams)
continue
}
can, err := bridge.AvailableFor(network, dest, token, toToken)
bridgeParams := bridge.BridgeParams{
FromChain: network,
ToChain: dest,
FromToken: token,
ToToken: toToken,
ToAddr: input.AddrTo,
FromAddr: input.AddrFrom,
AmountIn: amountToSend,
Username: input.Username,
PublicKey: input.PublicKey,
}
can, err := brdg.AvailableFor(bridgeParams)
if err != nil || !can {
continue
}
bonderFees, tokenFees, err := bridge.CalculateFees(network, dest, token, amountToSend)
bonderFees, tokenFees, err := brdg.CalculateFees(bridgeParams)
if err != nil {
continue
}
gasLimit := uint64(0)
if input.SendType.isTransfer(true) {
gasLimit, err = bridge.EstimateGas(network, dest, input.AddrFrom, input.AddrTo, token, toToken, amountToSend)
if err != nil {
continue
}
} else {
gasLimit = input.SendType.EstimateGas(r.ensService, r.stickersService, network, input.AddrFrom, input.TokenID)
gasLimit, err := brdg.EstimateGas(bridgeParams)
if err != nil {
continue
}
approvalContractAddress, err := bridge.GetContractAddress(network, token)
approvalContractAddress, err := brdg.GetContractAddress(bridgeParams)
if err != nil {
continue
}
@ -383,7 +458,7 @@ func (r *Router) SuggestedRoutesV2(ctx context.Context, input *RouteInputParams)
var l1FeeWei uint64
if input.SendType.needL1Fee() {
txInputData, err := bridge.PackTxInputData("", network, dest, input.AddrFrom, input.AddrTo, token, amountToSend)
txInputData, err := brdg.PackTxInputData(bridgeParams, "")
if err != nil {
continue
}
@ -407,7 +482,7 @@ func (r *Router) SuggestedRoutesV2(ctx context.Context, input *RouteInputParams)
selctedPriorityFee = priorityFees.Low
}
amountOut, err := bridge.CalculateAmountOut(network, dest, amountToSend, token.Symbol)
amountOut, err := brdg.CalculateAmountOut(bridgeParams)
if err != nil {
continue
}
@ -421,7 +496,7 @@ func (r *Router) SuggestedRoutesV2(ctx context.Context, input *RouteInputParams)
mu.Lock()
candidates = append(candidates, &PathV2{
BridgeName: bridge.Name(),
BridgeName: brdg.Name(),
FromChain: network,
ToChain: network,
FromToken: token,