Nhảy đến nội dung chính
Change page

Tiêu chuẩn token ERC-223

Lần cập nhật trang lần cuối: 6 tháng 9, 2025

Giới thiệu

ERC-223 là gì?

ERC-223 là một tiêu chuẩn cho các token có thể thay thế, tương tự như tiêu chuẩn ERC-20. Sự khác biệt chính là ERC-223 không chỉ xác định API của token mà còn cả logic để chuyển token từ người gửi đến người nhận. Nó giới thiệu một mô hình giao tiếp cho phép các lần chuyển token được xử lý ở phía người nhận.

Sự khác biệt so với ERC-20

ERC-223 giải quyết một số hạn chế của ERC-20 và giới thiệu một phương thức tương tác mới giữa hợp đồng token và hợp đồng có thể nhận các token. Có một vài điều có thể thực hiện với ERC-223 nhưng không thể với ERC-20:

  • Xử lý việc chuyển token ở phía người nhận: Người nhận có thể phát hiện rằng một token ERC-223 đang được gửi vào.
  • Từ chối các token được gửi không đúng cách: Nếu người dùng gửi token ERC-223 đến một hợp đồng không được cho là sẽ nhận token, hợp đồng có thể từ chối giao dịch, ngăn chặn việc mất token.
  • Siêu dữ liệu trong các lần chuyển: Các token ERC-223 có thể bao gồm siêu dữ liệu, cho phép đính kèm thông tin tùy ý vào các giao dịch token.

Điều kiện tiên quyết

Nội dung

ERC-223 là một tiêu chuẩn token triển khai một API cho các token trong các hợp đồng thông minh. Nó cũng khai báo một API cho các hợp đồng được cho là sẽ nhận token ERC-223. Các hợp đồng không hỗ trợ API Người nhận ERC-223 không thể nhận các token ERC-223, ngăn ngừa lỗi từ người dùng.

Nếu một hợp đồng thông minh triển khai các phương thức và sự kiện sau đây, nó có thể được gọi là một hợp đồng token tương thích với ERC-223. Sau khi được triển khai, nó sẽ chịu trách nhiệm theo dõi các token được tạo trên Ethereum.

Hợp đồng không bắt buộc chỉ có các hàm này và một nhà phát triển có thể thêm bất kỳ tính năng nào khác từ các tiêu chuẩn token khác vào hợp đồng này. Ví dụ: các hàm approvetransferFrom không phải là một phần của tiêu chuẩn ERC-223 nhưng các hàm này có thể được triển khai nếu cần thiết.

Từ EIP-223 (opens in a new tab):

Các phương thức

Token ERC-223 phải triển khai các phương thức sau:

1function name() public view returns (string)
2function symbol() public view returns (string)
3function decimals() public view returns (uint8)
4function totalSupply() public view returns (uint256)
5function balanceOf(address _owner) public view returns (uint256 balance)
6function transfer(address _to, uint256 _value) public returns (bool success)
7function transfer(address _to, uint256 _value, bytes calldata _data) public returns (bool success)

Một hợp đồng được cho là sẽ nhận token ERC-223 phải triển khai phương thức sau:

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

Nếu các token ERC-223 được gửi đến một hợp đồng không triển khai hàm tokenReceived(..), thì việc chuyển phải thất bại và các token không được di chuyển khỏi số dư của người gửi.

Sự kiện

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

Ví dụ

API của token ERC-223 tương tự như của ERC-20, vì vậy từ quan điểm phát triển giao diện người dùng (UI) thì không có sự khác biệt. Ngoại lệ duy nhất ở đây là các token ERC-223 có thể không có các hàm approve + transferFrom vì chúng là tùy chọn cho tiêu chuẩn này.

Các ví dụ về Solidity

Ví dụ sau đây minh họa cách hoạt động của một hợp đồng token ERC-223 cơ bản:

1pragma solidity ^0.8.19;
2abstract contract IERC223Recipient {
3 function tokenReceived(address _from, uint _value, bytes memory _data) public virtual;
4}
5contract VeryBasicERC223Token {
6 event Transfer(address indexed from, address indexed to, uint value, bytes data);
7 string private _name;
8 string private _symbol;
9 uint8 private _decimals;
10 uint256 private _totalSupply;
11 mapping(address => uint256) private balances;
12 function name() public view returns (string memory) { return _name; }
13 function symbol() public view returns (string memory) {return _symbol; }
14 function decimals() public view returns (uint8) { return _decimals; }
15 function totalSupply() public view returns (uint256) { return _totalSupply; }
16 function balanceOf(address _owner) public view returns (uint256) { return balances[_owner]; }
17 function isContract(address account) internal view returns (bool) {
18 uint256 size;
19 assembly { size := extcodesize(account) }
20 return size > 0;
21 }
22 function transfer(address _to, uint _value, bytes calldata _data) public returns (bool success){
23 balances[msg.sender] = balances[msg.sender] - _value;
24 balances[_to] = balances[_to] + _value;
25 if(isContract(_to)) {
26 IERC223Recipient(_to).tokenReceived(msg.sender, _value, _data);
27 }
28 emit Transfer(msg.sender, _to, _value, _data);
29 return true;
30 }
31 function transfer(address _to, uint _value) public returns (bool success){
32 bytes memory _empty = hex"00000000";
33 balances[msg.sender] = balances[msg.sender] - _value;
34 balances[_to] = balances[_to] + _value;
35 if(isContract(_to)) {
36 IERC223Recipient(_to).tokenReceived(msg.sender, _value, _empty);
37 }
38 emit Transfer(msg.sender, _to, _value, _empty);
39 return true;
40 }
41}
Hiện tất cả

