mirror of
https://github.com/status-im/status-go.git
synced 2025-01-14 08:44:46 +00:00
79b1c547d1
* chore_: unused `BuildTx` function removed from the processor interface and types that are implement it Since the `BuildTx` function is not used anywhere, it's removed from the code. * fix_: resolving nonce improvements When the app sends more than a single tx from the same account on the same chain, some chains do not return appropriate nonce (they do not consider pending txs), because of that we place more tx with the same nonce, where all but the first one fail. Changes in this PR keep track of nonces being used in the same sending/bridging flow, which means for the first tx from the multi txs the app asks the chain for the nonce, and every next nonce is resolved by incrementing the last used nonce by 1.
173 lines
5.2 KiB
Go
173 lines
5.2 KiB
Go
package pathprocessor
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"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/ierc1155"
|
|
"github.com/status-im/status-go/eth-node/types"
|
|
"github.com/status-im/status-go/rpc"
|
|
"github.com/status-im/status-go/transactions"
|
|
)
|
|
|
|
type ERC1155TxArgs struct {
|
|
transactions.SendTxArgs
|
|
TokenID *hexutil.Big `json:"tokenId"`
|
|
Recipient common.Address `json:"recipient"`
|
|
Amount *hexutil.Big `json:"amount"`
|
|
}
|
|
|
|
type ERC1155Processor struct {
|
|
rpcClient *rpc.Client
|
|
transactor transactions.TransactorIface
|
|
}
|
|
|
|
func NewERC1155Processor(rpcClient *rpc.Client, transactor transactions.TransactorIface) *ERC1155Processor {
|
|
return &ERC1155Processor{rpcClient: rpcClient, transactor: transactor}
|
|
}
|
|
|
|
func createERC1155ErrorResponse(err error) error {
|
|
return createErrorResponse(ProcessorERC1155Name, err)
|
|
}
|
|
|
|
func (s *ERC1155Processor) Name() string {
|
|
return ProcessorERC1155Name
|
|
}
|
|
|
|
func (s *ERC1155Processor) AvailableFor(params ProcessorInputParams) (bool, error) {
|
|
return params.FromChain.ChainID == params.ToChain.ChainID && params.ToToken == nil, nil
|
|
}
|
|
|
|
func (s *ERC1155Processor) CalculateFees(params ProcessorInputParams) (*big.Int, *big.Int, error) {
|
|
return ZeroBigIntValue, ZeroBigIntValue, nil
|
|
}
|
|
|
|
func (s *ERC1155Processor) PackTxInputData(params ProcessorInputParams) ([]byte, error) {
|
|
abi, err := abi.JSON(strings.NewReader(ierc1155.Ierc1155ABI))
|
|
if err != nil {
|
|
return []byte{}, createERC1155ErrorResponse(err)
|
|
}
|
|
|
|
id, success := big.NewInt(0).SetString(params.FromToken.Symbol, 0)
|
|
if !success {
|
|
return []byte{}, createERC1155ErrorResponse(fmt.Errorf("failed to convert %s to big.Int", params.FromToken.Symbol))
|
|
}
|
|
|
|
return abi.Pack("safeTransferFrom",
|
|
params.FromAddr,
|
|
params.ToAddr,
|
|
id,
|
|
params.AmountIn,
|
|
[]byte{},
|
|
)
|
|
}
|
|
|
|
func (s *ERC1155Processor) EstimateGas(params ProcessorInputParams) (uint64, error) {
|
|
if params.TestsMode {
|
|
if params.TestEstimationMap != nil {
|
|
if val, ok := params.TestEstimationMap[s.Name()]; ok {
|
|
return val, nil
|
|
}
|
|
}
|
|
return 0, ErrNoEstimationFound
|
|
}
|
|
|
|
ethClient, err := s.rpcClient.EthClient(params.FromChain.ChainID)
|
|
if err != nil {
|
|
return 0, createERC1155ErrorResponse(err)
|
|
}
|
|
|
|
value := new(big.Int)
|
|
|
|
input, err := s.PackTxInputData(params)
|
|
if err != nil {
|
|
return 0, createERC1155ErrorResponse(err)
|
|
}
|
|
|
|
msg := ethereum.CallMsg{
|
|
From: params.FromAddr,
|
|
To: ¶ms.FromToken.Address,
|
|
Value: value,
|
|
Data: input,
|
|
}
|
|
|
|
estimation, err := ethClient.EstimateGas(context.Background(), msg)
|
|
if err != nil {
|
|
return 0, createERC1155ErrorResponse(err)
|
|
}
|
|
increasedEstimation := float64(estimation) * IncreaseEstimatedGasFactor
|
|
return uint64(increasedEstimation), nil
|
|
}
|
|
|
|
func (s *ERC1155Processor) sendOrBuild(sendArgs *MultipathProcessorTxArgs, signerFn bind.SignerFn, lastUsedNonce int64) (tx *ethTypes.Transaction, err error) {
|
|
ethClient, err := s.rpcClient.EthClient(sendArgs.ChainID)
|
|
if err != nil {
|
|
return tx, createERC1155ErrorResponse(err)
|
|
}
|
|
|
|
contract, err := ierc1155.NewIerc1155(common.Address(*sendArgs.ERC1155TransferTx.To), ethClient)
|
|
if err != nil {
|
|
return tx, createERC1155ErrorResponse(err)
|
|
}
|
|
|
|
var nonce uint64
|
|
if lastUsedNonce < 0 {
|
|
nonce, err = s.transactor.NextNonce(s.rpcClient, sendArgs.ChainID, sendArgs.ERC1155TransferTx.From)
|
|
if err != nil {
|
|
return tx, createERC1155ErrorResponse(err)
|
|
}
|
|
} else {
|
|
nonce = uint64(lastUsedNonce) + 1
|
|
}
|
|
|
|
argNonce := hexutil.Uint64(nonce)
|
|
sendArgs.ERC1155TransferTx.Nonce = &argNonce
|
|
txOpts := sendArgs.ERC1155TransferTx.ToTransactOpts(signerFn)
|
|
from := common.Address(sendArgs.ERC1155TransferTx.From)
|
|
tx, err = contract.SafeTransferFrom(
|
|
txOpts, from,
|
|
sendArgs.ERC1155TransferTx.Recipient,
|
|
sendArgs.ERC1155TransferTx.TokenID.ToInt(),
|
|
sendArgs.ERC1155TransferTx.Amount.ToInt(),
|
|
[]byte{},
|
|
)
|
|
if err != nil {
|
|
return tx, createERC1155ErrorResponse(err)
|
|
}
|
|
err = s.transactor.StoreAndTrackPendingTx(from, sendArgs.ERC1155TransferTx.Symbol, sendArgs.ChainID, sendArgs.ERC1155TransferTx.MultiTransactionID, tx)
|
|
if err != nil {
|
|
return tx, createERC1155ErrorResponse(err)
|
|
}
|
|
return tx, nil
|
|
}
|
|
|
|
func (s *ERC1155Processor) Send(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64, verifiedAccount *account.SelectedExtKey) (hash types.Hash, usedNonce uint64, err error) {
|
|
tx, err := s.sendOrBuild(sendArgs, getSigner(sendArgs.ChainID, sendArgs.ERC1155TransferTx.From, verifiedAccount), lastUsedNonce)
|
|
if err != nil {
|
|
return hash, 0, createERC1155ErrorResponse(err)
|
|
}
|
|
return types.Hash(tx.Hash()), tx.Nonce(), nil
|
|
}
|
|
|
|
func (s *ERC1155Processor) BuildTransaction(sendArgs *MultipathProcessorTxArgs, lastUsedNonce int64) (*ethTypes.Transaction, uint64, error) {
|
|
tx, err := s.sendOrBuild(sendArgs, nil, lastUsedNonce)
|
|
return tx, tx.Nonce(), err
|
|
}
|
|
|
|
func (s *ERC1155Processor) CalculateAmountOut(params ProcessorInputParams) (*big.Int, error) {
|
|
return params.AmountIn, nil
|
|
}
|
|
|
|
func (s *ERC1155Processor) GetContractAddress(params ProcessorInputParams) (common.Address, error) {
|
|
return params.FromToken.Address, nil
|
|
}
|