はじめに

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

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

今回は、物理的かつデジタルなアセットを、ANCHORと呼ばれる仕組みを使用してオンチェーン上のNFTと1:1で紐付ける、Asset-Bound NFTという仕組みを提案している規格であるERC6956についてまとめていきます!

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

6956は現在(2024年1月13日)では「Review」段階です。

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

概要

この標準は、ERC721の拡張を通じて、物理的かつデジタルなアセットをdAppsなどに統合することを可能にするものです。 具体的には、物理的なオブジェクトなどのASSETは、それぞれ固有の識別が可能なANCHORによってマークされ、このアンカーはASSETの全ライフサイクルを通じて、オンチェーン上のNFTと1対1で安全かつ分離できない方法で結合されます。

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

このプロセスでは、ORACLEという役割が重要です。 ORACLEはATTESTATIONを通じて、特定のASSETが特定の操作(mint、transfer、burn、approveなど)のためのto-addressを定義する時にコントロールされていることを証明します。 この証明はオフチェーンで行われ、オンチェーンでその証明が信頼できるオラクルによって署名されたことを確認することにより、これらの操作が承認されます。 重要なのは、ASSETのコントロールの証(PROOF-OF-CONTROL)によってのみ承認が行われるという点で、これによりASSETのコントローラーがAsset-Bound NFTのコントローラーであることが保証されます。

また、transferAnchor(attestation)のような証明による承認操作は許可不要で、現在の所有者(from-address)や受取人(to-address)の署名は必要ありません。 これにより、より柔軟かつ迅速なアセットの移転が可能となります。

図1に示されるASSET-BOUND NFTのtransferのデータフローでは、ユーザーはスマートフォンを使用して物理的なASSETと対話し、転送先のto-addressを指定することができます。 これにより、物理的なアセットとデジタルなNFTの統合が容易になり、web3やdAppsの領域での応用が広がることが期待されます。

erc6956_concept.png

  • アセット(Asset)

    • これは物理的またはデジタルのアセットを表し、ブロックチェーン上にアンカーされる(つまり登録される)ことが示されています。
    • アンカーはアセットの一意の識別子で、ここでは「0x123...456」と表記されています。
  • アンカー技術(Anchor-Technology)

    • アセットをブロックチェーン上に固定する技術。
    • これにより、アセットに一意のIDが割り当てられ、ブロックチェーンの不変性を利用してアセットの所有権や真正性を証明できます。
  • ユーザー端末(User Device)

    • ユーザーがアンカーをブロックチェーン上に登録するために使用するデバイス。
    • 「to 0xaa..aa」というアドレスが示されているのがユーザーのウォレットアドレスです。
  • オラクル(Oracle)

    • ブロックチェーン外のデータやイベントをブロックチェーン内のスマートコントラクトに提供するサービス。ここではオラクルがアンカーの証明(Attestation)をブロックチェーンに提供していることが示されています。
  • 証明(Attestation)

    • アンカーに関する情報を含む文書で、ユーザー端末からオラクルを経由してERC6956スマートコントラクトに提供されます。
    • これには「to 0xaa..aa, anchor: 0x123...456, signed: {}」という情報が含まれています。
  • ERC-6956

    • この規格で提案されているスマートコントラクト。
    • ここでは、アンカーに関連するトークン(NFT)や所有権の情報がこのスマートコントラクトに登録されています。
  • NFT

    • 「token: 2402, anchor: 0x123...456」という情報を持っているNFT。
  • オンチェーン/オフチェーン(ON-CHAIN / OFF-CHAIN)

    • ブロックチェーンの外(オフチェーン)と内(オンチェーン)の活動を区別するために使われます。
    • 証明(Attestation)はオフチェーンからオンチェーンへのプロセスの一部です。

物理的またはデジタルのアセットがブロックチェーン上でどのように登録され、管理されるかのフローを概念的に説明しています。 アセットはアンカー技術を通じてトークン化され、オラクルを介してブロックチェーン上のスマートコントラクト(ERC6956)に登録されます。 その後、NFTとしてのアセットの所有権が証明されます。

動機

ERC721は、NFT(ノンファンジブルトークン)が物理的な財産やデジタルコレクタブル、さらには所有権などを表現できることを確立しています。 この文脈で、これらの所有権を表すものすべてを、一般的に価値を持つとされるものとしてASSETS(アセット)と呼びます。

ERC721によって、NFTは単なるデジタルアート作品だけでなく、実際の物理的な財産(例えば不動産や美術品など)の所有権を表す手段としても使われるようになりました。 さらに、デジタルコレクタブル(例えば、限定版のデジタルカードやゲーム内アイテム)や、もっと抽象的な概念(例えば、特定のプロジェクトにおける責任や権利)の表現にも利用されています。

この標準により、所有権のデジタル化が可能になり、ブロックチェーン上での所有権の透明かつ確実な追跡が実現します。 これは、物理的なアイテムだけでなく、デジタルアセットや様々な権利や責任を含む広範なアセットに適用されるため、NFTの応用範囲が大きく拡張されることを意味しています。 例えば、特定のアート作品の所有権や、デジタルゲーム内のレアアイテム、あるいは著作権など、多様な形態のアセットがNFTとして表現され、取引されるようになります。

このようにERC721は、ブロックチェーンとNFTの概念を使って、物理的およびデジタルの境界を越えたアセットの所有権を確実に表現する新しい道を開きました。

問題

ERC721では、NFTがデジタルまたは物理的なアセットの所有権を表すことができるとされています。 この標準は、アセットが「特定のコントラクトのトークンを保持している」とき、またはNFTのメタデータ自体がアセットである場合に、デジタル、オンチェーンのアセットの所有権を表すのに特に適しています。 現在、多くの人々はNFTのメタデータ(画像や特性など)をアセットクラスとして扱い、その希少性がNFTの個々の価値を直接定義すると考えています。

しかし、ERC721では解決できない問題が存在します。 特に、NFTがオフチェーンのASSET(物理的な製品の所有権、デジタルコレクタブル、ゲーム内アセット、責任など)を表す場合、問題が顕著になります。 アセットのライフサイクルにおいて、所有権と所持状態は何度も変更される可能性があります。 これらの変更は、関係する当事者に対する義務や特権の移動を引き起こす可能性があります。 そのため、アセットの義務や特性をトークンに確実に結びつけることなくアセットをトークン化することは、不完全なものとなります。 現在、オフチェーンのアセットはしばしば、NFTのメタデータにアセット識別子を追加することで「アンカー」されています。

NFT-ASSETの完全性の問題点は、多くのNFT投資家の間で一般的な信念とは異なり、メタデータは変更可能であり、オフチェーンに存在します。 したがって、変更可能なメタデータ内のアセット識別子を介してアセットとリンクされることは、tokenURIを介してNFTにのみリンクされるため、弱いリンクと見なされます。

NFTは、ブロックチェーン上で一意に識別され、所有権が追跡可能なデジタルアセットです。 各NFTは、tokenURIと呼ばれるデータ要素を持っており、このtokenURIはNFTに関連するメタデータへのリンクを提供します。 メタデータは、NFTに関する詳細情報(例えば画像、説明、アセット識別子など)を含むことができます。

問題は、このメタデータが「変更可能」であるという点です。 つまり、メタデータは時間の経過とともに変更される可能性があります。 例えば、NFTが表す物理的なアイテムに関する情報が変更される場合、そのメタデータは更新されるかもしれません。

このため、tokenURIを通じてNFTと関連付けられたメタデータ内のアセット識別子を介してアセットとリンクすることは、「弱いリンク」と見なされます。 これは、メタデータが変更可能であるため、NFTと実際のアセットとの間の関連が時間とともに変化する可能性があるためです。 結果として、NFTが表すアセットの真の状態や所有権を確実に追跡するのが難しくなる場合があります。

メタデータとトークン間の完全性を保証する方法として、メタデータのハッシュをオンチェーンに格納する方法があります。 しかし、ハッシュ化によって新たな問題が生じます。 多くのアプリケーションでは、アセット識別子以外のメタデータ(例えば特性やプレイ時間など)は更新可能であるべきですが、ハッシュを格納することによってメタデータを不変にすることは問題を引き起こします。 また、tokenURIを介して指定されたオフチェーンのメタデータリソースは、長期間にわたって利用可能である必要がありますが、これは過去に失敗の例があります(IPFSバケットの消失、tokenURIプロバイダーのダウンタイムなど)。

オフチェーンとオンチェーンの完全性に関しては、オフチェーンのASSET所有権がオンチェーン表現の所有権を持つことによって強制されたり、条件付けられたりするアプローチがあります。 一般的な方法は、物理的なASSETを入手するためにトークンをburnすることですが、これでは完全性を維持することができません。 また、オフチェーンのASSETの所有権を持つことによってオンチェーンの所有権が強制されるアプローチはまだ知られていません。 特に、現在のNFT所有者が非協力的または無能力である場合、完全性は通常、現在のNFT所有者の署名権限の欠如によって失敗します。

