はじめに

初めまして。 CryptoGamesというブロックチェーンゲーム企業でエンジニアをしている cardene(かるでね) です! スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。

代表的なゲームはクリプトスペルズというブロックチェーンゲームです。

今回はERC1155の拡張機能であるERC5615について解説していきます。

主に以下の記事をもとに解説していきます。

概要

ERC1155の拡張機能です。 ERC1155トークンに、与えられたトークンIDを持つトークンの数を取得するtotalSupply関数と、与えられたトークンIDの存在を確認するexists関数を追加します。

ERC1155nいついては以下の記事を参考にしてください。

仕様

ERC165インターフェースをサポートできるが、利用者はそれに依存してはならない。

javascript
interface ERC1155Supply is ERC1155 {
  function exists(uint256 id) external view returns (bool);

  function totalSupply(uint256 id) external view returns (uint256);
}

exists

特定のトークンIDが「存在する」、「存在しない」、「存在する可能性がある」を返す関数。 「存在する可能性がある」とは、まだ発行されていないがトークンIDとしては存在する状態。

引数
  • id
    • トークンID。
戻り値

特定のトークンIDが「存在するか」、「存在したか」、「存在する可能性があるか」。

totalSupply

特定のトークンIDのトークン数を返す関数。 存在しないトークンIDを指定した場合は0を返す。

引数
  • id
    • トークンID。
戻り値

指定したトークンIDの総供給量。

補足

ERC165を実装していません。 理由としては、このインターフェースは十分にシンプルで、既存の実装との互換性を損なう可能性があるからです。

totalSupplyとexists関数は、ERC721とERC20を参考に作られました。

totalSupplyは、トークンIDが存在しない場合でもリバートしません。 なぜなら、存在の確認のためにはexistsを使用すべきだからです(totalSupplyが0であっても、falseを返す可能性があります)。

existsは、totalSupplyがゼロになる以下の2つを区別するために使用されます。

  • 与えられたIDを持つトークンがまだ発行されていない。
  • 与えられたIDを持つトークンが一切発行されない。

後方互換性

OpenZeppelinのERC1155Supplyとの後方互換性を持つように設計されています。

実装

Openzeppelinでの実装コードです。

javascript
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC1155/extensions/ERC1155Supply.sol)

pragma solidity ^0.8.19;

import {ERC1155} from "../ERC1155.sol";

abstract contract ERC1155Supply is ERC1155 {
    mapping(uint256 => uint256) private _totalSupply;
    uint256 private _totalSupplyAll;

    function totalSupply(uint256 id) public view virtual returns (uint256) {
        return _totalSupply[id];
    }

    function totalSupply() public view virtual returns (uint256) {
        return _totalSupplyAll;
    }

    function exists(uint256 id) public view virtual returns (bool) {
        return totalSupply(id) > 0;
    }

    /**
     * @dev See {ERC1155-_update}.
     */
    function _update(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory values
    ) internal virtual override {
        super._update(from, to, ids, values);

        if (from == address(0)) {
            uint256 totalMintValue = 0;
            for (uint256 i = 0; i < ids.length; ++i) {
                uint256 value = values[i];
                // Overflow check required: The rest of the code assumes that totalSupply never overflows
                _totalSupply[ids[i]] += value;
                totalMintValue += value;
            }
            // Overflow check required: The rest of the code assumes that totalSupplyAll never overflows
            _totalSupplyAll += totalMintValue;
        }

        if (to == address(0)) {
            uint256 totalBurnValue = 0;
            for (uint256 i = 0; i < ids.length; ++i) {
                uint256 value = values[i];

                unchecked {
                    // Overflow not possible: values[i] <= balanceOf(from, ids[i]) <= totalSupply(ids[i])
                    _totalSupply[ids[i]] -= value;
                    // Overflow not possible: sum_i(values[i]) <= sum_i(totalSupply(ids[i])) <= totalSupplyAll
                    totalBurnValue += value;
                }
            }
            unchecked {
                // Overflow not possible: totalBurnValue = sum_i(values[i]) <= sum_i(totalSupply(ids[i])) <= totalSupplyAll
                _totalSupplyAll -= totalBurnValue;
            }
        }
    }
}

最後に

今回の記事では、ERC5615について解説してきました。 いかがだったでしょうか?

実行については今後追記していきたいと思います!

質問などがある方は以下のTwitterのDMなどからお気軽に質問してください!

採用強化中!

CryptoGamesでは一緒に働く仲間を大募集中です。

この記事で書いた自分の経験からもわかるように、裁量権を持って働くことができて一気に成長できる環境です。 「ブロックチェーンやWeb3、NFTに興味がある」、「スマートコントラクトの開発に携わりたい」など、少しでも興味を持っている方はまずはお話ししましょう!