[ERC7015] NFTクリエイターと作品の帰属を明確にする署名メカニズムを理解しよう！

# はじめに

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

https://cryptogames.co.jp/

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

https://cryptospells.jp/

今回は、NFTクリエイターが、自分の作品に関する帰属を明確にするための署名メカニズムを提案している**ERC7015**についてまとめていきます！

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

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

他にも様々なEIPについてまとめています。

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4

# 概要

このEthereum Improvement Proposal（EIP）は、Non-Fungible Token（NFT）標準（**ERC721**、**ERC1155**）におけるクリエーター帰属問題を解決することを目的としています。
この提案の主な目標は、NFTの作成者がその作品の正当なクリエーターであることを確実に証明し、NFTプラットフォームが正確にクリエーターを帰属できるようにすることです。
この方法は、特にデジタルアートやコレクタブルアイテムの世界で重要な問題である、NFTの不正コピーと偽造を防ぐのに役立ちます。

:::note info
**ERC721**については以下の記事を参考にしてください。
:::

https://chaldene.net/erc721

:::note info
**ERC1155**については以下の記事を参考にしてください。
:::

https://chaldene.net/erc1155

### 解決方法の概要

このEIPでは、NFTのクリエーターがNFTの作成に必要なパラメータ（例えば、NFTのメタデータやその他の関連情報）をハッシュ化し、このハッシュに対してデジタル署名を行う仕組みを提案しています。
このデジタル署名は、クリエーターのプライベートキーを使用して生成され、NFTの真正性とクリエーターの身元を証明するためのものです。

- **NFTメタデータのハッシュ化**
    - メタデータとその他の必要な情報はハッシュ関数を通じて一意のハッシュ値に変換されます。
    - このハッシュは、データの完全性を保証し、変更があった場合に検出可能にします。
- **デジタル署名**
    - クリエーターはプライベートキーを使用してハッシュに署名します。
    - この署名は、データがクリエーターによって承認され、以降変更されていないことを証明します。
- **署名とパラメータの検証**
    - NFTがブロックチェーンにデプロイされる時、署名されたパラメータと署名自体がトランザクションで検証されます。
    - これにより、NFTプラットフォームはクリエーターを正確に識別し、帰属を決定できます。

### 利点

- **クリエーター認証**
    - この方法により、NFTのクリエーターは自身の作品に対して確固たる所有権と帰属を持つことができます。
- **不正防止**
    - デジタル署名を通じて、不正なコピーまたは偽造が大幅に難しくなります。
- **透明性の向上**
    - NFTの真正性とクリエーターの身元がブロックチェーン上で明確に追跡できるため、市場全体の信頼性が向上します。

### 実装における考慮事項

- **セキュリティ**
    - クリエーターのプライベートキーの安全な管理が必須です。
    - プライベートキーが漏洩すると、クリエーターの身元が偽装される可能性があります。
- **ユーザビリティ**
    - クリエーターがこのプロセスを簡単に実行できるように、ユーザーフレンドリーなインターフェースの提供が重要です。

この提案は、NFTのクリエーターと消費者双方にとって信頼性と安全性を高める重要なステップを提供します。
ブロックチェーン技術の進化とともに、このような改善がデジタルアセットの未来を形作る鍵となるでしょう。

# 動機

現行のNFTプラットフォームでは、スマートコントラクトをデプロイするウォレットがNFTのクリエーターであると仮定されています。
しかし、デプロイメントトランザクションを送信するウォレットが異なる場合に、クリエーターの誤帰属が発生する問題があります。
これは、コントラクトウォレットアカウントの使用や、最初のコレクターがNFTコントラクトをデプロイするなどの新しいコントラクトデプロイメント戦略を取り入れている場合によく起こります。
提案されているこのEIPは、クリエーターがNFTの作成に必要なパラメータを署名し、どのウォレットでもデプロイメントトランザクションを送信できるようにすることで、クリエーターが誰であるかを検証可能な方法で示すことができる解決策を目指しています。

### 主な問題点

- **クリエーター誤帰属**
    - 現行のシステムでは、NFTを作成するためのスマートコントラクトをデプロイするウォレットが、そのNFTのクリエーターと自動的に見なされます。
    - これは、特に代理人やプラットフォームを通じて作品を公開するクリエーターにとって、所有権とクリエーターとしての帰属が正確に反映されない可能性があります。

- **コントラクトウォレットと新しいデプロイメント戦略**
    - コントラクトウォレットや、最初のコレクターがNFTコントラクトをデプロイするなどの新しい戦略の使用は、クリエーターとデプロイメントを行うウォレット間の直接的なリンクを欠くため、誤帰属の問題をさらに複雑にします。

