pragma solidity ^0.5.9;
/**
@title ERC-1155 Multi Token Standard
@dev See https://eips.ethereum.org/EIPS/eip-1155
Note: The ERC-165 identifier for this interface is 0xd9b67a26.
*/
interface ERC1155 /* is ERC165 */ {
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 _owner, address indexed _operator, bool _approved);
event URI(string _value, uint256 indexed _id);
function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external;
function safeBatchTransferFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external;
function balanceOf(address _owner, uint256 _id) external view returns (uint256);
function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) external view returns (uint256[] memory);
function setApprovalForAll(address _operator, bool _approved) external;
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}
노션에 정리한 내용이 더 가독성이 좋음.
EIP-1155: Multi Token Standard
[목차]
fragrant-comfort-49c.notion.site
[Summary]
EIP-20, EIP-721 은 한가지 종류의 토큰에 대한 인터페이스를 정의한다. 즉 해당 인터페이스로는 하나의 컨트랙트는 하나의 토큰만 다룰 수 있다. EIP-1155는 하나의 컨트랙트에서 여러개의 토큰을 다루는 것에 대한 표준 인터페이스를 제공한다.
[Specification]
1) ERC1155 Interface code
2) Token Receiver code
pragma solidity ^0.5.9;
/**
Note: The ERC-165 identifier for this interface is 0x4e2312e0.
*/
interface ERC1155TokenReceiver {
function onERC1155Received(address _operator, address _from, uint256 _id, uint256 _value, bytes calldata _data) external returns(bytes4);
function onERC1155BatchReceived(address _operator, address _from, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external returns(bytes4);
}
3) Safe Transfer Rules
⇒ safeTransferFrom 과 safeBatchTransferFrom 는 ERC1155TokenReceiver 함수와 적절히 사용되어야 하는데, 사용예는 다음 시나리오와 규칙들을 따라야한다.
Safe Transfer RulesScenarios (#1~#8)
- 수신자가 컨트랙트가 아닌 경우
⇒onERC1155Received
,onERC1155BatchReceived
는 EOA에서 호출되어서는 안된다. - 트랜잭션이 토큰 전송이나 발행이 아닌 경우
⇒onERC1155Received
,onERC1155BatchReceived
는토큰의 발행과정이나 전송과정에서만 호출되어야한다. - 수신자가
ERC1155TokenReceiver
인터페이스를 구현하지 않았을 경우
⇒ 기본적으로는 토큰 전송이 revert 되어야한다. 하지만 다른 EIP 표준을 함께 구현하여ERC1155TokenReceiver
함수가 아닌 다른 함수를 구현하였을 경우에는 하위호환성을 고려하여 허용될 수 있다. - 수신자가
ERC1155TokenReceiver
인터페이스를 구현했지만, 반환값이 유효하지 않은 경우
⇒ 토큰 전송은 revert 되어야함. - 수신자가
ERC1155TokenReceiver
인터페이스를 구현했지만, 오류를 던진 경우
⇒ 토큰 전송은 revert 되어야함. - 수신자가
ERC1155TokenReceiver
인터페이스를 구현했고, 하나의 잔고만 변화할 경우
⇒ 수신자 측에서ERC1155TokenReceiver
를 호출하기 전에, 수신 계좌의 잔고 변화 적용이 완료되어야 한다.
⇒ 수신자 측에서ERC1155TokenReceiver
를 호출하기 전에, transfer event가 발생되어야한다.
⇒onERC1155Received
,onERC1155BatchReceived
둘 중하나는 수신 컨트랙트에서 호출되어야한다. - 수신자가
ERC1155TokenReceiver
인터페이스를 구현했고, 여러 잔고가 변화할 경우
⇒ERC1155TokenReceiver
를 호출하기 전에, 수신자의 모든 계좌 잔고 변화가 먼저 반영 완료되어야한다.
⇒ERC1155TokenReceiver
를 호출하기 전에, transfer event가 먼저 발생해야한다.
⇒onERC1155Received
,onERC1155BatchReceived
는 모든 잔고 변화에 대해 적절하게 대응하도록 수신 컨트랜트에서 필요한만큼 호출되어야한다. ERC1155TokenReceiver
인터페이스를 구현한 컨트랙트의 개발자가onERC1155Received
,onERC1155BatchReceived
를 내부에서 다른 계좌로 토큰을 전달(forwarding)할 때
⇒ 수신 과정에서 다른 계좌로 전달할 수 있고, 새로운 맥락에서safeTransferFrom
orsafeBatchTransferFrom
를 새롭게 수행해야한다.
⇒ forwarding이 성공적으로 완료된 후에 해시값(keccak256)을 리턴해야한다.
⇒ _data 파라미터는 forwarding 에 사용되는 인자로 사용될 수 있다.
⇒ forwarding 이 실패하면 revert 해도 되고, 그렇지 않아도 된다.
Rules
safeTransferFrom
- 이 함수를 호출하는 주체는 전송할 토큰에 대한 접근 권한이 있어야한다.
- 다음과 같은 경우에 revert 되어야한다.
- to ==_ 0
- 잔고가 부족할 경우
- 기타 다른 오류가 발생할 경우
- 잔고 변화를 반영하기 위해 TransferSingle 이벤트를 발생시켜야 한다.
- 수신자가 스마트컨트랙트이면(code size>0),
*onERC1155Received*
를 반드시 호출해야한다. data_ 를 같이 전달해야함.
safeBatchTransferFrom
- 이 함수를 호출하는 주체는 전송할 토큰에 대한 접근 권한이 있어야한다.
- 다음과 같은 경우에 revert 되어야한다.
- to == 0
- 토큰 종류(\ids_) 수만큼 대응하는 송금액(values_)이 기재되지 않은 경우
- 잔고가 하나라도 부족할 경우
- 기타 다른 오류가 발생할 경우
- 모든 잔고 변화를 반영하기 위해, TransferSingle 또는 TransferBatch 이벤트를 발생시켜야한다.
- 잔고 변화는 파라미터로 넘겨준 토큰 배열(ids[ ]_) 순으로 진행되어야한다.
- 수신자가 스마트컨트랙트이면(code size>0),
*onERC1155Received
* 또는*onERC1155BatchReceived*
를 반드시 호출해야한다. \data_ 를 같이 전달해야함.
TransferSingle event
,TransferBatch event
- 단일 잔고에 대한 변화가 일어난 경우에는
TransferSingle event
를 발생시켜야 한다.- 여러 잔고에 대해서 여러번 발생시킬 수 있지만, TransferBatch 이벤트를 이용하는 것이 가스 사용량 측면에 더 이득이다.
- operator_ 인자는 발신을 수행하는 계좌 또는 컨트랙트 주소이어야한다. (== msg.sender)
- from_ 인자는 토큰의 소유자로 잔액 감소의 대상이다.
- to_ 인자는 토큰의 수신자로 잔액 증가의 대상이다.
- id_ 인자는 전송될 토큰 타입이다.
- value_ 인자는 전송될 토큰의 개수이다.
- 토큰을 발행할 때는, from_ 인자를 0x0 으로 설정해야한다.
- 토큰을 폐기할 때는, to_ 인자를 0x0 으로 설정해야한다.
- 여러개의 잔고 변화가 일어난 경우에는
TransferBatch event
를 발생시켜야 한다.- 여러 잔고에 대해서 여러번 발생시킬 수 있지만, TransferBatch 이벤트를 이용하는 것이 가스 사용량 측면에 더 이득이다.
- operator_ 인자는 발신을 수행하는 계좌 또는 컨트랙트 주소이어야한다. (== msg.sender)
- from_ 인자는 토큰의 소유자로 잔액 감소의 대상이다.
- to_ 인자는 토큰의 수신자로 잔액 증가의 대상이다.
- ids_ 배열 인자는 전송될 토큰들의 타입이다.
- values_ 배열 인자는 ids_ 에 해당하는 토큰이 전송되는 개수이다.
- ids_ 와\values_ 는 같은 길이여야 한다.
- 토큰을 발행할 때는, from_ 인자를 0x0 으로 설정해야한다.
- 토큰을 폐기할 때는, to_ 인자를 0x0 으로 설정해야한다.
- 클라이언트는 이벤트를 관찰해서 토큰 발생량과 폐기량을 계산하여 총 유통량을 알아낼 수 있다.
- 실제 발행량 없이 특정 토큰의 존재를 브로트캐스트 하기 위해서는, 컨트랙트는
TransferSingle event
이벤트를 발생시키면 된다. (from_=0x0, to_=0x0, operator_=tokenCreator, value_=0) - 이벤트는
onERC1155Received
또는onERC1155BatchReceived
가 호출되기 전에 먼저 생성되어 잔고 변화를 반영해야한다.
- 단일 잔고에 대한 변화가 일어난 경우에는
onERC1155Received
,onERC1155BatchReceived
- operator_ 인자는 실제 전송을 수행하는 CA 또는 EOA 주소이다. (==msg.sender)
- from_ 는 토큰 발신자로 0x0 이면 신규 발생되는 토큰
- id(_ids)_ 는 전송된 토큰 타입.
- value(_values)_ 는 전송된 토큰 개수
- data_ 는 발신자에 의해 전달된 값이 그대로 할당되어야한다.
bytes4(keccak256("onERC1155Received(address,address,uint256[],uint256[],bytes)"))
를 리턴함으로써 성공적으로 수신을 완료할 수 있다.- 오류를 던지거나, revert 함으로써 수신을 거부할 수 있다.
- 반환값이
bytes4(keccak256("onERC1155Received(address,address,uint256[],uint256[],bytes)"))
에 해당하지 않으면 반드시 revert 되어야한다. - 단일 트랜잭션 내에서 여러번 호출될 수 있다. 이 때 인자로 넘겨받은 토큰 배열 순서에 맞게 호출되어야하고, 하나의 잔고에 하나의 이벤트만 발생한다.
- 자기 자신에게 토큰을 전송하면 호출하지 않을 수 있다.
- ERC-165
- interfaceId 인자에 0x01ffc9a7 를 전달하면 true를 반환해야한다.
(ERC-165 지원한다는 뜻) - interfaceId 인자에 0x4e2312e0를 전달하면 true를 반환해야한다.
(ERC1155 TokenReceiver 지원한다는 뜻)
function supportsInterface(bytes4 interfaceID) external view returns (bool) { return interfaceID == 0x01ffc9a7 || // ERC-165 support (i.e. `bytes4(keccak256('supportsInterface(bytes4)'))`). interfaceID == 0x4e2312e0; // ERC-1155 `ERC1155TokenReceiver` support (i.e. `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)")) ^ bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`). }
- interfaceId 인자에 0x01ffc9a7 를 전달하면 true를 반환해야한다.
- Implementation specific transfer API
- ERC-1155 토큰을 전송할 때, 수신자가
ERC1155TokenReceiver
인터페이스를 구현했다면 발신자는 반드시safeTransferFrom
또는safeBatchTransferFrom
를 구현해야한다. 수신자가 구현하지 않았어도 safe 메서드를 구현하는 것이 좋지만 그 때는 용인할수도 있다. - 수신주소가 컨트랙트이면
ERC1155TokenReceiver
를 반드시 호출해야한다. - 표준에서 벗어난 transfer 함수에 의해 전송된 토큰은 표준에 벗어난 컨트랙트만 수신할 수 있다. (다른 표준을 같이 구현한 bybrid standards 가 아닌 경우)
- ERC-1155 토큰을 전송할 때, 수신자가
- Minting/creating and burning/destroying
- tranfer event에서 from_ 인자가 0x0 이면 토큰 발행으로 취급한다.
- tranfer event에서 to_ 인자가 0x0 이면 토큰 폐기로 취급한다.
- tranfer event를 관찰해서 클라이언트는 총 토큰 발행량과 폐기랑, 유통량을 계산할 수 있다.
- 토큰 발행과 폐기 시에는
safeTransferFrom
또는safeBatchTransferFrom
를 이용하기보다는 관례상 다른 함수를 따로 선언해서 사용한다.
[Backwards Compatibility]
- 토큰 전송에 관한 다른 표준도 고려하여 hybrid 방식의 전송 api 호출도 가능하도록 했다.
- supportsInterface(0x4e2312e0) 를 호출
- (true 이면)
onERC1155Received
oronERC1155BatchReceived
를 사용 - (NOT true 이면) 다른 표준을 고려한다.
- (true 이면)
- 다른 표준 방식으로 토큰이 전송되었더라도, ERC-1155 전송 이벤트가 발생되어야만 한다. 이는 ERC-1155 멀티토큰 방식의 전송에 따른 잔고 변화를 적절히 반영하기 위한 것이다.
- hybrid 방식보다는 하나의 표준만 따르는 것을 권장한다.
[Implements]
'BlockChain > Blockchains' 카테고리의 다른 글
비잔틴 장애 허용 문제 (0) | 2022.12.14 |
---|---|
[Klaytn] 합의알고리즘 (1) | 2022.12.14 |
[Hyperledger Fabric] 개념 정리 및 활용 프로젝트 예시 (0) | 2022.08.22 |
EIP-721: Non-Fungible Token Standard (0) | 2022.08.12 |
비트코인이란? (Bitcoin WhitePaper 정리) (0) | 2022.08.04 |