Перейти к основному контенту

How to send ERC-20 tokens using Go

In this support guide we're going to learn how to send ERC-20 tokens using Go and the go-ethereum packages. 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:

  1. Go installed on your system
  2. The go-ethereum packages (they will be automatically installed when you run the code)
  3. 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 don't have to use environmental variables, but it's a good practice to use them so that sensitive 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_API_KEY")))
if err != nil {
log.Fatal(err)
}

Sending ERC-20 tokens

For this tutorial, let's try and send some UNI tokens. Sending ERC-20 tokens differs from sending ETH in 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 Sepoliascan 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_API_KEY")))
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())
}
Was this helpful?
Connect MetaMask to provide feedback
What is this?
This is a trial feedback system that uses Verax to record your feedback as onchain attestations on Linea Mainnet. When you vote, submit a transaction in your wallet.