メタデータはオフチェーンに存在し、実装の大部分はメタデータが変更可能であることを無視しています。 より真剣な実装では、例えばメタデータをハッシュ化し、そのハッシュをオンチェーンでtokenIdにマップして格納することによって完全性を維持しようとします。 しかし、このアプローチはアセット識別子以外のメタデータ(特性やプレイ時間など)が変更可能または進化する必要がある場合には適していません。

ASSET-BOUND NON-FUNGIBLE TOKENS

この提案された標準では、物理的またはデジタルのオフチェーンASSET(資産)をオンチェーンのNFTに分離不能にアンカー(固定)することを通じて、ASSETの表現を強化することを目指しています。 これは、オフチェーンでASSETをコントロールしていることが、オンチェーンでそのアンカーされたNFTをコントロールしていることを意味するようにすることを意図しています。

具体的には、オフチェーンでのASSETの所有権の変更は、オンチェーンでのアンカーされたNFTの所有権の変更に必然的に反映されるべきです。 これは、現在のNFT所有者が協力的でない場合でも適用されるべきです。 つまり、ASSETのコントロールや所有権が、NFTの所持よりも重要であるべきだということです。

このために、オフチェーンでのASSETのコントロールが、オンチェーンでのアンカーされたNFTのコントロールを強制する「ASSET-BOUND NFT」という新しいタイプのNFTを提案しています。 このASSET-BOUND NFTは、デジタルメタデータをASSETに分離不能に結び付けることも可能にします。 物理的なASSETの場合、これにより物理的およびデジタルコンポーネントが分離できない「フィジタル(phygital)」資産を設計することが可能になります。 ただし、メタデータ自体は変更可能です。

さらに、ERC721に基づいたトークンの転送コントロールメカニズムに、ATTESTATION(証明)という新しいメカニズムを追加することも提案されています。 この証明は、オフチェーンでORACLE(オラクル)によって署名され、ASSETをコントロールしている者がtoアドレスまたは受け取りアドレスを指定していることを確認した場合にのみ発行されます。 この証明によって承認されたトランザクションは、送信者や受取人からの署名や承認を必要とせず、許可不要のtransferを可能にします。

この標準の使用には、Web2ユーザーのオンボーディングの障壁を大幅に下げ、セキュリティを向上させるなど、二つの主要な副次効果があります。 例えば、新しいユーザーはガスレスウォレットを使用してWeb3・dApps・DeFiに参加し、暗号通貨を所有せずにトークンをmintやtransferすることができます。 また、ユーザーが詐欺に遭うリスクが減少し、間違いや攻撃からの回復が容易になります。

この標準は物理的およびデジタルのオフチェーンASSETとオンチェーンNFTとの間に強固な関連を確立し、ASSETとNFTの一貫性を保証することを目指しています。 これにより、ASSETの完全性と所有権の透明性が向上し、新しい形態のNFTの使用が可能になります。 同時に、この標準は、暗号通貨市場への新規参入者の参入障壁を下げるとともに、より安全で使いやすい環境を提供します。 これは、特に物理的なアイテムとデジタル資産の組み合わせ、いわゆる「フィジタル」資産において、革新的なアプローチとなり得ます。

関連作品

この関連作業では、自分自身の署名機能を持たない物理的またはデジタルのASSET(資産)を、分散型アプリケーション(dApps)に統合することが主な目的です。 これは、暗号チップを使用する他の提案とは異なるアプローチを採っています。 一般的に、暗号チップを用いた提案は、ASSETに直接署名機能を組み込むことに依存していますが、この作業では異なる方法を採用しています。

この取り組みの重要な点は、暗号チップのアドレスをANCHOR(アンカー)として利用することで、この新しい標準と他のソリューションを組み合わせて使用できる可能性があることです。 このアンカーとしてのアドレスは、ASSETがブロックチェーン上で確実に追跡可能な識別子を持つことを保証し、その結果、物理的またはデジタルのASSETがdAppsにより容易に統合されることになります。

署名機能を持たないASSETをdAppsに統合し、ブロックチェーン技術の利用範囲を広げることを目指しています。 このプロセスでは、暗号チップなどの追加的な技術を使用せずに、ASSETをブロックチェーン上のNFTと関連付けることが可能です。 これにより、物理的またはデジタルのASSETをより広範囲に活用できるようになり、dAppsの機能性やアクセシビリティが向上することが期待されます。

仕様

定義

ANCHOR(アンカー)

アンカーは、物理的またはデジタルのオフチェーンASSETを特定するためのユニークな識別子です。 これにより、ASSETが物理的なものであれデジタルであれ、明確に識別されます。

ANCHOR-TECHNOLOGY(アンカー技術)

アンカー技術は、アンカーがASSETから物理的または他の方法によって分離不可能であることを保証する必要があります。 また、ORACLEがASSETのコントロールを合理的な疑いを超えて証明できるようにする必要があります。 物理的なASSETの場合は、物理的資産のセキュリティに関する追加の考慮が必要です。

ASSET(アセット)

アセットは、物理的またはデジタルの「もの」で、提案された標準に従ってNFTを通じて表現されます。 通常、アセットは署名機能を持っていません。

ATTESTATION(証明)

証明は、toアドレス(受取人や受益者)を指定する時に、ASSETのコントロールの証明が確立されたことを確認するものです。

PROOF-OF-CONTROL(コントロールの証明)

ASSETのコントロールの証明は、アセットを所有するか、またはそれを何らかの方法でコントロールしていることを意味します。 コントロールの証明はASSETに依存し、技術的、法的、または他の手段を使用して確立されることがあります。 物理的なASSETでは、コントロールは通常、物理的なASSETとtoアドレスを指定するために使用されるデバイス(例えばスマートフォン)との物理的な近接によって確認されます。

ORACLE(オラクル)

オラクルは署名機能を有し、オフチェーンで証明を署名する能力があります。 これらの署名はオンチェーンで検証可能でなければなりません。

この標準は、物理的またはデジタルのASSETをブロックチェーンと統合し、それをNFTにアンカーすることを目指しています。 ASSETのコントロールを証明するための手段としてORACLEとATTESTATIONが重要な役割を果たし、ASSETの真実性と所有権の透明性を確保するために使用されます。

ベースインターフェース

この標準に準拠するすべてのコントラクトは、提案されている標準インタフェース、ERC721、ERC165インタフェースを実装する必要があります。

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

javascript
// SPDX-License-Identifier: MIT OR CC0-1.0
pragma solidity ^0.8.18;

/**
 * @title IERC6956 Asset-Bound Non-Fungible Tokens 
 * @notice Asset-bound Non-Fungible Tokens anchor a token 1:1 to a (physical or digital) asset and token transfers are authorized through attestation of control over the asset
 * @dev See https://eips.ethereum.org/EIPS/eip-6956
 *      Note: The ERC-165 identifier for this interface is 0xa9cf7635
 */
interface IERC6956 {
   
    /** @dev Authorization, typically mapped to authorizationMaps, where each bit indicates whether a particular ERC6956Role is authorized 
     *      Typically used in constructor (hardcoded or params) to set burnAuthorization and approveAuthorization
     *      Also used in optional updateBurnAuthorization, updateApproveAuthorization, I
     */ 
    enum Authorization {
        NONE,               // = 0,      // None of the above
        OWNER,              // = (1<<OWNER), // The owner of the token, i.e. the digital representation
        ISSUER,             // = (1<<ISSUER), // The issuer of the tokens, i.e. this smart contract
        ASSET,              // = (1<<ASSET), // The asset, i.e. via attestation
        OWNER_AND_ISSUER,   // = (1<<OWNER) | (1<<ISSUER),
        OWNER_AND_ASSET,    // = (1<<OWNER) | (1<<ASSET),
        ASSET_AND_ISSUER,   // = (1<<ASSET) | (1<<ISSUER),
        ALL                 // = (1<<OWNER) | (1<<ISSUER) | (1<<ASSET) // Owner + Issuer + Asset
    }
    
    /**
     * @notice This emits when approved address for an anchored tokenId is changed or reaffirmed via attestation
     * @dev This emits when approveAnchor() is called and corresponds to ERC-721 behavior
     * @param owner The owner of the anchored tokenId
     * @param approved The approved address, address(0) indicates there is no approved address
     * @param anchor The anchor, for which approval has been changed
     * @param tokenId ID (>0) of the anchored token
     */
    event AnchorApproval(address indexed owner, address approved, bytes32 indexed anchor, uint256 tokenId);

    /**
     * @notice This emits when the ownership of any anchored NFT changes by any mechanism
     * @dev This emits together with tokenId-based ERC-721.Transfer and provides an anchor-perspective on transfers
     * @param from The previous owner, address(0) indicate there was none.
     * @param to The new owner, address(0) indicates the token is burned
     * @param anchor The anchor which is bound to tokenId
     * @param tokenId ID (>0) of the anchored token
     */
    event AnchorTransfer(address indexed from, address indexed to, bytes32 indexed anchor, uint256 tokenId);
    /**
     * @notice This emits when an attestation has been used indicating no second attestation with the same attestationHash will be accepted
     * @param to The to address specified in the attestation
     * @param anchor The anchor specified in the attestation
     * @param attestationHash The hash of the attestation, see ERC-6956 for details
     * @param totalUsedAttestationsForAnchor The total number of attestations already used for the particular anchor
     */
    event AttestationUse(address indexed to, bytes32 indexed anchor, bytes32 indexed attestationHash, uint256 totalUsedAttestationsForAnchor);

