Cairo 最近リリースされたバージョン 2.0.0-rc0 による構文の変更#
一部関連情報のチャンネル#
GitHub の Cairo プロジェクトタスク進捗ボード:https://github.com/orgs/starkware-libs/projects/1/views/1
GitHub リリース情報リスト:https://github.com/starkware-libs/cairo/releases
一般的な変更#
(1). 整数リテラルはもはやその型の変数を指定する必要がない
// 以前
let n:u8 = 8_u8;
// 現在はサフィックスを省略でき、付けてもエラーにならない
let n:u8 = 8;
(2). 辞書の作成
以前
use dict::Felt252DictTrait;
fn main(){
let mut dict = Felt252DictTrait::new();
}
現在は Default trait を使用
use dict::Felt252DictTrait;
use traits::Default;
fn main(){
let mut map : Felt252Dict<felt252> = Default::default();
}
コントラクトの構文変更#
まず旧バージョンのコントラクトコードを示します:
#[abi]
trait IOtherContract {
fn decrease_allowed() -> bool;
}
#[contract]
mod CounterContract {
use starknet::ContractAddress;
use super::{
IOtherContractDispatcher,
IOtherContractDispatcherTrait,
IOtherContractLibraryDispatcher
};
struct Storage {
counter: u128,
other_contract: IOtherContractDispatcher
}
#[event]
fn counter_increased(amount: u128) {}
#[event]
fn counter_decreased(amount: u128) {}
#[constructor]
fn constructor(initial_counter: u128, other_contract_addr: ContractAddress) {
counter::write(initial_counter);
other_contract::write(IOtherContractDispatcher { contract_address: other_contract_addr });
}
#[external]
fn increase_counter(amount: u128) {
let current = counter::read();
counter::write(current + amount);
counter_increased(amount);
}
#[external]
fn decrease_counter(amount: u128) {
let allowed = other_contract::read().decrease_allowed();
if allowed {
let current = counter::read();
counter::write(current - amount);
counter_decreased(amount);
}
}
#[view]
fn get_counter() -> u128 {
counter::read()
}
}
以下のコードは新しい構文のコントラクトコードです#
(1). external 関数は特定の trait と対応する impl に集中している
上記のコントラクトには 3 つの公開関数があります:increase_counter
、decrease_counter
、および get_counter
。
- まずこれらの公開関数は、
#[starknet::interface]
でマークされた trait に関数シグネチャ(または関数セレクタ)を定義します。 - この trait には、コントラクトのストレージ構造体を表すジェネリック変数
TContractState
が含まれています。 - これらの公開関数はすべて
TContractState
のメソッドです。 - メソッドの最初の引数は
self
です;もし view メソッドであれば、self はTContractState
のスナップショットself: @TContractState
です;もし状態を変更するメソッドであれば、self はTContractState
の参照ref self: TContractState
です。後にメソッドの他の引数が続きます。 - 公開関数のロジックは、
#[external(v0)]
でマークされた impl に書かれています。
以上は公開関数に関する新しい構文ルールで、変更はかなり大きいです。コード内のコメントにはさらに詳細があります:
/// @notice 現在のコントラクトの外部インターフェースを定義し、すべてのexternal関数はこのtraitのimplに定義されます
#[starknet::interface]
trait ICounterContract<TContractState> {
fn increase_counter(ref self: TContractState, amount: u128);
fn decrease_counter(ref self: TContractState, amount: u128);
fn get_counter(self: @TContractState) -> u128;
}
#[starknet::contract]
mod CounterContract {
...
/// @notice ここで全てのexternal関数を定義し、ContractStateはコントラクトのストレージ状態を表します
/// @dev スナップショットまたは参照を渡すことでview関数かどうかを区別します。スナップショットであればview関数です
/// @dev コントラクトの構文はまだ更新中で、v0は現在のコントラクトが将来のアップグレード後の新しいバージョンのコンパイラと互換性を持つためのものです
#[external(v0)]
impl CounterContract of super::ICounterContract<ContractState> {
// スナップショットが渡されるため、view関数です
fn get_counter(self: @ContractState) -> u128 {
self.counter.read()
}
// 参照が渡されるため、コントラクトのストレージ状態を変更します
fn increase_counter(ref self: ContractState, amount: u128) {
// コントラクトの状態変数を読み取ります
let current = self.counter.read();
// コントラクトの状態変数を変更します
self.counter.write(current + amount);
// ContractStateは同時にイベントをemitする能力を持ちます
self.emit(Event::CounterIncreased(CounterIncreased { amount }));
}
fn decrease_counter(ref self: ContractState, amount: u128) {
let allowed = self.other_contract.read().decrease_allowed();
if allowed {
let current = self.counter.read();
self.counter.write(current - amount);
self.emit(Event::CounterDecreased(CounterDecreased { amount }));
}
}
}
...
}
(2). コントラクトの外部呼び出し
公開関数の書き方が変更されたため、コントラクトの外部呼び出しも自然に変更されます。
- 元々
#[abi]
でマークされていた部分は、#[starknet::interface]
でマークされるようになりました。 - trait はジェネリック trait を使用し、使い方は上記の内容と一致します。
/// @notice 外部コントラクトインターフェースの定義
/// @dev #[abi] を #[starknet::interface] に置き換えました
/// @dev ジェネリックtraitを使用し、TContractStateはコントラクト状態を表すジェネリック名です
#[starknet::interface]
trait IOtherContract<TContractState> {
fn decrease_allowed(self: @TContractState) -> bool;
}
(3). Event の変更
Event の変更もかなり大きく、現在は Enum と struct を使用して表現されています。
- すべての event は
#[event]
と#[derive(Drop, starknet::Event)]
でマークされた enum 内に定義されています。 - 各 event は、受け取るフィールドと型を表す個別の構造体によって表され、
#[derive(Drop, starknet::Event)]
でマークされる必要があります。 - event の呼び出しには
ContractState
を使用します:self.emit(Event::CounterDecreased(CounterDecreased { amount }));
/// @notice コントラクトのeventも非常に大きな変更を受けました
/// @dev すべてのeventは #[event] でマークされ、名前が Event の enum に定義されています
/// @dev 各eventの定義構造は: event_name: event_type、event_type はイベント内のパラメータ構造を格納します
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
CounterIncreased: CounterIncreased,
CounterDecreased: CounterDecreased
}
#[derive(Drop, starknet::Event)]
struct CounterIncreased {
amount: u128
}
#[derive(Drop, starknet::Event)]
struct CounterDecreased {
amount: u128
}