見出し画像

Solana Developer Hub #7: Escrow入門

この記事は2024/07/26に開催したSolana Developer Hub Online #7 で話をした「Escrow入門」を再編集したものになります。

Escrow入門

Escrow大好きおじさんです。Solanaに入門したら一度は触るEscrow。かれこれ3、4回ほどEscrowを触るぐらいにはEscrow大好きです。

EscrowにはSolanaの開発に必要なすべてが詰まっている。と言っても過言ではないほどSolanaのプログラム(スマートコントラクト)開発に必要な知識の宝庫です。

このEscrowはいろいろなサイトで入門の総括として出てきます。
しかし、このEscrowとは何か、なぜそう作るのかというところまで踏み込んだ解説はなく、ちゃんと理解するには敷居が高いです。

そこで、今日はEscrowを作るための前提してその辺りに言及した解説を行えたらと思います。

Escrowというのは商取引で扱われる用語で安全な取引を行うために第三者(エスクローエージェントと呼ばれる)を仲介して取引を行う仕組みのことです。

同様の仕組みをSolana上に構築するのがEscrowを開発することが目的となります。

なぜこのEscrowが必要になるのか、まずは"安全ではない取引"とはどういうものか考えてみましょう。

単純な取引の場合

  • AはBにT1を送る

  • BはAにT2を送る

という交換が発生します。
これは同時にお互いの期待するT1/T2を送信した場合にのみ正しい取引として成立します。

この交換では不正の入る余地が入ります。

  • AはBの期待するT1以外を送った

  • Aの送信後にBがT2を送らなかった

  • Aの送信後にBがAの期待するT2以外を送った

それぞれの送信自体は成立してしまうため、仮に不正がおきても取り消すことは困難です。

というので、最も簡単な方法での取引では不正を行う余地があり安全とはいえません。
もちろん、不正が行われなければ取引は成立するため、例えばAとBが事前に合意し信頼があれば問題はありません。

逆説的にいえば単純な交換が成立するのはお互いに信頼があるときのみです。

この方式では信頼のない見知らぬ人と取引を行うことができません。
そこで、別の方法で取引を行うことを考えてみましょう。

はじめのEscrowの図のように信頼できる第三者に仲介してもらう方法を考えてみます。

  • AはCにT1を送る

  • BはCにT2を送る

  • Cは取引が成立したとみなしたら、それぞれにT1とT2を送る

この方法では信頼できる第三者を介することで、単純な交換のときに発生したような不正は行うことができなくなりました。
仮にBが適切なT2を送らなかった場合、Cは預かったT1をAに返却することができるためより安全な取引となっています。

しかし、この方法が完全かというとそうではありません。

  • AとBが信頼するCは存在するのか

  • Cはすべての取引の仲介するというのは現実的に可能な仕事量なのか

  • C自体が不正を行う可能性はないか

  • Cの監査は誰が行うのか。

というのでCという第三者を実現するためのコストはとても大きいです。

ここでの問題は第三者を置いたとしても、そこには一定の信頼が必要であり不正の余地が残ってしまうことです。

では人を介在させずに、ルールに基づいて機械的に執行する仕組みがあればどうでしょうか?
Solanaにはちょうど良い仕組みとしてプログラムが存在しており、そちらを使って機械的に取引を執行する仕組みを考えていきましょう

先ほどの第三者であったCをProgramに置き換えます。
Aが取引が成立する条件とT1を送信し、Bがその条件に合致T2を送信することでProgramが取引を成立させます。(もしくはProgram自体が条件を持つでも可)

条件に合致しない場合は取引が成立しないため、この方法なら安全に取引ができるようになります。

このように信頼を必要とせずに機械的に取引を執行するプログラムを作ることがSolanaのEscrow開発の目的になります。
つまり、Escrowという一般的な手法をSolanaに落とし込むにはどうすればいいのかという話ですね。

ここまでEscrowの考え方を説明させていただきました。
Solana上で作るには最後に出した図をそのまま作ればいい・・・と考えるかもしれませんが、実はあの図の形のものはSolana上では作ることができません。

ここからEscrowの考え方を元に、Solanaのプログラムとして実現可能な最適な形にする方法について解説していきます。

まず、スマートコントラクトの説明としてよくルールを基に機械的、または自動的に執行すると言われることが多いです。
が、これはあまり正確ではなく、正確には執行できる状態になる。というので執行自体は誰かが行わないといけません。

つまり、Programが取引を成立させるためにAとBにT1/T2を送信するという処理を誰かが実行しないといけません。

