# ERC-223: Token with Transaction Handling

Source: https://www.eipsfordesigners.com/standards/ERC-223
Agent brief: https://www.eipsfordesigners.com/standards/ERC-223/agent.md
Machine-readable JSON: https://www.eipsfordesigners.com/api/standards/ERC-223
Last reviewed: 2026-04-05
Last updated: 2026-04-05

| Field | Value |
| --- | --- |
| Status | Final |
| Chain | both |
| Category | Transaction Friction |
| Journey stages | Executing Transactions |
| Detailed guide | Yes |
| Official specification | https://eips.ethereum.org/EIPS/eip-223 |
| Discussion search | https://ethereum-magicians.org/search?q=ERC-223 |

## UX Impact

Tokens notify receiving contracts and revert if handler missing — prevents tokens being permanently lost to incompatible contracts. Design implications: show 'safe transfer' indicators, remove 'tokens may be lost' warnings for 223 tokens, simplify deposit flows since callback handles everything. Design decisions: low adoption limits usefulness — must handle mixed token standards gracefully, decide whether to surface the safety difference to users or abstract it away, consider that 223 transfers to EOAs work normally. Addresses Sending to Wrong Address pain point (Critical severity) — users sending tokens to contracts that can't handle them is a permanent-loss scenario. ERC-223 addresses the contract-send case specifically (tokens bounce back), complementing ENS/address-book solutions which address the human-error case.

## Summary

ERC-223 prevents tokens from being permanently lost by adding a safety mechanism: contracts must explicitly accept tokens or the transfer reverts. Unlike ERC-20 where sending tokens to a contract that doesn't handle them means they're gone forever, ERC-223 tokens bounce back if the recipient can't process them. It also combines approve+transferFrom into a single transfer with data, reducing steps.

## For Designers

- You can design UI that delivers transfer reverts if contract doesn't implement receiver.
- You can design UI that delivers single transfer() with data parameter triggers action.
- You can design UI that delivers tokenReceived() callback lets contract process immediately.

## Applicability

### When to Use

- Your product addresses: tokens sent to wrong contracts are lost forever.
- Your product addresses: transfer to contracts requires approve + transferFrom.
- The flow should deliver: transfer reverts if contract doesn't implement receiver.
- You are designing a safe transfer with callback experience with visible states and recovery paths.

### When to Avoid

- Clear message: "Contract can't receive these tokens, yours are safe".
- Highlight "One-step deposit" when interacting with contracts.
- Badge indicating "Protected transfer" for ERC-223.
- The flow is a single low-risk transfer where batching adds confusion.

## Problems It Solves

### Tokens sent to wrong contracts are lost forever

Impact: critical

Old way: Send ERC-20 to contract without handler = permanent loss

New way: Transfer reverts if contract doesn't implement receiver

### Transfer to contracts requires approve + transferFrom

Impact: high

Old way: Two transactions: approve contract, then call contract

New way: Single transfer() with data parameter triggers action

### No way for contracts to react to incoming tokens

Impact: high

Old way: Contract has no idea tokens arrived, must be notified separately

New way: tokenReceived() callback lets contract process immediately

### Users accidentally send tokens to token contract itself

Impact: medium

Old way: Common mistake: send USDC to USDC contract address = lost

New way: Token contract can reject or return accidental sends

### Deposit flows are fragmented across transactions

Impact: medium

Old way: Approve → Deposit → Contract pulls tokens (3 interactions)

New way: Transfer to contract triggers deposit in one action

## Anti-Patterns

### Not explaining why transfers can fail

Severity: high

Users confused when transaction reverts

Instead: Clear message: "Contract can't receive these tokens, yours are safe"

### Hiding the callback/data functionality

Severity: high

Users miss the one-transaction benefit

Instead: Highlight "One-step deposit" when interacting with contracts

### Showing ERC-223 transfers same as ERC-20

Severity: medium

Users don't understand the safety difference

Instead: Badge indicating "Protected transfer" for ERC-223

### Not pre-checking contract compatibility

Severity: medium

Users waste gas on doomed transfers

Instead: Simulate transfer, warn if it would revert

### Complex data encoding exposed to users

Severity: medium

Technical details confuse users

Instead: UI constructs data payload, shows human-readable summary

## UI Components

### ContractCompatibilityCheck

Verify if recipient handles ERC-223
States: checking, compatible, incompatible, unknown
Props: address, tokenAddress, onResult

### TransferWithData

Transfer input with optional data payload
States: simple, with-data, encoding, ready
Props: amount, recipient, data, onTransfer

### SafetyIndicator

Badge showing ERC-223 protection status
States: protected, unprotected, unknown
Props: tokenStandard, recipient

### RevertExplainer

Friendly explanation when transfer reverts
States: displaying, dismissed
Props: reason, tokenName, alternatives

## On Monad

### Callback Execution

Ethereum: tokenReceived callback may be gas-heavy

Monad: Cheap gas makes callbacks practical for complex logic

Design implication: Can offer richer callback-triggered actions

### Revert Speed

Ethereum: Failed transfer still takes time to confirm failure

Monad: Sub-second feedback on incompatible transfers

Design implication: Instant "tokens safe" confirmation on revert

### Simulation

Ethereum: Pre-checking compatibility requires RPC calls

Monad: Fast simulation for compatibility checking

Design implication: Real-time compatibility indicator as user types address

### Atomic Operations

Ethereum: Transfer+action atomic but slow confirmation

Monad: Atomic operations with instant finality

Design implication: Buy NFT flow completes visibly in under 1 second

## Key Takeaways

- ERC-223 = tokens that can't be lost to incompatible contracts
- Always explain the safety benefit vs ERC-20
- Use positive messaging when transfers revert ("tokens safe!")
- Highlight one-step contract interactions
- On Monad: instant feedback on both successful and failed transfers

## UX Patterns

### Safe Transfer with Callback

One-step deposit that triggers action

User flow:

- User enters deposit amount
- UI shows this is a one-step process
- User clicks deposit
- Transfer with data triggers vault deposit
- Vault credits user automatically

Mockup registry key: `generic/token-approval` (React UI on the live standard page).

### Protected Address Warning

Prevent sending to incompatible addresses

User flow:

- User enters contract address
- UI detects it's a contract (not EOA)
- Shows warning but explains safety
- ERC-223 protection reassures user
- Transaction reverts if incompatible

Mockup registry key: `generic/token-transfer` (React UI on the live standard page).

### Transfer Revert Explanation

When transfer fails due to incompatible recipient

User flow:

- Transfer to incompatible contract
- Transaction reverts (tokens safe)
- UI explains what happened positively
- Shows balance unchanged
- Suggests alternatives

Mockup registry key: `concept/tx-status` (React UI on the live standard page).

### Token Transfer with Payload

Attach data to trigger specific actions

User flow:

- User clicks buy on NFT
- UI shows payment will include data
- Explains atomic nature
- Transfer triggers NFT delivery
- Both happen in one transaction

Mockup registry key: `concept/nft-gallery` (React UI on the live standard page).

## Technical Notes

ERC-223 adds a transfer(address, uint256, bytes) function that calls tokenReceived(address, uint256, bytes) on the recipient if it's a contract. If the recipient doesn't implement this interface, the transfer reverts. This prevents tokens from being stuck in contracts that don't handle them. The data parameter allows passing arbitrary info to trigger actions.
