はじめに

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

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

今回は、「NFTの作者である」という情報や作者の同意の証明などをメタデータに格納する提案であるERC5375についてまとめていきます!

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

概要

この提案(EIP)は、NFTに関連する改善案です。 NFTは一意で交換できないトークンであり、デジタルアートやコレクションアイテムなどに使用されます。

この提案では、NFTの制作者である「作者」に関する情報を取り扱うための方法を提供しています。 注意が必要なのは、この情報が「オフチェーン」に存在するため、ブロックチェーン上の取引やデータとは別の場所に保存されることです。

提案では、JSONというデータ形式を使用して、作者に関する情報を整理します。 新しい情報「フィールド」がNFTに追加され、その中には作者の名前やアドレスなどの情報が入ります。 そして、重要なのは、「作者の同意の証明」という部分です。 これは、NFTの作者であることに同意したことを示すもので、実際に作者であることを証明するものではありません。 これにより、作者でない人も同意することができます。

背景として、今までNFTの作者情報を取り扱う方法が一般的にはっきりしておらず、問題がありました。 例えば、NFTを作成した人と作者が同じだとは限りません。 この提案は、NFTを作成した人(mintする人)が、誰が作者であるかを提供できるようにすると同時に、作者でない人が無断で作者と主張することを防ぐための基準を定めています。

まとめると、この提案はNFTの制作者情報を整理し、公正なやり方で誰が作者であるかを示すための手段を提供しています。

動機

NFT(Non-Fungible Token)とは、一意で交換できないデジタルアイテムを表すトークンです。 これらのNFTには、誰がそのアイテムを制作したか、すなわち「作者」に関する情報が重要です。 しかし、現在までNFTの作者情報を明確に識別するための共通の方法がなかったため、いくつかの問題が生じていました。

これまでに試みられた既存の方法には、次のようなものがあります。

mint tx.originやmsg.senderを使用する方法

この方法は、NFTをmint(作成)した人を作者とみなすものです。 しかし、作者とmintした人が常に同じとは限りません。 たとえば、コントラクトによってmintされる場合や、複数の人が関与している場合もあります。

特定のIDの最初のTransferイベントを使用する方法

この方法は、特定のNFTの最初の所有者を作者と見なすものです。 しかし、コントラクトやmintを制御する人が勝手に他人を作者と主張することができ、正確さが保証されません。 また、複数の作者を考慮することも難しいです。

カスタムな方法やカスタムなJSONフィールドを使用する方法

これはNFTプラットフォームごとに異なる方法で、カスタムなデータフィールドを使用して作者情報を提供するアプローチです。 しかし、一貫性がなく、作者情報の取り扱いが複雑で、不正確な主張が行われる可能性があります。

この新しい提案(EIP)は、これらの問題を解決するために生まれました。 提案では、NFTに作者情報を含む新しいデータフィールドを追加することで、正確で信頼性のある作者情報を提供します。 また、作者の同意を示す証明を含めることで、作者の同意なしに作者と主張することを防ぐ仕組みが構築されています。

つまり、この提案はNFTの作者情報を明確に識別し、公正な方法で誰が作者であるかを示すための新しい基準を提供することを目的としています。 これにより、mintした人と作者が同じでない場合でも、また複数の作者が関与する場合でも、適切な情報が提供されることが期待されています。

仕様

この標準では、NFTの「作者」や「mint」などの概念を定義し、NFTの作者情報を取り扱うための方法を提供しています。

定義

  • Authors(作者)
    • NFTの制作者です。
  • Minter(発行者)
    • NFTを実際に作成するトランザクションを行うエンティティです。
    • mintした人と作者が同じであることもあれば、異なることもあります。
  • Verifier(検証者)
    • NFTの作者情報を検証したいエンティティです。
    • 例えば、ユーザーやNFTマーケットプレイスなどです。
  • Author Consent Proof(ACP、作者同意証明)
    • 署名されたメッセージで、署名者がNFTの作者とみなされることに同意したことを示す証明です。

作者情報のサポート

この標準は、新しいJSONフィールド「authorInfo」を導入しています。 このフィールドは、作者情報の主張に必要なインターフェースを提供することが必須であり、また作者の同意証明に関するオプションのインターフェースも提供します。

