Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ERC-223 to token standards. #9651

Merged
merged 18 commits into from
Jul 3, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
624ed01
Add ERC-223 to the Standards list
Dexaran Mar 7, 2023
be40b72
Add the description of ERC-223 tokens
Dexaran Mar 7, 2023
a9530c1
Deleted an extra word
Dexaran Mar 28, 2023
2bd6bac
Update src/content/developers/docs/standards/tokens/erc-223/index.md
Dexaran May 17, 2023
c362962
Update src/content/developers/docs/standards/tokens/erc-223/index.md
Dexaran May 17, 2023
c02d0f2
Update src/content/developers/docs/standards/tokens/erc-223/index.md
Dexaran May 17, 2023
7aab160
Update src/content/developers/docs/standards/tokens/erc-223/index.md
Dexaran May 17, 2023
3088d2c
Update src/content/developers/docs/standards/tokens/erc-223/index.md
Dexaran May 17, 2023
d3c7283
Update src/content/developers/docs/standards/tokens/erc-223/index.md
Dexaran May 17, 2023
d86f609
Update src/content/developers/docs/standards/tokens/erc-223/index.md
Dexaran May 17, 2023
bddeaa7
Update src/content/developers/docs/standards/tokens/erc-223/index.md
Dexaran May 17, 2023
f048d36
Update src/content/developers/docs/standards/tokens/erc-223/index.md
Dexaran May 21, 2023
6d7faa1
Update src/content/developers/docs/standards/index.md
Dexaran May 21, 2023
66b444b
Update src/content/developers/docs/standards/tokens/erc-223/index.md
Dexaran May 21, 2023
094cd05
Update src/content/developers/docs/standards/tokens/erc-223/index.md
Dexaran May 21, 2023
9ebc9ba
Changes requested by the Ethereum PR mod
Dexaran May 21, 2023
c6b2dac
Reimplemented FAQ as headers
Dexaran May 21, 2023
d30f2e4
Update src/content/developers/docs/standards/tokens/erc-223/index.md
Dexaran May 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/content/developers/docs/standards/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ More detailed information on these different types and categories can be found i
### Token standards {#token-standards}

