ブロックチェーンへの書き込み
この内容では、Sequence SDKを使ってブロックチェーンに書き込む方法について詳しく説明しています。非同期でのトランザクション処理や、生のトランザクション、ERC20・ERC721・ERC1155トークンの送信、スマートコントラクトとのやり取りについて解説しています。
ブロックチェーンへの書き込み
ブロックチェーンは、汎用的で公開されており、検証可能なデータベースと考えることができます。ブロックチェーンに書き込むには、一般的なデータベースと同様にトランザクションを作成する必要があります。
通常、ブロックチェーンのトランザクション作成は非常に複雑ですが、Embedded Walletがその複雑さを解消し、5種類のTransactions
を提供しています。
トランザクションの送信は非同期タスクです。SequenceWallet.SendTransaction
を呼び出す際にawait
を使えば、TransactionReturn
オブジェクトを直接取得できます。もしくは、推奨される方法として、SequenceWallet.OnSendTransactionComplete
やSequenceWallet.OnSendTransactionFailed
イベント用のハンドラ関数を設定し、どこからでも(awaitなしで)SequenceWallet.SendTransaction
メソッドを呼び出すことも可能です。例:
Unityでイベントの扱いに慣れていない場合は、この素晴らしい Reddit投稿 をご覧ください。
RawTransaction
Transaction
の最も基本的な形であるRawTransactionは、ETHや利用中ネットワークのガス通貨をAddress
に送る際に非常に便利です。
例えば、1 MATICを0x9766bf76b2E3e7BCB8c61410A3fC873f1e89b43f
に送る場合、以下のスニペットを利用できます。
ここで _wallet は SequenceWallet です。
注意:EVMは浮動小数点数をサポートしていません。そのため、トークン(およびガス通貨)の値は整数と「decimals」値で表現されます。1 ETH(または上記例の1 MATIC)は1000000000000000000
(1 * 10^18)として表され、ETHやMATICなど多くのガス通貨は「decimals」値が18です。DecimalNormalizer.Normalize
(上記)は、input value * 10^decimals
を返す基本的なヘルパー関数で、オプションで「decimals」値を第2引数として指定できます(省略時は18)。
さらに、RawTransactionには16進数形式のデータを文字列として含めることも可能です。詳細は本ドキュメントの上級セクションをご覧ください。
sendERC20
ERC20トークンは、代替可能トークンの標準です。Builderを使えば、ERC20コントラクトのデプロイやトークンのミントも簡単に行えます。詳しくはBuilderのドキュメントをご覧ください。
ERC20トークンのトランザクションを送信するには、次のコードスニペットを利用できます。
注意:上記と同様に、DecimalNormalizer.Normalize
を使って金額を人間が読みやすい形式からEVM形式に変換することを推奨します。ERC20トークンの「decimals」値が18でない場合は、オプションの「decimals」intパラメータを必ず指定してください。ERC20の「decimals」値が分からない場合は、Builderの「Read Contract」内の「decimals」メソッドで簡単に確認できます。
複雑なERC20操作
基本的なトークン送信以外のERC20トークン操作には、SDKに含まれるSequenceEthereum
ライブラリをご利用ください。Embedded WalletsでRawTransactions
を作成・送信できるよう、ERC20スマートコントラクトのラッパー関数をご用意しています。
まず、コントラクトアドレスと、必要に応じてABI文字列(ERC20標準のカスタムバリエーションを使う場合のみ、推奨はしません)を指定してERC20
オブジェクトを作成します。
この参照を使えば、ERC20クラスで実装されているすべてのメソッドにアクセスできます。Mint
などCallContractFunction
を返すメソッドは、Embedded WalletsでRawTransactionを作成する際に利用できます。例:
sendERC721
ERC721トークンは非代替性トークン(NFT)の標準です。NFTとして知られています。Builderを使えば、ERC721コントラクトのデプロイやトークンのミントも簡単に行えます。詳しくはBuilderのドキュメントをご覧ください。
ERC721トークンのトランザクションを送信するには、次のコードスニペットを利用できます。
複雑なERC721操作
基本的なトークン送信以外のERC721トークン操作には、SDKに付属しているSequenceEthereum
ライブラリをご利用ください。Embedded WalletsでRawTransactions
を作成・送信できるよう、ERC721スマートコントラクトのラッパー関数をご用意しています。
まず、コントラクトアドレスと、カスタムのERC721規格(推奨されません)を使う場合はオプションでABI文字列を指定して、ERC721
オブジェクトを作成します。
この参照を使うことで、ERC721クラスで実装されているすべてのメソッドにアクセスできます。たとえばSafeMint
のようにCallContractFunction
を返すメソッドは、Embedded WalletsでRawTransactionを作成する際に利用できます。例:
sendERC1155
ERC1155トークンはマルチトークン規格で、SFT(セミ・ファンジブルトークン)とも呼ばれます。ERC1155規格の共同開発者として、私たちはこの規格がゲームにおいて非常に有用であると確信しています。Builderを使えば、ERC1155コントラクトのデプロイやトークンのミントも簡単です。詳しくはBuilderのドキュメントをご覧ください。
ERC1155トークンのトランザクションを送信するには、次のコードスニペットを利用できます。
注意:同じERC1155コントラクトから複数のトークンIDを一度に送信したい場合は、トランザクション内に複数のSendERC1155Values
オブジェクトを含めてください。
複雑なERC1155操作
基本的なトークン送信以外のERC1155トークン操作には、SDKに付属しているSequenceEthereum
ライブラリをご利用ください。Embedded WalletsでRawTransactions
を作成・送信できるよう、ERC1155スマートコントラクトのラッパー関数をご用意しています。
まず、コントラクトアドレスと、カスタムのERC1155規格(推奨されません)を使う場合はオプションでABI文字列を指定して、ERC1155
オブジェクトを作成します。
この参照を使うことで、ERC1155クラスで実装されているすべてのメソッドにアクセスできます。たとえばMint
のようにCallContractFunction
を返すメソッドは、Embedded WalletsでRawTransactionを作成する際に利用できます。例:
SequenceContractCall
EVMベースのネットワークでスマートコントラクトを呼び出す際、クライアントは「ABIエンコーディング」と呼ばれる複雑な処理を行い、呼び出したい関数のシグネチャやパラメータをバイナリ形式に変換します。この処理は複雑でミスが起きやすいため、私たちが抽象化し、ユーザーが直接扱う必要がないようにしています。仕組みに興味がある方は、こちらのドキュメントをご覧ください。
SequenceContractCallトランザクションを使うことで、任意のスマートコントラクトの任意のメソッドを呼び出すことができ、複雑なABIエンコーディング処理もサーバー側で対応します。
SequenceContractCallトランザクションを送信するには、次のコードスニペットを利用できます:
上記の内容を詳しく見て、分かりにくい変数について理解を深めましょう。
ValueAsString:通常は “0” ですが、payableメソッド(スマートコントラクト定義で payable
キーワードが付いているもの)を呼び出す場合は異なります。payableメソッドを利用する場合は、DecimalNormalizer.Normalize
を使って、人間が読みやすい形式からEVM形式に金額を変換することを推奨します。なお、ユーザーは指定した金額を支払うための十分な資金をウォレットに用意しておく必要があります。このパラメータは省略可能で、省略時は “0” になります。
FunctionABIAsString:操作したい関数です。コントラクトのソースコード(Etherscanやご利用のネットワークのブロックエクスプローラー)から関数シグネチャ(パラメータ付き)をコピー&ペーストし、空白や変数名を削除して使うことをおすすめします。
ParametersAsObjectArray:呼び出したいメソッドに渡すパラメータです。パラメータ名は不要で、ABIに記載されている順番通りに値だけを指定してください。迷った場合は文字列形式で渡すと良いでしょう。
これらを組み合わせると、SequenceContractCall
を使ってERC20の “mint” 関数を呼び出す例は次のようになります:
バッチトランザクション
Sequenceスマートコントラクトウォレットの機能により、SDKを使って複数のトランザクションを簡単にバッチ処理できます。バッチ処理はガス代の節約に大きく貢献し、複雑なトランザクションもすべて成功またはすべて失敗としてまとめて実行できるため、用途ごとにカスタムスマートコントラクトをデプロイする必要がなくなり、新たな設計の可能性が広がります。
バッチトランザクションの送信はとても簡単です。SendTransaction
リクエスト時に、トランザクション配列に複数の種類のトランザクションを含めるだけです。
例えば、各タイプのトランザクションをバッチで送信する場合:
これらのトランザクションは、Sequenceスマートコントラクトウォレットによってネットワークに送信される前に1つのトランザクションにまとめられるため、受け取るトランザクションレシートも1つだけです。
FeeOptions
デフォルトでは、SDKはBuilder APIクレジットを使って、すべてのEmbedded Walletトランザクションのガス代を自動的にスポンサーします。ただし、特定のケースではユーザー自身にガス代を負担してもらいたい場合もあるでしょう。その場合、ユーザーはWeb3に慣れていて、ウォレットにガス代として使えるトークンや通貨を持っている必要があります。選択したネットワークのガス通貨だけでなく、特定のERC20やERC1155トークンでもガス代の支払いが可能です。
まず、バッチで送信したいトランザクションを組み立てます。その後、FeeOptionsをリクエストしてください。
FeeOptionsResponse
には、各 FeeOptionReturn
の価格を一定時間ロックするFeeQuote(文字列)が含まれています。これは後ほどトランザクション送信時に必要となります。SDKは自動的にユーザーのウォレットを確認し、Indexer を使ってユーザーが利用可能なFeeOptionsを調べます。
ここから、ユーザーにどの方法で手数料を支払うか選択してもらうUIを表示できます。
ユーザーが支払い方法を選択したら、選択したFeeOptionとFeeQuote文字列を含めてトランザクションを送信します。
Package Manager > Samples
からインポートできる Demo Scene
では、FeeOptionsのシンプルな使用例を確認できます。ここではUIを用意せず、ユーザーのウォレットで利用可能な最初のFeeOptionを自動的に選択しています。実際のゲームでこの方法を使うことは推奨しませんが、ご自身の統合の参考例としてご活用ください。サンプルコードは以下をご覧ください:
Transaction Queuers
ブロックチェーンを扱う際は、トランザクションをバッチ処理 してガス代を最小限に抑えることが重要です。そのため、SDKには柔軟に設定・拡張できる TransactionQueuer
を用意しています。Unityでトランザクションが多いゲームを開発する際のポイントについては、こちらのガイドもご参照ください。
シーンに TransactionQueuer
のMonoBehaviourを追加すると、いくつかの設定変数を指定できます。
AutoSubmitTransactions
:デフォルトはfalseです。これを有効にすると、ThresholdTimeBetweenTransactionsAddedBeforeSubmittedInSeconds
で指定した秒数、新しいトランザクションがキューに追加されなかった場合、自動的にキュー内のトランザクションを送信します。ThresholdTimeBetweenTransactionsAddedBeforeSubmittedInSeconds
:AutoSubmitTransactions == true
の場合、指定した秒数の間に新しいトランザクションが追加されなければ、自動的にキュー内のトランザクションを送信します。MinimumTimeBetweenTransactionSubmissionsInSeconds
:キューに入れたトランザクションを送信する際の最小間隔を秒単位で指定します。これにより、コード内でTransactionQueuer.SubmitTransactions()
を何度呼び出しても、前回の送信からMinimumTimeBetweenTransactionSubmissionsInSeconds
秒が経過していなければトランザクションは送信されません。注意:オプションのoverrideWait
ブールフラグを true にしてTransactionQueuer.SubmitTransactions(overrideWait: true)
を呼び出した場合は、MinimumTimeBetweenTransactionSubmissionsInSeconds
の経過に関わらず、キュー内のトランザクションが送信されます。
TransactionQueuer
では、いくつかのメソッドが利用できます:
- セットアップ:他のメソッドを呼び出す前に、必ず
TransactionQueuer
に対してSetup
を実行してください。これにより必要な依存関係が作成・キャッシュされます。 - Enqueue:トランザクションをキューに追加します。
- SubmitTransactions(bool overrideWait = false, bool waitForReceipt = true):
TransactionQueuer
による前回のトランザクション送信からMinimumTimeBetweenTransactionSubmissionsInSeconds
が経過していれば、キュー内のトランザクションを送信します。overrideWait = true
の場合は、すぐにキュー内のトランザクションを送信します。waitForReceipt = false
の場合、WaaS API からレスポンスを受け取った時点でTransactionReturn
を返します(注:これはWaaS APIがトランザクションレシートの待機中にタイムアウトした場合のみ関係します。waitForReceipt = true
の場合は、レシートが返るまでノードに継続的に問い合わせます)。 - ToString():標準の ToString() 関数をオーバーライドし、より詳細なログ出力をサポートします。
TransactionQueuer
には必ず Setup
を呼び出すのを忘れないでください!現在、SDK では TransactionQueuer
クラスの2種類の継承クラスが提供されています。
SequenceWalletTransactionQueuer
SequenceWalletTransactionQueuer
を使うことで、ユーザーの Sequence Embedded Wallet 用のトランザクションをキューに追加できます。
SequenceWalletTransactionQueuer
では、IQueueableTransaction
をキューに追加することが求められます。このインターフェースは QueuedTokenTransaction
クラスで実装されています。必要に応じて、他のクラスで IQueueableTransaction
インターフェースを実装してご利用いただけます。
PermissionedMinterTransactionQueuer
PermissionedMinterTransactionQueuer
は、プレイヤーのEmbedded Walletから署名済みメッセージを受け取った際に、バックエンドサーバーからトランザクションをキューに追加して送信する用途向けです。主に、ミント権限が必要なコントラクト(多くのトークンコントラクト)とやり取りする際に、プレイヤーのウォレットへトークンをミントするのに役立ちます。
PermissionedMinterTransactionQueuer
では、ミントする TokenId と Amount、必要に応じて IMinter を指定する PermissionedMintTransaction
(基本的なデータ転送オブジェクト)をキューに追加します。IMinter を指定しない場合は、デフォルトで PermissionedMinter
クラスが使用されます。PermissionedMinter
クラスは多くのケースで便利に使え、次の形式でペイロードを送信します:
このペイロードをサーバー側で検証し、ユーザーのアドレスにトークンをミントできます。実装例やセットアップについては、Jelly Forestガイドの該当セクションをご覧ください。
その他の用途では、独自の IMinter クラスを実装することも可能です。これにより、サーバーに送信するペイロードの形式や内容を必要に応じてカスタマイズできます。