Transferring Tokens (ERC-20) · Ethereum Development with Go (2024)

This section will walk you through on how to transfer ERC-20 tokens. To learn how to transfer other types of tokens that are non-ERC-20 compliant check out the section on smart contracts to learn how to interact with smart contracts.

To transfer ERC-20 tokens, we'll need to broadcast a transaction to the blockchain just like before, but with a few changed parameters:

  • Instead of setting a value for the broadcasted transaction, we'll need to embed the value of tokens to transfer in the data send in the transaction.
  • Construct a contract function call and embed it in the data field of the transaction we're broadcasting to the blockchain.

We'll assume that you've already completed the previous section on transferring ETH, and have a Go application that has:

  1. Connected a client.
  2. Loaded your account private key.
  3. Configured the gas price to use for your transaction.

Creating a Token for testing

You can create a token using the Token Factory https://tokenfactory.surge.sh, a website for conveniently deploying ERC-20 token contracts, to follow the examples in this guide.

When you create your ERC-20 Token, be sure to note down the address of the token contract.

For demonstration purposes, I've created a token (HelloToken HTN) using the Token Factory and deployed it to the Rinkeby testnet at the token contract address 0x28b149020d2152179873ec60bed6bf7cd705775d.

You can check it out with a Web3-enabled browser here (make sure to be connected to the Rinkeby testnet in MetaMask): https://tokenfactory.surge.sh/#/token/0x28b149020d2152179873ec60bed6bf7cd705775d

ETH value and destination address

First, we'll set a few variables.

Set the value of the transaction to 0.

value := big.NewInt(0)

This value is the amount of ETH to be transferred for this transaction, which should be 0 since we're transferring ERC-20 Tokens and not ETH. We'll set the value of Tokens to be transferred in the data field later.

Then, store the address you'll be sending tokens to in a variable.

toAddress := common.HexToAddress("0x4592d8f8d7b001e72cb26a73e4fa1806a51ac79d")

Forming the data field

Now the fun part. We'll need to figure out what goes into the data field of the transaction. This is the message that we broadcast to the blockchain as part of the transaction.

To make a token transfer, we need to use this data field to invoke a function on the smart contract. For more information on the functions available on an ERC-20 token contract, see the ERC-20 Token Standard specification.

To transfer tokens from our active account to another, we need to invoke the transfer() function in our ERC-20 token in our transactions data field. We do this by doing the following:

  1. Figure out the function signature of the transfer() smart contract function we'll be calling.
  2. Figure out the inputs for the function — the address of the token recipients, and the value of tokens to be transferred.
  3. Get the first 8 characters (4 bytes) of the Keccak256 hash of that function signature. This is the method ID of the contract function we're invoking.
  4. Zero-pad (on the left) the inputs of our function call — the address and value. These input values need to be 256-bits (32 bytes) long.

First, let's assign the token contract address to a variable.

tokenAddress := common.HexToAddress("0x28b149020d2152179873ec60bed6bf7cd705775d")

