# SNIP 13 - Index \`Transfer\` and \`Approval\` events in ERC20s

**URL:** <https://community.starknet.io/t/snip-13-index-transfer-and-approval-events-in-erc20s/114212>\
**Category:** SNIPs\
**Created:** [June 13, 2024, 1:27pm UTC](https://community.starknet.io/t/snip-13-index-transfer-and-approval-events-in-erc20s/114212 "2024-06-13T13:27:13Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![NatanSW](https://avatars.discourse-cdn.com/v4/letter/n/9d8465/32.png) [@NatanSW](https://community.starknet.io/u/NatanSW)\
**Post date:** [June 13, 2024, 1:27pm UTC](https://community.starknet.io/t/snip-13-index-transfer-and-approval-events-in-erc20s/114212/1 "2024-06-13T13:27:13Z")

</div>

**snip** : 13  
**Title:** Index `Transfer` and `Approval` events in ERC20s  
**Author:** @NatanSW  
Status: Draft  
Type: Standards Track  
Creation date: May 5, 2024  
Github link: [SNIPs/SNIPS/snip-13.md at main · starknet-io/SNIPs · GitHub](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-13.md)

* * *

## Abstract

Events in Starknet consist of two felt arrays, `keys` and `data`, the former is analogous to topics on Ethereum. Similarly to Ethereum, Starknet’s json-rpc allows you to filter over event keys via the `starknet_getEvents` method.

In this SNIP we suggest updating StarkGate’s ERC20s (including ETH, STRK, USDC [and others](https://github.com/starknet-io/starknet-addresses/blob/master/bridged_tokens/mainnet.json)) to index more fields in the `Transfer` and `Approval` events in order to allow filtration over the sender or receiver.

## Motivation

Dapps, for example exchanges that operate on Starknet, need to track transfers from & to specific addresses. At the moment, Starknet’s json-rpc only allows receiving all `Transfer` or `Approval` events from a given ERC20 in a particular block range. This SNIP would enable filtering those events, allowing filteration by `from` or `to` in `Transfer` events and by `owner` or `spender` in `Approval` events.

This is already the case on Ethereum and other EVM chains. Due to limitations in early iterations of Cairo, events had only one key corresponding to the event name. This lead to only being able to filter over all transfer events, which is far from ideal.

## Backward Compatability

**This change is NOT backward compatible**. All DAPPs listenting to ERC20 transfer and approval events will have to adjust their events decoding, in order to look for fields in the `keys` array instead of in the `data` array.

## Specification

Starknet’s json-rpc [`starknet_getEvents` method](https://github.com/starkware-libs/starknet-specs/blob/76bdde23c7dae370a3340e40f7ca2ef2520e75b9/api/starknet_api_openrpc.json#L798), takes an `EventFilter` object, which contains a nested list of keys to be matched against. For example, if the user sent an event filter containing \big[[k\_1, k\_2], [\;], [k\_3]\big], then the node should return events whose first key is k\_1 or k\_2, and the third key is k\_3, and the second key is unconstrained and can take any value. This functionality is supported by variuous Starknet SDKs, for example, see the following [starknet.js tutorial](https://www.starknetjs.com/docs/guides/events#without-transaction-hash) to see how to filter events.

Currently, these are the `Transfer` and `Approval` events in all StarkGate’s ERC20s:

```rust
    /// Emitted when tokens are moved from address `from` to address `to`.
    #[derive(Copy, Drop, PartialEq, starknet::Event)]
    struct Transfer {
        // #[key] - Not indexed, to maintain backward compatibility.
        from: ContractAddress,
        // #[key] - Not indexed, to maintain backward compatibility.
        to: ContractAddress,
        value: u256
    }

    /// Emitted when the allowance of a `spender` for an `owner` is set by a call
    /// to [approve](approve). `value` is the new allowance.
    #[derive(Copy, Drop, PartialEq, starknet::Event)]
    struct Approval {
        // #[key] - Not indexed, to maintain backward compatibility.
        owner: ContractAddress,
        // #[key] - Not indexed, to maintain backward compatibility.
        spender: ContractAddress,
        value: u256
    }

```

This SNIP basically suggests to uncomment the above `#[key]` annotations:

```rust
    /// Emitted when tokens are moved from address `from` to address `to`.
    #[derive(Drop, PartialEq, starknet::Event)]
    struct Transfer {
        #[key]
        from: ContractAddress,
        #[key]
        to: ContractAddress,
        value: u256
    }

    /// Emitted when the allowance of a `spender` for an `owner` is set by a call
    /// to `approve`. `value` is the new allowance.
    #[derive(Drop, PartialEq, starknet::Event)]
    struct Approval {
        #[key]
        owner: ContractAddress,
        #[key]
        spender: ContractAddress,
        value: u256
    }

```

That is, a transfer from 0x1 to 0x2 of 100 tokens, now emits:

`keys`: [selector(“Transfer”)]

`data`: [0x1, 0x2, 100, 0]

The first two felts in the data array are the values of `from` and `to` correspondingly, and the last two felts are the low and high 128bits of the u256 of the amount.

If this SNIP is accepted, the emitted event will change to:

`keys`: [selector(“Transfer”), 0x1, 0x2]

`data`: [100, 0]

Where `selector(x)` is the [sn\_keccak](https://docs.starknet.io/documentation/architecture_and_concepts/Cryptography/hash-functions/#starknet_keccak) of `x` .

## Security Considerations

Dapps who did not change their code to parse events differently may break after the ERC20 contracts are upgraded.

We considered whether or not the change suggested in this SNIP can be leveraged to cause more damage. The scenario we analyzed is the following: can an exchange that did not change its code be led to thinking that a transfer has been made to its account, thus crediting an account on the exchange, while in fact no such transaction took place.

We claim that this is not possible. Currently, DAPPs take the `from` and `to` values from the first and second members of the `data` array. After the change, the first and second members of the `data` array would be `amount_low` and `amount_high` correspondingly. Since both `amount_low` and `amount_high` are enforced to be 128bit numbers, and thus contain 124 leading zeros, these can not collide with an account address on Starknet, which is [necessarily](https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/contract-address/) the result of a hash computation.

## Copyright

Copyright and related rights waived via MIT.

---

<div class="post-metadata">

**Author:** ![fracek](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/fracek/32/23_2.png) [@fracek](https://community.starknet.io/u/fracek)\
**Post date:** [June 16, 2024, 12:03pm UTC](https://community.starknet.io/t/snip-13-index-transfer-and-approval-events-in-erc20s/114212/2 "2024-06-16T12:03:47Z")

</div>

I agree with the changes in this SNIP, but I’m worried about the amount of applications it will break.

Can we have a timeline for the update so that we can start informing users about the required update?

I propose we start by updating the tokens with the least activity and gradually move all tokens to the new spec. Since developers will have to support both specs for a while, it won’t result in additional work for developers, but it will give time to the community to notice if any application breaks.

---

<div class="post-metadata">

**Author:** ![NatanSW](https://avatars.discourse-cdn.com/v4/letter/n/9d8465/32.png) [@NatanSW](https://community.starknet.io/u/NatanSW)\
**Post date:** [June 25, 2024, 8:15am UTC](https://community.starknet.io/t/snip-13-index-transfer-and-approval-events-in-erc20s/114212/3 "2024-06-25T08:15:14Z")

</div>

We plan to incorporate this update with 13.3 SN version timeline which gives us more then ~2 months before integration.  
I agree with updating “weaker” tokens at first, but only on the Mainnet. This means the Integration and Sepolia upgrades will include all tokens and the mainnet one will be split into two.

---

<div class="post-metadata">

**Author:** ![libc.eth](https://avatars.discourse-cdn.com/v4/letter/l/b19c9b/32.png) [@libc.eth](https://community.starknet.io/u/libc.eth)\
**Post date:** [September 4, 2024, 2:45pm UTC](https://community.starknet.io/t/snip-13-index-transfer-and-approval-events-in-erc20s/114212/4 "2024-09-04T14:45:54Z")

</div>

> [@NatanSW](#):
>
> That is, a transfer from 0x1 to 0x2 of 100 tokens, now emits:
> 
> `keys`: [selector(“Transfer”)]
> 
> `data`: [0x1, 0x2, 100, 0]
> 
> The first two felts in the data array are the values of `from` and `to` correspondingly, and the last two felts are the low and high 128bits of the u256 of the amount.
> 
> If this SNIP is accepted, the emitted event will change to:
> 
> `keys`: [selector(“Transfer”), 0x1, 0x2]
> 
> `data`: [100, 0]
> 
> Where `selector(x)` is the [sn\_keccak](https://docs.starknet.io/documentation/architecture_and_concepts/Cryptography/hash-functions/#starknet_keccak) of `x` .

I feel like the way event selectors work atm makes this SNIP a bit odd to me.  
I also think that it will certainly cause more trouble in the future when migrating other standards/contracts.

Why not use this SNIP to improve event selectors ? More context in the selector (for example like [Solidity events](https://docs.soliditylang.org/en/latest/contracts.html#members-of-events)) would allow (I believe) a smoother transition. The way I see it, the proposed changes mean that a consumer has to check the length of the `keys` and `data` events, which does not feel reliable ?

On another note, I think this proposal does not take into account on-chain consumption of events (via storage proofs for example). I think adding this special case could create some confusion when dealing with these events.

---

<div class="post-metadata">

**Author:** ![die.herdplatte](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/die.herdplatte/32/85280_2.png) [@die.herdplatte](https://community.starknet.io/u/die.herdplatte)\
**Post date:** [April 2, 2025, 9:36am UTC](https://community.starknet.io/t/snip-13-index-transfer-and-approval-events-in-erc20s/114212/5 "2025-04-02T09:36:43Z")

</div>

I remember reading something about the status of this SNIP but can’t find it again.  
Has this been cancelled or postponed?

[The roadmap](https://www.starknet.io/developers/roadmap/) still shows it as a breaking change in 0.13.4.

---

<div class="post-metadata">

**Author:** ![Immanuelolivia1](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/immanuelolivia1/32/85409_2.png) [@Immanuelolivia1](https://community.starknet.io/u/Immanuelolivia1)\
**Post date:** [April 2, 2025, 6:19pm UTC](https://community.starknet.io/t/snip-13-index-transfer-and-approval-events-in-erc20s/114212/6 "2025-04-02T18:19:48Z")

</div>

I fully support the proposed changes in SNIP 13. Indexing the `from` and `to` fields in Transfer and Approval events will be a game changer for dApps, especially for exchanges and other services that need to filter events by specific addresses. While I recognise this update isn’t backward compatible and will require dApp maintainers to adjust their event parsing, the benefits of more precise event filtering far outweigh the inconvenience.This improvement will streamline how we interact with ERC20 events on StarkNet, ultimately enhancing the overall functionality and integration of the ecosystem.

---

<div class="post-metadata">

**Author:** ![wind.rider](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/wind.rider/32/1346_2.png) [@wind.rider](https://community.starknet.io/u/wind.rider)\
**Post date:** [April 4, 2025, 6:35am UTC](https://community.starknet.io/t/snip-13-index-transfer-and-approval-events-in-erc20s/114212/7 "2025-04-04T06:35:07Z")

</div>

> [@die.herdplatte](#):
>
> I remember reading something about the status of this SNIP but can’t find it again.  
> Has this been cancelled or postponed?
> 
> [The roadmap](https://www.starknet.io/developers/roadmap/) still shows it as a breaking change in 0.13.4.

Thanks for bringing this up!ser, it was cancelled,as for whether it will be included in a future version, there’s no confirmed info at the moment,please stay tuned.
