무지개곰
article thumbnail
Published 2023. 5. 18. 14:59
[Solidity] ERC-1155란? BlockChain/solidity
반응형

ERC-1155는 이더리움 블록체인에서 다중 자산을 관리하는 표준입니다. 이 표준은 이더리움 기반의 스마트 컨트랙트를 사용하여 개발자가 게임 아이템, 디지털 자산, 토큰화된 자산 등을 효율적으로 관리할 수 있게 해 줍니다.

1. ERC-1155 표준

ERC_1155는 게임 개발자뿐만 아니라 다양한 분야에서 자산을 토큰화하고 거래할 수 있는 유연한 토큰 관의 표준입니다. 이러한 기능을 구현하기 위하여 아래의 함수가 반드시 포함되어야 합니다.

<java />
balanceOf(address _owner, uint256 _id) balanceOfBatch(address[] _owners, uint256[] _ids) setApprovalForAll(address _operator, bool _approved) isApprovedForAll(address _owner, address _operator) safeTransferFrom(address _from, address _to, uint256 _id, uint256 _amount, bytes _data) safeBatchTransferFrom(address _from, address _to, uint256[] _ids, uint256[] _amounts, bytes _data)

balanceOf : _onwer가 보유한 _id 자산의 잔액을 반환

balanceOfBatch : address배열로 받은 _owners에 포함된 주소에 대하여 각 주소가 보유한 _ids의 잔액을 조회하고 배열에 담아 반환

setApprovalForAll : _operator에 대한 _onwer의 모든 자산에 대한 인출 권한을 부여하거나 취소합니다.

isApprovaedForAll : _operator가 _onwer의 자산에 대한 인출 권한을 가지고 있는지 여부를 반환

safeTransferFrom : _from에서 _to로 _amount만큼의 _id에 해당하는 자산을 전송

safeBatchTransferFrom : _from에서 _to로 _ids에 해당하는 자산들을 _amounts에 맞게 전송합니다.

 

또한 위의 함수 이외에도 사용되는 이벤트는 아래와 같습니다.

<java />
TransferSingle(address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _amount) TransferBatch(address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _amounts) ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved) URI(string _value, uint256 indexed _id)

한 가지 자산을 전송할 때는 TransferSingle, 여러 가지 자산을 전송할 때는 TransferBatch, 권한을 승인하는 경우 ApprovalForAll, 자산의 URI가 업데이트되는 경우 URI 이벤트가 발생됩니다.

 

위의 내용을 통하여 interface를 작성한다면 아래와 같습니다.

<java />
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IERC1155 is IERC165 { 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); function balanceOf(address account, uint256 id) external view returns (uint256); function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory); function setApprovalForAll(address operator, bool approved) external; function isApprovedForAll(address account, address operator) external view returns (bool); 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; }

2. mint와 burn

ERC-20, ERC-721과 달리 ERC-1155는 mint와 burn을 제공하지 않습니다. mint와 burn 대신 safeTransferFrom 및 safeBatchTransferFrom과 같은 함수를 이용하여 자산을 생성하지 않고, 다른 주소로 전송하거나 이동시킬 수 있습니다.

 

*Openzeppelin에서 제공하는 ERC-1155의 경우 _mint, _mintBatch, _burn, _burnBatch 함수가 존재합니다.

 

_mint

<java />
function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal virtual { require(to != address(0), "ERC1155: mint to the zero address"); address operator = _msgSender(); uint256[] memory ids = _asSingletonArray(id); uint256[] memory amounts = _asSingletonArray(amount); _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); _balances[id][to] += amount; emit TransferSingle(operator, address(0), to, id, amount); _afterTokenTransfer(operator, address(0), to, ids, amounts, data); _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data); }

_mintBatch

<java />
function _mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) internal virtual { require(to != address(0), "ERC1155: mint to the zero address"); require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); address operator = _msgSender(); _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); for (uint256 i = 0; i < ids.length; i++) { _balances[ids[i]][to] += amounts[i]; } emit TransferBatch(operator, address(0), to, ids, amounts); _afterTokenTransfer(operator, address(0), to, ids, amounts, data); _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data); }