### 解決策

この提案は、クリエーターが直接NFTの作成に必要なパラメータ（メタデータ、アートワークのハッシュ値など）を署名することで、NFTのクリエーターとしての帰属を明確にする方法を提供します。
これにより、どのウォレットからでもデプロイメントトランザクションを送信することが可能となり、同時にクリエーターが誰であるかを確実に検証できるようになります。
このプロセスは以下のステップを含みます。

1. **署名の作成**
    - クリエーターはNFT作成に必要なパラメータを含むデータをハッシュ化し、そのハッシュに対して自分のプライベートキーで署名します。
2. **トランザクションの送信**
    - 署名されたデータと共に、任意のウォレットからデプロイメントトランザクションがブロックチェーンに送信されます。
3. **検証と帰属**
    - トランザクションがブロックチェーンに記録された後、署名は公開キーを用いて検証され、クリエーターの身元が確認されます。
    - この情報はNFTの帰属を正確に反映するために使用されます。

### 利点

このアプローチは、NFTクリエーターの正確な帰属を確保し、誤解を招く可能性のある現行のシステムを改善します。
また、NFTの真正性を確認し、市場全体の信頼性を高めることにも寄与します。
クリエーターは自分の作品に対する明確な所有権と帰属権を持つことができ、消費者は購入するNFTが正当なクリエーターによって作成されたものであることを確信できます。

# 仕様

このEthereum Improvement Proposal（EIP）によって提案されたNFT Creator Attribution拡張機能は、**ERC721**および**ERC1155**準拠のコントラクトが、コントラクト作成時にNFTクリエーターを定義する標準イベントを発行することを可能にするものです。
このイベントを通じて、NFTクリエーターの正確な帰属がブロックチェーン上に記録され、確認可能となります。

### コントラクトアドレスの事前計算

この提案が利用している重要な特性の一つは、コントラクトアドレスがコントラクトがデプロイされる前に事前に計算できるという点です。
Ethereumにおいては、コントラクトアドレスはデプロイを行うアカウント（外部所有アカウント、EOA）と、そのアカウントのトランザクション数（`nonce`）に基づいて生成されます。
この特性を利用することで、NFTクリエーターは自らの作品に関連付けられるコントラクトのアドレスを事前に知ることができ、それを署名の一部として使用することが可能になります。

### コントラクトのデプロイ

NFTコントラクトが他のコントラクト（ファクトリー）を介して、または外部所有アカウント（EOA）を介してデプロイされるかに関わらず、この仕様を使用してクリエーターを正確に帰属させることができます。
このプロセスは、NFTクリエーターが自身の作品をどのようにデプロイするかに柔軟性を提供し、同時にクリエーターの帰属情報を正確かつ透明に保持します。

### 実装方法

1. **イベントの定義**
    - **ERC721**または**ERC1155**準拠のコントラクトは、コントラクトが作成される時にNFTクリエーターを定義するイベントを発行する拡張機能を実装することができます。
    - このイベントは、コントラクトがブロックチェーン上にデプロイされる瞬間にクリエーター情報を公開し、永続化します。

2. **クリエーターの署名**
    - コントラクトアドレスの事前計算機能を利用して、クリエーターはコントラクトのデプロイに必要な情報を署名し、これをデプロイメントプロセスの一部として提供します。
    - これにより、コントラクトがどのようにしてデプロイされても、クリエーターの帰属が確実に行われます。

この拡張機能により、NFTのクリエーターは自らの作品に関してより大きな制御を持つことができ、クリエーター帰属の問題を解決するための標準化された方法を提供します。
これは、NFTの透明性と信頼性を高める上で重要なステップです。

## 署名メカニズム

このEIP（Ethereum Improvement Proposal）では、NFT（Non-Fungible Token）クリエーターの帰属を確定するための署名機構が提案されています。
この署名機構は、**EIP712**互換のメッセージによってクリエーターの同意が与えられることを利用しています。
**EIP712**は、イーサリアム上で安全に型付きメッセージを署名するための標準です。
この提案で要求されるすべての署名は、定義された全てのフィールドを含む必要があり、署名される構造体はトークンの作成方法を定義する任意のデータを含むことができます。
この構造体は、適切な**EIP712**ドメインを使用して**EIP712**互換の形式でハッシュ化される必要があります。

:::note info
**EIP712**については以下の記事を参考にしてください。
:::

https://qiita.com/cardene/items/f54bc85cb66de5a54257

### 署名機構の例