Bây giờ chúng ta muốn một hợp đồng khác chấp nhận các khoản tiền gửi tokenA giả sử rằng tokenA là một token ERC-223. Hợp đồng phải chỉ chấp nhận tokenA và từ chối mọi token khác. Khi hợp đồng nhận tokenA, nó phải phát ra một sự kiện Deposit() và tăng giá trị của biến nội bộ deposits.

Đây là mã:

1contract RecipientContract is IERC223Recipient {
2 event Deposit(address whoSentTheTokens);
3 uint256 deposits = 0;
4 address tokenA; // Token duy nhất mà chúng ta muốn chấp nhận.
5 function tokenReceived(address _from, uint _value, bytes memory _data) public override
6 {
7 // Điều quan trọng là phải hiểu rằng trong hàm này
8 // msg.sender là địa chỉ của token đang được nhận,
9 // msg.value luôn là 0 vì hợp đồng token không sở hữu hoặc gửi ether trong hầu hết các trường hợp,
10 // _from là người gửi của lần chuyển token,
11 // _value là số lượng token đã được gửi.
12 require(msg.sender == tokenA);
13 deposits += _value;
14 emit Deposit(_from);
15 }
16}
Hiện tất cả

Những câu hỏi thường gặp

Điều gì sẽ xảy ra nếu chúng ta gửi một số tokenB đến hợp đồng?

Giao dịch sẽ thất bại, và việc chuyển token sẽ không xảy ra. Các token sẽ được trả lại cho địa chỉ của người gửi.

Làm thế nào chúng ta có thể gửi tiền vào hợp đồng này?

Gọi hàm transfer(address,uint256) hoặc transfer(address,uint256,bytes) của token ERC-223, chỉ định địa chỉ của RecipientContract.

Điều gì sẽ xảy ra nếu chúng ta chuyển một token ERC-20 đến hợp đồng này?

Nếu một token ERC-20 được gửi đến RecipientContract, các token sẽ được chuyển, nhưng việc chuyển sẽ không được công nhận (không có sự kiện Deposit() nào được kích hoạt, và giá trị tiền gửi sẽ không thay đổi). Các khoản tiền gửi ERC-20 không mong muốn không thể được lọc hoặc ngăn chặn.

Điều gì sẽ xảy ra nếu chúng ta muốn thực thi một hàm nào đó sau khi việc gửi token hoàn tất?

Có nhiều cách để làm điều đó. Trong ví dụ này, chúng ta sẽ làm theo phương pháp khiến cho các lần chuyển ERC-223 giống hệt như các lần chuyển ether:

1contract RecipientContract is IERC223Recipient {
2 event Foo();
3 event Bar(uint256 someNumber);
4 address tokenA; // Token duy nhất mà chúng ta muốn chấp nhận.
5 function tokenReceived(address _from, uint _value, bytes memory _data) public override
6 {
7 require(msg.sender == tokenA);
8 address(this).call(_data); // Xử lý giao dịch đến và thực hiện một lệnh gọi hàm tiếp theo.
9 }
10 function foo() public
11 {
12 emit Foo();
13 }
14 function bar(uint256 _someNumber) public
15 {
16 emit Bar(_someNumber);
17 }
18}
Hiện tất cả

Khi RecipientContract nhận được một token ERC-223, hợp đồng sẽ thực thi một hàm được mã hóa dưới dạng tham số _data của giao dịch token, giống hệt như cách các giao dịch ether mã hóa các lệnh gọi hàm dưới dạng data giao dịch. Đọc trường dữ liệu để biết thêm thông tin.

Trong ví dụ trên, một token ERC-223 phải được chuyển đến địa chỉ của RecipientContract bằng hàm transfer(address,uin256,bytes calldata _data). Nếu tham số dữ liệu là 0xc2985578 (chữ ký của hàm foo()), thì hàm foo() sẽ được gọi sau khi nhận được tiền gửi token và sự kiện Foo() sẽ được kích hoạt.

Các tham số cũng có thể được mã hóa trong data của lần chuyển token, ví dụ: chúng ta có thể gọi hàm bar() với giá trị 12345 cho _someNumber. Trong trường hợp này, data phải là 0x0423a13200000000000000000000000000000000000000000000000000000000000004d2, trong đó 0x0423a132 là chữ ký của hàm bar(uint256)00000000000000000000000000000000000000000000000000000000000004d2 là 12345 dưới dạng uint256.

Các hạn chế

Mặc dù ERC-223 giải quyết một số vấn đề được tìm thấy trong tiêu chuẩn ERC-20, nó không phải là không có những hạn chế riêng:

  • Việc áp dụng và tính tương thích: ERC-223 vẫn chưa được áp dụng rộng rãi, điều này có thể hạn chế khả năng tương thích của nó với các công cụ và nền tảng hiện có.
  • Khả năng tương thích ngược: ERC-223 không tương thích ngược với ERC-20, nghĩa là các hợp đồng và công cụ ERC-20 hiện có sẽ không hoạt động với các token ERC-223 nếu không có sửa đổi.
  • Chi phí gas: Các kiểm tra và chức năng bổ sung trong các lần chuyển ERC-223 có thể dẫn đến chi phí gas cao hơn so với các giao dịch ERC-20.

Đọc thêm

Bài viết này hữu ích không?