具体的には、以下のように定義されています。

  • 「authorInfo」は、NFTのメタデータのトップレベルにあるフィールドです。
  • EIP721のメタデータ拡張をサポートするコントラクトの場合、tokenURI(uint256 _tokenId)で指定されるJSONドキュメントは、「authorInfo」というトップレベルのフィールドを含む必要があります。
  • EIP1155のメタデータ拡張をサポートするコントラクトの場合、uri(uint256 _id)で指定されるJSONドキュメントは、「authorInfo」というトップレベルのフィールドを含む必要があります。

また、「authorInfo」のJSONスキーマ(ERC5375AuthorInfoSchema)は次のように定義されています。

json
{
    "type": "object",
    "properties": {
        "consentInfo": {
            "type": "object",
            "description": "同意の検証のための補助フィールド",
            "properties": {
                "chainId": {
                    "type": "integer",
                    "description": "EIP-155 チェーンID"
                },
                "id": {
                    "type": "string",
                    "description": "NFTのID"
                },
                "contractAddress": {
                    "type": "string",
                    "description": "スマートコントラクトの0x接頭辞付きアドレス"
                }
            }
        },
        "authors": {
            "type": "array",
            "items": "ERC5375AuthorSchema"
        }
    },
    "required": ["authors"]
}

このスキーマは、「authorInfo」フィールドの中に含まれるデータの形式を定義しています。具体的には、「consentInfo」フィールドは同意の検証に関連する情報を、そして「authors」フィールドは作者の情報を配列として格納します。

この新しい基準によって、NFTの作者情報を整理し、公正かつ確実に誰が作者であるかを示すための枠組みが提供されています。

注意

  • 「authors」は空の配列である可能性があります。
  • つまり、何も作者情報がない場合もあるということです。

ERC5375AuthorSchemaの定義

これは、NFTの作者情報を取り扱うためのデータ形式を定義するスキーマです。 具体的な定義は次のようになります。

json
{
    "type": "object",
    "properties": {
        "address": {
            "type": "string",
            "description": "作者の0x接頭辞付きアドレス"
        },
        "consent": {
            "type": "ERC5375AuthorConsentSchema",
            "description": "作者の同意情報"
        }
    },
    "required": ["address"]
}

ここで、「address」フィールドは、NFTの作者のアドレスを示します。 そして、もしも「consent」フィールドが存在する場合、その中に作者の同意に関する情報が含まれることになります。

もし「consent」フィールドが存在する場合、「authorInfo」というNFTの作者情報を含むトップレベルのフィールドには、「consentInfo」というフィールドも必ず存在する必要があります。 これによって、作者の同意情報が適切に伝えられる仕組みが確立されます。

これにより、NFTの作者情報を整理し、作者が同意した情報を適切に管理することが可能となります。

もちろんです。以下に詳細な説明を提供します。

ERC5375AuthorConsentSchemaの定義:

このスキーマは、作者の同意情報を扱うためのデータ形式を定義しています。 具体的な定義は以下の通りです。

json
{
    "type": "object",
    "properties": {
        "consentData": {
            "type": "object",
            "properties": {
                "version": {
                    "type": "string",
                    "description": "NFT作者同意スキーマのバージョン"
                },
                "issuer": {
                    "type": "string",
                    "description": "作者の0x接頭辞付きアドレス"
                },
                "metadataFields": {
                    "type": "object"
                }
            },
            "required": ["version", "issuer", "metadataFields"]
        },
        "publicKey": {
            "type": "string",
            "description": "作者のEVM公開鍵"
        },
        "signature": {
            "type": "string",
            "description": "同意メッセージのEIP-712署名"
        }
    },
    "required": ["consentData", "publicKey", "signature"]
}

ここで、metadataFieldsは、作者が認証するためのJSONのトップレベルフィールド(authorInfoを除く)を含むオブジェクトです。 metadataFieldsのキーは、可能な場合はフィールドの一部または空の部分集合を表すことがあります。

consentDataは、他のEIPによって定義された追加のフィールドをサポートすることができます。 ただし、consentDataには、作者の同意証明の妥当性を検証するために必要な情報がすべて含まれている必要があります(他のフィールドにすでに存在しない情報)。

