StarknetAstro

StarknetAstro

Cairo最近发布的版本 2.0.0-rc0 產生的語法變化

Cairo 最近 released 的版本 2.0.0-rc0 產生的語法變化#

一些相關資訊的渠道#

GitHub 的 Cairo 項目任務進度版圖:https://github.com/orgs/starkware-libs/projects/1/views/1

GitHub release 資訊列表: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 中

以上合約中有三個公開的函數:increase_counterdecrease_counterget_counter

  • 首先這些公開的函數,會在由 #[starknet::interface] 標識的 trait 中定義出函數簽名(或稱函數選擇器)。
  • 這個 trait 中包含一個泛型變量 TContractState ,它代表合約的 storage 結構體。
  • 這些公開的函數都是 TContractState 的方法(method)。
  • 方法中,第一個參數是 self;如果是 view 方法,self 就是 TContractState 的 snapshot self: @TContractState;如果是會更改狀態的方法,self 就是 TContractState 的 reference 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代表合約的storage狀態
    /// @dev 通過傳遞 snapshot 還是 reference 來區分是否是view函數,如果是snapshot,那麼就是view函數
    /// @dev 合約語法還在更新中,v0是為了現在的合約可以兼容將來升級後的新版本編譯器
    #[external(v0)]
    impl CounterContract of super::ICounterContract<ContractState> {
        // 傳入的是snapshot,因此是view函數
        fn get_counter(self: @ContractState) -> u128 {
            self.counter.read()
        }

        // 傳入的是reference,所以會更改合約 storage狀態
        fn increase_counter(ref self: ContractState, amount: u128) {
            // 讀取合約狀態變量
            let current = self.counter.read();
            // 更改合約狀態變量
            self.counter.write(current + amount);
            // ContractState 同時給出 emit event 的能力
            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 使用 #[starknet::interface] 替換 #[abi]
/// @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 的調用,需要使用 ContractStateself.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
    }
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。