들어가며
이 글에서는 이더리움의 두 주요 토큰 표준, ERC-20과 ERC-223을 소개하며, 이들의 차이점과 구현 예시를 통해 실제 활용 방안을 살펴 보겠다.
특히, 나와 같이 블록체인에 대한 기술 이제 막 뛰어든 개발자들에게 지금까지 알아보고 습득한 내용들을 정리하여 두 표준이 어떻게 다른지와 어떻게 사용하면 되는지에 대해 소개하여, 조금이나마 도움이 되었으면 한다.
스마트 컨트랙트란?
스마트 컨트랙트는 블록체인 기술을 기반으로 작동하는 자동화된 계약 시스템이다.
이더리움은 이러한 스마트 컨트랙트 구현을 위한 주요 플랫폼 중 하나로, 사용자와 개발자가 토큰과 같은 디지털 자산을 쉽게 생성하고 관리할 수 있게 해준다. 이 글에서는 이더리움 FT(Fungible Token)의 두 가지 주요 토큰 표준인 ERC-20과 ERC-223을 소개한다.
ERC-20 표준 이해하기
먼저 ERC-20 토큰을 보자면, ERC-20 표준은 이더리움 기반 토큰의 교환과 작동을 위한 기본 규칙을 설정한다.
이 표준은 토큰의 발행과 전송, 잔액 조회 등을 표준화하여 개발자가 서로 호환 가능한 토큰을 쉽게 생성할 수 있도록 하는 역할을 한다.
ERC-20의 주요 기능:
- 토큰 생성: 개발자가 정의한 규칙에 따라 새로운 토큰을 생성할 수 있다.
- 전송 메커니즘: 사용자들이 토큰을 서로 전송할 수 있는 기능을 제공한다.
- 토큰 조회: 토큰 소유자의 잔액을 확인할 수 있는 기능이다.
이러한 표준화 덕분에 ERC-20 토큰은 광범위하게 사용되며, 많은 디지털 지갑과 교환 플랫폼에서 지원이 되고 있다.
ERC-20 표준에서는 토큰을 처리할 수 없는 주소로도 토큰의 전송이 가능한 점으로 인한 이슈가 존재한다. 즉, 잘못된 주소로 토큰을 전송하게 되면 해당 토큰을 잃어버리게 된다.
ERC-223 표준 이해하기 & 등장 배경
ERC-223은 ERC-20의 단점을 보완하기 위해 등장한 표준이다.
ERC-20 표준에서는 토큰이 스마트 컨트랙트와 같이 토큰을 처리할 수 없는 주소로 전송될 때, 그 컨트랙트가 토큰을 처리할 준비가 되어 있지 않으면 토큰을 영원히 잃어버릴 수 있는 위험이 있다.
ERC-223은 이러한 문제를 해결하기 위해 토큰 전송 시 스마트 컨트랙트가 토큰 수령을 거부할 수 있는 메커니즘을 도입한 표준이다.
ERC-223의 기능:
- 데이터 전송 지원: 토큰과 함께 추가 데이터를 전송할 수 있다, 이를 통해 보다 복잡한 트랜잭션을 지원한다.
- 자동 토큰 반환: 잘못된 주소로의 토큰 전송을 방지하여 자산의 손실을 최소화한다.
ERC-223은 ERC-20에 비해 몇 가지 중요한 개선점을 제공한다. 가장 중요한 것은 ERC-223 토큰은 잘못된 컨트랙트로의 전송 시 자동으로 반환되므로, 사용자의 실수로 인한 토큰 손실 위험이 크게 감소하여 자산의 안전성을 강화하였다.
ERC-20과 ERC-223을 활용하는 방법
ERC-20과 ERC-223 표준을 활용하는 것은 블록체인 개발자들에게 매우 중요하다. 이 표준들은 디지털 토큰을 이더리움 네트워크 위에서 효과적으로 구현하고 운영할 수 있는 기반을 제공한다.
ERC-20 활용
- 금융 애플리케이션: ERC-20 토큰은 주로 금융 애플리케이션에서 사용된다. 예를 들어, ICO(Initial Coin Offering)에서 자금을 모집하거나, 스테이블 코인과 같은 가치 저장 수단으로 사용된다.
- 거래 플랫폼: 교환 플랫폼에서는 다양한 ERC-20 토큰들이 거래된다. 그렇기 때문에 이 표준을 활용하여 스마트 컨트랙트의 일관성 덕분에 개발자는 다양한 토큰을 쉽게 통합할 수 있다.
ICO가 무엇인지 궁금하여 조사해 보았다.
ICO, 즉 Initial Coin Offering은 스타트업이나 기업이 자신의 새로운 프로젝트나 서비스를 자금 조달하기 위해 신규 암호화폐 또는 토큰을 처음으로 공개하는 것을 말한다. ICO는 전통적인 주식공개(IPO)와 유사한 개념이지만, 투자자들에게 주식 대신 디지털 토큰을 제공한다는 점에서 차이가 있다.
ERC-223 활용
- 향상된 안전성: ERC-223 표준은 토큰을 잘못된 계약으로 보낼 때 발생할 수 있는 자산의 손실을 방지한다. 따라서 개발자들은 사용자의 자산을 보호할 수 있는 더 안전한 토큰을 제공할 수 있다.
- 복잡한 논리 구현: ERC-223은 데이터를 함께 전송할 수 있기 때문에, 보다 복잡한 논리와 조건을 토큰 전송 프로세스에 통합할 수 있다. 이는 블록체인 게임이나 고급 사용자 인증 시나리오에서 유용하게 사용될 수 있다.
이 표준들의 이해와 적절한 활용은 블록체인 애플리케이션의 성공적인 개발과 배포에 결정적인 역할을 한다. 또한, 이러한 표준들은 블록체인 생태계 내에서의 상호운용성을 향상시키고, 네트워크 전체의 안전성과 효율성을 증진시키는 데 기여한다.
ERC-20 & ERC-223 기본 구현 예시와 차이점
ERC-20
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// ERC-20 토큰 컨트랙트 예시
contract ERC20Token {
mapping(address => uint256) public balanceOf; // 각 주소의 잔액을 저장하는 매핑
uint256 public totalSupply; // 토큰의 총 공급량
event Transfer(address indexed from, address indexed to, uint256 value); // 토큰 전송 이벤트
// 컨트랙트 생성자에서 총 공급량을 설정하고, 생성자를 호출한 주소에 모든 토큰을 할당
constructor(uint256 initialSupply) {
totalSupply = initialSupply;
balanceOf[msg.sender] = totalSupply;
}
// 토큰을 전송하는 함수
function transfer(address _to, uint256 _value) public returns (bool success) {
require(balanceOf[msg.sender] >= _value, "Insufficient balance"); // 잔액이 충분한지 확인
balanceOf[msg.sender] -= _value; // 보내는 주소의 잔액 감소
balanceOf[_to] += _value; // 받는 주소의 잔액 증가
emit Transfer(msg.sender, _to, _value); // 이벤트 로깅
return true;
}
}
ERC-223
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// ERC-223 토큰 수신을 위한 인터페이스
interface ERC223Receiver {
function tokenFallback(address _from, uint _value, bytes calldata _data) external;
}
// ERC-223 토큰 컨트랙트 예시
contract ERC223Token {
mapping(address => uint256) public balanceOf; // 각 주소의 잔액을 저장하는 매핑
uint256 public totalSupply; // 토큰의 총 공급량
event Transfer(address indexed from, address indexed to, uint256 value, bytes data); // 토큰 전송 이벤트, ERC-20과 비교해 데이터 필드 추가
// 컨트랙트 생성자에서 총 공급량을 설정하고, 생성자를 호출한 주소에 모든 토큰을 할당
constructor(uint256 initialSupply) {
totalSupply = initialSupply;
balanceOf[msg.sender] = totalSupply;
}
// 토큰을 전송하는 함수, 데이터를 포함하여 보낼 수 있음
function transfer(address _to, uint _value, bytes memory _data) public {
require(balanceOf[msg.sender] >= _value, "Insufficient balance"); // 잔액이 충분한지 확인
uint codeLength;
assembly {
codeLength := extcodesize(_to) // 받는 주소가 컨트랙트인지 확인
}
if (codeLength > 0) {
ERC223Receiver receiver = ERC223Receiver(_to);
receiver.tokenFallback(msg.sender, _value, _data); // 받는 주소가 컨트랙트 주소인 경우, 토큰 수신 로직 호출
}
balanceOf[msg.sender] -= _value; // 보내는 주소의 잔액 감소
balanceOf[_to] += _value; // 받는 주소의 잔액 증가
emit Transfer(msg.sender, _to, _value, _data); // 이벤트 로깅, ERC-20과 비교해 데이터 필드 추가
}
}
ERC-223 코드를 보면 transfer
함수에 codeLength
라는 받는 주소가 컨트랙트인지 확인하는 부분이 있다. 이 부분은 이더리움 가상 머신(EVM)의 extcodesize
함수를 호출한다. 이 함수는 주소에 저장된 코드의 크기를 반환하며, 크기가 0보다 크면 해당 주소는 컨트랙트 주소이다.
스마트 컨트랙트의 transfer
함수 동작 순서
-
코드 사이즈 검증:
transfer
함수가 호출되면, 먼저 대상 주소_to
가 컨트랙트 주소인지를 확인한다. 이를 위해extcodesize
함수를 사용하는데, 이 함수는 지정된 주소의 코드 사이즈를 확인하여, 0보다 크면 컨트랙트라고 판단한다. -
컨트랙트 로직 호출: 만약
_to
주소가 컨트랙트 주소라면 (codeLength > 0
), 추가적인 컨트랙트 로직이 실행된다. 여기서tokenFallback
함수가 호출되며, 이 함수는 토큰을 받는 컨트랙트에서 특별히 정의해둔 로직을 수행한다. 예를 들어, 이 로직은 추가적인 토큰 처리나, 토큰 수신을 거부하고 트랜잭션을 되돌리는 등의 작업을 수행할 수 있다. - 잔액 조정: 주소가 컨트랙트 주소인지 아닌지의 여부와 관계없이, 발신자의 잔액에서 토큰이 차감되고, 수신자의 잔액에 토큰이 추가된다. 이는
transfer
의 기본적인 기능으로, 토큰의 실제 이동을 처리한다.
여기에서 알 수 있는점은 ERC223Receiver
함수를 사용해 자산을 보호 할 수는 있지만 해당 부분은 컨트랙트에 포함이 되어 있어야 된다는 이야기다. 즉, 이미 만들어진 ERC-20 토큰의 스마트 컨트랙트 주소라면 해당 함수가 존재하지 않으므로 여전히 토큰을 잃어버릴 수 있다.
그렇다면 codeLength > 0
조건문을 처음부터 실행하여 보내려는 주소가 컨트랙트라면 이후의 코드를 실행시키지 않으면 되지 않을까? 하는 생각이 들었으나, 이는 모든 컨트랙트 주소로의 토큰 전송을 차단함으로써, 일부 유효한 사용 사례(예: 다른 스마트 컨트랙트와의 상호 작용)가 제한될 수 있다고 한다.
transfer
함수에서의 데이터 활용
위에서 잠깐 나온 내용인 ERC-223 표준 기술에서는 토큰 전송시 데이터를 함께 전송 할 수 있다. 이는 스마트 컨트랙트 간의 상호작용을 더 유연하고 기능적으로 만들어 준다.
이 데이터 필드를 활용하는 방법에는 여러 가지가 있는데, 많이 사용될 법하다고 생각되는 2가지의 예시를 가져왔다.
1. 추가 메시지나 메타데이터 전송
토큰을 전송할 때 추가적인 정보나 메시지를 포함시킬 수 있다. 예를 들어, 기부 캠페인에 토큰을 기부할 때 기부 목적이나 메시지를 데이터 필드에 넣어 기부 받는 측이 기부자의 의도를 더 명확하게 이해할 수 있도록 할 수 있다.
function transfer(address to, uint256 amount, bytes memory data) public returns (bool) {
// 토큰 전송 로직
emit Transfer(msg.sender, to, amount, data); // 데이터를 포함한 이벤트 발생
return true;
}
2. 스마트 컨트랙트 명령 실행
토큰을 스마트 컨트랙트로 전송할 때 특정 기능을 실행하도록 지시하는 명령을 데이터 필드에 포함시킬 수 있다. 예를 들어, 토큰을 전송하면서 데이터 필드에 "unlock"이라는 명령을 포함시켜, 수신 컨트랙트에서 이 명령에 따라 특정 기능을 실행할 수 있게 할 수 있다.
contract ERC223Receiver {
function tokenFallback(address from, uint value, bytes memory data) public {
if (data.equals("unlock")) {
// 어떤 특정 조건을 해제하는 로직
}
}
}
마치며
이 글을 통해 ERC-20과 ERC-223 토큰 표준의 기본 개념과 차이점을 정리해 보았다. 두 표준 모두 이더리움 기반 토큰의 개발과 관리에 있어 중요한 역할을 하지만, 각기 다른 특성과 용도가 있음을 알 수 있었다.
특히 ERC-223 토큰 표준은 전송 오류를 줄이고 보다 안전한 토큰 거래를 가능하게 하여, 실수로 인한 자산 손실의 위험을 감소시킨다.
이러한 표준들을 이해하고 올바르게 적용함으로써, 사용자에게 더 나은 경험을 제공하고, 기술의 안정성을 높일 수 있을거라 생각이 된다. 앞으로도 새로운 기술을 배우고, 이를 실제 프로젝트에 적용해보는 과정에서 많은 도전이 있겠지만, 그만큼의 성장도 기대할 수 있을거 같다.
새로운 도전이고, 아직 첫발을 내딛은지 얼마 되지 않은 상황에서 나와 같은 이들에게 조금이나마 도움이 되었으면 한다.