Next, we need to form the smart contract function call. The signature of the function we'll be calling is the transfer() function in the ERC-20 specification, and the types of the argument we'll be passing to it. The first argument type is address (the address to which we're sending tokens), and the second argument's type is uint256 (the amount of tokens to send). The result is the string transfer(address,uint256) (no spaces!).

We need this function signature as a byte slice, which we assign to transferFnSignature:

transferFnSignature := []byte("transfer(address,uint256)") // do not include spaces in the string

We then need to get the methodID of our function. To do this, we'll import the crypto/sha3 to generate the Keccak256 hash of the function signature. The first 4 bytes of the resulting hash is the methodID:

hash := sha3.NewLegacyKeccak256()hash.Write(transferFnSignature)methodID := hash.Sum(nil)[:4]fmt.Println(hexutil.Encode(methodID)) // 0xa9059cbb

Next we'll zero pad (to the left) the account address we're sending tokens. The resulting byte slice must be 32 bytes long:

paddedAddress := common.LeftPadBytes(toAddress.Bytes(), 32)fmt.Println(hexutil.Encode(paddedAddress)) // 0x0000000000000000000000004592d8f8d7b001e72cb26a73e4fa1806a51ac79d

Next we'll set the value tokens to send as a *big.Int number. Note that the denomination used here is determined by the token contract that you're interacting with, and not in ETH or wei.

For example, if we were working with TokenA where 1 token is set as the smallest unit of TokenA (i.e. the decimal() value of the token contract is 0; for more information, see the ERC-20 Token Standard specification), then amount := big.NewInt(1000) would set amount to 1000 units of TokenA.

The example token we're using, HelloToken, uses 18 decimals which is standard practice for ERC-20 tokens. This means that in order to represent 1 token we have to do the calculation amount * 10^18. In this example we'll use 1,000 tokens so we'll need to calculate 1000 * 10^18 which is 1e+21 or 1000000000000000000000. This is the value the smart contract understands as 1,000 tokens from a user representation.

amount := new(big.Int)amount.SetString("1000000000000000000000", 10) // sets the value to 1000 tokens, in the token denomination

There are utility functions available in the utils section to easily do these conversions.

Left padding to 32 bytes will also be required for the amount since the EVM use 32 byte wide data structures.

paddedAmount := common.LeftPadBytes(amount.Bytes(), 32)fmt.Println(hexutil.Encode(paddedAmount)) // 0x00000000000000000000000000000000000000000000003635c9adc5dea00000

Now we concanate the method ID, padded address, and padded amount into a byte slice that will be our data field.

var data []bytedata = append(data, methodID...)data = append(data, paddedAddress...)data = append(data, paddedAmount...)

Set gas limit

The gas limit will depend on the size of the transaction data and computational steps that the smart contract has to perform. Fortunately the client provides the EstimateGas method which is able to esimate the gas for us based on the most recent state of the blockchain. This function takes a CallMsg struct from the ethereum package where we specify the data and the address of the token contract to which we're sending the function call message. It'll return the estimated gas limit units we'll use to generate the complete transaction.

gasLimit, err := client.EstimateGas(context.Background(), ethereum.CallMsg{ To: &tokenAddress, Data: data,})if err != nil { log.Fatal(err)}fmt.Println(gasLimit) // 23256

NOTE: The gas limit set by the EstimateGas() method is based on the current state of the blockchain, and is just an estimate. If your transactions are constantly failing, or if you prefer to have full control over the amount of gas your application spends, you may want to set this value manually.

Create transaction

Now we have all the information we need to generate the transaction.

We'll create a transaction similar the one we used in section on transferring ETH, EXCEPT that the to field should contain the token smart contract address, and the value field should be set to 0 since we're not transferring ETH. This is a gotcha that confuses people.

tx := types.NewTransaction(nonce, tokenAddress, value, gasLimit, gasPrice, data)

The next step is to sign the transaction with the private key of the sender. The SignTx method requires the EIP155 signer, which we derive the chain ID from the client.

chainID, err := client.NetworkID(context.Background())if err != nil { log.Fatal(err)}signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)if err != nil { log.Fatal(err)}

And finally, broadcast the transaction:

err = client.SendTransaction(context.Background(), signedTx)if err != nil { log.Fatal(err)}fmt.Printf("tx sent: %s", signedTx.Hash().Hex()) // tx sent: 0xa56316b637a94c4cc0331c73ef26389d6c097506d581073f927275e7a6ece0bc

You can check the progress on Etherscan: https://rinkeby.etherscan.io/tx/0xa56316b637a94c4cc0331c73ef26389d6c097506d581073f927275e7a6ece0bc

To learn how to load and interact with an ERC20 smart contract, check out the section on ERC20 token smart contracts.

Full code

transfer_tokens.go