    /**
     * @notice This emits when the trust-status of an oracle changes. 
     * @dev Trusted oracles must explicitly be specified. 
     *      If the last event for a particular oracle-address indicates it's trusted, attestations from this oracle are valid.
     * @param oracle Address of the oracle signing attestations
     * @param trusted indicating whether this address is trusted (true). Use (false) to no longer trust from an oracle.
     */
    event OracleUpdate(address indexed oracle, bool indexed trusted);

    /**
     * @notice Returns the 1:1 mapped anchor for a tokenId
     * @param tokenId ID (>0) of the anchored token
     * @return anchor The anchor bound to tokenId, 0x0 if tokenId does not represent an anchor
     */
    function anchorByToken(uint256 tokenId) external view returns (bytes32 anchor);
    /**
     * @notice Returns the ID of the 1:1 mapped token of an anchor.
     * @param anchor The anchor (>0x0)
     * @return tokenId ID of the anchored token, 0 if no anchored token exists
     */
    function tokenByAnchor(bytes32 anchor) external view returns (uint256 tokenId);

    /**
     * @notice The number of attestations already used to modify the state of an anchor or its bound tokens
     * @param anchor The anchor(>0)
     * @return attestationUses The number of attestation uses for a particular anchor, 0 if anchor is invalid.
     */
    function attestationsUsedByAnchor(bytes32 anchor) view external returns (uint256 attestationUses);
    /**
     * @notice Decodes and returns to-address, anchor and the attestation hash, if the attestation is valid
     * @dev MUST throw when
     *  - Attestation has already been used (an AttestationUse-Event with matching attestationHash was emitted)
     *  - Attestation is not signed by trusted oracle (the last OracleUpdate-Event for the signer-address does not indicate trust)
     *  - Attestation is not valid yet or expired
     *  - [if IERC6956AttestationLimited is implemented] attestationUsagesLeft(attestation.anchor) <= 0
     *  - [if IERC6956ValidAnchors is implemented] validAnchors(data) does not return true. 
     * @param attestation The attestation subject to the format specified in ERC-6956
     * @param data Optional additional data, may contain proof as the first abi-encoded argument when IERC6956ValidAnchors is implemented
     * @return to Address where the ownership of an anchored token or approval shall be changed to
     * @return anchor The anchor (>0)
     * @return attestationHash The attestation hash computed on-chain as `keccak256(attestation)`
     */
    function decodeAttestationIfValid(bytes memory attestation, bytes memory data) external view returns (address to, bytes32 anchor, bytes32 attestationHash);

    /**
     * @notice Indicates whether any of ASSET, OWNER, ISSUER is authorized to burn
     */
    function burnAuthorization() external view returns(Authorization burnAuth);

    /**
     * @notice Indicates whether any of ASSET, OWNER, ISSUER is authorized to approve
     */
    function approveAuthorization() external view returns(Authorization approveAuth);

    /**
     * @notice Corresponds to transferAnchor(bytes,bytes) without additional data
     * @param attestation Attestation, refer ERC-6956 for details
     */
    function transferAnchor(bytes memory attestation) external;

    /**
     * @notice Changes the ownership of an NFT mapped to attestation.anchor to attestation.to address.
     * @dev Permissionless, i.e. anybody invoke and sign a transaction. The transfer is authorized through the oracle-signed attestation.
     *  - Uses decodeAttestationIfValid()
     *  - When using a centralized "gas-payer" recommended to implement IERC6956AttestationLimited.
     *  - Matches the behavior of ERC-721.safeTransferFrom(ownerOf[tokenByAnchor(attestation.anchor)], attestation.to, tokenByAnchor(attestation.anchor), ..) and mint an NFT if `tokenByAnchor(anchor)==0`.
     *  - Throws when attestation.to == ownerOf(tokenByAnchor(attestation.anchor))
     *  - Emits AnchorTransfer  
     *  
     * @param attestation Attestation, refer ERC-6956 for details
     * @param data Additional data, may be used for additional transfer-conditions, may be sent partly or in full in a call to safeTransferFrom
     * 
     */
    function transferAnchor(bytes memory attestation, bytes memory data) external;

     /**
     * @notice Corresponds to approveAnchor(bytes,bytes) without additional data
     * @param attestation Attestation, refer ERC-6956 for details
     */
    function approveAnchor(bytes memory attestation) external;

     /**
     * @notice Approves attestation.to the token bound to attestation.anchor. .
     * @dev Permissionless, i.e. anybody invoke and sign a transaction. The transfer is authorized through the oracle-signed attestation.
     *  - Uses decodeAttestationIfValid()
     *  - When using a centralized "gas-payer" recommended to implement IERC6956AttestationLimited.
     *  - Matches the behavior of ERC-721.approve(attestation.to, tokenByAnchor(attestation.anchor)).
     *  - Throws when ASSET is not authorized to approve.
     * 
     * @param attestation Attestation, refer ERC-6956 for details 
     */
    function approveAnchor(bytes memory attestation, bytes memory data) external;

    /**
     * @notice Corresponds to burnAnchor(bytes,bytes) without additional data
     * @param attestation Attestation, refer ERC-6956 for details
     */
    function burnAnchor(bytes memory attestation) external;
   
    /**
     * @notice Burns the token mapped to attestation.anchor. Uses ERC-721._burn.
     * @dev Permissionless, i.e. anybody invoke and sign a transaction. The transfer is authorized through the oracle-signed attestation.
     *  - Uses decodeAttestationIfValid()
     *  - When using a centralized "gas-payer" recommended to implement IERC6956AttestationLimited.
     *  - Throws when ASSET is not authorized to burn
     * 
     * @param attestation Attestation, refer ERC-6956 for details
     */
    function burnAnchor(bytes memory attestation, bytes memory data) external;
}

Authorization

javascript
enum Authorization {
    NONE,               
    OWNER,              
    ISSUER,             
    ASSET,              
    OWNER_AND_ISSUER,   
    OWNER_AND_ASSET,    
    ASSET_AND_ISSUER,   
    ALL                 
}

概要 トークンに関連する様々なアクションの承認を表すための列挙型。

詳細 この列挙型は、トークンの所有者、発行者、または資産自体による操作が許可されているかどうかを示します。 各値は特定のロールを表し、これらのロールはビットフラグとして使用され、複数のロールを組み合わせることができます。 たとえば、トークンの所有者と発行者の両方によるアクションが許可されている場合は OWNER_AND_ISSUER を使用します。

パラメータ

  • NONE
    • 何のアクションも許可されていない。
  • OWNER
    • トークンの所有者によるアクションが許可されている。
  • ISSUER
    • トークンの発行者(このコントラクト)によるアクションが許可されている。
  • ASSET
    • 資産自体(証明による)によるアクションが許可されている。
  • OWNER_AND_ISSUER
    • 所有者と発行者の両方によるアクションが許可されている。
  • OWNER_AND_ASSET
    • 所有者と資産によるアクションが許可されている。
  • ASSET_AND_ISSUER
    • 資産と発行者によるアクションが許可されている。
  • ALL
    • 所有者、発行者、資産の全てによるアクションが許可されている。

AnchorApproval

javascript
event AnchorApproval(address indexed owner, address approved, bytes32 indexed anchor, uint256 tokenId);

概要 アンカー付きのトークンIDに対する承認されたアドレスが変更または再確認された時に発行されるイベント。

詳細 このイベントは、approveAnchor() 関数が呼び出された時に発行され、ERC721 の振る舞いに対応します。 アンカー(トークンに紐づいた物理的またはデジタルの資産)に対する承認状態の変更を監視するために使用されます。

パラメータ

  • owner
    • アンカー付きトークンIDの所有者。
  • approved
    • 承認されたアドレス、address(0) は承認されたアドレスがないことを示します。
  • anchor 承認が変更されたアンカー。
  • tokenId
    • アンカー付きのトークンID。

AnchorTransfer

javascript
event AnchorTransfer(address indexed from, address indexed to, bytes32 indexed anchor, uint256 tokenId);

概要 アンカー付きのNFTの所有権が何らかのメカニズムによって変更された時に発行されるイベント。

詳細 このイベントは、トークンIDに基づくERC721.Transferイベントと共に発生し、アンカーに関する視点からのトランスファーを提供します。 アンカー(トークンに紐づいた物理的またはデジタルの資産)の所有権の変更を追跡するために使用されます。

パラメータ

  • from
    • 前の所有者、address(0) は所有者がいなかったことを示します。
  • to
    • 新しい所有者、address(0) はトークンがburnされたことを示します。
  • anchor
    • トークンIDに紐づいたアンカー。
  • tokenId
    • アンカー付きのトークンID。

