[멋쟁이 사자처럼 블록체인 스쿨 3기] 23-05-30

임형석·2023년 5월 30일
0

Solidity


ERC-1155

ERC-1155 openzeppelin

ERC-1155는 대체 가능 아이템(ERC-20 토큰 아이템)과 대체 불가능 아이템(ERC-721 토큰 아이템)의 혼합 거래를 가능하게 한다.

ERC-1155에서는 단 하나의 트랜잭션으로 다수의 수신자에게 원하는 수량만큼의 아이템을 전송할 수 있다.

기존의 ERC-20과 ERC-721 토큰의 거래는 매우 비효율적인 방식으로 이뤄졌다. 예를 들어 마트에서 원하는 물건을 고르기 위해 장바구니에 우유와 과자, 계란 등 10개의 물건을 담았다. 이때, 장바구니에 담긴 물건을 각자 따로따로 계산해야 하는 경우 카드를 긁어 우유를 사고 영수증을 받고, 다시 과자에 대해 카드를 긁고 영수증을 받는 방식으로 10번의 결제를 하고 그만큼의 영수증을 받는 식이다.

하지만 ERC-1155에서는 단 하나의 트랜잭션으로 한 명 또는 다수의 수신자에게 원하는 만큼의 항목을 보낼 수 있다.

이렇게 하나의 트랜잭션으로 거래를 할 시, 가스비를 줄일 수 있다는 장점이 있다.

ERC-1155 의 중요한 코드 몇가지를 살펴보자.


setUri

ERC-1155 의 컨트랙트에는 constructor 로 uri 를 넣게 되어있다.

uri 는 url 과 비슷한 의미로 사용한다고 보고 넘어가면 될 것같다..

    constructor(string memory uri_) {
        _setURI(uri_);
    }

    function _setURI(string memory newuri) internal virtual {
        _uri = newuri;
    }

constructor 로 입력한 uri 는 json 파일을 올려둔 주소를 따라가고, json 파일에는 토큰의 메타데이터를 업로드 해두어 uri 가 자동으로 토큰에 대한 메타데이터를 읽어올 수 있도록 한다.

opensea 와 같은 NFT 거래 사이트에서는, 이렇게 사이트 자체적으로 메타데이터를 읽어와 화면에 띄워주고 거래를 중계해주는 것이다.


mapping

맵핑부분에서는 ERC-20 과 ERC-721 의 모습과는 다르게, 이중 맵핑을 사용한다.

ERC-1155 에서는, 여러 종류의 토큰을 여러개 발행이 가능하기에

uint => address => uint 형태로 balance 를 반환 받게된다.

토큰id =>balance address => balance 의 형태라고 볼 수 있다.

    // Mapping from token ID to account balances
    mapping(uint256 => mapping(address => uint256)) private _balances;

ERC-721 의 권한 부분을 그대로 가져온 모습이다. ERC-1155 에도 권한기능이 있다.

    // Mapping from account to operator approvals
    mapping(address => mapping(address => bool)) private _operatorApprovals;

balanceOfBatch

input 값으로 주소, 토큰id 를 여러개 받아 balance 값을 반환하는 함수이다.

function balanceOfBatch(
        address[] memory accounts,
        uint256[] memory ids
    ) public view virtual override returns (uint256[] memory) {
        require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");

        uint256[] memory batchBalances = new uint256[](accounts.length);

        for (uint256 i = 0; i < accounts.length; ++i) {
            batchBalances[i] = balanceOf(accounts[i], ids[i]);
        }

        return batchBalances;
    }

array 형태로 input 을 받고있으며, require 로 주소와 토큰id 의 길이가 같아야만 balance 값을 받을 수 있다.

for 문을 이용해서 배열을 하나씩 확인해 balanceOf 함수를 실행시켜 값을 가져온다.


safeTransferFrom

ERC-1155 의 토큰을 다른주소로 전송하는 함수이다.

 function _safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) internal virtual {
        require(to != address(0), "ERC1155: transfer to the zero address");

        address operator = _msgSender();
        uint256[] memory ids = _asSingletonArray(id);
        uint256[] memory amounts = _asSingletonArray(amount);

        _beforeTokenTransfer(operator, from, to, ids, amounts, data);

        uint256 fromBalance = _balances[id][from];
        require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
        unchecked {
            _balances[id][from] = fromBalance - amount;
        }
        _balances[id][to] += amount;

        emit TransferSingle(operator, from, to, id, amount);

        _afterTokenTransfer(operator, from, to, ids, amounts, data);

        _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
    }

input 값으로 4개를 받고있으며,

보내는사람, 받는사람, 토큰id, 보낼토큰 갯수 이다.

보내는 사람의 balance 와 보낼 토큰 갯수를 확인.

보내는 사람의 balance 에서 보낼 토큰 갯수만큼 빼고,

받는 사람의 balance 의 받는 토큰 갯수만큼을 늘린다.

그리고 _doSafeTransferAcceptanceCheck 함수를 마지막으로 실행하는데,

이 함수는, 이름 그대로 ERC-1155 토큰을 받을 Reciever 의 주소를 확인하고, 토큰을 받을 수 없는 주소라면 revert 시키는 함수이다.


WEB3 게임에서 게임아이템을 토큰화 시킨다면 ERC-1155 를 사용하면 ERC-721 보다 더 효율적으로 만들 수 있겠다..

예를 들어,
검 = tokenid 1, 10개
활 = tokenid 2, 5개
총 = tokenid 3, 3개

이렇게 여러개의 장비를 ERC-1155 를 이용해 토큰화 시킨다면 더 많은 것을 구현할 수 있을 것 같다..

0개의 댓글