# [ERC5615] ERC1155で作られた全てのNFTを取得してみよう！

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

- URL: https://cardene.dev/articles/58d0e490df74dff38e76
- 公開日: 2023-07-08
- 更新日: 2023-07-08
- トピック: Blockchain
- タグ: ethereum, solidity, ブロックチェーン, nft

## はじめに

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

https://cryptogames.co.jp/

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

https://cryptospells.jp/

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

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

https://eips.ethereum.org/EIPS/eip-5615

## 概要

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

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

https://chaldene.net/erc1155

## 仕様

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との後方互換性を持つように設計されています。

https://docs.openzeppelin.com/contracts/4.x/api/token/erc1155#ERC1155Supply

## 実装

Openzeppelinでの実装コードです。

https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC1155/extensions/ERC1155Supply.sol

```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などからお気軽に質問してください！

[Twitter @cardene777](https://twitter.com/cardene777)

## 採用強化中！

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

https://www.wantedly.com/companies/cryptogames

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