- [ERC-20](/developers/docs/standards/tokens/erc-20/) - A standard interface for fungible (interchangeable) tokens, like voting tokens, staking tokens or virtual currencies.
- [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
- [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.
- [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.
Dexaran marked this conversation as resolved.
Show resolved Hide resolved
- [ERC-721](/developers/docs/standards/tokens/erc-721/) - A standard interface for non-fungible tokens, like a deed for artwork or a song.
- [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.
- [ERC-4400](https://eips.ethereum.org/EIPS/eip-4400) - Interface extension for EIP-721 consumer role
- [ERC-4400](https://eips.ethereum.org/EIPS/eip-4400) - Interface extension for EIP-721 consumer role.
- [ERC-4907](https://eips.ethereum.org/EIPS/eip-4907) - Add a time-limited role with restricted permissions to ERC-721 tokens.
- [ERC-777](/developers/docs/standards/tokens/erc-777/) - **(NOT RECOMMENDED)** A token standard improving over ERC-20.
- [ERC-1155](/developers/docs/standards/tokens/erc-1155/) - A token standard which can contain both fungible and non-fungible assets.
Expand Down
187 changes: 187 additions & 0 deletions src/content/developers/docs/standards/tokens/erc-223/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
---
title: ERC-223 Token Standard
description:
Dexaran marked this conversation as resolved.
Show resolved Hide resolved
lang: en
---

## Introduction {#introduction}

**What is ERC-223?**

The ERC-223 is another standard for Fungible Tokens, like the ERC-20. The key difference is that ERC-223 defines not only the token API, but also the logic of how tokens should be transferred from sender to recipient and introduces a communication model that allows token transfers to be handled on the recipients side.
Dexaran marked this conversation as resolved.
Show resolved Hide resolved

**How is it different from ERC-20 and why we need another token standard?**

ERC-223 addresses some limitations of ERC-20 and introduces a new method of interactions between 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:

- Token transfer handling on the recipient's side. Recipient can detect that a ERC-223 token is being deposited.
Dexaran marked this conversation as resolved.
Show resolved Hide resolved
- Rejection of improperly sent tokens. If a user sent ERC-223 tokens to a contract that is not supposed to receive tokens then the contract can reject the transaction and the tokens will not be lost.
- The transfer of ERC-223 tokens may contain metadata, which allows arbitrary information to be attached to the token transactions.

## Prerequisites {#prerequisites}

- [Accounts](/developers/docs/accounts)
- [Smart Contracts](/developers/docs/smart-contracts/)
- [Token standards](/developers/docs/standards/tokens/)
- [ERC-20](/developers/docs/standards/tokens/erc-20/)

## Body {#body}

The ERC-223 (Ethereum Request for Comments 223), proposed by Dexaran in March 2017, is a Token Standard that
Dexaran marked this conversation as resolved.
Show resolved Hide resolved
implements an API for tokens within Smart Contracts and declares API for a contract that is supposed to receive ERC-223 tokens. Any contract that does not support ERC-223 Receiver API can not receive ERC-223 tokens which prevents the most common user mistakes.
Dexaran marked this conversation as resolved.
Show resolved Hide resolved

If a Smart Contract implements the following methods and events it can be called a ERC-223 compatible token contract and, once deployed, it
Dexaran marked this conversation as resolved.
Show resolved Hide resolved
will be responsible to keep track of the created tokens on Ethereum.

The contract is not obligated to have only this 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.
Dexaran marked this conversation as resolved.
Show resolved Hide resolved

From [EIP-223](https://eips.ethereum.org/EIPS/eip-223):

#### Methods {#methods}

ERC-223 token must implement the following methods:

```solidity
function name() public view returns (string)
function symbol() public view returns (string)
function decimals() public view returns (uint8)
function totalSupply() public view returns (uint256)
function balanceOf(address _owner) public view returns (uint256 balance)
function transfer(address _to, uint256 _value) public returns (bool success)
function transfer(address _to, uint256 _value, bytes calldata _data) public returns (bool success)
```

A contract that is supposed to receive ERC-223 tokens must implement the following method:

```solidity
function tokenReceived(address _from, uint _value, bytes calldata _data)
```

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.

#### Events {#events}

```solidity
event Transfer(address indexed _from, address indexed _to, uint256 _value, bytes calldata _data)
```

### Examples {#web3py-example}
Dexaran marked this conversation as resolved.
Show resolved Hide resolved

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.

### Examples {#solidity-example}
Dexaran marked this conversation as resolved.
Show resolved Hide resolved

The purpose of this example is to illustrate how a contract must work with ERC-223 tokens.

Assume that we have a very basic ERC-223 token:

```solidity
pragma solidity ^0.8.19;

abstract contract IERC223Recipient {
function tokenReceived(address _from, uint _value, bytes memory _data) public virtual;
}

contract VeryBasicERC223Token {
event Transfer(address indexed from, address indexed to, uint value, bytes data);

string private _name;
string private _symbol;
uint8 private _decimals;
uint256 private _totalSupply;

mapping(address => uint256) private balances;
function name() public view returns (string memory) { return _name; }
function symbol() public view returns (string memory) {return _symbol; }
function decimals() public view returns (uint8) { return _decimals; }
function totalSupply() public view returns (uint256) { return _totalSupply; }
function balanceOf(address _owner) public view returns (uint256) { return balances[_owner]; }

function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 0;
}
function transfer(address _to, uint _value, bytes calldata _data) public returns (bool success){
balances[msg.sender] = balances[msg.sender] - _value;
balances[_to] = balances[_to] + _value;
if(isContract(_to)) {
IERC223Recipient(_to).tokenReceived(msg.sender, _value, _data);
}
emit Transfer(msg.sender, _to, _value, _data);
return true;
}
function transfer(address _to, uint _value) public returns (bool success){
bytes memory _empty = hex"00000000";
balances[msg.sender] = balances[msg.sender] - _value;
balances[_to] = balances[_to] + _value;
if(isContract(_to)) {
IERC223Recipient(_to).tokenReceived(msg.sender, _value, _empty);
}
emit Transfer(msg.sender, _to, _value, _empty);
return true;
}
}
```

Now we want another contract to accept deposits of `tokenA` assuming that tokenA is a 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.
Dexaran marked this conversation as resolved.
Show resolved Hide resolved

Here is the code:

```solidity
contract RecipientContract is IERC223Recipient {
event Deposit(address whoSentTheTokens);
uint256 deposits = 0;
address tokenA; // The only token that we want to accept.
function tokenReceived(address _from, uint _value, bytes memory _data) public override
{
// It is important to understand that within this function
// msg.sender is the address of a token that is being received,
// msg.value is always 0 as the token contract does not own or send Ether in most cases,
// _from is the sender of the token transfer,
// _value is the amount of tokens that was deposited.
require(msg.sender == tokenA);
deposits += _value;
emit Deposit(_from);
}
}
```

- **What will happen if we send some tokenB to the contract?** - The transaction will fail and the transfer of tokens will simply not happen. The tokens will be returned to the sender's address.
- **How can we make a deposit to this contract?** - We can simply call the `transfer(address,uint256)` or `transfer(address,uint256,bytes)` function of the ERC-223 token and tell it to transfer some tokens to the address of the `RecipientContract`. That's it.
- **What will happen if we transfer a ERC-20 token to this contract?** - Well, ERC-20 standard supports two methods of transferring tokens: `transfer` function and `approve + transferFrom` pattern. This is not possible to make a deposit with `transferFrom` function as the `RecipientContract` does not have any functions that subsequently call `transferFrom`. If a ERC-20 token is sent with `transfer` function to the address of the `RecipientContract` then unfortunately the tokens will be transferred from the sender's address to the address of the `RecipientContract` but the transfer will not be recognized i.e. `Deposit()` event will not be fired and `deposits` value will not change. There is also no way to filter or prevent unwanted ERC-20 deposits that are made with the `transfer` function.
Dexaran marked this conversation as resolved.
Show resolved Hide resolved
- **What if we want to execute some function after the token deposit is completed?**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're breaking this answer out from the bulleted list... makes me think we should just turn these bullets into h3's underneith a new h2 of ## Frequently asked questions as we do in many other areas of the site.

Instead of bolding each question, would just place these on new lines beginning with ### and break each answer out on new lines. This will help with the table of contents, and screen reader usage.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


There are multiple ways of doing so. In this example we will follow the method which makes ERC-223 transfers identical to Ether transfers:

```solidity
contract RecipientContract is IERC223Recipient {
event Foo();
event Bar(uint256 someNumber);
address tokenA; // The only token that we want to accept.
function tokenReceived(address _from, uint _value, bytes memory _data) public override
{
require(msg.sender == tokenA);
address(this).call(_data); // Handle incoming transaction and perform a subsequent function call.
}
function foo() public
{
emit Foo();
}
function bar(uint256 _someNumber) public
{
emit Bar(_someNumber);
}
}
```

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.

In the above example a 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.
Dexaran marked this conversation as resolved.
Show resolved Hide resolved

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.

## Further reading {#further-reading}

- [EIP-223: ERC-223 Token Standard](https://eips.ethereum.org/EIPS/eip-223)
- [Initial ERC-223 proposal](https://github.com/ethereum/eips/issues/223)