메인 콘텐츠로 건너뛰기
Change page

ERC-223 토큰 표준

페이지 마지막 업데이트됨: 2025년 9월 6일

소개

ERC-223은 무엇인가요?

ERC-223은 ERC-20 표준과 유사한 대체 가능 토큰 표준입니다. 주요 차이점은 ERC-223이 토큰 API뿐만 아니라 발신자에서 수신자로 토큰을 전송하는 로직도 정의한다는 것입니다. 수신자 측에서 토큰 전송을 처리할 수 있는 통신 모델을 도입합니다.

ERC-20과의 차이점

ERC-223은 ERC-20의 몇 가지 한계를 해결하고 토큰 계약과 토큰을 받을 수 있는 계약 간의 새로운 상호 작용 방법을 도입합니다. ERC-20에서는 불가능하지만 ERC-223에서는 가능한 몇 가지 사항이 있습니다.

  • 수신자 측에서의 토큰 전송 처리: 수신자는 ERC-223 토큰이 입금되고 있음을 감지할 수 있습니다.
  • 부적절하게 전송된 토큰 거부: 사용자가 토큰을 받지 않아야 하는 계약에 ERC-223 토큰을 보내는 경우, 해당 계약은 트랜잭션을 거부하여 토큰 손실을 방지할 수 있습니다.
  • 전송 시 메타데이터: ERC-223 토큰은 메타데이터를 포함할 수 있어 토큰 트랜잭션에 임의의 정보를 첨부할 수 있습니다.

필수 구성 요소

본문

ERC-223은 스마트 계약 내의 토큰을 위한 API를 구현하는 토큰 표준입니다. 또한 ERC-223 토큰을 받도록 되어 있는 계약을 위한 API를 선언합니다. ERC-223 수신자 API를 지원하지 않는 계약은 ERC-223 토큰을 받을 수 없어 사용자 실수를 방지합니다.

스마트 계약이 다음 메서드와 이벤트를 구현하면 ERC-223 호환 토큰 계약이라고 할 수 있습니다. 배포되면 이더리움에서 생성된 토큰을 추적할 책임이 있습니다.

계약이 이러한 함수만 가질 의무는 없으며, 개발자는 다른 토큰 표준의 다른 기능을 이 계약에 추가할 수 있습니다. 예를 들어, approvetransferFrom 함수는 ERC-223 표준의 일부는 아니지만 필요한 경우 구현할 수 있습니다.

EIP-223 (opens in a new tab)에서:

메서드

ERC-223 토큰은 다음 메서드를 구현해야 합니다.

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)

ERC-223 토큰을 받도록 되어 있는 계약은 다음 메서드를 구현해야 합니다.

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

tokenReceived(..) 함수를 구현하지 않는 계약으로 ERC-223 토큰을 보내면 전송이 실패해야 하며, 토큰이 발신자의 잔액에서 이동해서는 안 됩니다.

이벤트

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

예시

ERC-223 토큰의 API는 ERC-20과 유사하므로 UI 개발 관점에서 차이가 없습니다. 여기서 유일한 예외는 ERC-223 토큰에 approve + transferFrom 함수가 없을 수 있다는 것입니다. 이 함수들은 이 표준에서 선택 사항이기 때문입니다.

솔리디티 예제

다음 예제는 기본 ERC-223 토큰 계약이 어떻게 작동하는지 보여줍니다.

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}
모두 보기

이제 tokenA가 ERC-223 토큰이라고 가정하고, tokenA의 입금을 수락하는 다른 계약을 원합니다. 계약은 tokenA만 수락하고 다른 모든 토큰은 거부해야 합니다. 계약이 tokenA를 받으면 Deposit() 이벤트를 발생시키고 내부 deposits 변수의 값을 증가시켜야 합니다.

코드는 다음과 같습니다.