AttestationUse

javascript
event AttestationUse(address indexed to, bytes32 indexed anchor, bytes32 indexed attestationHash, uint256 totalUsedAttestationsForAnchor);

概要 証明が使用されたことを示し、同じ証明ハッシュを持つ2番目の証明が受け入れられない時に発行されるイベント。

詳細 このイベントは、証明に基づいて特定のアンカーに関する状態が変更された時に発行されます。 これは、証明が一度使用されると、それ以上使用されないことを保証するために使用されます。

パラメータ

  • to
    • 証明に指定されたアドレス。
  • anchor
    • 証明に指定されたアンカー。
  • attestationHash
    • 証明のハッシュ。
  • totalUsedAttestationsForAnchor
    • 特定のアンカーに対して既に使用された証明の総数。

OracleUpdate

javascript
event OracleUpdate(address indexed oracle, bool indexed trusted);

概要 オラクルの信頼ステータスが変更された時に発行されるイベント。

詳細 信頼されるオラクルは明示的に指定される必要があります。特定のオラクルアドレスに関する最後のイベントが信頼を示している場合、そのオラクルからの証明は有効とみなされます。 このイベントは、オラクルの信頼状態の変更を追跡するために使用され、どのオラクルが証明の署名に信頼されるかを示します。

パラメータ

  • oracle
    • 証明を署名するオラクルのアドレス。
  • trusted
    • このアドレスが信頼されるかどうかを示す、trueで信頼される、falseで信頼されなくなる。

anchorByToken

javascript
function anchorByToken(uint256 tokenId) external view returns (bytes32 anchor);

概要 トークンIDに対応するアンカーを返す関数。

詳細 この関数は、指定されたトークンIDに1:1でマッピングされているアンカーを返します。 トークンIDがアンカーを表さない場合は、0x0を返します。

引数

  • tokenId
    • アンカー付きトークンのID (>0)。

戻り値

  • anchor
    • トークンIDにバインドされたアンカー、トークンIDがアンカーを表さない場合は0x0。

tokenByAnchor

javascript
function tokenByAnchor(bytes32 anchor) external view returns (uint256 tokenId);

概要 アンカーに対応するトークンIDを返す関数。

詳細 この関数は、指定されたアンカーに1:1でマッピングされているトークンIDを返します。 アンカーに対応するトークンが存在しない場合は、0を返します。

引数

  • anchor
    • アンカー (>0x0)。

戻り値

  • tokenId
    • アンカー付きトークンのID、アンカーにトークンが存在しない場合は0。

attestationsUsedByAnchor

javascript
function attestationsUsedByAnchor(bytes32 anchor) view external returns (uint256 attestationUses);

概要 特定のアンカーまたはそのトークンの状態を変更するために使用された証明の数を返す関数。

詳細 この関数は、アンカーの状態変更に使用された証明の総数を返します。 アンカーが無効な場合、0を返します。

引数

  • anchor
    • アンカー (>0)。

戻り値

  • attestationUses
    • 特定のアンカーに対する証明の使用回数、アンカーが無効な場合は0。

decodeAttestationIfValid

javascript
function decodeAttestationIfValid(bytes memory attestation, bytes memory data) external view returns (address to, bytes32 anchor, bytes32 attestationHash);

概要 証明が有効であれば、その証明をデコードして、to アドレス、アンカー、証明ハッシュを返す関数。

詳細 この関数は、証明が有効な条件(使用済みでない、信頼されたオラクルによって署名されている、有効期限内など)を満たしている場合に限り、証明をデコードします。 不正な証明や使用済みの証明が入力された場合は例外を投げます。

引数

  • attestation
    • 証明、ERC6956のフォーマットに準拠。
  • data
    • 追加データ、オプション。
    • IERC6956ValidAnchorsが実装されている場合、最初のabiエンコードされた引数として証明が含まれる可能性があります。

戻り値

  • to
    • アンカー付きトークンの所有権または承認を変更するアドレス。
  • anchor
    • アンカー (>0)。
  • attestationHash
    • チェーン上で計算された証明のハッシュ (keccak256(attestation))。

burnAuthorization

javascript
function burnAuthorization() external view returns(Authorization burnAuth);

概要 ASSET、OWNER、ISSUERのいずれかがトークンを焼却するための承認を持っているかどうかを示す関数。

詳細 この関数は、トークンを焼却する権限が誰にあるかを示す Authorization 列挙型の値を返します。 これにより、どのロールがトークンの焼却を行うことが許可されているかがわかります。

戻り値

  • burnAuth
    • burnに関する承認。
    • Authorization 列挙型の値。

approveAuthorization

javascript
function approveAuthorization() external view returns(Authorization approveAuth);

概要 ASSET、OWNER、ISSUERのいずれかがトークンの承認を行うための承認を持っているかを示す関数。

詳細 この関数は、トークンの承認を行う権限が誰にあるかを示す Authorization 列挙型の値を返します。 これにより、どのロールがトークンの承認を行うことが許可されているかがわかります。

戻り値

  • approveAuth
    • 承認に関する承認。
    • Authorization 列挙型の値。

transferAnchor

javascript
function transferAnchor(bytes memory attestation) external;

概要 証明によってアンカー付きNFTの所有権を変更する関数。

詳細 証明がオラクルによって署名され、有効である場合に限り、アンカー付きNFTの所有権を attestation.to アドレスに変更します。 この関数は decodeAttestationIfValid を使用し、必要な検証を行います。

引数

  • attestation
    • 証明。

approveAnchor

javascript
function approveAnchor(bytes memory attestation) external;

概要 証明によってアンカー付きトークンの承認を行う関数。

詳細 この関数は、オラクルによって署名された有効な証明に基づいて、アンカー付きトークンの承認を行います。 ASSETが承認することを許可されている場合に限り、動作します。

引数

  • attestation
    • 証明。

burnAnchor

javascript
function burnAnchor(bytes memory attestation) external;

概要 証明によってアンカー付きトークンをburnする関数。

詳細 オラクルによって署名された有効な証明に基づき、アンカー付きトークンをburnします。 この関数は decodeAttestationIfValid を使用し、必要な検証を行います。 ASSETがburnすることを許可されている場合に限り、動作します。

引数

  • attestation
    • 証明。

ベース・インターフェースに関する注意事項

提案された基本インターフェースには以下のような注意点があります。

  • ERC721およびERC165の実装が必須です。

    • これにより、標準的なNFTの機能と相互運用性が保証されます。
  • tokenByAnchor(anchor) および anchorByToken(tokenId) の双方向マッピングが必要です。

    • これは、各アンカーに対して最大1つのトークンが存在することを意味し、アンカーとトークン間の1:1の関係を確立します。
  • コントラクトに対してアンカーが有効かどうかを判断するメカニズムが必要で、ValidAnchorsインターフェースの実装が推奨されます。

    • これにより、有効なアンカーのみがNFTとして使用されることを保証します。
  • decodeAttestationIfValid(attestation, data) 関数を実装し、証明を検証およびデコードする必要があります。

    • この関数は、証明のtoアドレス、アンカー、証明のハッシュを返します。
  • decodeAttestationIfValid 関数は状態を変更しないようにする必要があります。

    • これにより、証明の妥当性を変更することなく確認することができます。
  • 証明が信頼できるオラクルによって署名されていない、期限切れまたはまだ有効でない、または未使用の場合にエラーを投げる必要があります。

    • また、AttestationLimitedインターフェースやValidAnchorsインターフェースが実装されている場合は、それらの条件にも従う必要があります。
  • アンカーリリースメカニズムがあり、アンカーされたNFTがリリースされたり、transfer可能であるかどうかを示します。

    • デフォルトではリリースされていないアンカーは存在しません。
  • ERC721のトークンtransferメカニズムを拡張し、アンカーがリリースされていない場合やバッチtransferがサポートされていない場合にエラーを投げる必要があります。

    • また、AnchorTransferイベントを発行する必要があります。
  • transferAnchor(..)、burnAnchor(..)、approveAnchor(..) などの状態変更操作を実装し、decodeAttestationIfValid() を使用してtoアドレス、アンカー、証明のハッシュを決定する必要があります。

    • また、使用済みの証明のハッシュを保存し、attestationsUsedByAnchor[anchor] をインクリメントし、AttestationUsedイベントを発行する必要があります。
  • transferAnchor(attestation) は ERC-721.safeTransferFrom のように振る舞い、イベントを発行する必要があります。

    • tokenByAnchor(anchor)==0 の場合は新しいNFTを発行します。
  • tokenURI(tokenId) を実装し、アンカーベースのURIを返すことが推奨されます。

    • これにより、メタデータをASSETにアンカーします。
    • アンカーが初めて使用される前は、アンカーとtokenIdのマッピングが不明なので、tokenIdの代わりにアンカーを使用することが好ましいです。