要するに、このスキーマによって、作者の同意情報を詳細に定義し、その情報が正当であることを確認する手段が提供されています。 これによって、作者が実際に同意した情報を確実に管理できるようになります。

作者の同意

作者の同意は、EIP712という標準に準拠したメッセージに署名することで得られます。 具体的なメッセージの構造は、次のように定義されています。

solidity
struct Author {
    address subject;
    uint256 tokenId;
    string metadata;
}

ここで、「subject」はNFTコントラクトのアドレス、tokenIdはNFTのID、そしてmetadataはmetadataFieldsにリストされたフィールドのJSONエンコードです。

  • metadataFieldsにリストされたフィールドと同じ順序で、まったく同じフィールドを含む必要があります。
  • 非ASCII文字をすべてエスケープする必要があります。
    • エスケープされた文字に16進数の文字が含まれている場合、大文字である必要があります。
  • フィールド名や値の一部でないホワイトスペースを含むことはできません。

例えば、トップレベルのJSONフィールドが次のようにあるとします。

json
{
    "name": "The Holy Hand Grenade of Antioch",
    "description": "Throw in the general direction of your favorite rabbit, et voilà",
    "damage": 500,
    "authors": [...],
    ...
}

そして、metadataFieldsの内容が["name", "description"]である場合、metadataの内容は次のようになります。

json
{
    "name": "The Holy Hand Grenade of Antioch",
    "description": "Throw in the general direction of your favorite rabbit, et voil\u00E0"
}

同意情報の構造は、consentDataと同様に、他のEIPによって定義された追加のフィールドをサポートすることがあります。

ドメインセパレータの構造は次の通りです。

solidity
struct EIP712Domain {
    string name;
    string version;
    uint256 chainId;
}

ドメインセパレータとは?

ドメインセパレータは、EIP712と呼ばれる標準において、メッセージの署名の妥当性を検証する際に使用される概念です。 これは、メッセージがどのドメイン(ドメインとは一般的には特定のプロトコルやコントラクトのことを指します)に関連しているかを定義し、署名の検証をより堅牢にするためのものです。

ドメインセパレータの役割

ドメインセパレータは、メッセージの署名のコンテキストを指定します。 メッセージに含まれる情報だけでなく、メッセージがどのコントラクトやプロトコルに関連しているかも考慮されることで、署名の偽造を難しくする役割を果たします。

ドメインセパレータの構造

ドメインセパレータは、以下のような構造を持ちます。

solidity
struct EIP712Domain {
    string name;
    string version;
    uint256 chainId;
}
  • name
    • ドメイン(コントラクトやプロトコル)の名前を表します。
  • version
    • ドメインのバージョンを表します。
  • chainId
    • EIP155のチェーンIDを表します。

例

たとえば、特定のNFTプロジェクトで使用されるメッセージの署名を検証する場合、ドメインセパレータはそのプロジェクトの名前やバージョン、そしてチェーンのIDを含むことで、そのプロジェクト固有のコンテキストを提供します。 これによって、他のプロジェクトやコントラクトで署名を使い回すことが難しくなります。

総じて、ドメインセパレータはメッセージの署名を安全に検証するための重要な概念であり、メッセージがどのドメインに属しているかを明示的に示す役割を果たします。

ここで、nameとversionはconsentDataで説明されたフィールドと同じです。 同様に、この構造も他のEIPによって定義された追加のフィールドをサポートすることができます。

これにより、作者の同意情報が適切に署名され、検証される仕組みが提供されています。

作者の同意の検証

作者の同意の検証は、EIP712という規格を使用して、個々の作者ごとに行われます。 具体的には、JSONドキュメントD1が与えられた場合、同意の証明が有効であるためには、次の条件をすべて満たす必要があります。

  1. D1にはERC5375AuthorInfoSchemaに一致するトップレベルのauthorInfoフィールドが存在すること。
  2. 同意が存在し、ERC5375AuthorConsentSchemaに一致すること。
  3. EIP721の場合はtokenURIを呼び出し、EIP1155の場合はuriを呼び出してJSONドキュメントD2のURIが返された場合、metadataFieldsにリストされたすべてのトップレベルフィールドが存在し、同じ値を持つこと。
  4. signature内のEIP712署名(JSONドキュメントで指定されたフィールドを使用して計算される)が有効であること。