提案文に示された例では、`TokenCreation`という構造体が導入されています。
この構造体は、トークンが作成される時に必要な`metadataUri`（メタデータのURI）、`price`（価格）、および`nonce`（一意性を保証するための数値）というフィールドを含んでいます。
この構造体は、NFTの作成に必要な具体的なパラメータを定義する一例であり、これを`structHash`にエンコードして署名することで、クリエーターがそのトークンの作成を承認したことを証明します。

### EIP712の利点

- **型付きメッセージ**
    - **EIP712**は型付きデータを使用することで、署名されたメッセージの内容が明確になり、より安全なトランザクションが可能になります。
- **ユーザーの理解**
    - 署名するデータの構造が明確であるため、ユーザーは自分が署名している内容をより理解しやすくなります。
- **セキュリティ**
    - **EIP712**ドメインと型付きメッセージの使用は、フィッシング攻撃などのセキュリティリスクを軽減します。

### 実装の意味

この署名機構を採用することにより、NFTのクリエーターは、NFTの作成とそれに関連する条件（メタデータのURI、価格など）に同意したことを確実に証明できます。
また、この情報はブロックチェーン上で検証可能な形で保存されるため、NFTの真正性やクリエーターの帰属を明確にするのに役立ちます。
これは、NFT市場における信頼性と透明性を高める重要なステップです。

```ts
// example struct that can be encoded in `structHash`; defines that a token can be created with a metadataUri and price:

struct TokenCreation {
  string metadataUri;
  uint256 price;
  uint256 nonce;
}
```

## 署名検証

このEIPでは、NFTクリエーターの帰属を確立するために、署名検証プロセスが必要とされています。
この検証は、デプロイされるNFTコントラクトによって行われ、デプロイメントトランザクションの間にNFTコントラクトによって発生するイベントを通じて行われます。
このイベントは、署名されたダイジェストを再構築し、指定されたクリエーターと一致することを確認するために必要なすべてのフィールドを含んでいます。
イベント名は`CreatorAttribution`で、以下のフィールドを含みます。

- `structHash`
    - NFTコントラクトのデプロイに必要な情報をハッシュ化したもの（例: 名前、シンボル、管理者など）。
    - これは**EIP712**の`hashStruct`標準の定義における`hashStruct`の値に相当します。
- `domainName`
    - 署名の検証を行うコントラクトのドメイン名（**EIP712**署名検証用）。
- `version`
    - 署名を検証するコントラクトのバージョン（**EIP712**署名検証用）。
- `creator`
    - クリエーターのアカウント。
- `signature`
    - クリエーターの署名。

イベント定義は以下の通りです。

```solidity
event CreatorAttribution(
  bytes32 structHash,
  string domainName,
  string version,
  address creator,
  bytes signature
);
```

**EIP712**署名には`chainId`パラメータが必要ですが、トランザクションデータを通じて推測できるため、イベントからは省略されています。
同様に、署名検証のための`verifyingContract`パラメータも省略されています
これは、トランザクションの`emitter`フィールドと同一でなければならないためです。
`emitter`はトークンでなければなりません。

プラットフォームは、発生したパラメータを使って署名ダイジェストを再構築し、署名パラメータから署名者を回復することにより、クリエーター帰属の妥当性を検証できます。
回復された署名者は、イベントとして出力されているクリエーターと一致しなければなりません。
`CreatorAttribution`イベントが存在し、署名が正しく検証された場合、トランザクションを提出したアカウントではなく、クリエーターに帰属が与えられなければなりません。

このシステムは、クリエーターが自身の作品に対する正当な帰属を受けることを保証し、NFT市場の透明性と信頼性を向上させることを目的としています。

# 参考実装

```ts
pragma solidity 0.8.20;
import "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/interfaces/IERC1271.sol";

abstract contract ERC7015 is EIP712 {
  error Invalid_Signature();
  event CreatorAttribution(
    bytes32 structHash,
    string domainName,
    string version,
    address creator,
    bytes signature
  );

  /// @notice Define magic value to verify smart contract signatures (ERC1271).
  bytes4 internal constant MAGIC_VALUE =
    bytes4(keccak256("isValidSignature(bytes32,bytes)"));

  function _validateSignature(
    bytes32 structHash,
    address creator,
    bytes memory signature
  ) internal {
    if (!_isValid(structHash, creator, signature)) revert Invalid_Signature();
    emit CreatorAttribution(structHash, "ERC7015", "1", creator, signature);
  }

  function _isValid(
    bytes32 structHash,
    address signer,
    bytes memory signature
  ) internal view returns (bool) {
    require(signer != address(0), "cannot validate");

    bytes32 digest = _hashTypedDataV4(structHash);

    // if smart contract is the signer, verify using ERC-1271 smart-contract
    /// signature verification method
    if (signer.code.length != 0) {
      try IERC1271(signer).isValidSignature(digest, signature) returns (
        bytes4 magicValue
      ) {
        return MAGIC_VALUE == magicValue;
      } catch {
        return false;
      }
    }

    // otherwise, recover signer and validate that it matches the expected
    // signer
    address recoveredSigner = ECDSA.recover(digest, signature);
    return recoveredSigner == signer;
  }
}
```