このインターフェースは、物理的またはデジタルのASSETをNFTにアンカーし、それらのtransferや管理を行うためのフレームワークを提供し、ASSETの透明性と追跡可能性を大幅に向上させることを目指しています。

オラクル

  • ORACLE(オラクル)は、特定のANCHOR(アンカー、つまりアセット識別子)に関連付けられたPROOF-OF-CONTROL(コントロールの証明)の前提条件の下で、転送先のtoアドレスが指定されたことを証明するATTESTATION(証明書)を提供する必要があります。

  • ATTESTATION(証明書)は、以下の情報をABIエンコード形式で含む必要があります。

    • to
      • アドレス形式で、受取手(たとえばtransfer先のアドレス、approveされたアカウントなど)を指定します。
    • ANCHOR
      • ASSET識別子として、ASSETと1:1の関係を持つ必要があります。
    • attestationTime
      • UTC秒単位で、ORACLEによって証明書が署名された時間です。
    • validStartTime
      • UTC秒単位で、ATTESTATIONの有効期間の開始時刻です。
    • validEndTime
      • UTC秒単位で、ATTESTATIONの有効期間の終了時刻です。
    • signature
      • ETH署名(65バイト)。
      • これは、ORACLEがattestationHash(keccak256([to, anchor, attestationTime, validStartTime, validEndTime]))を署名した結果です。
  • ANCHOR-TECHNOLOGYを通じて、PROOF-OF-CONTROLがどのように確立されるかの詳細は、この標準の対象外です。

ORACLEがASSETに関連するトランザクションを承認するためにどのようにATTESTATIONを生成し使用するかを明確にします。 これにより、ブロックチェーン上でのASSETの所有権の移転や承認プロセスを透明かつ信頼性のあるものにすることができます。

認証限定インターフェース

この標準に準拠するすべてのコントラクトは、提案されているAttestationLimitedインターフェースを実装することが可能です。

javascript
// SPDX-License-Identifier: MIT OR CC0-1.0
pragma solidity ^0.8.18;
import "./IERC6956.sol";

/**
 * @title Attestation-limited Asset-Bound NFT
 * @dev See https://eips.ethereum.org/EIPS/eip-6956
 *      Note: The ERC-165 identifier for this interface is 0x75a2e933
 */
interface IERC6956AttestationLimited is IERC6956 {
  enum AttestationLimitPolicy {
    IMMUTABLE,
    INCREASE_ONLY,
    DECREASE_ONLY,
    FLEXIBLE
  }
      
  /// @notice Returns the attestation limit for a particular anchor
  /// @dev MUST return the global attestation limit per default
  ///      and override the global attestation limit in case an anchor-based limit is set
  function attestationLimit(bytes32 anchor) external view returns (uint256 limit);

  /// @notice Returns number of attestations left for a particular anchor
  /// @dev Is computed by comparing the attestationsUsedByAnchor(anchor) and the current attestation limit 
  ///      (current limited emitted via GlobalAttestationLimitUpdate or AttestationLimit events)
  function attestationUsagesLeft(bytes32 anchor) external view returns (uint256 nrTransfersLeft);

  /// @notice Indicates the policy, in which direction attestation limits can be updated (globally or per anchor)
  function attestationLimitPolicy() external view returns (AttestationLimitPolicy policy);

  /// @notice This emits when the global attestation limit is updated
  event GlobalAttestationLimitUpdate(uint256 indexed transferLimit, address updatedBy);

  /// @notice This emits when an anchor-specific attestation limit is updated
  event AttestationLimitUpdate(bytes32 indexed anchor, uint256 indexed tokenId, uint256 indexed transferLimit, address updatedBy);

  /// @dev This emits in the transaction, where attestationUsagesLeft becomes 0
  event AttestationLimitReached(bytes32 indexed anchor, uint256 indexed tokenId, uint256 indexed transferLimit);
}

AttestationLimitPolicy

javascript
enum AttestationLimitPolicy {
    IMMUTABLE,
    INCREASE_ONLY,
    DECREASE_ONLY,
    FLEXIBLE
}

概要 証明の使用回数制限ポリシーを定義している列挙型。

詳細 この列挙型は、特定のアンカーに対する証明の使用回数を制限するポリシーを表します。 各ポリシーは証明の使用回数がどのように変更されるかを定義し、アンカーの状態変更やトークン操作に対する証明の再利用可能性を制御します。

パラメータ

  • IMMUTABLE
    • 証明の使用回数が変更不可能。
    • 一度設定されると、それ以上変更できません。
  • INCREASE_ONLY
    • 証明の使用回数を増加させることのみ可能。
    • 一度使用回数が増加すると、減少させることはできません。
  • DECREASE_ONLY
    • 証明の使用回数を減少させることのみ可能。
    • 一度使用回数が減少すると、増加させることはできません。
  • FLEXIBLE
    • 証明の使用回数を増加させることも減少させることも可能。
    • 使用回数の調整が柔軟に行えます。

GlobalAttestationLimitUpdate

javascript
event GlobalAttestationLimitUpdate(uint256 indexed transferLimit, address updatedBy);

概要 グローバルな証明使用回数制限が更新された時に発行されるイベント。

詳細 このイベントは、全体的な証明使用回数の限界が変更された時に発行されます。 証明の使用回数制限は、コントラクト全体で適用される一般的な制限を示します。

パラメータ

  • transferLimit
    • 更新された証明使用回数の限界。
  • updatedBy
    • 限界を更新したアドレス。

AttestationLimitUpdate

javascript
event AttestationLimitUpdate(bytes32 indexed anchor, uint256 indexed tokenId, uint256 indexed transferLimit, address updatedBy);

概要 特定のアンカーに関する証明使用回数制限が更新された時に発行されるイベント。

詳細 このイベントは、アンカー固有の証明使用回数制限が変更された時に発行されます。 これは、個々のアンカーまたはトークンに対する特定の制限を示します。

パラメータ

  • anchor
    • 制限が更新されたアンカー。
  • tokenId
    • アンカーに関連付けられたトークンID。
  • transferLimit
    • 更新された証明使用回数の限界。
  • updatedBy
    • この限界を更新したアドレス。

AttestationLimitReached

javascript
event AttestationLimitReached(bytes32 indexed anchor, uint256 indexed tokenId, uint256 indexed transferLimit);

概要 アンカー固有の証明使用回数が限界に達した時に発行されるイベント。

詳細 このイベントは、特定のアンカーやトークンの証明使用回数が設定された限界に達した時に発行されます。 これは、証明の使用回数がゼロになったことを示し、これ以上の証明の使用が不可能になったことを通知します。

パラメータ

  • anchor
    • 証明使用回数の限界に達したアンカー。
  • tokenId
    • 証明使用回数の限界に達したトークンID。
  • transferLimit
    • 達成された証明使用回数の限界。

attestationLimit

javascript
function attestationLimit(bytes32 anchor) external view returns (uint256 limit);

概要 特定のアンカーに対する証明使用回数の限界を返す関数。

詳細 この関数は、指定されたアンカーに設定された証明使用回数の限界を返します。 デフォルトでは、グローバルな証明使用回数の限界を返し、アンカー固有の限界が設定されている場合はその値を返します。

引数

  • anchor
    • 証明使用回数の限界を知りたいアンカー。

戻り値

  • limit
    • 指定されたアンカーの証明使用回数の限界。

attestationUsagesLeft

javascript
function attestationUsagesLeft(bytes32 anchor) external view returns (uint256 nrTransfersLeft);

概要 特定のアンカーに対する残りの証明使用回数を返す関数。

詳細 この関数は、指定されたアンカーに対する残りの証明使用回数を計算し返します。 これは、attestationsUsedByAnchor(anchor) と現在の証明使用回数の限界(GlobalAttestationLimitUpdate または AttestationLimit イベント経由で設定された)とを比較して計算されます。

引数

  • anchor
    • 証明使用回数の残りを知りたいアンカー。

戻り値

  • nrTransfersLeft
    • 指定されたアンカーの残りの証明使用回数。

attestationLimitPolicy

javascript
function attestationLimitPolicy() external view returns (AttestationLimitPolicy policy);

概要 証明の使用回数制限を更新する方針(グローバルまたはアンカー固有)を示す関数。

詳細 この関数は、証明の使用回数制限がどのように更新されるかの方針を返します。 これには、グローバルな制限や特定のアンカーに対する制限がどのように変更できるかが含まれます。

戻り値

  • policy
    • 証明使用回数制限の更新方針。
    • AttestationLimitPolicy 列挙型の値。

認証限定インターフェースに関する注意事項

提案された標準インターフェースの拡張

このインターフェースは、提案された標準インターフェースを拡張する必要があります。 これにより、基本的な機能に加えて、特定の追加機能を提供することができます。

AttestationLimitポリシーの定義と公開

AttestationLimit(証明の制限)更新ポリシーのうちの1つを定義し、attestationLimitPolicy()関数を通じて公開する必要があります。 更新ポリシーには、FIXED(固定)、INCREASE_ONLY(増加のみ)、DECREASE_ONLY(減少のみ)、FLEXIBLE(柔軟、つまり増加および減少可能)があります。