1contract RecipientContract is IERC223Recipient {
2 event Deposit(address whoSentTheTokens);
3 uint256 deposits = 0;
4 address tokenA; // 우리가 수락하려는 유일한 토큰입니다.
5 function tokenReceived(address _from, uint _value, bytes memory _data) public override
6 {
7 // 이 함수 내에서 다음을 이해하는 것이 중요합니다
8 // msg.sender는 수신 중인 토큰의 주소이며,
9 // msg.value는 대부분의 경우 토큰 계약이 이더를 소유하거나 전송하지 않으므로 항상 0입니다,
10 // _from은 토큰 전송의 발신자이고,
11 // _value는 입금된 토큰의 양입니다.
12 require(msg.sender == tokenA);
13 deposits += _value;
14 emit Deposit(_from);
15 }
16}
모두 보기

자주 묻는 질문

계약에 tokenB를 보내면 어떻게 될까요?

트랜잭션이 실패하고 토큰 전송이 발생하지 않습니다. 토큰은 발신자의 주소로 반환됩니다.

이 계약에 어떻게 입금할 수 있나요?

ERC-223 토큰의 transfer(address,uint256) 또는 transfer(address,uint256,bytes) 함수를 호출하여 RecipientContract의 주소를 지정합니다.

이 계약에 ERC-20 토큰을 전송하면 어떻게 될까요?

RecipientContract에 ERC-20 토큰을 보내면 토큰은 전송되지만, 전송이 인식되지 않습니다(Deposit() 이벤트가 발생하지 않으며, deposits 값도 변경되지 않음). 원치 않는 ERC-20 입금은 필터링하거나 방지할 수 없습니다.

토큰 입금이 완료된 후 일부 함수를 실행하려면 어떻게 해야 할까요?

여러 가지 방법이 있습니다. 이 예제에서는 ERC-223 전송을 이더 전송과 동일하게 만드는 방법을 따릅니다.

1contract RecipientContract is IERC223Recipient {
2 event Foo();
3 event Bar(uint256 someNumber);
4 address tokenA; // 수락하려는 유일한 토큰입니다.
5 function tokenReceived(address _from, uint _value, bytes memory _data) public override
6 {
7 require(msg.sender == tokenA);
8 address(this).call(_data); // 들어오는 트랜잭션을 처리하고 후속 함수 호출을 수행합니다.
9 }
10 function foo() public
11 {
12 emit Foo();
13 }
14 function bar(uint256 _someNumber) public
15 {
16 emit Bar(_someNumber);
17 }
18}
모두 보기

RecipientContract가 ERC-223 토큰을 받으면, 계약은 이더리움 트랜잭션이 트랜잭션 data로 함수 호출을 인코딩하는 방식과 동일하게 토큰 트랜잭션의 _data 매개변수로 인코딩된 함수를 실행합니다. 자세한 내용은 데이터 필드를 읽어보세요.

위 예에서 ERC-223 토큰은 transfer(address,uin256,bytes calldata _data) 함수를 사용하여 RecipientContract의 주소로 전송되어야 합니다. 데이터 매개변수가 0xc2985578(foo() 함수의 서명)인 경우, 토큰 입금이 수신된 후 foo() 함수가 호출되고 Foo() 이벤트가 발생합니다.

매개변수는 토큰 전송의 data에도 인코딩될 수 있습니다. 예를 들어, _someNumber에 12345 값을 사용하여 bar() 함수를 호출할 수 있습니다. 이 경우 data0x0423a13200000000000000000000000000000000000000000000000000000000000004d2여야 합니다. 여기서 0x0423a132bar(uint256) 함수의 서명이고 00000000000000000000000000000000000000000000000000000000000004d2는 uint256으로서의 12345입니다.

한계

ERC-223이 ERC-20 표준에서 발견된 여러 문제를 해결하지만, 자체적인 한계도 있습니다.

  • 채택 및 호환성: ERC-223은 아직 널리 채택되지 않아 기존 도구 및 플랫폼과의 호환성이 제한될 수 있습니다.
  • 하위 호환성: ERC-223은 ERC-20과 하위 호환되지 않습니다. 즉, 기존 ERC-20 계약 및 도구는 수정 없이는 ERC-223 토큰과 작동하지 않습니다.
  • 가스 비용: ERC-223 전송의 추가 확인 및 기능으로 인해 ERC-20 트랜잭션에 비해 가스 비용이 더 많이 발생할 수 있습니다.

더 읽어보기

이 문서가 도움이 되셨나요?