### `_validateSignature`

```javascript
function _validateSignature(
  bytes32 structHash,
  address creator,
  bytes memory signature
) internal {
  if (!_isValid(structHash, creator, signature)) revert Invalid_Signature();
  emit CreatorAttribution(structHash, "ERC7015", "1", creator, signature);
}
```

**概要**

署名が有効であるかを検証し、有効であれば`CreatorAttribution`イベントを発行する関数。

**詳細**

この関数は、指定された`structHash`、`creator`、および`signature`が有効であるかどうかを検証する内部関数です。
署名が無効である場合、`Invalid_Signature`エラーを発生させます。
署名が有効である場合、`CreatorAttribution`イベントを発行して、NFTクリエーターの帰属を記録します。
このプロセスは、NFTクリエーターが自身の作品に対して署名を提供することによって、その作品の真の作成者であることを証明するのに役立ちます。

**引数**

- `structHash`
    - デプロイするNFTコントラクトのためのハッシュ化された情報。
- `creator`
    - クリエーターのアカウントアドレス。
- `signature`
    - クリエーターによる署名。

### `_isValid`

```javascript
function _isValid(
  bytes32 structHash,
  address signer,
  bytes memory signature
) internal view returns (bool) {
  require(signer != address(0), "cannot validate");

  bytes32 digest = _hashTypedDataV4(structHash);

  if (signer.code.length != 0) {
    try IERC1271(signer).isValidSignature(digest, signature) returns (
      bytes4 magicValue
    ) {
      return MAGIC_VALUE == magicValue;
    } catch {
      return false;
    }
  }

  address recoveredSigner = ECDSA.recover(digest, signature);
  return recoveredSigner == signer;
}
```

**概要**

与えられた署名が指定された署名者によるものであるか検証する関数。

**詳細**

この関数は、`structHash`と`signature`から得られる署名が指定された`signer`によって行われたものであるかを検証します。
署名者がスマートコントラクトの場合は、**ERC1271**の`isValidSignature`メソッドを使用して署名を検証します。
それ以外の場合は、`ECDSA.recover`メソッドを使用して署名から署名者を復元し、その署名者が期待される`signer`と一致するかを確認します。
署名が有効であれば`true`を、無効であれば`false`を返します。

:::note info
**ERC1271**については以下の記事を参考にしてください。
:::

https://qiita.com/cardene/items/da237b1b8cc185491512

**引数**

- `structHash`
    - 署名対象となる構造体のハッシュ。
- `signer`
    - 署名を行ったと想定されるアカウントアドレス。
- `signature`
    - 検証する署名。

**戻り値**

- `bool`
    - 署名が有効である場合は`true`、そうでない場合は`false`。


# 補足

このEIP（Ethereum Improvement Proposal）は、クリエーター帰属の標準化を通じて、プラットフォームが暗黙の仮定に依存せずにクリエーターの帰属を確認できるようにすることを目的としています。
クリエーター帰属に関する標準を確立することで、コントラクトのデプロイメントの複雑さを管理しつつ、正確なオンチェーンのクリエーター情報を保持することができます。
このアプローチは、NFTクリエーターの特定方法をより信頼性が高く透明性のあるものにし、NFTエコシステムの参加者間の信頼を育むことを保証します。

**ERC5375**も同様の問題を解決しようと試みていますが、オフチェーンデータは後方互換性を向上させるものの、NFTにとって重要な正確かつ不変のクリエーター帰属を保証することは不可欠です。
クリエーター帰属に関する標準化されたオンチェーン方法は、本質的により信頼性が高く、安全です。

:::note info
**ERC5375**については以下の記事を参考にしてください。
:::

https://qiita.com/cardene/items/ff4ed253fc6a793f6643

この提案とは対照的に、**ERC5375**は、特に新しい使用例において一般的な実践である、NFTコレクション内のすべてのトークンのクリエーターを指定することを容易にしません。

この提案と**ERC5375**は、アドレスベースのクリエーター帰属に関して同様の制限を共有しています。

