Go Eth - How to send ERC-20 Tokens (EIP-1559)

Hello peeps! :raised_hands:t4:

In this support tip we’re going to learn together how to use Go ETH to send EIP-1559 transactions for ERC-20 token. As usual, if you only need the script’s code, feel free to scroll down to the end of the article.

Prerequisites

For this tutorial to work, you will need to have installed: go eth (can be installed by running the comamnds below)
brew tap ethereum/ethereum
brew install ethereum)
dotenv (optional, but recommended for better security)

Setting up our project

Let’s start by importing the required libraries and creating our .env file, which will contain our account’s private key (you can use a test wallet without any real funds on it) and the Infura project ID.

If you need a little more help on creating a .env file, you can check out this repository.

For this tutorial’s purposes you can also not use environmental variables, but it’s a good practice to use them, so the sensible information is not easily accessible within the code.

package main

import (
	"context"
	"fmt"
	"log"
	"math/big"
	"os"

	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/ethclient"
)

func main() {
	// Connect to an Ethereum node using Infura
	client, err := ethclient.Dial(fmt.Sprintf("https://goerli.infura.io/v3/%s", os.Getenv("INFURA_PROJECT_ID")))
	if err != nil {
		log.Fatal(err)
	}

Sending ERC-20 Tokens

For this tutorial, let’s try and send some UNI tokens. What makes sending ERC-20 tokens different than sending plain ETH, is the fact that our script will need the contract’s ABI. The ABI can be easily found on etherscan, by searching for the contract’s address and going to the ‘Contract’ section.

We can navigate to the token’s etherscan page , under the Contract tab. Then, we can create an abi.json file in our project’s directory and store the copied ABI there.

	// Load the ABI for the ERC-20 token contract
	tokenAddress := common.HexToAddress("0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984")
	contract, err := bind.NewBoundContract(tokenAddress, abi, client, client, client)
	if err != nil {
		log.Fatal(err)
	}

After fetching the ABI from the local abi.json file, we can create our contract object and pass all these parameters to the send_ERC20 function.

	// Create a new transaction
	nonce, err := client.PendingNonceAt(context.Background(), common.HexToAddress("<insert_here_the_signer_address>"))
	if err != nil {
		log.Fatal(err)
	}

	gasPrice, err := client.SuggestGasPrice(context.Background())
	if err != nil {
		log.Fatal(err)
	}

	auth := bind.NewKeyedTransactor(<insert_here_the_signer_private_key>)
	auth.Nonce = big.NewInt(int64(nonce))
	auth.Value = big.NewInt(0)      // in wei
	auth.GasLimit = uint64(300000) // in units
	auth.GasPrice = gasPrice
	
	toAddress := common.HexToAddress("<insert_here_the_token_destination_address>")
	amount := big.NewInt(1000000000000000000) // in wei
	
	tx, err := contract.Transfer(auth, toAddress, amount)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Tx Hash: %s", tx.Hash().Hex())

And that’s it! Make sure to declare your ‘from’ and ‘to’ addresses in the main function and you should be good to go.

Complete code overview

package main

import (
	"context"
	"fmt"
	"log"
	"math/big"
	"os"

	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/ethclient"
)

func main() {
	// Connect to an Ethereum node using Infura
	client, err := ethclient.Dial(fmt.Sprintf("https://goerli.infura.io/v3/%s", os.Getenv("INFURA_PROJECT_ID")))
	if err != nil {
		log.Fatal(err)
	}

	// Load the ABI for the ERC-20 token contract
	tokenAddress := common.HexToAddress("0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984")
	contract, err := bind.NewBoundContract(tokenAddress, abi, client, client, client)
	if err != nil {
		log.Fatal(err)
	}

	// Create a new transaction
	nonce, err := client.PendingNonceAt(context.Background(), common.HexToAddress("<insert_here_the_signer_address>"))
	if err != nil {
		log.Fatal(err)
	}

	gasPrice, err := client.SuggestGasPrice(context.Background())
	if err != nil {
		log.Fatal(err)
	}

	auth := bind.NewKeyedTransactor(<insert_here_the_signer_private_key>)
	auth.Nonce = big.NewInt(int64(nonce))
	auth.Value = big.NewInt(0)      // in wei
	auth.GasLimit = uint64(300000) // in units
	auth.GasPrice = gasPrice
	
	toAddress := common.HexToAddress("<insert_here_the_token_destination_address>")
	amount := big.NewInt(1000000000000000000) // in wei
	
	tx, err := contract.Transfer(auth, toAddress, amount)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Tx Hash: %s", tx.Hash().Hex())
}
4 Likes