上記わかりにくいので、ここでもう少し噛み砕いて説明します。

1. ERC5375AuthorInfoSchemaに一致するトップレベルのauthorInfoフィールドが存在すること。

この条件は、NFTのメタデータにauthorInfoフィールドが存在することを要求しています。 例えば、以下のようなNFTのメタデータがあるとしましょう。

json
{
    "name": "My NFT",
    "description": "This is an example NFT",
    "authorInfo": {
        // authorInfoの内容がここに入る
    },
    // 他のフィールドもここに入る
}

2. 同意が存在し、ERC5375AuthorConsentSchemaに一致すること。

authorInfoに含まれる各作者の情報は、ERC5375AuthorConsentSchemaに一致する必要があります。 このスキーマには、作者の同意情報が含まれています。

json
"authors": [
    {
        "address": "0x123...",
        "consent": {
            // 同意情報の内容がここに入る
        }
    },
    // 他の作者も同様に続く
]

3. EIP721の場合はtokenURIを呼び出し、EIP1155の場合はuriを呼び出してJSONドキュメントD2のURIが返された場合、metadataFieldsにリストされたすべてのトップレベルフィールドが存在し、同じ値を持つこと。

この条件は、EIP721またはEIP1155準拠のコントラクトからJSONドキュメントD2のURIを取得し、そのドキュメントに含まれるトップレベルのフィールドが、metadataFieldsにリストされたフィールドと同じ値を持つことを要求します。 例えば、metadataFieldsが["name", "description"]の場合、D2のメタデータが以下のような場合が考えられます。

json
{
    "name": "My NFT",
    "description": "This is an example NFT",
    // 他のフィールドもここに入る
}

4. signature内のEIP712署名が有効であること。

この条件は、各作者の同意情報のsignatureフィールドに含まれるEIP712署名が、該当するメッセージと共に正しく検証されることを要求します。 これにより、同意情報が改ざんされていないことを確認します。

以上の条件を満たすことで、NFTの作者情報と同意情報が正当であることが検証されます。 検証者はこれらのステップを順番に実行し、NFTの作者が実際に同意した情報であるかどうかを確認します。

検証者は、有効な同意の証明を持つアドレスXに対してNFTがある場合でも、Xが実際の作者であると絶対に断定してはいけません。 しかし、検証者は、NFTがアドレスXのための有効な同意の証明を提供しない場合、Xが実際の作者でない可能性が高いと仮定することができます。

総じて、検証者は、同意の証明の妥当性を確認し、NFTの作者情報が正当かどうかを確かめるために、特定の手順と基準を遵守する必要があります。

補足

作者の同意証明だけを提供する理由

NFTのオリジナルな作者を確定的に特定することは難しいため、この標準では作者の同意証明だけを提供することになっています。

もしも、与えられたNFTが本当にどのユーザーによって作成されたかを確認するプロトコルが存在すると仮定してみましょう。 しかし、その方法が存在したとしても、攻撃者はNFTをわずかに変更して新しいNFTを作成することができます。 その新しいNFTについても正当な作者として主張することができるでしょう。 実際の例として、画像の一部を変更したり、テキストの一部を置き換えたりすることが挙げられます。 このような行動を防ぐためには、2つのNFTが意味的に同等であるときを正確に定義する必要があります。 しかし、そのような概念を定義すること自体が難しいだけでなく、この標準の範囲を超えてしまいます。

同様に、mintしたアドレスを作者の代理として使用する場合も同じ問題が発生します。

このため、オリジナルな作者の特定は複雑で困難な問題であり、その解決には現実的な方法が存在しません。 その代わりに、作者の同意証明を提供することで、NFTの作者が同意したことを確認し、その作者による情報が提供されることを重視しています。

オリジナルな作者を特定するためには、「NFT YとユーザーXがオリジナルの作者であると主張している場合、Xは本当にYのオリジナルの作者なのか?」という疑問に答えるプロトコルが必要です。

なぜオフチェーンなのか

  • オフチェーンのサポートを提供する理由は3つあります。
    1. 既存のスマートコントラクトの変更が不要であること。
    2. オフチェーンのストレージは通常、オンチェーンのストレージよりも安価であり、実装のハードルを低減できること。
    3. オンチェーンの作者同意は主にユーザーがNFTの主観的な価値を決定するために使用されるため、オンチェーンの作者性の証明が必要なケースは限られているため。

