はじめに

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

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

今回は、ERC2612の仕組みをERC1155形式のNFTに適用して、approve + transferFromのUXを向上させる仕組みを提案している仕組みを提案しているERC7604についてまとめていきます!

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

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

概要

ERC2612やERC4494を使用したPermitのフローは、ERC20やERC721トークンのUXを大幅に改善しました。 この規格では、ERC1155にPerimtの仕組みを定期ようすることを提案しています。 ERC1155では、tokenIdとvalueの両方を考慮する必要があるため、新しい規格として提案しています。

Permitとは、第3者に自信が保有するトークンの送付をガス代を負担させて実行させることができる仕組みです。 通常、自信が保有しているトークンを運営などの第3者に実行してもらうためには、approve関数を実行して送付許可を与える必要があります。 ただ、この処理はトランザクションを発行する必要があるため、少額でもETHが必要になります。 つまりユーザーは少額のETHを入手してからしか実行できないためUXが良いとは言えません。 そこで提案されたERC2612やERC4494では、approve部分を署名を行うだけにして、コントラクト側で署名の検証が通れば運営などの第3者のアドレスがapproveとtransferFromを実行できるようにする仕組みを提案しています。 これにより、ユーザーはガス代を保有する必要がなくなります。

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

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

この規格は、ERC5216も使用しています。

ERC5216は、ERC1155形式のNFTを保有する特定のアドレスが、自信が保有するtokenIdの保有量の内一部を他のアドレスにapproveする仕組みを提案しています。 ERC5216については以下の記事を参考にしてください。

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

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

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

動機

ERC2612とERC4494では、ERC20とERC721にしかPermitの仕組みを適用できないため、この規格ではERC1155に適用させる仕組みを提案します。

仕様

ERC1155とERC5216に以下の3つの機能を追加する必要があります。

js
interface IERC1155Permit {
	function permit(address owner, address operator, uint256 tokenId, uint256 value, uint256 deadline, bytes memory sig) external;
	function nonces(address owner, uint256 tokenId) external view returns (uint256);
	function DOMAIN_SEPARATOR() external view returns (bytes32);
}

permit実行には、allowance(owner, spender, tokenId)で保有している特定のtokenIdの保有量の一部であるvalueを指定し、nonces(owner, tokenId)を1だけインクリメントし、ERC5216で定義されているApprovalイベントを発行する必要があります。

また、以下の条件も満たす必要があります。

  • 現在のブロックタイムがdeadline以下である。
  • トークンの所有者(owner)がゼロアドレスでない。
  • 指定されたtokenIdのnonce(nonces[owner][tokenId])が現在のnonceと一致する。
  • 署名sigがsecp256k1やERC2098、ERC1271などの有効な署名である。
js
keccak256(abi.encodePacked(
 hex"1901",
 DOMAIN_SEPARATOR,
 keccak256(abi.encode(
          keccak256("Permit(address owner,address spender,uint256 tokenId,uint256 value,uint256 nonce,uint256 deadline)"),
          owner,
          spender,
          tokenId,
          value,
          nonce,
          deadline))
));

これらの条件が満たされない場合、permitの実行は失敗します。

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

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

また、DOMAIN_SEPARATORはEIP712に従って定義される必要があります。 DOMAIN_SEPARATORは、他のドメインからのリプレイ攻撃を防ぐために、コントラクトとチェーンで一意でなければなりません。

js
DOMAIN_SEPARATOR = keccak256(
    abi.encode(
        keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
        keccak256(bytes(name)),
        keccak256(bytes(version)),
        chainid,
        address(this)
));

よって、署名のメッセージは以下のような構造になります。

json
{
  "types": {
    "EIP712Domain": [
      {
        "name": "name",
        "type": "string"
      },
      {
        "name": "version",
        "type": "string"
      },
      {
        "name": "chainId",
        "type": "uint256"
      },
      {
        "name": "verifyingContract",
        "type": "address"
      }
    ],
    "Permit": [
	  {
	    "name": "owner".
	    "type": "address"
	  },
      {
        "name": "spender",
        "type": "address"
      },
      {
        "name": "tokenId",
        "type": "uint256"
      },
      {
        "name": "value",
        "type": "uint256"
      },
      {
        "name": "nonce",
        "type": "uint256"
      },
      {
        "name": "deadline",
        "type": "uint256"
      }
    ],
    "primaryType": "Permit",
    "domain": {
      "name": erc1155name,
      "version": version,
      "chainId": chainid,
      "verifyingContract": tokenAddress
  },
  "message": {
    "owner": owner,
    "spender": spender,
    "tokenId": tokenId,
    "value": value,
    "nonce": nonce,
    "deadline": deadline
  }
}}

上記に加えて以下の条件があります。

permit関数は署名者がゼロアドレスでないことをチェックする必要があります。

この仕組みでは、msg.sender(関数実行アドレス)を参照する仕組みがなく、permit関数の呼び出しもとは任意のアドレスにすることができます。

EIP165

この規格にはEIP165が必要になります。 EIP165を使用することで、他のNFTコントラクトがこのEIPを実装しているか簡単に検証できるようになります。 この規格で提案されているコントラクトがEIP165で返されるインターフェースIDは0x7409106dです。

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

補足

permit関数は追加のトランザクションを必要とせずに、safeTransferFromを実行できるようになります。 このフォーマットは予期しないコードへの呼び出しを避けるように設計されています。 また、リプレイ保護のためにnoncesマッピングが提供されています。

一般的なpermitの使用ケースとして、リレーヤーが所有者に代わってPermitを提出するシナリオがあります。 この場合、リレーヤーはPermitを提出するかどうかの選択権を持つことになります。 この点が懸念される場合、所有者はdeadlineを近い将来に設定することで、Permitの有効期間を制限できます。 また、deadline引数をuint(-1)に設定することで有効期限のないPermitを作成することもできます。

ERC712形式のメッセージはERC2612やERC4494での使用を考慮しており、多くのウォレットプロバイダで広く採用されているためこのEIPでも採用されています。

ERC2612ではapproveするvalueに焦点を当てていて、ERC4494ではapproveするtokenIdに焦点を当てています。 このEIPはpermitによってapproveされるNFTのtokenIdとvalueの両方に焦点を当てています。 また、ERC1155ではvalueによるapproveをネイティブにサポートしていないため、ERC5216が必要になります。

ERC2612では署名がv, r, sのコンポーネントに分割されていますが、このEIPでは可変長のバイト配列を使用してEIP2098署名(64バイト)をサポートします。 EIP2098署名はr, s, vコンポーネント(65バイト)から簡単に分離・再構成することができません。

セキュリティ

以下と同じ内容です。

引用

calvbore (@calvbore), emiliolanzalaco (@emiliolanzalaco), "ERC-7604: ERC-1155 Permit Approvals [DRAFT]," Ethereum Improvement Proposals, no. 7604, January 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7604.

最後に

今回は「ERC2612の仕組みをERC1155形式のNFTに適用して、approve + transferFromのUXを向上させる仕組みを提案している仕組みを提案しているERC7604」についてまとめてきました! いかがだったでしょうか?

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

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