github.com/ChainSafe/chainbridge-core@v1.4.2/chains/evm/calls/evmtransaction/evm-tx.go (about) 1 package evmtransaction 2 3 import ( 4 "context" 5 "math/big" 6 7 "github.com/ChainSafe/chainbridge-core/chains/evm/calls/evmclient" 8 9 "github.com/ethereum/go-ethereum/accounts/abi/bind" 10 "github.com/ethereum/go-ethereum/common" 11 "github.com/ethereum/go-ethereum/core/types" 12 ) 13 14 type TX struct { 15 tx *types.Transaction 16 } 17 18 // RawWithSignature mostly copies WithSignature interface of type.Transaction from go-ethereum, 19 // but return raw byte representation of transaction to be compatible and interchangeable between different go-ethereum forks 20 // WithSignature returns a new transaction with the given signature. 21 // This signature needs to be in the [R || S || V] format where V is 0 or 1. 22 func (a *TX) RawWithSignature(signer evmclient.Signer, domainID *big.Int) ([]byte, error) { 23 opts, err := newTransactorWithChainID(signer, domainID) 24 if err != nil { 25 return nil, err 26 } 27 tx, err := opts.Signer(signer.CommonAddress(), a.tx) 28 if err != nil { 29 return nil, err 30 } 31 a.tx = tx 32 33 data, err := tx.MarshalBinary() 34 if err != nil { 35 return nil, err 36 } 37 38 return data, nil 39 } 40 41 // NewTransaction is the ethereum transaction constructor 42 func NewTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit uint64, gasPrices []*big.Int, data []byte) (evmclient.CommonTransaction, error) { 43 // If there is more than one gas price returned we are sending with DynamicFeeTx's 44 if len(gasPrices) > 1 { 45 return newDynamicFeeTransaction(nonce, to, amount, gasLimit, gasPrices[0], gasPrices[1], data), nil 46 } else { 47 return newTransaction(nonce, to, amount, gasLimit, gasPrices[0], data), nil 48 } 49 } 50 51 func newDynamicFeeTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit uint64, gasTipCap *big.Int, gasFeeCap *big.Int, data []byte) *TX { 52 tx := types.NewTx(&types.DynamicFeeTx{ 53 Nonce: nonce, 54 To: to, 55 GasFeeCap: gasFeeCap, 56 GasTipCap: gasTipCap, 57 Gas: gasLimit, 58 Value: amount, 59 Data: data, 60 }) 61 return &TX{tx: tx} 62 } 63 64 func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *TX { 65 tx := types.NewTx(&types.LegacyTx{ 66 Nonce: nonce, 67 To: to, 68 Value: amount, 69 Gas: gasLimit, 70 GasPrice: gasPrice, 71 Data: data, 72 }) 73 return &TX{tx: tx} 74 } 75 76 func (a *TX) Hash() common.Hash { 77 return a.tx.Hash() 78 } 79 80 // newTransactorWithChainID is a utility method to easily create a transaction signer 81 // for an evmclient.Signer. 82 // Mostly copies bind.NewKeyedTransactorWithChainID but sings with the provided signer 83 // instead of a privateKey 84 func newTransactorWithChainID(s evmclient.Signer, chainID *big.Int) (*bind.TransactOpts, error) { 85 keyAddr := s.CommonAddress() 86 if chainID == nil { 87 return nil, bind.ErrNoChainID 88 } 89 signer := types.LatestSignerForChainID(chainID) 90 return &bind.TransactOpts{ 91 From: keyAddr, 92 Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) { 93 if address != keyAddr { 94 return nil, bind.ErrNotAuthorized 95 } 96 signature, err := s.Sign(signer.Hash(tx).Bytes()) 97 if err != nil { 98 return nil, err 99 } 100 return tx.WithSignature(signer, signature) 101 }, 102 Context: context.Background(), 103 }, nil 104 }