StarknetAstro

StarknetAstro

Cairo最近リリースされたバージョン 2.0.0-rc0 による文法の変更

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_counterdecrease_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
    }
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。