Skip to content

Instantly share code, notes, and snippets.

@akme
Created October 21, 2021 14:53
Show Gist options
  • Save akme/7419daacc7a6d48be2ef700d995c71c7 to your computer and use it in GitHub Desktop.
Save akme/7419daacc7a6d48be2ef700d995c71c7 to your computer and use it in GitHub Desktop.
Golang create and send EIP-1559 transaction
package main
import (
"context"
"encoding/hex"
"fmt"
"log"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
hdwallet "github.com/miguelmota/go-ethereum-hdwallet"
)
func GenRawTx(signedTx *types.Transaction) (string, error) {
data, err := signedTx.MarshalBinary()
if err != nil {
return "", err
}
return hexutil.Encode(data), nil
}
func SendRawTransaction(rpcClient *rpc.Client, signedTx *types.Transaction) (*common.Hash, error) {
rawTx, err := GenRawTx(signedTx)
if err != nil {
return nil, err
}
var result hexutil.Bytes
err = rpcClient.CallContext(context.Background(), &result, "eth_sendRawTransaction", rawTx)
if err != nil {
return nil, err
}
hash := common.HexToHash(hexutil.Encode(result))
return &hash, nil
}
func main() {
mnemonic := ""
wallet, err := hdwallet.NewFromMnemonic(mnemonic)
if err != nil {
log.Fatal(err)
}
path := hdwallet.MustParseDerivationPath("m/44'/60'/0'/0/0")
account, err := wallet.Derive(path, true)
if err != nil {
log.Fatal(err)
}
fmt.Println("From:", account.Address.Hex())
path2 := hdwallet.MustParseDerivationPath("m/44'/60'/0'/0/1")
dest, err := wallet.Derive(path2, false)
if err != nil {
log.Fatal(err)
}
fmt.Println("To:", dest.Address.Hex())
gasLimit := uint64(21000)
log.Println("GasLimit: ", gasLimit)
amount := big.NewInt(100000000)
log.Println("Amount: ", amount)
nodeUrl := ""
rpcClient, err := rpc.Dial(nodeUrl)
if err != nil {
log.Fatal(err)
}
client := ethclient.NewClient(rpcClient)
nonce, err := client.PendingNonceAt(context.Background(), account.Address)
if err != nil {
log.Fatal(err)
}
log.Println("Nonce: ", nonce)
gasPrice, err := client.SuggestGasPrice(context.Background())
if err != nil {
log.Fatal(err)
}
log.Println("GasPrice: ", gasPrice)
blockNumber, err := client.BlockNumber(context.Background())
if err != nil {
log.Fatal(err)
}
log.Println("Current block number: ", blockNumber)
balance, err := client.BalanceAt(context.Background(), account.Address, big.NewInt(int64(blockNumber)))
if err != nil {
log.Fatal(err)
}
log.Println("Balance: ", balance)
chainID, err := client.ChainID(context.Background())
if err != nil {
log.Fatal(err)
}
log.Println("ChainID: ", chainID)
gasTipCap, err := client.SuggestGasTipCap(context.Background())
if err != nil {
log.Fatal(err)
}
gasFeeCap := gasPrice
tx := types.NewTx(&types.DynamicFeeTx{
ChainID: chainID,
Nonce: nonce,
GasFeeCap: gasFeeCap,
GasTipCap: gasTipCap,
Gas: gasLimit,
To: &dest.Address,
Value: amount,
Data: []byte{},
})
privateKey, err := wallet.PrivateKey(account)
if err != nil {
log.Fatal(err)
}
signer := types.NewLondonSigner(chainID)
// Sign the transaction and verify the sender to avoid hardware fault surprises
signedTx, err := types.SignTx(tx, signer, privateKey)
if err != nil {
log.Fatal("signTx error", err)
}
sender, err := types.Sender(signer, signedTx)
if err != nil {
log.Fatal("Sender error: ", err)
}
if sender != account.Address {
log.Fatalf("signer mismatch: expected %s, got %s", account.Address.Hex(), sender.Hex())
}
data, err := signedTx.MarshalBinary()
if err != nil {
log.Fatal("Sender error: ", err)
}
fmt.Printf("Raw Transaction: 0x%s\n", hex.EncodeToString(data))
txHash, err := SendRawTransaction(rpcClient, signedTx)
if err != nil {
log.Fatal("SendRawTracnsaction error: ", err)
}
log.Println("tx hash: ", txHash)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment