[ERC4944] 1つのコントラクトで1つのNFTのみを管理する仕組みを理解しよう！

# はじめに

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

https://cryptogames.co.jp/

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

https://cryptospells.jp/

今回は、1つコントラクトで1つのNFTのみを管理する方法を提案している**ERC4944**についてまとめていきます！

:::note info
以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。
:::

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

:::note warn
**4944**は現在（2023年9月14日）では「**Draft**」段階です。
:::

# 概要

**ERC721**は、イーサリアムブロックチェーン上でユニークなデジタルアセットであるノンファンジブルトークン（NFT）を作成するための規格です。
今回提案されている規格を使用することで、1つのスマートコントラクトアドレスに対して唯一のNFTを関連付けることができます。

:::note info
**ERC721**コントラクトは、以下の特徴を持っています。

- **総供給量が1**
    - **ERC721**コントラクトで作成できるNFTの数が1つだけであることを意味します。
    - 他のトークン規格（例：**ERC20**）では、複数のトークンを発行できますが、**ERC721**では各NFTが一意であるため、1つのコントラクトからしか発行できません。
- **標準機能**
    - **ERC721**コントラクトには、NFTを所有者間で転送する機能、特定のNFTの存在を確認するための機能、NFTの現在の所有者を取得するための機能などが含まれています。
    - これらの標準機能により、NFTの発行、取引、管理が容易に行えます。
:::

# 動機

提案されている変更によって、**ERC721**は通常複数の異なるトークン（NFT）を1つのコントラクトから発行でき機能から、1つのコントラクトから1つのNFTだけを発行できるように制限されることになります。
この変更により、NFTが独自のアイデンティティとコントラクトアドレスを持つことができ、トークンIDとコントラクトアドレスの組み合わせを使用せずに、NFT自体でコントラクトを一意に識別できるようになります。
また、この変更により、**ERC998**と呼ばれる別の規格を必要とせずに、NFTが自動的にコンポーザブルトークンの機能を提供できるようになります。

この変更の重要なポイントは、1つのコントラクトから複数の異なるトークンを発行することができなくなることです。代わりに、各コントラクトは単一のNFTの発行に限定されます。
これにより、各NFTは唯一無二の存在となり、それ自体がコントラクトアドレスを一意に識別します。

この変更により、NFTは発行時に他の**ERC20**トークンを保有することができ、そのトークンを使用して自己保存や他のNFTとのトレードなどの操作を行うことができます。
これは、NFTが自己管理と自己決定を行う「自律エージェント」として機能する可能性を示唆しています。
最初のユースケースは、NFTの価値を保全することであり、NFTが独自の予算（**ERC20**トークン）を持つことで、自己保存を自動化できるようになります。

# 仕様

### コンストラクタ
コントラクトのコンストラクタは、コントラクトがデプロイされた時に、NFT（トークン）を発行します。
これは、コントラクトが作成されたときに、そのコントラクトに1つだけのNFTが自動的に生成され、そのNFTの所有権がコントラクトの所有者に設定されることを意味します。
この変更により、コントラクトはデプロイ時にトークンを発行し、その後の発行を防ぎます。

### mint関数
NFTが発行された後、`mint`関数を実行することはできません。
これにより、コントラクトは1つのトークンのみを保持し、追加のトークンの発行を防ぎます。

### tokenTransfer関数
この関数はコントラクトの所有者によって呼び出され、コントラクトが所有する**ERC20**トークンを他のアカウントに送信するための機能を提供します。
また、この関数を介してコントラクトが受け取った**ERC20**トークンをコントラクトの所有者が使用できるようになります。
これにより、コントラクトは自身が保持している**ERC20**トークンを管理し、必要に応じて取引を行えます。

# 補足

今回提案している規格では**ERC721**コントラクトとのの互換性を維持しています。

# 後方互換性

特に問題なし。

# 参考実装

コントラクトに変数`_minted`を追加します。
この変数は既にトークンがミントされているかの判定に使用されます。

```javascript
    bool private _minted;
```

コンストラクタで、最初のトークンを`mint`にし、`_minted`変数を`true`に設定します。

```javascript
    constructor(string memory name, string memory symbol, string memory base_uri) ERC721(name, symbol) {
        baseUri = base_uri;
        mint(msg.sender,0);
        _minted = true;
    }
```

NFTプロパティ（例えば**ERC20**）と相互作用する機能を追加します。

```javascript
    modifier onlyOwner() {
        require(balanceOf(msg.sender) > 0, "Caller is not the owner of the NFT");
        _;
    }

    function transferTokens(IERC20 token, address recipient, uint256 amount) public virtual onlyOwner {
        token.transfer(recipient, amount);
    }
	
    function balanceTokens(IERC20 token) public view virtual returns (uint256) {
        return token.balanceOf(address(this));
    }
```

### transferTokens

**ERC20**トークンのコントラクトアドレスを受け取り、対象のコントラクト内の`transfer`関数を実行して`recipient`に指定されたアドレスに`amount`分の**ERC20**トークンを送っています。

### balanceTokens

**ERC20**トークンのコントラクトアドレスを受け取り、対象のコントラクト内の`balanceOf`関数を実行してこのコントラクトが**ERC20**トークンをどれくらい保有しているか確認しています。

# セキュリティ考慮事項

特になし。

# 引用

Víctor Muñoz (@victormunoz), Josep Lluis de la Rosa (@peplluis7), Andres El-Fakdi (@Bluezfish), "ERC-4944: Contract with Exactly One Non-fungible Token [DRAFT]," Ethereum Improvement Proposals, no. 4944, March 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-4944.

# 最後に

今回は「1つコントラクトで1つのNFTのみを管理する方法を提案している**ERC4944**」についてまとめてきました！
いかがだったでしょうか？

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

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

他の媒体でも情報発信しているのでぜひ他も見ていってください！

https://chaldene.net/

https://zenn.dev/heku

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58