package mainimport ( "context" "crypto/ecdsa" "fmt" "log" "math/big" "golang.org/x/crypto/sha3" "github.com/ethereum/go-ethereum" "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/crypto" "github.com/ethereum/go-ethereum/ethclient")func main() { client, err := ethclient.Dial("https://rinkeby.infura.io") if err != nil { log.Fatal(err) } privateKey, err := crypto.HexToECDSA("fad9c8855b740a0b7ed4c221dbad0f33a83a49cad6b3fe8d5817ac83d38b6a19") if err != nil { log.Fatal(err) } publicKey := privateKey.Public() publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) if !ok { log.Fatal("cannot assert type: publicKey is not of type *ecdsa.PublicKey") } fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA) nonce, err := client.PendingNonceAt(context.Background(), fromAddress) if err != nil { log.Fatal(err) } value := big.NewInt(0) // in wei (0 eth) gasPrice, err := client.SuggestGasPrice(context.Background()) if err != nil { log.Fatal(err) } toAddress := common.HexToAddress("0x4592d8f8d7b001e72cb26a73e4fa1806a51ac79d") tokenAddress := common.HexToAddress("0x28b149020d2152179873ec60bed6bf7cd705775d") transferFnSignature := []byte("transfer(address,uint256)") hash := sha3.NewLegacyKeccak256() hash.Write(transferFnSignature) methodID := hash.Sum(nil)[:4] fmt.Println(hexutil.Encode(methodID)) // 0xa9059cbb paddedAddress := common.LeftPadBytes(toAddress.Bytes(), 32) fmt.Println(hexutil.Encode(paddedAddress)) // 0x0000000000000000000000004592d8f8d7b001e72cb26a73e4fa1806a51ac79d amount := new(big.Int) amount.SetString("1000000000000000000000", 10) // sets the value to 1000 tokens, in the token denomination paddedAmount := common.LeftPadBytes(amount.Bytes(), 32) fmt.Println(hexutil.Encode(paddedAmount)) // 0x00000000000000000000000000000000000000000000003635c9adc5dea00000 var data []byte data = append(data, methodID...) data = append(data, paddedAddress...) data = append(data, paddedAmount...) gasLimit, err := client.EstimateGas(context.Background(), ethereum.CallMsg{ To: &tokenAddress, Data: data, }) if err != nil { log.Fatal(err) } fmt.Println(gasLimit) // 23256 tx := types.NewTransaction(nonce, tokenAddress, value, gasLimit, gasPrice, data) chainID, err := client.NetworkID(context.Background()) if err != nil { log.Fatal(err) } signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey) if err != nil { log.Fatal(err) } err = client.SendTransaction(context.Background(), signedTx) if err != nil { log.Fatal(err) } fmt.Printf("tx sent: %s", signedTx.Hash().Hex()) // tx sent: 0xa56316b637a94c4cc0331c73ef26389d6c097506d581073f927275e7a6ece0bc}
Transferring Tokens (ERC-20) · Ethereum Development with Go (2024)

FAQs

Transferring Tokens (ERC-20) · Ethereum Development with Go? ›

To transfer tokens from our active account to another, we need to invoke the transfer() function in our ERC-20 token in our transactions data field. We do this by doing the following: Figure out the function signature of the transfer() smart contract function we'll be calling.

How are ERC-20 tokens transferred? ›

There are two main functions involved in transferring ERC-20 tokens: the `transfer` function, which directly moves tokens between sender and recipient, and the `transferFrom` function, which allows a third party to send tokens on behalf of the token holder, given that prior approval has been granted.

Can I transfer ERC-20 to ETH? ›

You can start by sending your ERC20 tokens to your Ethereum account from an exchange. Remember, your tokens will only appear after the token transaction has been confirmed on the Ethereum blockchain. When you send ERC20 tokens from an exchange, make sure to select the ERC20/ETH network type.

How do I exchange my ERC20 token? ›

In the Ledger Live app Swap tab, select your crypto assets and the accounts of origin and destination. Enter the amount you want to exchange and check the rate. To exchange with ParaSwap, go in the Discover tab and select 'ParaSwap'. Open the Exchange application, or the ParaSwap application on your Ledger Nano.

How do I move my ERC-20? ›

Sending ERC20 tokens is very easy with MetaMask. You just need to paste the ERC20 address, ensure that you have enough ETH to cover the transaction fee, and click the “Send” button.

What is the signature of the transfer method ERC-20? ›

