> For the complete documentation index, see [llms.txt](https://docs.chainrpc.io/chainrpc/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.chainrpc.io/chainrpc/networks/ethereum/how-to/interact-with-erc-20-tokens.md).

# Interact with ERC-20 tokens

[ERC-20](https://eips.ethereum.org/EIPS/eip-20) is a simple token standard and the most common contract type on Ethereum.

You can:

* [Send ERC-20 transactions](#sending-transactions) using `eth_sendRawTransaction`.
* [Observe event logs of mined ERC-20 transactions](#mined-transactions) using `eth_getLogs`.
* Follow [this tutorial](broken://pages/0vvvf8FUroJuyIIFdMAL) to retrieve the balance of ERC-20 tokens.
* Follow [this tutorial](broken://pages/qa1t4Rj2GGuIumeP4mtF) to track ERC-20 token transfers.

## 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](https://eips.ethereum.org/EIPS/eip-20) for more details about how these functions work and when to emit these events.

## **Send transactions** <a href="#sending-transactions" id="sending-transactions"></a>

Use [`eth_sendRawTransaction`](broken://pages/V3saeD5ILKgu0hXM6XUn) 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](https://solidity.readthedocs.io/en/develop/abi-spec.html#function-selector). To do this, set the parameters for the function and run it through Ethereum’s [sha3 keccak hash](https://solidity.readthedocs.io/en/develop/abi-spec.html#function-selector):

{% tabs %}
{% tab title="Example node console request" %}

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

{% endtab %}

{% tab title="Example JS result" %}

```javascript
0x70a08231
```

{% endtab %}
{% endtabs %}

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`:

{% tabs %}
{% tab title="Example curl HTTPS request" %}

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

{% endtab %}

{% tab title="Example JSON result" %}

```json
{
    "id": 1,
    "jsonrpc": "2.0",
    "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}
```

{% endtab %}
{% endtabs %}

## **Observe logs of mined transactions** <a href="#mined-transactions" id="mined-transactions"></a>

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

Once the event logs are published, you can execute [`eth_getLogs`](broken://pages/MdfIp73c68wfJvxjQg9j) to investigate what changed relative to the events that you care about, and react to them.

{% hint style="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.
{% endhint %}

The following example uses `eth_getLogs` on the DAI ERC-20 Solidity contract [`0x6B175474E89094C44Da98b954EedeAC495271d0F`](https://etherscan.io/address/0x6b175474e89094c44da98b954eedeac495271d0f#code):

{% tabs %}
{% tab title="Example curl HTTPS request" %}

```bash
curl https://eth.chainrpc.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"}]}
```

{% endtab %}

{% tab title="Example JSON result" %}

<pre class="language-json"><code class="lang-json">{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
<strong>    {
</strong>      "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
      "topics": [
        "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
        "0x000000000000000000000000ee25e1ba53c2250250861c8e5a9a3e0fe19c790e",
        "0x000000000000000000000000dfbaf3e4c7496dad574a1b842bc85b402bdc298d"
      ],
      "data": "0x00000000000000000000000000000000000000000000041f900d25d6693623a6",
      "blockNumbern": "0x91F37C"
    }
  ]
}
</code></pre>

{% endtab %}
{% endtabs %}

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

{% hint style="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.
{% endhint %}

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`](https://etherscan.io/address/0x6b175474e89094c44da98b954eedeac495271d0f#code) used in this example, there are two event signatures that could be associated with it on lines 94 and 95:

```solidity
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](https://docs.soliditylang.org/en/develop/abi-spec.html#function-selector) of the event and take the [sha3 keccak hash](https://docs.soliditylang.org/en/develop/abi-spec.html#function-selector) of it. Let’s try the event on line 94:

{% tabs %}
{% tab title="Example node console request" %}

```javascript
web3.sha3('Approval(address,address,uint256)')
```

{% endtab %}

{% tab title="Example JS result" %}

```javascript
0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925
```

{% endtab %}
{% endtabs %}

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:

{% tabs %}
{% tab title="Example node console request" %}

```javascript
web3.sha3('Transfer(address,address,uint256)')
```

{% endtab %}

{% tab title="Example JS result" %}

```javascript
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
```

{% endtab %}
{% endtabs %}

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** <a href="#more-event-logs" id="more-event-logs"></a>

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`.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.chainrpc.io/chainrpc/networks/ethereum/how-to/interact-with-erc-20-tokens.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