Solanaにおいてはトランザクションを送信するたびにチェーン上に書き込まれ、そのさいに一定のfeeがかかってきます。
そのため、トランザクションはできる限り少なくすることが望ましいです。

そう考えた場合、Aが送信し、Bが送信し、取引と処理を考えるとBが送信と取引を同時に実行するのがタイミングとしてあっています。
Bが送信と取引のプログラム実行を1つのトランザクションで実行することでトランザクション数を2回で行えるようになりました。

このような形にした場合、BがProgramにT2を送信し、ProgramがAにT2を送信するという処理が同一トランザクションで実行されることになり冗長になります。
同一トランザクションではアトミックに更新されるため、BからAに直接T2を送信するように変更します。

BからAに直接送信することでかなりフローとトランザクションがシンプルになりました。
無駄な送信があってもいいと思われるかもしれませんが、Solanaのプログラム開発にはCompute Unit/Budgetという概念があり、このCUを小さくすることはとても重要です。
最小の方法で実現するように意識しましょう。

これでできたと言いたいところですが、この形ではProgramがBからAにT2がいくつ送られたかを知ることができず取引の成立可否を判断できません。
そこでProgram上からBからAに送信を行えるようにします。

Solanaではトランザクションの送信時に署名することで人ができる操作をプログラムに移譲させることができます。

今回のケースではBが署名することで、プログラム上からBからAにT2を送信することができるようになります。

Solana上ではこういった送信の仕組みは別のプログラムが行います。
例えばBからAにトークンを送るのであればトークンプログラムのTransfer Instructionを署名して送信する形です。

プログラム上で同様に他にプログラムを呼び出す場合はCPIと呼ばれる機能を使って実現します。

CPIを利用するさいに、一つネックになるのがProgramからBへの送信です。

先ほど、トークンを送るのであればトークンプログラムのTransfer Instructionを署名して送信する形になると書いた通り、送信には送信者の署名が必要になります。
人の場合は秘密鍵を生成することで署名可能になりますが、プログラムは秘密鍵を保持することはできません。

そういったさいに必要になるのがPDAです。
このPDAはいろんな用途で使われることがありますが、今回はプログラム上で署名するために利用します。

SolanaのCPI、PDAという機能を使うことで、最後に紹介したフローを実現することができるようになります。

ここまで紹介した知識でSolanaのEscrowを十分開発できると思います。ただ、合わせてこれも知っていると捗るという知識があるので合わせて紹介したいと思います。

ここまでT1、T2といった記号で説明していましたが、これらは何なのでしょうか?

A、またはBが所有することが可能なデータであり、単一のものなら所有権の移譲、数量があるならAとBそれぞれ数量の変化で表現できるデータです。
Solanaではこういったものは俗にトークンと呼ばれます。

Solanaではトークンを管理するトークンプログラムというものがSPLで提供されています。
特に理由がなければEscrowではこのトークンプログラムが管理するトークンを使って取引を作るのが簡単です。
(もちろん、理由があるならこのトークンを扱わない選択肢はあります)

トークンプログラムが扱うアカウントは2つあります。

  1. トークン自体を表すミントトークンアカウント

  2. ユーザーのトークンの所有を表す関連トークンアカウント

トークンの送信というのは先に紹介した関連アカウントの操作であり、Aの関連トークンアカウントが数量を引き、Bの関連トークンアカウントの数量を足すの送信の中身になります。

関連トークンアカウント上にはownerフィールドが存在し、そのフィールドに指定されたアドレスが所有者になります。

Aが関連トークンアカウントを所有する場合、Aの持つアドレスが関連トークンアカウントのownerフィールドに入っている状態のことを指します。

ここまで説明したアカウントというものはシステムプログラムが作成した空のアカウントを任意のプログラムが初期化したものになります。
例えばトークンプログラムが扱うアカウントは、システムプログラムが作成した空のアカウントをトークンプログラムが初期化して初めてミントトークンアカウント、関連トークンアカウントとして扱える形ですね。

というので、ここまでの話をまとめるとEscrowの全体像は図のようになります。

Escrow Stateなんかは割愛してしまいましたが、取引を成立させるための条件の保持、取引済みか判断するために必要なアカウントだと思ってください。

Escrow楽しい!!!!!!!!


今回は前提知識部分の紹介が主だったため、実際にEscrowを実装してよりEscrowへの理解を深めたいという方は下記のリンクを参照ください。


この記事が気に入ったらサポートをしてみませんか?