[Astar]Swankyで作成するpsp22コントラクトを読んでみよう!
こんにちは、CryptoGamesのユウキと申します。
今回は、swankyで作成する、「psp22」のコントラクトを見ていきたいと思います。
swankyを使うまでの過程については、こちらの記事をご確認ください。
1 テストプロジェクトを作成しよう
では、テストプロジェクトを作っていきたいと思います。
swanky init test_project
このように、今回見ていきたいプロジェクトができました。
こちらを一つ一つ見ていきましょう。
2 psp22のコードを確認しよう
1 #![cfg_attr(not(~))]について
こちらについては、下の記事の第1章の1をご参照ください。
2 #![feature(min_specialization)]について
では、こちらの#![feature(min_specialization)]について見ていきましょう。
min_specializationは「特殊化」最小限に制限することのようです。
特殊化を必要以上に行わないことを保証することでコードの信頼性が向上します。
chatGPTからの引用
3 SpreadAllocateについて
次はこちらの「ink_storage::traits::SpreadAllocate」についてです。
具体的な中身はこのようになっています。
allocate_spreadというメソッドが存在しています。
https://docs.rs/ink_storage/3.3.1/ink_storage/traits/trait.SpreadAllocate.html
また、このように、structの前で使われています。
下のように、スマートコントラクトのステートをSubstrateのステートストレージに格納する際に使われるようです。
chatGPTからの引用
ちなみに、[#derive]アトリビュートは、このように継承を表しています。
https://doc.rust-jp.rs/rust-by-example-ja/trait/derive.html
4 ink_lang::codegen::Envについて
では、こちらのEnvを見ていきましょう。
実装はこのようになっています。
https://paritytech.github.io/ink/ink/codegen/trait.Env.html
下のように、「EnvAccess型」を定義し、env関数で、その「EnvAccess型」を返しています。
chatGPTからの引用
5 ink_lang::codegen::EmitEventについて
では、こちらのEmitEventを見てみましょう。
このように定義されています。
https://paritytech.github.io/ink/ink/codegen/trait.EmitEvent.html
下のように、「ContractEventBase」というトレイトを実装しているかを確認しているようです。
chatGPTからの引用
6 ContractEventBaseについて
「ContractEventBase」については、こちらです。
このように、型パラメータの「Type」をもっているようです。
https://paritytech.github.io/ink/ink/reflect/trait.ContractEventBase.html
7 #[ink(event)]について
では、こちらの#[ink(event)]を見ていきましょう。
下のように、ink!イベントを定義しているようです。
「TransferEvent」や「ApprovalEvent」を定義していたようです。
https://use.ink/macros-attributes/event
8 #[ink(topic)]について
次は、こちらの#[ink(topic)]についてです。
イベントの構造体の中の一部についていますね。
このように書かれています。
solidityにおける、イベント時のインデックスのようなもののようです。
https://use.ink/macros-attributes/topic
下のように、トピックをつけることにより、トランザクションやブロックの検索時に用いることができるようです。
chatGPTからの引用
9 psp22::Dataについて
次は、こちらのpsp22::Dataを見ていきましょう。
下のように、モジュールのデータ構造をコントラクトに埋め込む必要があります。
そして、それぞれのモジュールのデータ構造の名前は「Data」となっているようです。
https://docs.openbrush.io/smart-contracts/overview
Githubを見ると、Dataの中身がこのようになっていることが確認できます。
https://github.dev/Supercolony-net/openbrush-contracts
10 AccountIdについて
では、こちらのAccountIdを見てみましょう。
このように、ink!の環境変数として、AccountIdが設定されています。
https://use.ink/basics/chain-environment-types
11 Transferについて
下のように、「_before_token_transfer」という関数が定義されています。
4つの引数をとり、to(宛先)が「hated_account」に一致するとエラーとなっています。
Githubを確認すると、このようになっています。
下のように、「_before_token_transfer」と「_after_token_transfer」の2つがあることが確認できました。
https://github.dev/Supercolony-net/openbrush-contracts
なお、OpenBrushのGithubを見ると、PSP22Errorは下のようになっています。
https://github.dev/Supercolony-net/openbrush-contracts
ちなみに、OptionとはNoneとSome(T)を持つ列挙型です。
https://doc.rust-jp.rs/rust-by-example-ja/std/option.html
12 psp22::Internalについて
では、次に、こちらを見てみましょう。
中に二つの関数があり、4章と5章で出てきた、envとemit_eventが出てきます。
イベントを発火する時に使う関数のようですね。
そして、下にあるように、内部でのみ使うときは、「○○::Internal」とするようです。
https://docs.openbrush.io/smart-contracts/overview
下のように、「Internal」というトレイトには9個のメソッドが入っており、
https://github.dev/Supercolony-net/openbrush-contracts
このように、それぞれ実装されています。
https://github.dev/Supercolony-net/openbrush-contracts
13 PSP22について
では、こちらのPSP22を見てみましょう。
このように、{}の中に記載がないので、デフォルトの実装をそのまま利用しています。
では、そのデフォルトの実装をGithubで見てみましょう。
https://github.dev/Supercolony-net/openbrush-contracts
14 constructor,messageなど
constructor,messageなどにつきましては、こちらの記事をご確認ください。(第3章と第6章)
その上で、こちらは引数に渡した値をミントし、3つの関数を用意しているようです。
15 テストについて
今回、chatGPTで作ったコードをこちらに貼っておきます。
#[cfg(test)]
mod tests {
use super::*;
use ink_lang as ink;
#[ink::test]
fn new_method_test() {
let psp22 = Psp22::new(100);
assert_eq!(psp22.get_total_supply(), 100);
}
#[ink::test]
fn set_hated_account_test() {
let mut psp22 = Psp22::new(100);
let hated_account = AccountId::from([0x1; 32]);
psp22.set_hated_account(hated_account.clone());
assert_eq!(psp22.get_hated_account(), hated_account);
}
#[ink::test]
fn get_hated_account_test() {
let mut psp22 = Psp22::new(100);
let hated_account = AccountId::from([0x1; 32]);
psp22.set_hated_account(hated_account.clone());
let result = psp22.get_hated_account();
assert_eq!(result, hated_account);
}
}
#[cfg(test)]などにつきましては、こちらの記事の第7章をご確認ください。
今回は、下のようなテストを行っています。
初期化時にミントを行った値はきちんと反映されているか、hated_accountにセットし、ゲットできるかを確かめています。
ちなみに、AccountId::from([0x01; 32])の部分は、下のように、任意のAccountIdを作成しています。
https://use.ink/ink-vs-solidity
なお、下のように、テストを実施すると、このように、うまく行っているようです。
今回は以上です。
最後まで、ありがとうございました!
Discussion