この標準は、特定のアドレスが同意を提供したことを検証するプロトコルを定義しています。
しかし、そのアドレスが期待されるクリエーターに対応していることを保証するものではありません。
アドレスとそれに背後にあるエンティティとの間のリンクを証明することは、この文書の範囲を超えています。

要するに、このEIPはオンチェーンでクリエーターの帰属を標準化することにより、クリエーター帰属の確認をより信頼性高く透明なものにします。
これは、クリエーターが自らの作品に対する帰属を確実に主張できるようにし、NFTマーケットプレイスやプラットフォームがクリエーターの情報を正確に管理し、ユーザーに提供することを容易にします。
しかし、アドレスと実際のクリエーターとの直接的な関連付けを証明することは、この標準の範囲外であり、それぞれのケースで追加の検証が必要になる場合があります。

# 互換性

このEIP（Ethereum Improvement Proposal）が提案する標準では、NFTのデプロイメントトランザクション時に特定のイベント（`CreatorAttribution`イベント）を発行することが必須とされています。
このイベントは、NFTのクリエーターを識別し、クリエーター帰属情報をオンチェーン上に記録するためのものです。
イベントには、NFTのクリエーターに関する情報や、クリエーターによる署名などが含まれ、これにより、クリエーターの帰属が確認可能となります。

この要件により、すでにデプロイされている（既存の）NFTは、この標準を後から実装することができません。
なぜなら、この標準を実装するためには、NFTのデプロイメントトランザクション自体に`CreatorAttribution`イベントの発行が含まれている必要があるからです。
既存のNFTはすでにブロックチェーン上にデプロイされており、そのデプロイメントトランザクションは完了しているため、後からこのイベントを追加することは不可能です。

この制約は、この標準が新しくデプロイされるNFTや、将来的に作成されるNFTコレクションに対してのみ適用可能であることを意味します。
既存のNFTコレクションやアートワークにこの標準に基づくクリエーター帰属の確認方法を適用するためには、新たにNFTをデプロイし直すなどの手段を取る必要があります。
これは、NFTクリエーターにとって重要な考慮事項であり、クリエーター帰属の透明性と検証可能性を向上させるための新しいプロジェクトやコレクションにおいて、この標準の採用を促進することが期待されます。

# セキュリティ

このEIPに基づく潜在的な攻撃手法の一つは、クリエーターをだまして、意図せずにクリエーター帰属の同意メッセージに署名させることが考えられます。
このような攻撃は、クリエーターが自分の作品の帰属や権利を不正に主張されるリスクを高めるため、深刻な問題です。
このリスクを軽減するために、クリエーターは署名する前に、すべての署名フィールドが必要なものに対応していることを確認する必要があります。

### 攻撃の仕組み

攻撃者は、正規に見えるが実際は悪意のあるメッセージやトランザクションに、クリエーターを誘導し、署名させることで、クリエーターのデジタルアイデンティティや作品に関する権利を不正に取得しようとします。
この署名が成功すると、攻撃者はクリエーターの名前でNFTを発行したり、既存のNFTのクリエーター帰属を不正に変更することが可能になるかもしれません。

### 対策

クリエーターは以下の点に注意することで、このような攻撃から自身を守ることができます。

- **署名フィールドの確認**
    - 署名する前に、すべてのフィールドが適切であり、必要な情報だけが含まれていることを確認します。
    - 特に、NFTの作成に関連する情報（メタデータのURI、価格など）が正確に記載されているかを検証します。

- **信頼できるツールの使用**
    - 署名プロセスには、信頼できるウォレットやコントラクトプラットフォームを使用してください。
    - これらのプラットフォームは通常、不正なトランザクションやメッセージを識別するセキュリティ機能を備えています。

- **メッセージの内容の検証**
    - **EIP712**のように、メッセージの内容がユーザーにとって理解しやすい形式で提示されることを利用して、署名する内容が正確であることを再確認します。

これらの対策は、クリエーターが自分のデジタルアセットとアイデンティティを保護するのに役立ちます。
クリエーターが意図せずに署名することを防ぐためには、署名プロセスにおける注意深さと正確な情報の確認が不可欠です。

# 引用

Carlos Flores (@strollinghome), "ERC-7015: NFT Creator Attribution [DRAFT]," Ethereum Improvement Proposals, no. 7015, May 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7015.

# 最後に

今回は「NFTクリエイターが、自分の作品に関する帰属を明確にするための署名メカニズムを提案している**ERC7015**」についてまとめてきました！
いかがだったでしょうか？

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

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

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

https://chaldene.net/

https://zenn.dev/heku

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4