[ERC] 마스터링 토큰 표준 : ERC-20, ERC-721, ERC-1155, ERC-6960

드림보이즈·2025년 3월 26일
0

Smart Contract

목록 보기
6/11

목표 : 이더리움 토큰 표준들을 비교하며 특징을 이해하자.

배경 : 기술면접에서 ERC-1155 까먹음.


1. ERC-20 인터페이스 (대체 가능 토큰)

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}
  • totalSupply() : 총 발행량 조회
  • balanceOf() : 특정 주소의 토큰 잔액 조회
  • transfer() : 토큰 전송
  • approve() : 다른 주소가 내 토큰을 사용할 수 있도록 허용
  • transferFrom() : 허용된 주소가 토큰을 전송하도록 허용

정말 별 거 없다. 마치 화폐처럼, 모든 개별 토큰이 동일한 가치다.


2. ERC-720 인터페이스 (대체 불가능 토큰)

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IERC721 {
    function balanceOf(address owner) external view returns (uint256 balance);
    function ownerOf(uint256 tokenId) external view returns (address owner);
    function safeTransferFrom(address from, address to, uint256 tokenId) external;
    function transferFrom(address from, address to, uint256 tokenId) external;
    function approve(address to, uint256 tokenId) external;
    function getApproved(uint256 tokenId) external view returns (address operator);
    function setApprovalForAll(address operator, bool approved) external;
    function isApprovedForAll(address owner, address operator) external view returns (bool);
    
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
}
  • balanceOf() : 특정 주소가 소유한 NFT 개수 조회

  • ownerOf() : 특정 NFT의 소유자 조회

  • transferFrom() : NFT 전송

  • safeTransferFrom() : 안전한 NFT 전송 (컨트랙트 주소도 받을 수 있도록 보장)

  • approve() : 특정 NFT의 사용 권한 부여

  • setApprovalForAll() : 모든 NFT에 대한 사용 권한 부여

다 필요없고 이것만 보면 된다.

tokenId

이걸로 토큰을 유니크하게 구분하는 것이다.
겉으로는 똑같이 보이는 토큰일지라도, 유니크한 tokenId를 토큰에 부여해
각 토큰이 다른 것이다.


3. ERC-1155 인터페이스 (멀티 토큰)

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IERC1155 {
    function balanceOf(address account, uint256 id) external view returns (uint256);
    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory);
    function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
    function safeBatchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data) external;
    function setApprovalForAll(address operator, bool approved) external;
    function isApprovedForAll(address account, address operator) external view returns (bool);

    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
    event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values);
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);
    event URI(string value, uint256 indexed id);
}

balanceOf() : 특정 ID의 토큰 개수 조회

balanceOfBatch() : 여러 개의 ID에 대해 토큰 개수 조회

safeTransferFrom() : 특정 ID의 토큰 전송

safeBatchTransferFrom() : 여러 개의 ID를 한 번에 전송 (가스 절약)

setApprovalForAll() : 모든 토큰에 대한 사용 권한 부여

자, 생각해보자. 20과 721을 구별하는 식별자는? ID를 두는 것이라고 했다.
그러면 한 컨트랙트에서, FT, NFT 두 종류의 토큰을 관리할 수 있게 하려면?

ID는 그대로 두고, 발행량을 조절해서 1개면 NFT, 1개 초과면 FT가 되는 것 아니겠는가?
어려울 것 없다. 걍 ID를 두는 것이다. 대신 NFT와 구별되어야 하니 FT도 id는 주되, 발행량을 많이 하면 되는 것이다.

또 하나의 1155의 특징은 Batch가 가능해 가스비를 절약하는 것이다.

safeBatchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data)

위를 보자. A가 B에게 토큰을 보내는데, 원래 같았으면 3종류라면 트랜잭션 3번 보내야 했다.
근데 ids를 통해 3종류와 토큰 개수를 한번에 적어서 보낼 수 있는 것이다.

balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory)

이것도 보자. 주소 A,B,C의 토큰 보유량을 조회하고 싶다면? 각각 3번 조회해야 된다.
이제는 accounts에 한번에 넣고, 어떤 토큰인지 ids를 배열로 둬서 한번에 조회가 가능한 것이다.


4. ERC-6960 (Dual Layer Token)

모든 기술은 기존의 기술을 부모삼아 발전하다.
1~3번까지 읽으면 기존의 기술에 리틀 터치를 해서 발전을 한 양상임을 알 수 있다.
즉, ERC-6960은 1155의 기술 + 알파 라는 것이다.
아래 그림을 보자.

이제 ERC-20 + ERC-721을 커버하면서, 동시에
한 토큰 안에 여러 개의 하위 토큰을 둘 수 있는 것이다.
위의 그림을 보자. 너무너무 쉽다.

기존에 토큰을 구분했던 ID를 mainID로 두고, 그 아래에 여러 개의 SubId를 둬서
위 그림처럼 부모-자식 관계의 토큰을 만들 수 있다.
머리로는 이해했는데, 이건 어떤 분야에서 써야 하는 건지 감이 안 올 수 있다.

우리는 24년 체인링크 해커톤에서 이를 주제로 했는데,
선박 금융에서, 한 회사마다 한 컨트랙트가 있다.
배를 만들 때 마다, 새로운 MainID를 부여해 토큰을 만들어서 투자를 받고 투자자들에게 나눠준다.
여기가 끝이라면, ERC-721이랑 똑같다. 지루하다.
그래서 한 MainID인 배 마다, 아래 여러 SubID를 가진 토큰들을 만든다.
멤버쉽, 티켓 등으로 활용할 수 있게.

ㅈㄴ 별거 없다. 막말로 나도 이더리움 컨트리뷰터할 만 하지 않나?

마무리

ERC-20은 토큰들이 동일하고,
ERC-721은 토큰마다 ID를 둬서 서로를 구별하고,
ERC-1155는 ERC-20과 ERC-721 두 종류의 토큰을 한 컨트랙트 안에서 생성가능하고,
이는 ID를 둬서 가능하다.
추가로 Batch 조회, 전송을 추가해 가스비도 절약할 수 있다!
ERC-6960은 하나의 MainID 하위에, 추가로 SubID 토큰들을 둬서 부모-자식 관계의 토큰을 관리할 수 있는 Dual Layer Token도 구현 가능하다.

와 너무 이지하다. 쏘이지~

profile
시리즈 클릭하셔서 카테고리 별로 편하게 보세용

0개의 댓글