なぜid、chainId、contractAddressを繰り返すのか

作者の同意を検証するためにJSONドキュメント自体に必要な情報を含めることにあります。

これらの情報は通常、文脈情報から導き出すことができるかもしれません。 しかし、作者の同意を検証するためには、JSONドキュメント単体で十分な情報を持っている必要があります。 繰り返して情報を含めることで、JSONドキュメントが他の情報なしに作者の同意を検証するのに十分なものとなります。

このような設計によって、外部の文脈情報やリクエストを必要とせずに、JSONドキュメント自体が作者の同意を検証するための完全な情報を提供できるようになります。 その結果、効率的で信頼性のある検証が可能となります。

なぜリヴォケーションシステムを実装しないのか

一般的に、NFTの作者性は最終的なものです。 つまり、誰かがNFTを作成した場合、そのNFTの作者は確定されます。 従って、作者が誰であるかという事実は変更されないものとされています。 このため、作者性を後から無効化したり変更したりする必要は通常はありません。

一方で、リヴォケーションシステムを実装すると、スマートコントラクトにさらなる実装要件が追加されます。 そして、リヴォケーションシステムの導入によって、検証の複雑さが増加する可能性があります。

リヴォケーションシステムは、作成されたNFTの状態を変更するための仕組みであり、これには複雑なロジックや管理が必要です。 これによってスマートコントラクトのコードが複雑化し、バグやセキュリティリスクが増加する可能性があります。

そのため、このEIPではリヴォケーションシステムを導入しない選択がされています。 ただし、スマートコントラクトが他のEIPで定義されたリヴォケーションシステムを実装することは可能です。 このEIPでは、作者の同意証明の仕組みに焦点を当て、作者の同意に基づく仕組みを提供することが主な目的とされています。

なぜ署名メッセージ内の非ASCII文字をエスケープするのか

EIP712は、スマートコントラクト内でのトランザクションの検証を考慮して設計された規格です。 つまり、スマートコントラクト内でトランザクションの妥当性を確認する場面を想定しています。 しかし、このEIP(提案)自体はオンチェーンでの検証よりもオフチェーンでのサポートが優先されています。 そのため、オンチェーンでの検証は主要な焦点ではないとされています。

しかし、スマートコントラクト内で非ASCII文字を含む文字列を処理することは、複雑であることがあります。 非ASCII文字は通常、Unicodeの特定のコードポイントを表すために使用されます。 スマートコントラクト内でこのような文字列を処理するには、コードの複雑性が増加し、バグや予測できない動作が発生する可能性があります。

そのため、このEIPでは、スマートコントラクト内で非ASCII文字列を処理する難しさを考慮し、署名メッセージ内の非ASCII文字をエスケープすることが求められています。 エスケープすることで、スマートコントラクト内での処理が安定し、予測可能な動作が実現されます。この手法は、スマートコントラクトの複雑性を抑えつつ、署名メッセージの安全な処理を支援します。

作者の利便性向上

EIP712は、特定のプロトコルに基づいて署名されたメッセージの検証を可能にするものです。 このEIPにより、NFTの作者は新しい作品を作成する際に、その作品が自分のものであることを証明することができます。 しかし、このプロセスが煩雑で技術的な知識を必要とすることがあるため、作者の利便性を向上させるための仕組みが提供されています。

具体的には、以下の点が考慮されています。

  1. Mintの技術的な部分をMintorに任せる 作者は自身の作品をNFTとしてmintするために必要な手続きやトランザクションを行う必要がありますが、これらの技術的な手続きを専門家であるMintorに任せることができます。 これにより、作者は技術的な詳細や手続きに関する心配を軽減することができます。

  2. EIP712メッセージの署名に注力 作者には、EIP712**メッセージに署名するだけでよいという簡単な手続きが求められます。 これにより、作者は自身の作品がオリジナルであることを証明する一方で、複雑な技術的な手続きを心配することなく、よりクリエイティブな活動に集中できるようになります。

  3. EVMウォレットの取得 作者はEVM(Ethereum Virtual Machine)ウォレットを取得する必要があります。 これにより、署名メッセージを作成して署名するためのプラットフォームが提供されます。

  4. 簡素化された手続き 多くの場合、Dapp(分散型アプリケーション)を使用することで、EIP712メッセージの読み取りと署名が簡素化されます。 Dappはユーザーに対して直感的なインターフェースを提供し、署名手続きを簡単に行えるようにします。

