Skip to main content

Interact with ERC-20 tokens

ERC-20 is a simple token standard and the most common contract type on Ethereum.

You can:

ERC-20 token functions and events

An ERC-20 token must implement the following functions:

  • totalSupply() - Returns the total token supply.
  • balanceOf(owner) - Returns the account balance of another account with address owner.
  • allowance(owner, spender) - Returns the amount which spender is still allowed to withdraw from owner.
  • transfer(to, value) - Transfers value amount of tokens to address to.
  • approve(spender, value) - Allows spender to withdraw from your account multiple times, up to the value amount.
  • transferFrom(from, to, value) - Transfers value amount of tokens from address from to address to.

At certain times, an ERC-20 token also must emit the following events:

  • Transfer(from, to, value) - Must trigger when tokens are transferred, including zero value transfers.
  • Approval(owner, spender, value) - Must trigger on any successful call to approve(spender, value).

View EIP-20 for more details about how these functions work and when to emit these events.

Send transactions

Use eth_sendRawTransaction to send ERC-20 token transactions.

The JSON-RPC format expects eth_sendRawTransaction to have a specific data field format that requires normalizing the Transfer function to a short function selector. To do this, set the parameters for the function and run it through Ethereum’s sha3 keccak hash:

web3.sha3('Transfer(address,address,uint256)')[0..4]

The first four bytes of this hash comprise its four-byte signature. Take this four-byte signature, pad it with zeros, and package this information into a data string. Then sign the transaction and send it using eth_sendRawTransaction:

curl https://mainnet.infura.io/v3/YOUR-API-KEY \
-X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params": ["0xf869018203e882520894f17f52151ebef6c7334fad080c5704d77216b732881bc16d674ec80000801ba02da1c48b670996dcb1f447ef9ef00b33033c48a4fe938f420bec3e56bfd24071a062e0aa78a81bf0290afbc3a9d8e9a068e6d74caa66c5e0fa8a46deaae96b0833"],"id":1}'

Observe logs of mined transactions

When a transaction is mined, event logs are published for public viewing.

Once the event logs are published, you can execute eth_getLogs to investigate what changed relative to the events that you care about, and react to them.

success

For example, an event ticketing service that wants to issue off-chain tickets based on crypto payments can use eth_getLogs to find payments to their address, and react to these events by processing some logic in their backend servers to issue tickets to users.

The following example uses eth_getLogs on the DAI ERC-20 Solidity contract 0x6B175474E89094C44Da98b954EedeAC495271d0F:

curl https://mainnet.infura.io/v3/YOUR-API-KEY \
-X POST \
-H "Content-Type: application/json" \
-d {"jsonrpc":"2.0","method":"eth_getLogs","id":1,"params":[{"fromBlock":"Ox91F37C","toBlock":"0x91F37C","topics":[ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x000000000000000000000000ee25e1ba53c225d250861c8e5a9a3e0fe19c790e", "0x000000000000000000000000dfbaf3e4c7496dad574a1b842bc85b402bdc298d" ],"address":"0x6B175474E89094C44Da98b954EedeAC495271d0F"}]}

In this example request, the parameters fromBlock and toBlock specify the hexadecimal block number to retrieve logs from.

info

If fromBlock and toBlock are omitted, eth_getLogs returns the entire chain history by default. Infura has a cap on requests of 10,000 events per query. We recommend requesting a single block, as in this example, and to do that for each mined block.

This request tells the blockchain to retrieve event logs related to address 0x6B175474E89094C44Da98b954EedeAC495271d0F emitted in block 0x91F37C that matches topics 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x000000000000000000000000ee25e1ba53c225d250861c8e5a9a3e0fe19c790e and 0x000000000000000000000000dfbaf3e4c7496dad574a1b842bc85b402bdc298d.

The response returned for this request is an array of events. In this example, only one event for one address matches the specified topics.

Topics

Topics are events emitted by smart contracts. Looking at the source code of the original contract 0x6B175474E89094C44Da98b954EedeAC495271d0F used in this example, there are two event signatures that could be associated with it on lines 94 and 95:

event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
event Transfer(address indexed from, address indexed to, uint tokens);

To find out which topic (event) it actually was, create the function selector of the event and take the sha3 keccak hash of it. Let’s try the event on line 94:

web3.sha3("Approval(address,address,uint256)");

The resulting hash doesn’t match the hash provided in the initial request response. Now let’s try the event on line 95 of the contract:

web3.sha3("Transfer(address,address,uint256)");

The resulting hash matches the hash provided in the initial request response. Now you know that 0xddf25 is the transfer event in this example.

Data

The data field in the request response refers to all the "non-indexed stuff" captured in the events. In this example, for the transfer topic, data represents the number of tokens that were transferred. That is, 0x41f900d25d6693623a6 or 19471.6949921 DAI tokens were transferred from ee25e1ba53c225d250861c8e5a9a3e0fe19c790e to dfbaf3e4c7496dad574a1b842bc85b402bdc298d.