solanaのアビトラbotで必要そうなところとか、わかったところわかっていないところとか
必要なこと
要は特定通貨からいくつかのルートを通って、最初の通貨に戻ったときにプラスが発生する取引を実現できればいい
つまり
- 裁定パス算出及び取引を行うProgram(ethでいうcontract)
- そのProgramを利用するclient
がざっくりいうと必要になる。
client
- rpc_clientを用意する
- 最新のブロックハッシュを取得する(ブロックチェーンの仕組み的に必要っぽい)
- 作成しておいたProgramのID(後述)
- instructionが必要とするdataの配列(escrow用のamountとか)
- payerとなるAccountのPubkey(要は手数料払うアカウント、自己ウォレットが該当するはず)
- ブロックハッシュ、program_id、data、payerをもとにtransactionを作成
- rpc_clientにsend_and_confirm_transactionとかつかってtransactionを送る
ざっくりとしたイメージ。
solana-client, solana-sdkのクレートを使う(言語はRust)
多分トランザクションの作成には transaction::Transaction::{new_with_payer, new_signed_with_payer} あたりを使うんじゃないかというイメージ。2つの違いは未署名か署名有りかっぽい。
署名はどっかではする必要あるけど、任意にしている感じタイミングをコントロールしたくなる場面があるのだと思う。この辺はまだわからない、実装してたら気づけそうな気がする
Program
Programをちゃんと説明すると長くなるので、短めに書くとinstructionの集合体って表現でいい気がする。
instrucitionは命令のことで、プログラマの標準的なニュアンスで言うならメソッドみたいな捉え方でいいんじゃないかなと思う。しらんけど
Programの実装はこれが詳しい
Anchorを使うことで、デシリアライズなどの実装以外の手間を取り除くことができるのだけど、Anchorの場合ProgramはRust実装だけどTestはtypescript実装。BotでまたRust実装みたいになってなんかキモかったので、使わない上の記事を参考にした。
※あといきなりAnchorから入るとentrypoint!()など秘匿化されてしまう部分もあり、理解度が落ちるのも良くないと思った。現時点の判断なので「Anchorでいいじゃん」になる可能性は十二分にあります。
Programでやりたいことは要はAccount同士でtokenをtransferしていくこと。
そこで必要になってくるのがEscrowという概念
EscrowはAとBが取引をする上でお互いに相手が持ち逃げをする可能性があるので先に渡したくない問題を解決するためのもの。(AとBの資金を一旦預かる信頼できる第三者Cみたいな感じ)
あとはinvoke()で他のinstructionを実行することもできるため、そんな感じでうまいことProgramを実装していく感じっぽい
Anchorで実装したほうが間違いなく楽っぽいんだけど、Rustにも慣れたいのでひとまずは修行の意味も込めてRustで書いていこうかなと思ったりした。イテレータを手動でnext_account_info()?で読み取りまくるのは「えっ」てなったりはしたのでいつかはAnchor使ってそうではあるけど
SolanaのEscrow実装でつまずいた人へ送る有意義な情報
他備忘録的ななにか
※この辺は間違ってる可能性高い。とりあえず現状の理解
Program
ethでいうスマートコントラクト。ステートレス
Account
ステートを持つのはこっち。Solanaであらゆるデータを表現している。walletにせよtokenにせよ全部これ
多分最も上位なのはProgramで具体的にはSystem Programがそれにあたる。
基本的にTokenはToken Programを上位に持つProgram。Token自体はProgram?なのでwalletでそれを持つためにはmint addressからwalletに紐付くtoken accountを生成してそこで状態管理をするイメージ
Transaction
solana上に存在するなんのProgramを実行するのかの指示みたいなイメージ。solのtransferとかはProgramIdの指定もいらない(System Programで管理するようなやつだからかなぁという勝手なイメージ)
RpcClient
ブロックチェーンに作成したTransactionを反映してもらうためにはノードにそれを投げる必要がある。ノードはjson-rpcを用意するものらしいのでRpcClientを用意して、それを使って作成したtransactionを投げるイメージ
payer
作成されたTransactionは処理するために手数料が必要。それを払う必要があるのでpayerがいる。だからtransaction::Transaction.new_with_payer()でtransactionを作るんだろうけど、頭の中でpayerの優先度が低くてなんか違和感があったりした。そのうち違和感なくなるはず、多分
ノード
ブロックチェーンに接続されたサーバー。ノード同士はpeer。ちょっとこの辺は自分でノード立てたりしないと詳細わかんない気がする。
RpcClientでは何かしらのノードを指定するんだけど、指定したノードによってはRustのライブラリでは存在するけど、ノード側では非対応みたいなことがあったりするので困ったりする。solanaのドキュメントに書いてあるやつなら大丈夫だけど、その場合はlimitで悩むことになったりする
バリデーター
こいつがマジで一番わからない。承認してるんだろうなというだけ
localnetを立てたときにsolana-test-validatorでバリデーターを立てないとうんともすんとも言わないので、トランザクションの処理に関わっているのは確かだと思う。
トランザクションの中身の処理はノードでやってて、それをブロックチェーンに入れるかどうかの承認はバリデーターがやってる感じ?あまりわからない。ethとかでいうマイナーのポジションなのかな
今後やること
Programのデプロイとsolana-clientの大まかな使い方はわかったので、spl-tokenを送金するようなProgramをデプロイして、それを実際に使ってみる。みたいなことをしてみたいなと思ったりした。
そのためにはRustでテストコードの作成実行のやり方を勉強する必要があるので、まずはそこからになりそう。
Rust難しいけど、すでに書いててちょっと気持ちよさがあるので好きになれそうな気がする。Result<T, E>は最初困惑したけど、なれるといざという時エラーハンドリングやろうと思ったらすぐできる感じなのがめっちゃ便利そうだとか思ったりしてた。