これらの仕組みにより、作者は作品の制作に集中しながら、技術的な側面を最小限に抑えてNFTの作成と署名を行うことができます。 技術的な障壁を減少させ、作者の利便性を向上させることが、この提案の目的の一つです。

アドレスベースの同意の制限

このEIPは、特定のアドレスが同意を提供したことを検証するためのプロトコルを提供しています。 これは、NFTの作者が自身の作品に関する同意を示す手段として利用されます。 しかし、注意が必要なのは、このプロトコルが同意を提供したアドレスと実際の作者が一致することを保証しないという点です。

例えば、NFTの名前フィールドに記載された作者名と関連するアドレスが一致しているとは限りません。 また、同意を提供したアドレスが実際の作者であることを保証するためには、アドレスとそれに関連するエンティティ(例:実際の個人や組織)のリンクを明確に証明する必要があります。

しかしながら、このドキュメントの範囲内では、アドレスとエンティティのリンクを確立するプロトコルや方法についての詳細は提供されていません。 このEIPは、アドレスベースの同意を検証する方法を提供するだけであり、アドレスと実際の作者の関連性を明確にすることは対象外とされています。

セキュリティに関する考慮事項について説明いたします。

後方互換性

特になし。

セキュリティ考慮事項

攻撃

このEIPには、特定のアクション(たとえばNFTの作成)に同意するための署名メッセージが含まれています。 攻撃者が作者の同意メッセージを無断で署名させる攻撃を行う可能性があります。 例えば、作者の同意なしにその署名が行われることで、攻撃者が作者であるかのように振る舞うことができます。

したがって、作者は自身の意志に反して行われた署名を防ぐために、署名メッセージのすべてのフィールドが正しいか確認する必要があります。 これによって、攻撃者による不正な署名が無効化されます。

また、より巧妙な攻撃方法として、重要な情報をmetadataFieldsに含めないというアプローチが考えられます。 例えば、重要な情報を含まない場合、Mintorがその情報を変更しても、作者の署名は有効なままである可能性があります。 このため、作者の署名だけでなく、含まれる情報の正当性も確認することが重要です。

簡潔に言えば、作者は自分の同意を示す署名メッセージが正当かどうかを確認し、その署名が無断で行われないように注意する必要があるということです。 そして、重要な情報をmetadataFieldsに含めて正当性を確認することで、攻撃者が情報を変更しても有効な署名を行うことを防ぎます。

非推奨の機能

元々、ERC5375AuthorInfoSchemaには作者の名前を指定するフィールドが含まれていましたが、これは悪意のある作者のなりすまし(スプーフィング)の高いリスクのために取り下げられました。

  1. AliceがBobの名前とAliceのアドレスを使用してNFTをmint。
  2. Charlieはアドレスを確認せずに提供された名前に依存。
  3. CharlieはBobが作成したと信じてAliceのNFTを購入。

そのため、スマートコントラクト開発者は、JSONドキュメントに検証できない情報を追加しないように注意する必要があります。 作者情報(例:作者の名前)を提供する最も安全な方法は、情報が作者のアドレスと関連付けられていることを証明することであり、NFT自体と関連付けるのではありません。

リプレイ攻撃への抵抗

チェーンID、コントラクトアドレス、トークンIDはNFTを一意に識別します。 そのため、追加のリプレイ攻撃対策(例:ノンスシステム)の実装は必要ありません。

リプレイ攻撃については以下を参照してください。

引用

Samuele Marro (@samuelemarro), Luca Donno (@lucadonnoh), "ERC-5375: NFT Author Information and Consent," Ethereum Improvement Proposals, no. 5375, July 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-5375.

最後に

今回は「商品を購入したレシートをNFTのメタデータに書きこんで、ブロックチェーン上に書き込むことができるERC5570」についてまとめてきました! いかがだったでしょうか?

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