feat: added functionality to ask a client to sign a transaction and an endpoint to continue sending using provided signature
This functionality is needed in case the user wants to send a transaction and signs it using the signature provided by the keycard (or any other compatible way).
This commit is contained in:
parent
abac55c778
commit
b348cca15c
|
@ -1897,7 +1897,7 @@ func (b *GethStatusBackend) SendTransactionWithChainID(chainID uint64, sendArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *GethStatusBackend) SendTransactionWithSignature(sendArgs transactions.SendTxArgs, sig []byte) (hash types.Hash, err error) {
|
func (b *GethStatusBackend) SendTransactionWithSignature(sendArgs transactions.SendTxArgs, sig []byte) (hash types.Hash, err error) {
|
||||||
hash, err = b.transactor.SendTransactionWithSignature(sendArgs, sig)
|
hash, err = b.transactor.SendTransactionWithSignature(b.transactor.NetworkID(), sendArgs, sig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -2,7 +2,7 @@ module github.com/status-im/status-go
|
||||||
|
|
||||||
go 1.19
|
go 1.19
|
||||||
|
|
||||||
replace github.com/ethereum/go-ethereum v1.10.26 => github.com/status-im/go-ethereum v1.10.25-status.7
|
replace github.com/ethereum/go-ethereum v1.10.26 => github.com/status-im/go-ethereum v1.10.25-status.9
|
||||||
|
|
||||||
replace github.com/docker/docker => github.com/docker/engine v1.4.2-0.20190717161051-705d9623b7c1
|
replace github.com/docker/docker => github.com/docker/engine v1.4.2-0.20190717161051-705d9623b7c1
|
||||||
|
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -1982,8 +1982,8 @@ github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/y
|
||||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||||
github.com/status-im/doubleratchet v3.0.0+incompatible h1:aJ1ejcSERpSzmWZBgtfYtiU2nF0Q8ZkGyuEPYETXkCY=
|
github.com/status-im/doubleratchet v3.0.0+incompatible h1:aJ1ejcSERpSzmWZBgtfYtiU2nF0Q8ZkGyuEPYETXkCY=
|
||||||
github.com/status-im/doubleratchet v3.0.0+incompatible/go.mod h1:1sqR0+yhiM/bd+wrdX79AOt2csZuJOni0nUDzKNuqOU=
|
github.com/status-im/doubleratchet v3.0.0+incompatible/go.mod h1:1sqR0+yhiM/bd+wrdX79AOt2csZuJOni0nUDzKNuqOU=
|
||||||
github.com/status-im/go-ethereum v1.10.25-status.7 h1:egCCdvUQSdfnnDcv2vP1RCuIDr184eYlBvyucxuKJj8=
|
github.com/status-im/go-ethereum v1.10.25-status.9 h1:NDuRs5TC4JjqPcYE8/sUtspdA+OwV1JRy3bbRLdIcL0=
|
||||||
github.com/status-im/go-ethereum v1.10.25-status.7/go.mod h1:Dt4K5JYMhJRdtXJwBEyGZLZn9iz/chSOZyjVmt5ZhwQ=
|
github.com/status-im/go-ethereum v1.10.25-status.9/go.mod h1:Dt4K5JYMhJRdtXJwBEyGZLZn9iz/chSOZyjVmt5ZhwQ=
|
||||||
github.com/status-im/go-multiaddr-ethv4 v1.2.5 h1:pN+ey6wYKbvNNu5/xq9+VL0N8Yq0pZUTbZp0URg+Yn4=
|
github.com/status-im/go-multiaddr-ethv4 v1.2.5 h1:pN+ey6wYKbvNNu5/xq9+VL0N8Yq0pZUTbZp0URg+Yn4=
|
||||||
github.com/status-im/go-multiaddr-ethv4 v1.2.5/go.mod h1:Fhe/18yWU5QwlAYiOO3Bb1BLe0bn5YobcNBHsjRr4kk=
|
github.com/status-im/go-multiaddr-ethv4 v1.2.5/go.mod h1:Fhe/18yWU5QwlAYiOO3Bb1BLe0bn5YobcNBHsjRr4kk=
|
||||||
github.com/status-im/go-sqlcipher/v4 v4.5.4-status.2 h1:Oi9JTAI2DZEe5UKlpUcvKBCCSn3ULsLIrix7jPnEoPE=
|
github.com/status-im/go-sqlcipher/v4 v4.5.4-status.2 h1:Oi9JTAI2DZEe5UKlpUcvKBCCSn3ULsLIrix7jPnEoPE=
|
||||||
|
|
|
@ -553,6 +553,11 @@ func (api *API) CreateMultiTransaction(ctx context.Context, multiTransactionComm
|
||||||
return api.s.transactionManager.CreateMultiTransactionFromCommand(ctx, multiTransactionCommand, data, api.router.bridges, password)
|
return api.s.transactionManager.CreateMultiTransactionFromCommand(ctx, multiTransactionCommand, data, api.router.bridges, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *API) ProceedWithTransactionsSignatures(ctx context.Context, signatures map[string]transfer.SignatureDetails) (*transfer.MultiTransactionCommandResult, error) {
|
||||||
|
log.Debug("[WalletAPI:: ProceedWithTransactionsSignatures] sign with signatures and send multi transaction")
|
||||||
|
return api.s.transactionManager.ProceedWithTransactionsSignatures(ctx, signatures)
|
||||||
|
}
|
||||||
|
|
||||||
func (api *API) GetMultiTransactions(ctx context.Context, transactionIDs []transfer.MultiTransactionIDType) ([]*transfer.MultiTransaction, error) {
|
func (api *API) GetMultiTransactions(ctx context.Context, transactionIDs []transfer.MultiTransactionIDType) ([]*transfer.MultiTransaction, error) {
|
||||||
log.Debug("wallet.api.GetMultiTransactions", "IDs.len", len(transactionIDs))
|
log.Debug("wallet.api.GetMultiTransactions", "IDs.len", len(transactionIDs))
|
||||||
return api.s.transactionManager.GetMultiTransactions(ctx, transactionIDs)
|
return api.s.transactionManager.GetMultiTransactions(ctx, transactionIDs)
|
||||||
|
|
|
@ -94,4 +94,5 @@ type Bridge interface {
|
||||||
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
|
||||||
|
BuildTransaction(sendArgs *TransactionBridge) (*ethTypes.Transaction, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
ethTypes "github.com/ethereum/go-ethereum/core/types"
|
ethTypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
|
@ -244,33 +245,32 @@ func (s *CBridge) GetContractAddress(network *params.Network, token *token.Token
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CBridge) Send(sendArgs *TransactionBridge, verifiedAccount *account.SelectedExtKey) (types.Hash, error) {
|
func (s *CBridge) sendOrBuild(sendArgs *TransactionBridge, signerFn bind.SignerFn) (*ethTypes.Transaction, error) {
|
||||||
fromNetwork := s.rpcClient.NetworkManager.Find(sendArgs.ChainID)
|
fromNetwork := s.rpcClient.NetworkManager.Find(sendArgs.ChainID)
|
||||||
if fromNetwork == nil {
|
if fromNetwork == nil {
|
||||||
return types.HexToHash(""), errors.New("network not found")
|
return nil, errors.New("network not found")
|
||||||
}
|
}
|
||||||
tk := s.tokenManager.FindToken(fromNetwork, sendArgs.CbridgeTx.Symbol)
|
tk := s.tokenManager.FindToken(fromNetwork, sendArgs.CbridgeTx.Symbol)
|
||||||
if tk == nil {
|
if tk == nil {
|
||||||
return types.HexToHash(""), errors.New("token not found")
|
return nil, errors.New("token not found")
|
||||||
}
|
}
|
||||||
addrs := s.GetContractAddress(fromNetwork, nil)
|
addrs := s.GetContractAddress(fromNetwork, nil)
|
||||||
if addrs == nil {
|
if addrs == nil {
|
||||||
return types.HexToHash(""), errors.New("contract not found")
|
return nil, errors.New("contract not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
backend, err := s.rpcClient.EthClient(sendArgs.ChainID)
|
backend, err := s.rpcClient.EthClient(sendArgs.ChainID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.HexToHash(""), err
|
return nil, err
|
||||||
}
|
}
|
||||||
contract, err := celer.NewCeler(*addrs, backend)
|
contract, err := celer.NewCeler(*addrs, backend)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.HexToHash(""), err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
txOpts := sendArgs.CbridgeTx.ToTransactOpts(getSigner(sendArgs.ChainID, sendArgs.CbridgeTx.From, verifiedAccount))
|
txOpts := sendArgs.CbridgeTx.ToTransactOpts(signerFn)
|
||||||
var tx *ethTypes.Transaction
|
|
||||||
if tk.IsNative() {
|
if tk.IsNative() {
|
||||||
tx, err = contract.SendNative(
|
return contract.SendNative(
|
||||||
txOpts,
|
txOpts,
|
||||||
sendArgs.CbridgeTx.Recipient,
|
sendArgs.CbridgeTx.Recipient,
|
||||||
(*big.Int)(sendArgs.CbridgeTx.Amount),
|
(*big.Int)(sendArgs.CbridgeTx.Amount),
|
||||||
|
@ -278,8 +278,9 @@ func (s *CBridge) Send(sendArgs *TransactionBridge, verifiedAccount *account.Sel
|
||||||
uint64(time.Now().UnixMilli()),
|
uint64(time.Now().UnixMilli()),
|
||||||
500,
|
500,
|
||||||
)
|
)
|
||||||
} else {
|
}
|
||||||
tx, err = contract.Send(
|
|
||||||
|
return contract.Send(
|
||||||
txOpts,
|
txOpts,
|
||||||
sendArgs.CbridgeTx.Recipient,
|
sendArgs.CbridgeTx.Recipient,
|
||||||
tk.Address,
|
tk.Address,
|
||||||
|
@ -289,6 +290,9 @@ func (s *CBridge) Send(sendArgs *TransactionBridge, verifiedAccount *account.Sel
|
||||||
500,
|
500,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *CBridge) Send(sendArgs *TransactionBridge, verifiedAccount *account.SelectedExtKey) (types.Hash, error) {
|
||||||
|
tx, err := s.sendOrBuild(sendArgs, getSigner(sendArgs.ChainID, sendArgs.CbridgeTx.From, verifiedAccount))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.HexToHash(""), err
|
return types.HexToHash(""), err
|
||||||
}
|
}
|
||||||
|
@ -296,6 +300,10 @@ func (s *CBridge) Send(sendArgs *TransactionBridge, verifiedAccount *account.Sel
|
||||||
return types.Hash(tx.Hash()), nil
|
return types.Hash(tx.Hash()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *CBridge) BuildTransaction(sendArgs *TransactionBridge) (*ethTypes.Transaction, error) {
|
||||||
|
return s.sendOrBuild(sendArgs, nil)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *CBridge) CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error) {
|
func (s *CBridge) CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error) {
|
||||||
amt, err := s.estimateAmt(from, to, amountIn, symbol)
|
amt, err := s.estimateAmt(from, to, amountIn, symbol)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -3,8 +3,10 @@ package bridge
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"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/account"
|
||||||
"github.com/status-im/status-go/contracts/community-tokens/collectibles"
|
"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/eth-node/types"
|
||||||
|
@ -74,32 +76,43 @@ func (s *ERC721TransferBridge) EstimateGas(from, to *params.Network, account com
|
||||||
return 80000, nil
|
return 80000, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ERC721TransferBridge) Send(sendArgs *TransactionBridge, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) {
|
func (s *ERC721TransferBridge) sendOrBuild(sendArgs *TransactionBridge, signerFn bind.SignerFn) (tx *ethTypes.Transaction, err error) {
|
||||||
ethClient, err := s.rpcClient.EthClient(sendArgs.ChainID)
|
ethClient, err := s.rpcClient.EthClient(sendArgs.ChainID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return hash, err
|
return tx, err
|
||||||
}
|
}
|
||||||
|
|
||||||
contract, err := collectibles.NewCollectibles(common.Address(*sendArgs.ERC721TransferTx.To), ethClient)
|
contract, err := collectibles.NewCollectibles(common.Address(*sendArgs.ERC721TransferTx.To), ethClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return hash, err
|
return tx, err
|
||||||
}
|
}
|
||||||
|
|
||||||
nonce, unlock, err := s.transactor.NextNonce(s.rpcClient, sendArgs.ChainID, sendArgs.ERC721TransferTx.From)
|
nonce, unlock, err := s.transactor.NextNonce(s.rpcClient, sendArgs.ChainID, sendArgs.ERC721TransferTx.From)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return hash, err
|
return tx, err
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
unlock(err == nil, nonce)
|
unlock(err == nil, nonce)
|
||||||
}()
|
}()
|
||||||
argNonce := hexutil.Uint64(nonce)
|
argNonce := hexutil.Uint64(nonce)
|
||||||
sendArgs.ERC721TransferTx.Nonce = &argNonce
|
sendArgs.ERC721TransferTx.Nonce = &argNonce
|
||||||
txOpts := sendArgs.ERC721TransferTx.ToTransactOpts(getSigner(sendArgs.ChainID, sendArgs.ERC721TransferTx.From, verifiedAccount))
|
txOpts := sendArgs.ERC721TransferTx.ToTransactOpts(signerFn)
|
||||||
tx, err := contract.SafeTransferFrom(txOpts, common.Address(sendArgs.ERC721TransferTx.From), sendArgs.ERC721TransferTx.Recipient, sendArgs.ERC721TransferTx.TokenID.ToInt())
|
return contract.SafeTransferFrom(txOpts, common.Address(sendArgs.ERC721TransferTx.From), sendArgs.ERC721TransferTx.Recipient,
|
||||||
|
sendArgs.ERC721TransferTx.TokenID.ToInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ERC721TransferBridge) Send(sendArgs *TransactionBridge, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) {
|
||||||
|
tx, err := s.sendOrBuild(sendArgs, getSigner(sendArgs.ChainID, sendArgs.ERC721TransferTx.From, verifiedAccount))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return hash, err
|
return hash, err
|
||||||
}
|
}
|
||||||
return types.Hash(tx.Hash()), nil
|
return types.Hash(tx.Hash()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ERC721TransferBridge) BuildTransaction(sendArgs *TransactionBridge) (*ethTypes.Transaction, error) {
|
||||||
|
return s.sendOrBuild(sendArgs, nil)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *ERC721TransferBridge) CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error) {
|
func (s *ERC721TransferBridge) CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error) {
|
||||||
return amountIn, nil
|
return amountIn, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"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/account"
|
||||||
"github.com/status-im/status-go/contracts"
|
"github.com/status-im/status-go/contracts"
|
||||||
"github.com/status-im/status-go/contracts/hop"
|
"github.com/status-im/status-go/contracts/hop"
|
||||||
|
@ -173,15 +174,15 @@ func (h *HopBridge) GetContractAddress(network *params.Network, token *token.Tok
|
||||||
return &address
|
return &address
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HopBridge) Send(sendArgs *TransactionBridge, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) {
|
func (h *HopBridge) sendOrBuild(sendArgs *TransactionBridge, signerFn bind.SignerFn) (tx *ethTypes.Transaction, err error) {
|
||||||
fromNetwork := h.contractMaker.RPCClient.NetworkManager.Find(sendArgs.ChainID)
|
fromNetwork := h.contractMaker.RPCClient.NetworkManager.Find(sendArgs.ChainID)
|
||||||
if fromNetwork == nil {
|
if fromNetwork == nil {
|
||||||
return hash, err
|
return tx, err
|
||||||
}
|
}
|
||||||
|
|
||||||
nonce, unlock, err := h.transactor.NextNonce(h.contractMaker.RPCClient, sendArgs.ChainID, sendArgs.HopTx.From)
|
nonce, unlock, err := h.transactor.NextNonce(h.contractMaker.RPCClient, sendArgs.ChainID, sendArgs.HopTx.From)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return hash, err
|
return tx, err
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
unlock(err == nil, nonce)
|
unlock(err == nil, nonce)
|
||||||
|
@ -191,25 +192,37 @@ func (h *HopBridge) Send(sendArgs *TransactionBridge, verifiedAccount *account.S
|
||||||
|
|
||||||
token := h.tokenManager.FindToken(fromNetwork, sendArgs.HopTx.Symbol)
|
token := h.tokenManager.FindToken(fromNetwork, sendArgs.HopTx.Symbol)
|
||||||
if fromNetwork.Layer == 1 {
|
if fromNetwork.Layer == 1 {
|
||||||
hash, err = h.sendToL2(sendArgs.ChainID, sendArgs.HopTx, verifiedAccount, token)
|
tx, err = h.sendToL2(sendArgs.ChainID, sendArgs.HopTx, signerFn, token)
|
||||||
return hash, err
|
return tx, err
|
||||||
}
|
}
|
||||||
hash, err = h.swapAndSend(sendArgs.ChainID, sendArgs.HopTx, verifiedAccount, token)
|
tx, err = h.swapAndSend(sendArgs.ChainID, sendArgs.HopTx, signerFn, token)
|
||||||
return hash, err
|
return tx, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HopBridge) sendToL2(chainID uint64, hopArgs *HopTxArgs, verifiedAccount *account.SelectedExtKey, token *token.Token) (hash types.Hash, err error) {
|
func (h *HopBridge) Send(sendArgs *TransactionBridge, verifiedAccount *account.SelectedExtKey) (hash types.Hash, err error) {
|
||||||
|
tx, err := h.sendOrBuild(sendArgs, getSigner(sendArgs.ChainID, sendArgs.HopTx.From, verifiedAccount))
|
||||||
|
if err != nil {
|
||||||
|
return types.Hash{}, err
|
||||||
|
}
|
||||||
|
return types.Hash(tx.Hash()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HopBridge) BuildTransaction(sendArgs *TransactionBridge) (*ethTypes.Transaction, error) {
|
||||||
|
return h.sendOrBuild(sendArgs, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HopBridge) sendToL2(chainID uint64, hopArgs *HopTxArgs, signerFn bind.SignerFn, token *token.Token) (tx *ethTypes.Transaction, err error) {
|
||||||
bridge, err := h.contractMaker.NewHopL1Bridge(chainID, hopArgs.Symbol)
|
bridge, err := h.contractMaker.NewHopL1Bridge(chainID, hopArgs.Symbol)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return hash, err
|
return tx, err
|
||||||
}
|
}
|
||||||
txOpts := hopArgs.ToTransactOpts(getSigner(chainID, hopArgs.From, verifiedAccount))
|
txOpts := hopArgs.ToTransactOpts(signerFn)
|
||||||
if token.IsNative() {
|
if token.IsNative() {
|
||||||
txOpts.Value = (*big.Int)(hopArgs.Amount)
|
txOpts.Value = (*big.Int)(hopArgs.Amount)
|
||||||
}
|
}
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
deadline := big.NewInt(now.Unix() + 604800)
|
deadline := big.NewInt(now.Unix() + 604800)
|
||||||
tx, err := bridge.SendToL2(
|
tx, err = bridge.SendToL2(
|
||||||
txOpts,
|
txOpts,
|
||||||
big.NewInt(int64(hopArgs.ChainID)),
|
big.NewInt(int64(hopArgs.ChainID)),
|
||||||
hopArgs.Recipient,
|
hopArgs.Recipient,
|
||||||
|
@ -220,25 +233,22 @@ func (h *HopBridge) sendToL2(chainID uint64, hopArgs *HopTxArgs, verifiedAccount
|
||||||
big.NewInt(0),
|
big.NewInt(0),
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
return tx, err
|
||||||
return hash, err
|
|
||||||
}
|
|
||||||
return types.Hash(tx.Hash()), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HopBridge) swapAndSend(chainID uint64, hopArgs *HopTxArgs, verifiedAccount *account.SelectedExtKey, token *token.Token) (hash types.Hash, err error) {
|
func (h *HopBridge) swapAndSend(chainID uint64, hopArgs *HopTxArgs, signerFn bind.SignerFn, token *token.Token) (tx *ethTypes.Transaction, err error) {
|
||||||
ammWrapper, err := h.contractMaker.NewHopL2AmmWrapper(chainID, hopArgs.Symbol)
|
ammWrapper, err := h.contractMaker.NewHopL2AmmWrapper(chainID, hopArgs.Symbol)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return hash, err
|
return tx, err
|
||||||
}
|
}
|
||||||
|
|
||||||
txOpts := hopArgs.ToTransactOpts(getSigner(chainID, hopArgs.From, verifiedAccount))
|
txOpts := hopArgs.ToTransactOpts(signerFn)
|
||||||
if token.IsNative() {
|
if token.IsNative() {
|
||||||
txOpts.Value = (*big.Int)(hopArgs.Amount)
|
txOpts.Value = (*big.Int)(hopArgs.Amount)
|
||||||
}
|
}
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
deadline := big.NewInt(now.Unix() + 604800)
|
deadline := big.NewInt(now.Unix() + 604800)
|
||||||
tx, err := ammWrapper.SwapAndSend(
|
tx, err = ammWrapper.SwapAndSend(
|
||||||
txOpts,
|
txOpts,
|
||||||
big.NewInt(int64(hopArgs.ChainID)),
|
big.NewInt(int64(hopArgs.ChainID)),
|
||||||
hopArgs.Recipient,
|
hopArgs.Recipient,
|
||||||
|
@ -250,11 +260,7 @@ func (h *HopBridge) swapAndSend(chainID uint64, hopArgs *HopTxArgs, verifiedAcco
|
||||||
deadline,
|
deadline,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
return tx, err
|
||||||
return hash, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return types.Hash(tx.Hash()), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CalculateBonderFees logics come from: https://docs.hop.exchange/fee-calculation
|
// CalculateBonderFees logics come from: https://docs.hop.exchange/fee-calculation
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
ethTypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/status-im/status-go/account"
|
"github.com/status-im/status-go/account"
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
"github.com/status-im/status-go/params"
|
"github.com/status-im/status-go/params"
|
||||||
|
@ -44,6 +45,10 @@ func (s *TransferBridge) Send(sendArgs *TransactionBridge, verifiedAccount *acco
|
||||||
return s.transactor.SendTransactionWithChainID(sendArgs.ChainID, *sendArgs.TransferTx, verifiedAccount)
|
return s.transactor.SendTransactionWithChainID(sendArgs.ChainID, *sendArgs.TransferTx, verifiedAccount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TransferBridge) BuildTransaction(sendArgs *TransactionBridge) (*ethTypes.Transaction, error) {
|
||||||
|
return s.transactor.ValidateAndBuildTransaction(sendArgs.ChainID, *sendArgs.TransferTx)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TransferBridge) CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error) {
|
func (s *TransferBridge) CalculateAmountOut(from, to *params.Network, amountIn *big.Int, symbol string) (*big.Int, error) {
|
||||||
return amountIn, nil
|
return amountIn, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -715,7 +715,7 @@ func TestFindBlocksCommand(t *testing.T) {
|
||||||
|
|
||||||
db, err := helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
|
db, err := helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
tm := &TransactionManager{db, nil, nil, nil, nil, nil, nil}
|
tm := &TransactionManager{db, nil, nil, nil, nil, nil, nil, nil, nil, nil}
|
||||||
|
|
||||||
wdb := NewDB(db)
|
wdb := NewDB(db)
|
||||||
tc := &TestClient{
|
tc := &TestClient{
|
||||||
|
|
|
@ -3,17 +3,21 @@ package transfer
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
ethTypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/status-im/status-go/account"
|
"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/eth-node/types"
|
||||||
"github.com/status-im/status-go/multiaccounts/accounts"
|
"github.com/status-im/status-go/multiaccounts/accounts"
|
||||||
"github.com/status-im/status-go/params"
|
"github.com/status-im/status-go/params"
|
||||||
|
@ -21,6 +25,7 @@ import (
|
||||||
"github.com/status-im/status-go/services/wallet/bridge"
|
"github.com/status-im/status-go/services/wallet/bridge"
|
||||||
wallet_common "github.com/status-im/status-go/services/wallet/common"
|
wallet_common "github.com/status-im/status-go/services/wallet/common"
|
||||||
"github.com/status-im/status-go/services/wallet/walletevent"
|
"github.com/status-im/status-go/services/wallet/walletevent"
|
||||||
|
"github.com/status-im/status-go/signal"
|
||||||
"github.com/status-im/status-go/transactions"
|
"github.com/status-im/status-go/transactions"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -33,6 +38,18 @@ const (
|
||||||
EventMTTransactionUpdate walletevent.EventType = "multi-transaction-update"
|
EventMTTransactionUpdate walletevent.EventType = "multi-transaction-update"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type SignatureDetails struct {
|
||||||
|
R string `json:"r"`
|
||||||
|
S string `json:"s"`
|
||||||
|
V string `json:"v"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TransactionDescription struct {
|
||||||
|
chainID uint64
|
||||||
|
builtTx *ethTypes.Transaction
|
||||||
|
signature []byte
|
||||||
|
}
|
||||||
|
|
||||||
type TransactionManager struct {
|
type TransactionManager struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
gethManager *account.GethManager
|
gethManager *account.GethManager
|
||||||
|
@ -41,6 +58,10 @@ type TransactionManager struct {
|
||||||
accountsDB *accounts.Database
|
accountsDB *accounts.Database
|
||||||
pendingTracker *transactions.PendingTxTracker
|
pendingTracker *transactions.PendingTxTracker
|
||||||
eventFeed *event.Feed
|
eventFeed *event.Feed
|
||||||
|
|
||||||
|
multiTransactionForKeycardSigning *MultiTransaction
|
||||||
|
transactionsBridgeData []*bridge.TransactionBridge
|
||||||
|
transactionsForKeycardSingning map[common.Hash]*TransactionDescription
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTransactionManager(
|
func NewTransactionManager(
|
||||||
|
@ -271,6 +292,7 @@ func (tm *TransactionManager) UpdateMultiTransaction(multiTransaction *MultiTran
|
||||||
return updateMultiTransaction(tm.db, multiTransaction)
|
return updateMultiTransaction(tm.db, multiTransaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In case of keycard account, password should be empty
|
||||||
func (tm *TransactionManager) CreateMultiTransactionFromCommand(ctx context.Context, command *MultiTransactionCommand,
|
func (tm *TransactionManager) CreateMultiTransactionFromCommand(ctx context.Context, command *MultiTransactionCommand,
|
||||||
data []*bridge.TransactionBridge, bridges map[string]bridge.Bridge, password string) (*MultiTransactionCommandResult, error) {
|
data []*bridge.TransactionBridge, bridges map[string]bridge.Bridge, password string) (*MultiTransactionCommandResult, error) {
|
||||||
|
|
||||||
|
@ -286,6 +308,33 @@ func (tm *TransactionManager) CreateMultiTransactionFromCommand(ctx context.Cont
|
||||||
}
|
}
|
||||||
|
|
||||||
multiTransaction.ID = uint(multiTransactionID)
|
multiTransaction.ID = uint(multiTransactionID)
|
||||||
|
if password == "" {
|
||||||
|
acc, err := tm.accountsDB.GetAccountByAddress(types.Address(multiTransaction.FromAddress))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
kp, err := tm.accountsDB.GetKeypairByKeyUID(acc.KeyUID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !kp.MigratedToKeycard() {
|
||||||
|
return nil, fmt.Errorf("account being used is not migrated to a keycard, password is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
tm.multiTransactionForKeycardSigning = multiTransaction
|
||||||
|
tm.transactionsBridgeData = data
|
||||||
|
hashes, err := tm.buildTransactions(bridges)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
signal.SendTransactionsForSigningEvent(hashes)
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
hashes, err := tm.sendTransactions(multiTransaction, data, bridges, password)
|
hashes, err := tm.sendTransactions(multiTransaction, data, bridges, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -302,6 +351,61 @@ func (tm *TransactionManager) CreateMultiTransactionFromCommand(ctx context.Cont
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tm *TransactionManager) ProceedWithTransactionsSignatures(ctx context.Context, signatures map[string]SignatureDetails) (*MultiTransactionCommandResult, error) {
|
||||||
|
if tm.multiTransactionForKeycardSigning == nil {
|
||||||
|
return nil, errors.New("no multi transaction to proceed with")
|
||||||
|
}
|
||||||
|
if len(tm.transactionsBridgeData) == 0 {
|
||||||
|
return nil, errors.New("no transactions bridge data to proceed with")
|
||||||
|
}
|
||||||
|
if len(tm.transactionsForKeycardSingning) == 0 {
|
||||||
|
return nil, errors.New("no transactions to proceed with")
|
||||||
|
}
|
||||||
|
if len(signatures) != len(tm.transactionsForKeycardSingning) {
|
||||||
|
return nil, errors.New("not all transactions have been signed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if all transactions have been signed
|
||||||
|
for hash, desc := range tm.transactionsForKeycardSingning {
|
||||||
|
sigDetails, ok := signatures[hash.String()]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("missing signature for transaction %s", hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
rBytes, _ := hex.DecodeString(sigDetails.R)
|
||||||
|
sBytes, _ := hex.DecodeString(sigDetails.S)
|
||||||
|
vByte := byte(0)
|
||||||
|
if sigDetails.V == "1" {
|
||||||
|
vByte = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
desc.signature = make([]byte, crypto.SignatureLength)
|
||||||
|
copy(desc.signature[32-len(rBytes):32], rBytes)
|
||||||
|
copy(desc.signature[64-len(rBytes):64], sBytes)
|
||||||
|
desc.signature[64] = vByte
|
||||||
|
}
|
||||||
|
|
||||||
|
// send transactions
|
||||||
|
hashes := make(map[uint64][]types.Hash)
|
||||||
|
for _, desc := range tm.transactionsForKeycardSingning {
|
||||||
|
hash, err := tm.transactor.SendBuiltTransactionWithSignature(desc.chainID, desc.builtTx, desc.signature)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hashes[desc.chainID] = append(hashes[desc.chainID], hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := tm.storePendingTransactions(tm.multiTransactionForKeycardSigning, hashes, tm.transactionsBridgeData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &MultiTransactionCommandResult{
|
||||||
|
ID: int64(tm.multiTransactionForKeycardSigning.ID),
|
||||||
|
Hashes: hashes,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (tm *TransactionManager) storePendingTransactions(multiTransaction *MultiTransaction,
|
func (tm *TransactionManager) storePendingTransactions(multiTransaction *MultiTransaction,
|
||||||
hashes map[uint64][]types.Hash, data []*bridge.TransactionBridge) error {
|
hashes map[uint64][]types.Hash, data []*bridge.TransactionBridge) error {
|
||||||
|
|
||||||
|
@ -359,6 +463,29 @@ func multiTransactionFromCommand(command *MultiTransactionCommand) *MultiTransac
|
||||||
return multiTransaction
|
return multiTransaction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tm *TransactionManager) buildTransactions(bridges map[string]bridge.Bridge) ([]string, error) {
|
||||||
|
tm.transactionsForKeycardSingning = make(map[common.Hash]*TransactionDescription)
|
||||||
|
var hashes []string
|
||||||
|
for _, bridgeTx := range tm.transactionsBridgeData {
|
||||||
|
builtTx, err := bridges[bridgeTx.BridgeName].BuildTransaction(bridgeTx)
|
||||||
|
if err != nil {
|
||||||
|
return hashes, err
|
||||||
|
}
|
||||||
|
|
||||||
|
signer := ethTypes.NewLondonSigner(big.NewInt(int64(bridgeTx.ChainID)))
|
||||||
|
txHash := signer.Hash(builtTx)
|
||||||
|
|
||||||
|
tm.transactionsForKeycardSingning[txHash] = &TransactionDescription{
|
||||||
|
chainID: bridgeTx.ChainID,
|
||||||
|
builtTx: builtTx,
|
||||||
|
}
|
||||||
|
|
||||||
|
hashes = append(hashes, txHash.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return hashes, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (tm *TransactionManager) sendTransactions(multiTransaction *MultiTransaction,
|
func (tm *TransactionManager) sendTransactions(multiTransaction *MultiTransaction,
|
||||||
data []*bridge.TransactionBridge, bridges map[string]bridge.Bridge, password string) (
|
data []*bridge.TransactionBridge, bridges map[string]bridge.Bridge, password string) (
|
||||||
map[uint64][]types.Hash, error) {
|
map[uint64][]types.Hash, error) {
|
||||||
|
|
|
@ -17,7 +17,7 @@ import (
|
||||||
func setupTestTransactionDB(t *testing.T) (*TransactionManager, func()) {
|
func setupTestTransactionDB(t *testing.T) (*TransactionManager, func()) {
|
||||||
db, err := helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
|
db, err := helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
return &TransactionManager{db, nil, nil, nil, nil, nil, nil}, func() {
|
return &TransactionManager{db, nil, nil, nil, nil, nil, nil, nil, nil, nil}, func() {
|
||||||
require.NoError(t, db.Close())
|
require.NoError(t, db.Close())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,16 @@ const (
|
||||||
walletEvent = "wallet"
|
walletEvent = "wallet"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type UnsignedTransactions struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Transactions []string `json:"transactions"`
|
||||||
|
}
|
||||||
|
|
||||||
// SendWalletEvent sends event from services/wallet/events.
|
// SendWalletEvent sends event from services/wallet/events.
|
||||||
func SendWalletEvent(event interface{}) {
|
func SendWalletEvent(event interface{}) {
|
||||||
send(walletEvent, event)
|
send(walletEvent, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SendTransactionsForSigningEvent(transactions []string) {
|
||||||
|
send(walletEvent, UnsignedTransactions{Type: "sing-transactions", Transactions: transactions})
|
||||||
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ const (
|
||||||
|
|
||||||
defaultGas = 90000
|
defaultGas = 90000
|
||||||
|
|
||||||
validSignatureSize = 65
|
ValidSignatureSize = 65
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrInvalidSignatureSize is returned if a signature is not 65 bytes to avoid panic from go-ethereum
|
// ErrInvalidSignatureSize is returned if a signature is not 65 bytes to avoid panic from go-ethereum
|
||||||
|
@ -93,23 +93,50 @@ func (t *Transactor) SendTransactionWithChainID(chainID uint64, sendArgs SendTxA
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Transactor) ValidateAndBuildTransaction(chainID uint64, sendArgs SendTxArgs) (tx *gethtypes.Transaction, err error) {
|
||||||
|
wrapper := newRPCWrapper(t.rpcWrapper.RPCClient, chainID)
|
||||||
|
tx, err = t.validateAndBuildTransaction(wrapper, sendArgs)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Transactor) SendBuiltTransactionWithSignature(chainID uint64, tx *gethtypes.Transaction, sig []byte) (hash types.Hash, err error) {
|
||||||
|
if len(sig) != ValidSignatureSize {
|
||||||
|
return hash, ErrInvalidSignatureSize
|
||||||
|
}
|
||||||
|
|
||||||
|
rpcWrapper := newRPCWrapper(t.rpcWrapper.RPCClient, chainID)
|
||||||
|
chID := big.NewInt(int64(rpcWrapper.chainID))
|
||||||
|
|
||||||
|
signer := gethtypes.NewLondonSigner(chID)
|
||||||
|
signedTx, err := tx.WithSignature(signer, sig)
|
||||||
|
if err != nil {
|
||||||
|
return hash, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), t.rpcCallTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := rpcWrapper.SendTransaction(ctx, signedTx); err != nil {
|
||||||
|
return hash, err
|
||||||
|
}
|
||||||
|
return types.Hash(signedTx.Hash()), nil
|
||||||
|
}
|
||||||
|
|
||||||
// SendTransactionWithSignature receive a transaction and a signature, serialize them together and propage it to the network.
|
// SendTransactionWithSignature receive a transaction and a signature, serialize them together and propage it to the network.
|
||||||
// It's different from eth_sendRawTransaction because it receives a signature and not a serialized transaction with signature.
|
// It's different from eth_sendRawTransaction because it receives a signature and not a serialized transaction with signature.
|
||||||
// Since the transactions is already signed, we assume it was validated and used the right nonce.
|
// Since the transactions is already signed, we assume it was validated and used the right nonce.
|
||||||
func (t *Transactor) SendTransactionWithSignature(args SendTxArgs, sig []byte) (hash types.Hash, err error) {
|
func (t *Transactor) SendTransactionWithSignature(chainID uint64, args SendTxArgs, sig []byte) (hash types.Hash, err error) {
|
||||||
if !args.Valid() {
|
if !args.Valid() {
|
||||||
return hash, ErrInvalidSendTxArgs
|
return hash, ErrInvalidSendTxArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(sig) != validSignatureSize {
|
if len(sig) != ValidSignatureSize {
|
||||||
return hash, ErrInvalidSignatureSize
|
return hash, ErrInvalidSignatureSize
|
||||||
}
|
}
|
||||||
|
|
||||||
chainID := big.NewInt(int64(t.networkID))
|
|
||||||
signer := gethtypes.NewLondonSigner(chainID)
|
|
||||||
|
|
||||||
tx := t.buildTransaction(args)
|
tx := t.buildTransaction(args)
|
||||||
expectedNonce, unlock, err := t.nonce.Next(t.rpcWrapper, args.From)
|
rpcWrapper := newRPCWrapper(t.rpcWrapper.RPCClient, chainID)
|
||||||
|
expectedNonce, unlock, err := t.nonce.Next(rpcWrapper, args.From)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return hash, err
|
return hash, err
|
||||||
}
|
}
|
||||||
|
@ -121,18 +148,7 @@ func (t *Transactor) SendTransactionWithSignature(args SendTxArgs, sig []byte) (
|
||||||
return hash, &ErrBadNonce{tx.Nonce(), expectedNonce}
|
return hash, &ErrBadNonce{tx.Nonce(), expectedNonce}
|
||||||
}
|
}
|
||||||
|
|
||||||
signedTx, err := tx.WithSignature(signer, sig)
|
return t.SendBuiltTransactionWithSignature(chainID, tx, sig)
|
||||||
if err != nil {
|
|
||||||
return hash, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), t.rpcCallTimeout)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
if err := t.rpcWrapper.SendTransaction(ctx, signedTx); err != nil {
|
|
||||||
return hash, err
|
|
||||||
}
|
|
||||||
return types.Hash(signedTx.Hash()), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Transactor) HashTransaction(args SendTxArgs) (validatedArgs SendTxArgs, hash types.Hash, err error) {
|
func (t *Transactor) HashTransaction(args SendTxArgs) (validatedArgs SendTxArgs, hash types.Hash, err error) {
|
||||||
|
@ -235,18 +251,14 @@ func (t *Transactor) validateAccount(args SendTxArgs, selectedAccount *account.S
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Transactor) validateAndPropagate(rpcWrapper *rpcWrapper, selectedAccount *account.SelectedExtKey, args SendTxArgs) (hash types.Hash, err error) {
|
func (t *Transactor) validateAndBuildTransaction(rpcWrapper *rpcWrapper, args SendTxArgs) (tx *gethtypes.Transaction, err error) {
|
||||||
if err = t.validateAccount(args, selectedAccount); err != nil {
|
|
||||||
return hash, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !args.Valid() {
|
if !args.Valid() {
|
||||||
return hash, ErrInvalidSendTxArgs
|
return tx, ErrInvalidSendTxArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
nonce, unlock, err := t.nonce.Next(rpcWrapper, args.From)
|
nonce, unlock, err := t.nonce.Next(rpcWrapper, args.From)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return hash, err
|
return tx, err
|
||||||
}
|
}
|
||||||
if args.Nonce != nil {
|
if args.Nonce != nil {
|
||||||
nonce = uint64(*args.Nonce)
|
nonce = uint64(*args.Nonce)
|
||||||
|
@ -261,10 +273,10 @@ func (t *Transactor) validateAndPropagate(rpcWrapper *rpcWrapper, selectedAccoun
|
||||||
if !args.IsDynamicFeeTx() && args.GasPrice == nil {
|
if !args.IsDynamicFeeTx() && args.GasPrice == nil {
|
||||||
gasPrice, err = rpcWrapper.SuggestGasPrice(ctx)
|
gasPrice, err = rpcWrapper.SuggestGasPrice(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return hash, err
|
return tx, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chainID := big.NewInt(int64(rpcWrapper.chainID))
|
|
||||||
value := (*big.Int)(args.Value)
|
value := (*big.Int)(args.Value)
|
||||||
var gas uint64
|
var gas uint64
|
||||||
if args.Gas != nil {
|
if args.Gas != nil {
|
||||||
|
@ -289,20 +301,34 @@ func (t *Transactor) validateAndPropagate(rpcWrapper *rpcWrapper, selectedAccoun
|
||||||
Data: args.GetInput(),
|
Data: args.GetInput(),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return hash, err
|
return tx, err
|
||||||
}
|
}
|
||||||
if gas < defaultGas {
|
if gas < defaultGas {
|
||||||
t.log.Info("default gas will be used because estimated is lower", "estimated", gas, "default", defaultGas)
|
t.log.Info("default gas will be used because estimated is lower", "estimated", gas, "default", defaultGas)
|
||||||
gas = defaultGas
|
gas = defaultGas
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tx := t.buildTransactionWithOverrides(nonce, value, gas, gasPrice, args)
|
tx = t.buildTransactionWithOverrides(nonce, value, gas, gasPrice, args)
|
||||||
|
return tx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Transactor) validateAndPropagate(rpcWrapper *rpcWrapper, selectedAccount *account.SelectedExtKey, args SendTxArgs) (hash types.Hash, err error) {
|
||||||
|
if err = t.validateAccount(args, selectedAccount); err != nil {
|
||||||
|
return hash, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, err := t.validateAndBuildTransaction(rpcWrapper, args)
|
||||||
|
if err != nil {
|
||||||
|
return hash, err
|
||||||
|
}
|
||||||
|
|
||||||
|
chainID := big.NewInt(int64(rpcWrapper.chainID))
|
||||||
signedTx, err := gethtypes.SignTx(tx, gethtypes.NewLondonSigner(chainID), selectedAccount.AccountKey.PrivateKey)
|
signedTx, err := gethtypes.SignTx(tx, gethtypes.NewLondonSigner(chainID), selectedAccount.AccountKey.PrivateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return hash, err
|
return hash, err
|
||||||
}
|
}
|
||||||
// ctx, cancel = context.WithTimeout(context.Background(), t.rpcCallTimeout)
|
ctx, cancel := context.WithTimeout(context.Background(), t.rpcCallTimeout)
|
||||||
// defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := rpcWrapper.SendTransaction(ctx, signedTx); err != nil {
|
if err := rpcWrapper.SendTransaction(ctx, signedTx); err != nil {
|
||||||
return hash, err
|
return hash, err
|
||||||
|
|
|
@ -374,7 +374,7 @@ func (s *TransactorSuite) TestSendTransactionWithSignature() {
|
||||||
Return(common.Hash{}, nil)
|
Return(common.Hash{}, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = s.manager.SendTransactionWithSignature(args, sig)
|
_, err = s.manager.SendTransactionWithSignature(s.nodeConfig.NetworkID, args, sig)
|
||||||
if scenario.expectError {
|
if scenario.expectError {
|
||||||
s.Error(err)
|
s.Error(err)
|
||||||
// local nonce should not be incremented
|
// local nonce should not be incremented
|
||||||
|
@ -393,7 +393,7 @@ func (s *TransactorSuite) TestSendTransactionWithSignature() {
|
||||||
|
|
||||||
func (s *TransactorSuite) TestSendTransactionWithSignature_InvalidSignature() {
|
func (s *TransactorSuite) TestSendTransactionWithSignature_InvalidSignature() {
|
||||||
args := SendTxArgs{}
|
args := SendTxArgs{}
|
||||||
_, err := s.manager.SendTransactionWithSignature(args, []byte{})
|
_, err := s.manager.SendTransactionWithSignature(1, args, []byte{})
|
||||||
s.Equal(ErrInvalidSignatureSize, err)
|
s.Equal(ErrInvalidSignatureSize, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,6 +106,11 @@ func (args SendTxArgs) ToTransactOpts(signerFn bind.SignerFn) *bind.TransactOpts
|
||||||
gasLimit = uint64(*args.Gas)
|
gasLimit = uint64(*args.Gas)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var noSign = false
|
||||||
|
if signerFn == nil {
|
||||||
|
noSign = true
|
||||||
|
}
|
||||||
|
|
||||||
return &bind.TransactOpts{
|
return &bind.TransactOpts{
|
||||||
From: common.Address(args.From),
|
From: common.Address(args.From),
|
||||||
Signer: signerFn,
|
Signer: signerFn,
|
||||||
|
@ -114,6 +119,7 @@ func (args SendTxArgs) ToTransactOpts(signerFn bind.SignerFn) *bind.TransactOpts
|
||||||
GasFeeCap: gasFeeCap,
|
GasFeeCap: gasFeeCap,
|
||||||
GasTipCap: gasTipCap,
|
GasTipCap: gasTipCap,
|
||||||
Nonce: nonce,
|
Nonce: nonce,
|
||||||
|
NoSign: noSign,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,7 @@ type TransactOpts struct {
|
||||||
|
|
||||||
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
|
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
|
||||||
|
|
||||||
|
NoSign bool // Do all transact steps but do not sign or send the transaction
|
||||||
NoSend bool // Do all transact steps but do not send the transaction
|
NoSend bool // Do all transact steps but do not send the transaction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,6 +388,9 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if opts.NoSign {
|
||||||
|
return rawTx, nil
|
||||||
|
}
|
||||||
// Sign the transaction and schedule it for execution
|
// Sign the transaction and schedule it for execution
|
||||||
if opts.Signer == nil {
|
if opts.Signer == nil {
|
||||||
return nil, errors.New("no signer to authorize the transaction with")
|
return nil, errors.New("no signer to authorize the transaction with")
|
||||||
|
|
|
@ -208,7 +208,7 @@ github.com/edsrzf/mmap-go
|
||||||
## explicit; go 1.14
|
## explicit; go 1.14
|
||||||
github.com/elastic/gosigar
|
github.com/elastic/gosigar
|
||||||
github.com/elastic/gosigar/sys/windows
|
github.com/elastic/gosigar/sys/windows
|
||||||
# github.com/ethereum/go-ethereum v1.10.26 => github.com/status-im/go-ethereum v1.10.25-status.7
|
# github.com/ethereum/go-ethereum v1.10.26 => github.com/status-im/go-ethereum v1.10.25-status.9
|
||||||
## explicit; go 1.17
|
## explicit; go 1.17
|
||||||
github.com/ethereum/go-ethereum
|
github.com/ethereum/go-ethereum
|
||||||
github.com/ethereum/go-ethereum/accounts
|
github.com/ethereum/go-ethereum/accounts
|
||||||
|
|
Loading…
Reference in New Issue