グローバルtransfer制限の推奨

トークンごとに上書き可能なグローバルtransfer制限を持つことが推奨されます。 これは、attestationLimitPolicy()がFIXEDでない場合に適用されます。

attestationLimit(anchor)の実装

特定のANCHORが合計で何回transferできるかを指定するattestationLimit(anchor)関数を実装する必要があります。 戻り値は、AttestationLimit-Policyに沿って変更される必要があります。

attestationUsagesLeft(anchor)の実装

特定のANCHORに対して残っている使用回数を返すattestationUsagesLeft(anchor)関数を実装する必要があります。 この数は、attestationLimit(anchor)とattestationsUsedByAnchor[anchor]の差によって計算されます。

これらの基準は、ANCHORのtransfer回数を制限し、ブロックチェーン上でのANCHORの利用を適切に管理するためのフレームワークを提供します。 これにより、ANCHORの使用が適切に制御され、取引の透明性と信頼性が確保されます。

フローティング・インターフェース

この拡張に準拠するすべてのコントラクトは、提案されているFloatableインターフェイスを実装することが可能です。

javascript
// SPDX-License-Identifier: MIT OR CC0-1.0
pragma solidity ^0.8.18;
import "./IERC6956.sol";

/**
 * @title Floatable Asset-Bound NFT
 * @notice A floatable Asset-Bound NFT can (temporarily) be transferred without attestation
 * @dev See https://eips.ethereum.org/EIPS/eip-6956
 *      Note: The ERC-165 identifier for this interface is 0xf82773f7
 */
interface IERC6956Floatable is IERC6956 {
  enum FloatState {
    Default, // 0, inherits from floatAll
    Floating, // 1
    Anchored // 2
  }

  /// @notice Indicates that an anchor-specific floating state changed
  event FloatingStateChange(bytes32 indexed anchor, uint256 indexed tokenId, FloatState isFloating, address operator);
  /// @notice Emits when FloatingAuthorization is changed.
  event FloatingAuthorizationChange(Authorization startAuthorization, Authorization stopAuthorization, address maintainer);
  /// @notice Emits, when the default floating state is changed
  event FloatingAllStateChange(bool areFloating, address operator);

  /// @notice Indicates whether an anchored token is floating, namely can be transferred without attestation
  function floating(bytes32 anchor) external view returns (bool);
  
  /// @notice Indicates whether any of OWNER, ISSUER, (ASSET) is allowed to start floating
  function floatStartAuthorization() external view returns (Authorization canStartFloating);
  
  /// @notice Indicates whether any of OWNER, ISSUER, (ASSET) is allowed to stop floating
  function floatStopAuthorization() external view returns (Authorization canStartFloating);

  /**
    * @notice Allows to override or reset to floatAll-behavior per anchor
    * @dev Must throw when newState == Floating and floatStartAuthorization does not authorize msg.sender
    * @dev Must throw when newState == Anchored and floatStopAuthorization does not authorize msg.sender
    * @param anchor The anchor, whose anchored token shall override default behavior
    * @param newState Override-State. If set to Default, the anchor will behave like floatAll
    */
  function float(bytes32 anchor, FloatState newState) external;    
}

FloatState

javascript
enum FloatState {
    Default, // 0, inherits from floatAll
    Floating, // 1
    Anchored // 2
}

概要 アンカーの状態を表す列挙型。

詳細 この列挙型は、アンカーがどのような状態にあるかを表すために使用されます。 Default はグローバルな floatAll 状態を継承し、Floating と Anchored はそれぞれアンカーが固定されているかを示します。

パラメータ

  • Default
    • グローバルな floatAll 状態を継承。
  • Floating
    • アンカーが固定されていない。
  • Anchored
    • アンカーが固定されている。

FloatingStateChange

javascript
event FloatingStateChange(bytes32 indexed anchor, uint256 indexed tokenId, FloatState isFloating, address operator);

概要 特定のアンカーのFloating状態が変更された時に発行されるイベント。

詳細 このイベントは、アンカー固有のFloating状態が変更されるときに発行され、アンカーの新しい状態を示します。

パラメータ

  • anchor
    • Floating状態が変更されたアンカー。
  • tokenId
    • 変更されたアンカーに関連付けられたトークンID。
  • isFloating
    • アンカーの新しいFloating状態。
  • operator
    • 状態変更を実行したアドレス。

FloatingAuthorizationChange

javascript
event FloatingAuthorizationChange(Authorization startAuthorization, Authorization stopAuthorization, address maintainer);

概要 Floating認証が変更された時に発行されるイベント。

詳細 このイベントは、Floating状態の開始と停止に関する認証が変更されたときに発行されます。 これにより、どのロールがFloating状態の制御を開始または停止できるかが更新されます。

パラメータ

  • startAuthorization
    • Floating状態の開始に関する新しい認証。
  • stopAuthorization
    • Floating状態の停止に関する新しい認証。
  • maintainer
    • 認証を更新したアドレス。

FloatingAllStateChange

javascript
event FloatingAllStateChange(bool areFloating, address operator);

概要 デフォルトの浮遊状態が変更された時に発行されるイベント。

詳細 このイベントは、すべてのアンカーに対するデフォルトのFloating状態が変更されたときに発行されます。 これにより、システム全体でのアンカーの浮遊状態のデフォルト設定が更新されたことが示されます。

パラメータ

  • areFloating
    • すべてのアンカーの新しいデフォルトFloating状態。
  • operator
    • 状態変更を実行したアドレス。

floating

javascript
function floating(bytes32 anchor) external view returns (bool);

概要 floating 関数は、特定のアンカーに紐づくトークンが浮遊状態(証明なしで転送可能)かどうかを示します。

詳細 この関数は、指定されたアンカーに紐づくトークンが現在浮遊状態にあるか(証明なしで転送が可能か)を確認し、その結果を真偽値として返します。

引数

  • anchor: 確認したいアンカー。

戻り値

  • 浮遊状態であれば true、そうでなければ false。

floatStartAuthorization

javascript
function floatStartAuthorization() external view returns (Authorization canStartFloating);

概要 OWNER、ISSUER、ASSET のいずれかがFloat状態の開始を許可されているかを示す関数。

詳細 この関数は、Float状態の開始に関する認証を返します。 これにより、どのロールがトークンをFloat状態に移行させることができるかがわかります。

戻り値

  • Float状態の開始を許可する Authorization 列挙型の値。

floatStopAuthorization

javascript
function floatStopAuthorization() external view returns (Authorization canStartFloating);

概要 OWNER、ISSUER、ASSETのいずれかがFloat状態の停止を許可されているかを示す関数。

詳細 この関数は、Float状態の停止に関する認証を返します。 これにより、どのロールがトークンのFloat状態を停止させることができるかがわかります。

戻り値

  • Float状態の停止を許可する Authorization 列挙型の値。

float

javascript
function float(bytes32 anchor, FloatState newState) external;

概要 特定のアンカーのFloat状態を変更またはデフォルトの floatAll 振る舞いにリセットすることを許可する関数。

詳細 この関数を使用して、アンカー固有のFloat状態を新しい状態に変更するか、デフォルトの floatAll 振る舞いにリセットすることができます。 newState が Floating の場合、floatStartAuthorization による承認が必要です。 newState が Anchored の場合、floatStopAuthorization による承認が必要です。

引数

  • anchor
    • Float状態を変更またはリセットするアンカー。
  • newState
    • 新しい浮遊状態またはデフォルトにリセットするための FloatState 列挙型の値。

フローティング・インターフェイスの注意点

  • floating(anchor)関数がtrueを返す場合、tokenByAnchor(anchor)によって識別されるトークンは、証明(attestation)なしでtransferが可能である必要があります。
    • この機能は、ERC721.isApprovedOrOwner(msg.sender, tokenId)を通じて通常の方法で承認されることが想定されています。

これは、特定のANCHOR(アンカー)に関連付けられたトークンが「フローティング」状態にある場合、そのトークンは証明書なしで自由にtransferできるということを意味します。 これにより、トークンはアンカーされているASSET(資産)から独立して、通常のERC721トークンとして取り扱われることになります。 フローティング状態のトークンは、特定の状況や条件下で柔軟に取り扱うことが可能になります。 この機能により、トークンのtransferや利用がより柔軟になり、さまざまなシナリオに対応できるようになります。

ValidAnchors-Interface

この拡張に準拠するすべてのコントラクトは、提案されてい** ValidAnchors**インターフェースを実装することができます。

javascript
// SPDX-License-Identifier: MIT OR CC0-1.0
pragma solidity ^0.8.18;
import "./IERC6956.sol";

/**
 * @title Anchor-validating Asset-Bound NFT
 * @dev See https://eips.ethereum.org/EIPS/eip-6956
 *      Note: The ERC-165 identifier for this interface is 0x051c9bd8
 */
