Cairo最近released的版本 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). 整数字面量不再需要指明是那个类型的变量

Copy
// 过去
let n:u8 = 8_u8;
// 现在可以省略后缀，加上也不会报错
let n:u8 = 8;

(2). 创建字典

过去

Copy
use dict::Felt252DictTrait;
fn main(){
let mut dict = Felt252DictTrait::new();
}

现在使用 Default trait

Copy
use dict::Felt252DictTrait;
use traits::Default;

fn main(){
let mut map : Felt252Dict<felt252> = Default::default();
}

编写合约的语法变化

首先给出旧版本的合约代码：

Copy
#[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_counter、decrease_counter 和 get_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 里。

以上是关于公开函数的新的语法规则，变动还是蛮大的。代码中的注释会有更多的细节：

Copy
/// @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，用法和上面👆内容一致。

Copy
/// @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 的调用，需要使用 ContractState： self.emit(Event::CounterDecreased(CounterDecreased { amount }));

Copy
/// @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
}