Skip to content

Commit e9351f3

Browse files
authored
Merge pull request #11787 from Dexaran/dev
Re-add ERC-223 to token standards (closes #12004, #10854)
2 parents e6c10bc + 924aef1 commit e9351f3

File tree

5 files changed

+203
-0
lines changed

5 files changed

+203
-0
lines changed

public/content/developers/docs/standards/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ More detailed information on these different types and categories can be found i
4040
### Token standards {#token-standards}
4141

4242
- [ERC-20](/developers/docs/standards/tokens/erc-20/) - A standard interface for fungible (interchangeable) tokens, like voting tokens, staking tokens or virtual currencies.
43+
- [ERC-223](/developers/docs/standards/tokens/erc-223/) - A fungible tokens standard that makes tokens behave identical to ether and supports token transfers handling on the recipients side.
4344
- [ERC-1363](https://eips.ethereum.org/EIPS/eip-1363) - Defines a token interface for ERC-20 tokens that supports executing recipient code after transfer or transferFrom, or spender code after approve.
4445
- [ERC-721](/developers/docs/standards/tokens/erc-721/) - A standard interface for non-fungible tokens, like a deed for artwork or a song.
4546
- [ERC-2309](https://eips.ethereum.org/EIPS/eip-2309) - A standardized event emitted when creating/transferring one, or many non-fungible tokens using consecutive token identifiers.
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
---
2+
title: ERC-223 Token Standard
3+
description: An overview of the ERC-223 fungible token standard, how it works, and a comparison to ERC-20.
4+
lang: en
5+
---
6+
7+
## Introduction {#introduction}
8+
9+
### What is ERC-223? {#what-is-erc223}
10+
11+
ERC-223 is a standard for fungible tokens, similar to the ERC-20 standard. The key difference is that ERC-223 defines not only the token API but also the logic for transferring tokens from sender to recipient. It introduces a communication model that allows token transfers to be handled on the recipient's side.
12+
13+
### Differences from ERC-20 {#erc20-differences}
14+
15+
ERC-223 addresses some limitations of ERC-20 and introduces a new method of interaction between the token contract and a contract that may receive the tokens. There are few things that are possible with ERC-223 but not with ERC-20:
16+
17+
- Token transfer handling on the recipient's side: Recipients can detect that an ERC-223 token is being deposited.
18+
- Rejection of improperly sent tokens: If a user sends ERC-223 tokens to a contract not supposed to receive tokens, the contract can reject the transaction, preventing token loss.
19+
- Metadata in transfers: ERC-223 tokens can include metadata, allowing arbitrary information to be attached to token transactions.
20+
21+
## Prerequisites {#prerequisites}
22+
23+
- [Accounts](/developers/docs/accounts)
24+
- [Smart Contracts](/developers/docs/smart-contracts/)
25+
- [Token standards](/developers/docs/standards/tokens/)
26+
- [ERC-20](/developers/docs/standards/tokens/erc-20/)
27+
28+
## Body {#body}
29+
30+
ERC-223 is a token standard that implements an API for tokens within smart contracts. It also declares an API for contracts that are supposed to receive ERC-223 tokens. Contracts that do not support the ERC-223 Receiver API cannot receive ERC-223 tokens, preventing user error.
31+
32+
If a smart contract implements the following methods and events it can be called an ERC-223 compatible token contract. Once deployed, it
33+
will be responsible to keep track of the created tokens on Ethereum.
34+
35+
The contract is not obligated to have only these functions and a developer can add any other feature from different token standards to this contract. For example, `approve` and `transferFrom` functions are not part of ERC-223 standard but these functions could be implemented should it be necessary.
36+
37+
From [EIP-223](https://eips.ethereum.org/EIPS/eip-223):
38+
39+
### Methods {#methods}
40+
41+
ERC-223 token must implement the following methods:
42+
43+
```solidity
44+
function name() public view returns (string)
45+
function symbol() public view returns (string)
46+
function decimals() public view returns (uint8)
47+
function totalSupply() public view returns (uint256)
48+
function balanceOf(address _owner) public view returns (uint256 balance)
49+
function transfer(address _to, uint256 _value) public returns (bool success)
50+
function transfer(address _to, uint256 _value, bytes calldata _data) public returns (bool success)
51+
```
52+
53+
A contract that is supposed to receive ERC-223 tokens must implement the following method:
54+
55+
```solidity
56+
function tokenReceived(address _from, uint _value, bytes calldata _data)
57+
```
58+
59+
If ERC-223 tokens are sent to a contract that doesn't implement the `tokenReceived(..)` function then the transfer must fail and the tokens must not be moved from the sender's balance.
60+
61+
### Events {#events}
62+
63+
```solidity
64+
event Transfer(address indexed _from, address indexed _to, uint256 _value, bytes calldata _data)
65+
```
66+
67+
### Examples {#examples}
68+
69+
The API of ERC-223 token is similar to that of ERC-20, so from UI development point of view there is no difference. The only exception here is that ERC-223 tokens may not have `approve` + `transferFrom` functions as these are optional for this standard.
70+
71+
#### Solidity examples {#solidity-example}
72+
73+
The following example illustrates how a basic ERC-223 token contract operates:
74+
75+
```solidity
76+
pragma solidity ^0.8.19;
77+
abstract contract IERC223Recipient {
78+
function tokenReceived(address _from, uint _value, bytes memory _data) public virtual;
79+
}
80+
contract VeryBasicERC223Token {
81+
event Transfer(address indexed from, address indexed to, uint value, bytes data);
82+
string private _name;
83+
string private _symbol;
84+
uint8 private _decimals;
85+
uint256 private _totalSupply;
86+
mapping(address => uint256) private balances;
87+
function name() public view returns (string memory) { return _name; }
88+
function symbol() public view returns (string memory) {return _symbol; }
89+
function decimals() public view returns (uint8) { return _decimals; }
90+
function totalSupply() public view returns (uint256) { return _totalSupply; }
91+
function balanceOf(address _owner) public view returns (uint256) { return balances[_owner]; }
92+
function isContract(address account) internal view returns (bool) {
93+
uint256 size;
94+
assembly { size := extcodesize(account) }
95+
return size > 0;
96+
}
97+
function transfer(address _to, uint _value, bytes calldata _data) public returns (bool success){
98+
balances[msg.sender] = balances[msg.sender] - _value;
99+
balances[_to] = balances[_to] + _value;
100+
if(isContract(_to)) {
101+
IERC223Recipient(_to).tokenReceived(msg.sender, _value, _data);
102+
}
103+
emit Transfer(msg.sender, _to, _value, _data);
104+
return true;
105+
}
106+
function transfer(address _to, uint _value) public returns (bool success){
107+
bytes memory _empty = hex"00000000";
108+
balances[msg.sender] = balances[msg.sender] - _value;
109+
balances[_to] = balances[_to] + _value;
110+
if(isContract(_to)) {
111+
IERC223Recipient(_to).tokenReceived(msg.sender, _value, _empty);
112+
}
113+
emit Transfer(msg.sender, _to, _value, _empty);
114+
return true;
115+
}
116+
}
117+
```
118+
119+
Now we want another contract to accept deposits of `tokenA` assuming that tokenA is an ERC-223 token. The contract must accept only tokenA and reject any other tokens. When the contract receives tokenA it must emit a `Deposit()` event and increase the value of the internal `deposits` variable.
120+
121+
Here is the code:
122+
123+
```solidity
124+
contract RecipientContract is IERC223Recipient {
125+
event Deposit(address whoSentTheTokens);
126+
uint256 deposits = 0;
127+
address tokenA; // The only token that we want to accept.
128+
function tokenReceived(address _from, uint _value, bytes memory _data) public override
129+
{
130+
// It is important to understand that within this function
131+
// msg.sender is the address of a token that is being received,
132+
// msg.value is always 0 as the token contract does not own or send Ether in most cases,
133+
// _from is the sender of the token transfer,
134+
// _value is the amount of tokens that was deposited.
135+
require(msg.sender == tokenA);
136+
deposits += _value;
137+
emit Deposit(_from);
138+
}
139+
}
140+
```
141+
142+
## Frequently asked questions {#faq}
143+
144+
### What will happen if we send some tokenB to the contract? {#sending-tokens}
145+
146+
The transaction will fail, and the transfer of tokens will not happen. The tokens will be returned to the sender's address.
147+
148+
### How can we make a deposit to this contract? {#contract-deposits}
149+
150+
Call the `transfer(address,uint256)` or `transfer(address,uint256,bytes)` function of the ERC-223 token, specifying the address of the `RecipientContract`.
151+
152+
### What will happen if we transfer an ERC-20 token to this contract? {#erc-20-transfers}
153+
154+
If an ERC-20 token is sent to the `RecipientContract`, the tokens will be transferred, but the transfer will not be recognized (no `Deposit()` event will be fired, and the deposits value will not change). Unwanted ERC-20 deposits cannot be filtered or prevented.
155+
156+
### What if we want to execute some function after the token deposit is completed? {#function-execution}
157+
158+
There are multiple ways of doing so. In this example we will follow the method which makes ERC-223 transfers identical to Ether transfers:
159+
160+
```solidity
161+
contract RecipientContract is IERC223Recipient {
162+
event Foo();
163+
event Bar(uint256 someNumber);
164+
address tokenA; // The only token that we want to accept.
165+
function tokenReceived(address _from, uint _value, bytes memory _data) public override
166+
{
167+
require(msg.sender == tokenA);
168+
address(this).call(_data); // Handle incoming transaction and perform a subsequent function call.
169+
}
170+
function foo() public
171+
{
172+
emit Foo();
173+
}
174+
function bar(uint256 _someNumber) public
175+
{
176+
emit Bar(_someNumber);
177+
}
178+
}
179+
```
180+
181+
When the `RecipientContract` will receive a ERC-223 token the contract will execute a function encoded as `_data` parameter of the token transaction, identical to how Ether transactions encode function calls as transaction `data`. Read [the data field](https://ethereum.org/en/developers/docs/transactions/#the-data-field) for more information.
182+
183+
In the above example an ERC-223 token must be transferred to the address of the `RecipientContract` with the `transfer(address,uin256,bytes calldata _data)` function. If the data parameter will be `0xc2985578` (the signature of a `foo()` function) then the function foo() will be invoked after the token deposit is received and the event Foo() will be fired.
184+
185+
Parameters can be encoded in the `data` of the token transfer as well, for example we can call the bar() function with 12345 value for `_someNumber`. In this case the `data` must be `0x0423a13200000000000000000000000000000000000000000000000000000000000004d2` where `0x0423a132` is the signature of the `bar(uint256)` function and `00000000000000000000000000000000000000000000000000000000000004d2` is 12345 as uint256.
186+
187+
## Limitations {#limitations}
188+
189+
While ERC-223 addresses several issues found in the ERC-20 standard, it is not without its own limitations:
190+
191+
- Adoption and Compatibility: ERC-223 is not yet widely adopted, which may limit its compatibility with existing tools and platforms.
192+
- Backward Compatibility: ERC-223 is not backward compatible with ERC-20, meaning that existing ERC-20 contracts and tools will not work with ERC-223 tokens without modifications.
193+
- Gas Costs: The additional checks and functionalities in ERC-223 transfers may result in higher gas costs compared to ERC-20 transactions.
194+
195+
## Further reading {#further-reading}
196+
197+
- [EIP-223: ERC-223 Token Standard](https://eips.ethereum.org/EIPS/eip-223)
198+
- [Initial ERC-223 proposal](https://github.com/ethereum/eips/issues/223)

public/content/developers/docs/standards/tokens/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Many Ethereum development standards focus on token interfaces. These standards h
1919
Here are some of the most popular token standards on Ethereum:
2020

2121
- [ERC-20](/developers/docs/standards/tokens/erc-20/) - A standard interface for fungible (interchangeable) tokens, like voting tokens, staking tokens or virtual currencies.
22+
- [ERC-223](/developers/docs/standards/tokens/erc-223/) - A fungible token standard with "transaction handling" model that makes token behave identical to ether.
2223

2324
### NFT standards {#nft-standards}
2425

src/data/developer-docs-links.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@
197197
items:
198198
- id: docs-nav-erc-20
199199
to: /developers/docs/standards/tokens/erc-20/
200+
- id: docs-nav-erc-223
201+
to: /developers/docs/standards/tokens/erc-223/
200202
- id: docs-nav-erc-721
201203
to: /developers/docs/standards/tokens/erc-721/
202204
- id: docs-nav-erc-1155

src/lib/utils/md.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ const getPostSlugs = (dir: string, files: string[] = []) => {
140140
"/developers/docs/standards",
141141
"/developers/docs/standards/tokens",
142142
"/developers/docs/standards/tokens/erc-20",
143+
"/developers/docs/standards/tokens/erc-223",
143144
"/developers/docs/standards/tokens/erc-721",
144145
"/developers/docs/standards/tokens/erc-777",
145146
"/developers/docs/standards/tokens/erc-1155",

0 commit comments

Comments
 (0)