interface IERC6956ValidAnchors is IERC6956 {
    /**
     * @notice Emits when the valid anchors for the contract are updated.
     * @param validAnchorHash Hash representing all valid anchors. Typically Root of Merkle-Tree
     * @param maintainer msg.sender when updating the hash
     */
    event ValidAnchorsUpdate(bytes32 indexed validAnchorHash, address indexed maintainer);

    /**
     * @notice Indicates whether an anchor is valid in the present contract
     * @dev Typically implemented via MerkleTrees, where proof is used to verify anchor is part of the MerkleTree 
     *      MUST return false when no ValidAnchorsUpdate-event has been emitted yet
     * @param anchor The anchor in question
     * @param proof Proof that the anchor is valid, typically MerkleProof
     * @return isValid True, when anchor and proof can be verified against validAnchorHash (emitted via ValidAnchorsUpdate-event)
     */
    function anchorValid(bytes32 anchor, bytes32[] memory proof) external view returns (bool isValid);        
}

ValidAnchorsUpdate

javascript
event ValidAnchorsUpdate(bytes32 indexed validAnchorHash, address indexed maintainer);

概要 コントラクトにおける有効なアンカーが更新された時に発行されるイベント。

詳細 このイベントは、コントラクトで使用される有効なアンカーのセットが更新されたときに発行されます。 通常、有効なアンカーはマークルツリーのルートとして表されるハッシュで管理され、このハッシュはコントラクト内でのアンカーの有効性を確認するために使用されます。

パラメータ

  • validAnchorHash
    • 有効なアンカーを表すハッシュ。
    • 通常はマークルツリーのルートです。
  • maintainer
    • ハッシュを更新したアドレス(通常は msg.sender)。

anchorValid

javascript
function anchorValid(bytes32 anchor, bytes32[] memory proof) external view returns (bool isValid);

概要 特定のアンカーが現在のコントラクト内で有効かどうかを示す関数。

詳細 この関数は、マークルツリーを利用して、提供されたアンカーが有効な一部であるかを検証します。 証明(通常はマークル証明)を使ってアンカーが有効なアンカーハッシュ(ValidAnchorsUpdate イベント経由で発行された)に対して検証され、それに基づいて真偽値を返します。 まだ ValidAnchorsUpdate イベントが発行されていない場合、必ず false を返します。

引数

  • anchor
    • 検証したいアンカー。
  • proof
    • アンカーが有効であることを証明するための証明、通常はマークル証明。

戻り値

  • isValid
  • アンカーと証明が有効なアンカーハッシュに対して検証できる場合は true、そうでない場合は false。

ValidAnchors-Interface の注意点

  • このインターフェースでは、validAnchor(anchor, proof) 関数の実装が必要です。

    • この関数は、特定のアンカーが有効かどうかを判断し、結果を返します。
    • 具体的には、与えられたマークル証明(MerkleProof)が正しいと判断された場合にtrueを返し、そうでなければfalseを返します。
  • この機能の主な目的は、特定のアンカーがコントラクトにおいて有効なものとして扱われるべきかどうかを判断することです。

    • マークル証明は、そのアンカーが有効なアンカーのセット(通常はメルクルツリーのルートによって表される)の一部であることを確認するために使用されます。
  • このメカニズムによって、アンカーの妥当性を効率的かつ安全に検証することが可能になります。

    • これにより、ブロックチェーン上でのASSET(資産)の管理がより信頼性が高く、透明性が確保されることになります。

ValidAnchorsインターフェースは、特定のアンカーがブロックチェーン上で有効かどうかを効率的に確認するためのメカニズムを提供します。 これにより、アセットに関連するトランザクションの安全性と信頼性が向上し、ブロックチェーンの利用がより柔軟かつ効率的になります。

補足

anchor<>tokenIdマッピングの使用理由

コレクタブルなシナリオにおいて、特定のtokenIdは特別な価値を持つことがあります。 例えば、tokenId=1を持つ所有者は、それが最初にクレームされたASSETであるため、価値が高まる可能性があります。 また、発行者が最初の100人のASSET-BOUND NFTの所有者に特別な扱いをする場合も考えられます。 これらのケースは、ブロックチェーンの状態変更を観察することで技術的に対応可能ですが、tokenIdに順序を反映させることがよりユーザーフレンドリーな方法と考えられます。 ただし、セキュリティ上の理由から、連続するanchorを避けるべきです。

tokenId=0とanchor=0x0が無効である理由

ガス効率を高めるためです。 存在しないキーのマッピングが0を返すため、anchor=0やtokenId=0と容易に区別することができず、トークンやanchorの存在に関するチェックや状態変数を省略できます。

ASSETがバッチ生産される場合、なぜERC721を拡張し、マルチトークン基準を使用しないのか

たとえASSETが大量生産されたとしても、各ASSETには独自の特性や所有権の履歴があり、非代替的な方法で表現されるべきです。 このEIPは、ASSET(anchorと呼ばれるユニークな資産識別子を介して表現される)とトークンが常に1:1でマップされるという設計決定に従います。

burnAnchor()とapproveAnchor()の存在理由

ASSET-BOUND NFTは許可不要な性質を持ち、任意のアドレスやランダムに生成されたアカウント(プライベートキーが不明)や、伝統的にERC721 NFTをサポートしないスマートコントラクトにもtransfer可能です。 ASSETの所有がNFTの所有と同等であるため、証明を通じて承認と焼却操作をサポートする必要があります。

その他の実装選択肢として、Consensual Soulbound Tokens(ERC-5484)などを通じたburnとmintの組み合わせが検討されましたが、採用されませんでした。

AttestationLimitedインターフェースの実装時期

各ASSETが限られた回数のみtransfer可能であるべき場合や、セキュリティ上の理由から、このインターフェースの実装が必要です。

IERC6956956Floatable.FloatState列挙型の存在理由

floatAll()のガス効率の良い実装を可能にするためです これにより、全てのanchorのフローティングを一括で管理し、必要に応じて個々のanchorに基づいたフローティングの可能性を設定できます。

floating(tokenId)関数が存在しない理由

この関数は他の多くのEIPで提案されているisTransferable(tokenId,...)メカニズムと同様に機能します。 さらに、提案されたfloating(anchorByToken(tokenId))を使用することが可能です。

開始と停止のための異なるFloatingAuthorizationsの存在理由

使用ケースに応じて、異なるロールがフローティングの開始または停止を行うことができるべきです。 多くの場合、発行者(ISSUER)がコレクションのフローティングを制御する権限を持つことが望ましいです。

これらの質問と回答は、提案されたコントラクトの様々な側面や設計選択の理由を説明しています。 これらの設計は、ASSET-BOUND NFTの運用において、柔軟性、効率性、およびセキュリティを確保するために重要です。

使用例と推奨インターフェースの組み合わせ

所有に基づくケース(IERC6956)

ASSETの所有者はそのASSETを所有しており、所有権は多くの社会的および経済的シナリオで重要な役割を果たします。 例えば、スポーツゲームでは「ボール」として参照されるASSETの所有が重要です。 所有権は義務や特権を伴うこともありますし、所有されたASSETは担保に使用されたり、貸し借りに利用されたり収益を生むこともあります。

所有に基づくトークンゲーティング

クラブのゲストが限定Tシャツ(ASSET)を所有している場合、VIPラウンジへの入場を許可するトークンを受け取ることができます。

所有に基づくデジタルツイン

物理的なスニーカー(ASSET)を所有するゲーマーは、メタバース内で着用するためのデジタルツイン(NFT)を受け取ります。

希少性に基づくデジタルツイン

スニーカー(ASSET)の製造者は、5つのデジタルツイン(NFT)に限定を設け、希少性を生み出すことを決定します。

貸し出し可能なデジタルツイン

ゲーマーはメタバース内で友人にスニーカートークン(NFT)を貸し出し、友人がより速く走ることを可能にします。

盗難からの所有権の保護**:

オフチェーンで所有されているASSETは、盗難を防ぐためにアンカーされたNFTのtransferを許可しないか、またはASSETを通じて簡単にNFTを回収することを望むかもしれません。

抵当のある家の販売

所有者はNFTを所有権の証明として持ち、DeFiバンクが家の資金提供を行いNFTのtransferにロックをかけます。 NFTのtransferを許可するには抵当を完済する必要があります。

リース付きの家の販売

リース契約によりASSETのアンカーされたNFTに抵当がかけられ、古い所有者がロックを解除し、新しい所有者が家を購入して再資金化します。

ダウンペイメントを伴う新車の購入

購入者は車を構成し、ダウンペイメントを提供し、将来的にAnchorが設定されます。 車が生産されるまで、NFTはフローティング状態となり、NFTマーケットプレイスで取引されます。 ASSETの納車時のNFT所有者は、車を受け取る権利と全額支払いの義務を持ちます。

先物取引による石油のバレルの購入

購入者は、一桶の石油(ASSET)に対する先物契約のオプションを購入します。 満期日には、購入者は石油を受け取る義務があります。