_burn

<java />
function _burn(address from, uint256 id, uint256 amount) internal virtual { require(from != address(0), "ERC1155: burn from the zero address"); address operator = _msgSender(); uint256[] memory ids = _asSingletonArray(id); uint256[] memory amounts = _asSingletonArray(amount); _beforeTokenTransfer(operator, from, address(0), ids, amounts, ""); uint256 fromBalance = _balances[id][from]; require(fromBalance >= amount, "ERC1155: burn amount exceeds balance"); unchecked { _balances[id][from] = fromBalance - amount; } emit TransferSingle(operator, from, address(0), id, amount); _afterTokenTransfer(operator, from, address(0), ids, amounts, ""); }

_burnBatch

<java />
function _burnBatch(address from, uint256[] memory ids, uint256[] memory amounts) internal virtual { require(from != address(0), "ERC1155: burn from the zero address"); require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); address operator = _msgSender(); _beforeTokenTransfer(operator, from, address(0), ids, amounts, ""); for (uint256 i = 0; i < ids.length; i++) { uint256 id = ids[i]; uint256 amount = amounts[i]; uint256 fromBalance = _balances[id][from]; require(fromBalance >= amount, "ERC1155: burn amount exceeds balance"); unchecked { _balances[id][from] = fromBalance - amount; } } emit TransferBatch(operator, from, address(0), ids, amounts); _afterTokenTransfer(operator, from, address(0), ids, amounts, ""); }

mint, burn과 Batch의 차이는 한 가지 자산을 mint 혹은 burn 하는지 여러 가지 자산을 다루는지 차이로 배열로 정보를 받아 for문을 이용하는 차이 이외에 큰 차이는 없습니다.


3. _beforeTokenTransfer과 _aftreTokenTransfer이란?

mint와 burn함수를 보면 _beforeTokenTransfer과 _afterTokenTransfer이 있습니다. ERC 표준에 포함된 함수가 아닌 사용자 정의 로직을 실행하기 위한 훅(hook)으로 사용됩니다.

 

주요 사용 사례는 다음과 같습니다.

 

1. 전송 제약사항: `_beforeTokenTransfer` 함수를 사용하여 토큰 전송 시 발송자와 수신자의 주소, 토큰 ID 등에 대한 추가적인 제약사항을 검사할 수 있습니다. 예를 들어, 특정 주소에 대한 전송을 제한하거나 전송 조건을 체크할 수 있습니다.

 

2. 이벤트 발행: `_beforeTokenTransfer` 함수를 사용하여 토큰 전송 이벤트 전에 사용자에게 알림을 보내거나 이벤트를 발행할 수 있습니다. 예를 들어, 토큰 전송에 대한 로그를 생성하거나, 특정 이벤트가 발생했음을 통지할 수 있습니다.

 

3. 추가 작업 수행: `_beforeTokenTransfer` 함수를 사용하여 토큰 전송 이전에 추가적인 작업을 수행할 수 있습니다. 예를 들어, 수신자 컨트랙트에 대한 초기화 작업을 수행하거나, 특정 데이터를 업데이트할 수 있습니다.

 

`_beforeTokenTransfer` 함수는 ERC-1155 컨트랙트의 내부 함수로, 토큰 전송 이전에 호출되는 지점을 제공합니다. 이 함수를 커스터마이즈 하여 원하는 로직을 추가할 수 있습니다. 구체적인 동작은 개별적인 ERC-1155 구현에 따라 다르며, 사용자 정의 함수로서 이벤트를 통해 투명하게 작동하도록 설계됩니다.

반응형

'BlockChain > solidity' 카테고리의 다른 글

[Solidity] ERC-2771이란? (ERC-2771Context란?)  (0) 2023.07.02
[Solidity] EIP-712란?  (0) 2023.07.02
[Solidity] ERC20 Permit이란?  (0) 2023.06.17
[Solidity] ERC-721이란?  (0) 2023.05.18
[Solidity] ERC20이란? (ERC20 토큰 발행)  (0) 2023.05.14
profile

무지개곰

@무지개곰

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!