For a step-by-step indexing walkthrough, see
Index Arc events. For the
conceptual model behind USDC’s native and ERC-20 interfaces, see
Stablecoin native model.
Two event streams
USDC movements surface as logs from two distinct emitters. The native system
emitter logs a Transfer for every USDC movement—native sends and ERC-20
transfers alike—so it is a single universal record of balance changes at
18-decimal precision. Filter by emitter address to tell the two streams apart.
| Source | Emitter address | Events | Decimals |
|---|
| Native USDC (system, EIP-7708) | 0xfffffffffffffffffffffffffffffffffffffffe | Transfer | 18 |
| ERC-20 USDC (NativeFiatToken) | 0x3600000000000000000000000000000000000000 | Transfer | 6 |
A single ERC-20 transfer() emits two logs: the ERC-20 contract’s own
Transfer (6 decimals, from 0x3600000000000000000000000000000000000000) and
the native system Transfer (18 decimals, from
0xfffffffffffffffffffffffffffffffffffffffe). A plain native send emits only
the system log. Match on the emitter address so you do not count the same
movement twice, and never mix the 6-decimal and 18-decimal values.
Native USDC system events (EIP-7708)
Native USDC movements emit a standard ERC-20 Transfer log from a designated
system address. This is Arc’s implementation of
EIP-7708, an Amsterdam-track Ethereum
proposal that Arc ships ahead of upstream. Native movements can be indexed the
same way as ERC-20 transfers. (For the legacy events that testnet emitted before
this behavior was activated, see
Historical events.)
The log covers native value transfers (CALL), contract creation with an
endowment (CREATE), SELFDESTRUCT balance transfers, and the
precompile-driven mint, burn, and transfer operations that back the ERC-20
USDC interface.
| Property | Value |
|---|
| Emitter | 0xfffffffffffffffffffffffffffffffffffffffe |
| Event | Transfer(address indexed from, address indexed to, uint256 value) |
| topic0 | 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef |
| Decimals | 18 |
Mint and burn are expressed as transfers involving the zero address:
- Mint:
Transfer(0x0, recipient, amount)
- Burn:
Transfer(from, 0x0, amount)
The following rules apply to the system Transfer log:
- The native
Transfer log is emitted first, before any other logs in the
transaction.
- Zero-value transfers emit no log.
- Self-transfers (
from == to) emit no log.
- A native value transfer (
CALL, CREATE, or SELFDESTRUCT) to or from the
zero address reverts with "Zero address not allowed". Mint and burn are the
only paths that produce a Transfer involving 0x0, and they go through the
precompile.
ERC-20 USDC contract events
The NativeFiatToken contract at
0x3600000000000000000000000000000000000000
emits its own standard ERC-20 Transfer log (6 decimals) for activity on
the ERC-20 interface. As on any ERC-20 token, mint and burn surface here as a
Transfer to and from the zero address. These events are independent of the
native system events: an ERC-20 transfer() produces a log from both emitters.
| Property | Value |
|---|
| Emitter | 0x3600000000000000000000000000000000000000 |
| Event | Transfer(address indexed from, address indexed to, uint256 value) |
| topic0 | 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef |
| Decimals | 6 |
Historical events (before Zero5)
On testnet, before the Zero5 hard fork activated, native USDC movements emitted
custom events from the NativeCoinAuthority precompile at
0x1800000000000000000000000000000000000000 (18 decimals) instead of the
standard Transfer log. These events are no longer emitted after
activation. Mainnet has used the EIP-7708 Transfer log since genesis, so this
only affects indexers that backfill pre-activation testnet history.
| Event | topic0 |
|---|
NativeCoinTransferred(address indexed from, address indexed to, uint256 amount) | 0x62f084c00a442dcf51cdbb51beed2839bf42a268da8474b0e98f38edb7db5a22 |
NativeCoinMinted(address indexed recipient, uint256 amount) | 0xb049859d09b3a7d0189a07db4d4becee1a2aa269023205478b1360ab6fc12114 |
NativeCoinBurned(address indexed from, uint256 amount) | 0xaaf1ef013644e67c5cea90217acdf0accd334f8437fc9a89a53cfc9b25fb5c25 |
If you backfill history across the hard fork boundary, read NativeCoin* from
0x1800000000000000000000000000000000000000 for blocks before activation and
Transfer from 0xfffffffffffffffffffffffffffffffffffffffe at and after
activation. For the exact activation time and node version requirements, see the
canonical arc-node
CHANGELOG.md and
BREAKING_CHANGES.md,
and the Run an Arc node tutorial.
Out of scope: gas fees and block rewards
Gas fees and block rewards are not emitted as Transfer events and are
unaffected by EIP-7708:
- Gas fees are derived from the receipt (
gasUsed × effectiveGasPrice).
- Block rewards are attributed via
block.miner.
See also