これらの使用例は、所有権に基づいたさまざまなシナリオを示しており、ASSETとNFTの関連性を強調しています。 例えば、限定品の所有権を証明するNFTが特定の特典へのアクセスを提供したり、物理的なアイテムとそれに対応するデジタルツインの関係を確立したりします。 また、ASSETの所有が盗難から保護されるケースや、不動産取引において抵当やリースなどの負債をNFTを通じて管理するケースも考えられます。 これらの例は、ASSET-BOUND NFTが実世界の資産とデジタル資産の両方でどのように機能するかを示しており、所有権の証明、アクセス権の管理、資産の取引など、多様な応用が可能であることを示しています。

これらは基本的なIERC6956インターフェースに加えて実装される必要があります。 また、Lockableに関しては、ERC721を拡張する任意のロックや抵当メカニズム(例えば、ERC5192やERC6982)と組み合わせることができます。 トークンがロックされているかどうかは、_beforeTokenTransfer()フックで確認することが推奨されています。 これはsafeTransferFrom()だけでなくtransferAnchor()からも呼び出され、標準的なERC721transferと提案された証明に基づくtransferの両方をブロックするのに適しています。

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

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

以下の表は、各使用例に対してどの拡張や設定が必要かを示しています。

使用例 approveAuthorization burnAuthorization IERC6956Floatable IERC6956AttestationLimited Lockable
管理所有
トークンゲーティング ASSET ANY incompatible - -
デジタルツイン ASSET ANY incompatible - -
希少デジタルツイン ASSET ANY incompatible required -
貸し出し可能デジタルツイン OWNER_AND_ASSET ASSET required - -
管理所有権
盗難からの所有権の保護 OWNER または OWNER_AND_ASSET ANY optional - required
抵当付き家の販売 ASSET または OWNER_AND_ASSET ANY optional optional required
リース付き家の販売 ASSET または OWNER_AND_ASSET ANY optional optional required
ダウンペイメント付き新車の購入 ASSET または OWNER_AND_ASSET ANY optional optional required
先物取引による石油のバレルの購入 ASSET または OWNER_AND_ASSET ANY optional optional required

凡例:

  • required
    • この使用例を実装するためには必要です。
  • incompatible
    • セキュリティリスクのため、この使用例には実装してはいけません。
  • optional
    • このオプションは実装することができます。

この表は、各使用例に適した拡張や設定を理解するためのガイドとなり、ASSET-BOUND NFTを効果的に使用するための構成を決定する時に役立ちます。 例えば、トークンゲーティングではASSETによるapproveAuthorizationが必要ですが、IERC6956Floatableは実装すべきではありません。 一方で、盗難からの所有権の保護では、Lockableが必要であり、OWNERまたはOWNER_AND_ASSETによるapproveAuthorizationがオプショナルとして実装できます。

互換性

提案されたEIP(Ethereum Improvement Proposal)は、既存のERC721と完全に互換性があるとともに、IERC6956Floatableインターフェースを拡張しています。 この拡張により、証明を通じた追加の承認メカニズムが導入され、よく知られたERC721の振る舞いに対応しています。 このため、特に物理的な資産に関しては、ERC721の代わりにこのEIPを使用し、ERC721用に設計された拡張機能で補完することが推奨されています。

さらに、マーケットプレイスでのNFTの転送可能性を示すインターフェースを、提案された標準に拡張することも推奨されています。 これには、例えばERC6454やERC5484などが含まれます。

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

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

また、多くのERC721の拡張機能では、transferメソッドに追加のエラー条件を加えることが提案されていますが、この標準はそれと完全に互換性があります。 特に、_beforeTokenTransfer()フックは、証明によって承認されたtransferを含むすべてのtransferに対して呼び出される必要があります。 また、参照実装では_beforeAnchorUse()フックが提案されており、これは証明を承認として使用する時にのみ呼び出されるようになっています。

これらの特徴により、提案されたEIPは既存のERC721標準と互換性を持ちながら、新しい承認メカニズムや追加のセキュリティ機能を提供し、物理的な資産に対して特に効果的なNFTの使用を実現することが可能です。

テスト

提案されている標準インターフェースの実装については以下を参照してください。

提案されている標準インターフェイス、Floatable 拡張モジュール、 ValidAnchors 拡張モジュール、AttestationLimited 拡張モジュールの実装については以下を参照ください。

実装

提案されている標準インターフェイスのみをサポートする最小限の実装は以下を参照ください。

提案されている標準インターフェース、Floatable 拡張、ValidAnchors 拡張、AttestationLimited 拡張をサポートした完全な実装は以下を参照ください。

ethers ライブラリを使用して ATTESTATION を生成するための、最小限の Typescript サンプルは以下を参照ください。

セキュリティ

ASSETが盗まれた場合、盗賊はNFTをコントロールできるか?

はい、この標準はNFTをASSETに不可分かつ無条件にアンカーすることを目的としています。 これには盗難も含まれます。 ORACLEはASSETのコントロールの証明を行いますが、そのコントローラーが正当な所有者であるかは証言しません。 ハッカーなどからASSETを受け取った人がアンカーとやり取りする場合、犯罪に関連する人物のオンチェーンアドレスが明らかになり、捜査の出発点になる可能性があります。 また、この標準は任意のロックメカニズムと組み合わせることができ、証明に基づくアクションを一時的または永続的にロックすることが可能です。

AttestationLimitsを使用して資金の枯渇を避ける方法

ブロックチェーンアプリケーションの中心的なセキュリティメカニズムはガス料金です。 ガス料金により、大量のトランザクション実行にペナルティが課され、DoS攻撃などの大規模攻撃が抑制されます。 証明による許可不要の操作により、ASSETの発行者(通常はASSET-BOUND NFTの発行者でもある)がすべてのトランザクション費用を負担するケースが多くなります。 悪意のあるユーザーがORACLEに複数回のコントロールの証明を承認させ、これらの証明を中央のガス支払い者に渡すことで、ガス料金を支払いつつ許可不要で実行されるため、ガス支払い者の資金が枯渇し、システムが使えなくなります。

シリアル番号のハッシュ化を推奨する理由

連続する識別子を使用すると、市場に出回っているASSETの総数に関する良い指標が提供されますが、多くの産業にとっては製品グループごとの正確な生産数を公開することは望ましくありません。 サプライチェーン内ではシリアル番号が必須ですが、物理的なシリアル番号を使用しながら実際のASSET数を隠すためには、シリアル番号をハッシュ化または暗号化するのが最も簡単な方法です。

提案されたEIPがASSETとNFTの関連性をどのように扱うか、またそのセキュリティ機能や操作の実現方法について明確にしています。 特に、ORACLEの役割やアンカーの検証方法、シリアル番号の取り扱いに関する詳細が示されており、これによりASSET-BOUND NFTの使用方法がより明確になります。

物理的資産のセキュリティに関する考慮事項

物理的アンカーのためのORACLE(オラクル)

ORACLEは、特定の物理的アンカーと関連する物理的オブジェクト、toアドレスを指定する入力デバイス(例:スマートフォン)との間の物理的接近を証明する必要があります。 許容される接近範囲は通常、数ミリメートルから数メートルです。 物理的存在は合理的な疑いを超えて検証されなければなりません。 使用される方法は、物理的アンカーの複製や再生の試みに対して堅牢で、スプーフィング(例:提示攻撃)に対しても堅牢でなければなりません。 この実装は、toアドレスを定義する当事者が悪意を持っており、物理的オブジェクトへの現在または将来のアクセスなしに誤った証明を取得しようとすることを前提とする必要があります。

物理的ASSET

ASSETには、ユニークな物理的オブジェクト識別子であるアンカーが含まれている必要があります。 これは通常、シリアル番号(プレーン(推奨されない)またはハッシュ化(推奨))として機能します。 ASSETには、物理的セキュリティデバイス、マーキング、ORACLEによる証明のための物理的存在を確認するための他の機能が含まれている必要があります。 複製不可能なセキュリティ機能を備えたアンカー技術の使用が推奨されます。 一般的に、容易に複製可能なアンカー技術(例:バーコード、通常のNFCチップなど)の使用は推奨されません。 複製には物理的およびデジタルな複製が含まれます。

これらのセキュリティ考慮事項は、物理的なASSETをNFTにアンカーする時に、どのようなセキュリティ対策を講じるべきかを明確にしています。 ORACLEによる物理的存在の確実な証明、複製やスプーフィングに対する堅牢性、そして物理的ASSET自体のユニーク性とセキュリティの確保が重要です。 これにより、物理的ASSETとNFTの関連付けがより信頼性と安全性を持ち、様々な用途での使用が可能になります。

引用

Thomas Bergmueller (@tbergmueller), Lukas Meyer (@ibex-technology), "ERC-6956: Asset-bound Non-Fungible Tokens [DRAFT]," Ethereum Improvement Proposals, no. 6956, April 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-6956.

最後に

今回は「物理的かつデジタルなアセットを、ANCHORと呼ばれる仕組みを使用してオンチェーン上のNFTと1:1で紐付ける、Asset-Bound NFTという仕組みを提案している規格であるERC6956」についてまとめてきました! いかがだったでしょうか?

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

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