The signature of the function we'll be calling is the transfer() function in the ERC-20 specification, and the types of the argument we'll be passing to it. The first argument type is address (the address to which we're sending tokens), and the second argument's type is uint256 (the amount of tokens to send).

Do I need ETH to receive ERC20 tokens? ›

Interacting with ERC-20 tokens requires the use of ETH.

How much gas does it take to send ERC20 tokens? ›

If you're sending ERC20 to your friend, you'll need around 65,000 gas (and 21000 for ETH) for the transaction at the moment. But if you want to seal the deal on Uniswap, your estimated gas limit would go up to 200,000. The gas limit refers to the maximum amount of gas users would use for a transaction.

Do all ERC20 tokens go to the same address? ›

All ERC-20 Tokens on Kraken use a shared address. For example, when generating an Augur (REP) address the same address will be generated for other listed ERC-20 tokens.

Where are ERC-20 tokens stored? ›

ERC-20 tokens operate on the Ethereum blockchain. You can store them using your Ethereum account in Trezor Suite. Every ERC-20 token can be stored using a Trezor device, as detailed in the following step-by-step guide: Open Trezor Suite (desktop or browser version)

How long does an ERC-20 transfer take? ›

Ethereum and ERC-20 tokens require 30 confirmations, which may take approximately five minutes. However, if the network is experiencing temporary congestion this may up to four hours or longer.

What can you do with ERC-20 tokens? ›

ERC-20 tokens can be stored in most ETH wallets and sent to any Ethereum wallet address. ERC-20 tokens represent ownership of any fungible asset, and are created on the Ethereum Network using smart contracts.

Can you convert ERC-20 tokens to ETH? ›

You can convert it using decentralised exchanges like Ethersweep it is one of the fastest, most convenient way to scan Ethereum wallets and convert ERC-20 tokens to ETH.

How do I send ERC-20 tokens to Ethereum wallet? ›

Sending ERC-20 tokens is as simple as entering or pasting the recipient's Ethereum wallet address. There are mainly two places you can send your ERC-20 tokens from: a wallet from your centralized exchange (Binance, Coinbase, etc) and a software wallet, also called hot wallet (Metamask, Trust Wallet, etc).

Can you cash out tokens? ›

Cashing out means selling crypto coins or tokens in exchange for fiat money and then withdrawing the money to your bank account.

How much gas does it take to send ERC-20 tokens? ›

If you're sending ERC20 to your friend, you'll need around 65,000 gas (and 21000 for ETH) for the transaction at the moment. But if you want to seal the deal on Uniswap, your estimated gas limit would go up to 200,000. The gas limit refers to the maximum amount of gas users would use for a transaction.

How long does it take to send ERC-20 tokens? ›

CoinList waits for 30 confirmations to consider an ETH or ERC-20 transaction final. Although typically this should only take about ~ 5 minutes, this can take anywhere from 5 minutes to 4 hours. Especially during periods of high network congestion, the transaction can take longer.

Top Articles
Boruto: Will Sasuke ever get his Rinnegan back?
Market Cap Calculator - Coin / Token Market Cap Estimation Tool
Craigslist Campers Greenville Sc
Algebra Calculator Mathway
9192464227
Big Spring Skip The Games
Puretalkusa.com/Amac
Mylife Cvs Login
Matthew Rotuno Johnson
Jcpenney At Home Associate Kiosk
Obituary | Shawn Alexander | Russell Funeral Home, Inc.
Dutchess Cleaners Boardman Ohio
24 Best Things To Do in Great Yarmouth Norfolk
Cashtapp Atm Near Me
Trac Cbna
ARK: Survival Evolved Valguero Map Guide: Resource Locations, Bosses, & Dinos
All Obituaries | Buie's Funeral Home | Raeford NC funeral home and cremation
Jbf Wichita Falls
Wgu Academy Phone Number
Quadcitiesdaily
Conan Exiles Sorcery Guide – How To Learn, Cast & Unlock Spells
2013 Ford Fusion Serpentine Belt Diagram
Pirates Of The Caribbean 1 123Movies
Magic Seaweed Daytona
Netwerk van %naam%, analyse van %nb_relaties% relaties
Skycurve Replacement Mat
Phantom Fireworks Of Delaware Watergap Photos
Snohomish Hairmasters
Danielle Ranslow Obituary
Valley Craigslist
Best Restaurants Ventnor
Account Now Login In
Kattis-Solutions
Fridley Tsa Precheck
Suspect may have staked out Trump's golf course for 12 hours before the apparent assassination attempt
Craigslist Greencastle
Family Fare Ad Allendale Mi
Bimar Produkte Test & Vergleich 09/2024 » GUT bis SEHR GUT
Mydocbill.com/Mr
Philadelphia Inquirer Obituaries This Week
Felix Mallard Lpsg
Weather Underground Corvallis
Ferguson Showroom West Chester Pa
Chathuram Movie Download
Courses In Touch
Mitchell Kronish Obituary
Ehome America Coupon Code
Woody Folsom Overflow Inventory
Phmc.myloancare.com
Research Tome Neltharus
Turning Obsidian into My Perfect Writing App – The Sweet Setup
Códigos SWIFT/BIC para bancos de USA
Latest Posts
Article information

Author: Edmund Hettinger DC

Last Updated:

Views: 5845

Rating: 4.8 / 5 (78 voted)

Reviews: 85% of readers found this page helpful

Author information

Name: Edmund Hettinger DC

Birthday: 1994-08-17

Address: 2033 Gerhold Pine, Port Jocelyn, VA 12101-5654

Phone: +8524399971620

Job: Central Manufacturing Supervisor

Hobby: Jogging, Metalworking, Tai chi, Shopping, Puzzles, Rock climbing, Crocheting

Introduction: My name is Edmund Hettinger DC, I am a adventurous, colorful, gifted, determined, precious, open, colorful person who loves writing and wants to share my knowledge and understanding with you.