合约接口和Trait生成

合约接口定义合约的结构和行为,充当合约的公共 ABI。它们列出了合约公开的所有函数签名。接口的详细说明可以参考 [Cairo之书](https://book.cairo-lang.org/ch99-01-02-a-simple-contract.html)。

在cairo中,要指定接口,您需要定义一个带有#[starknet::interface]注释的特征,然后在合约中实现该特征。

当函数需要访问协定状态时,它必须具有类型为ContractStateself参数。这意味着接口特征中的相应函数签名也必须采用TContractState类型作为参数。需要注意的是,合约接口中的每个函数都必须具有此类型为TContractStateself参数。

您可以使用#[generate_trait]属性隐式生成特定实现块的特征。此属性会自动生成一个特征,其功能与已实现块中的函数相同,将self参数替换为通用的TContractState参数。但是,您需要使用#[abi(per_item)] 属性注释块,并且每个函数都具有适当的属性,具体取决于它是外部函数、构造函数还是 l1 处理程序。

总之,有两种方法可以处理接口:

  • 显示地,通过定义一个用#[starknet::interface]标记的特征
  • 隐式地,通过将#[generate_trait]#[abi(per_item)]属性结合使用,并使用适当的属性注释实现块中的每个函数。

显式接口

#[starknet::interface]
trait IExplicitInterfaceContract<TContractState> {
    fn get_value(self: @TContractState) -> u32;
    fn set_value(ref self: TContractState, value: u32);
}

#[starknet::contract]
mod ExplicitInterfaceContract {
    #[storage]
    struct Storage {
        value: u32
    }

    #[abi(embed_v0)]
    impl ExplicitInterfaceContract of super::IExplicitInterfaceContract<ContractState> {
        fn get_value(self: @ContractState) -> u32 {
            self.value.read()
        }

        fn set_value(ref self: ContractState, value: u32) {
            self.value.write(value);
        }
    }
}

Remix 中尝试这个合约。

隐式接口

#[starknet::contract]
mod ImplicitInterfaceContract {
    #[storage]
    struct Storage {
        value: u32
    }

    #[abi(per_item)]
    #[generate_trait]
    impl ImplicitInterfaceContract of IImplicitInterfaceContract {
        #[external(v0)]
        fn get_value(self: @ContractState) -> u32 {
            self.value.read()
        }

        #[external(v0)]
        fn set_value(ref self: ContractState, value: u32) {
            self.value.write(value);
        }
    }
}

Remix 中尝试这个合约。

注意:您可以使用use contract::{GeneratedContractInterface}导入隐式生成的合约接口。但是,Dispatcher不会自动生成。

内部函数

您还可以将#[generate_trait]用于内部函数。 由于此特征是在合约的上下文中生成的,因此您也可以定义纯函数(没有“self”参数的函数)。

#[starknet::interface]
trait IImplicitInternalContract<TContractState> {
    fn add(ref self: TContractState, nb: u32);
    fn get_value(self: @TContractState) -> u32;
    fn get_const(self: @TContractState) -> u32;
}

#[starknet::contract]
mod ImplicitInternalContract {
    #[storage]
    struct Storage {
        value: u32
    }

    #[generate_trait]
    impl InternalFunctions of InternalFunctionsTrait {
        fn set_value(ref self: ContractState, value: u32) {
            self.value.write(value);
        }
        fn get_const() -> u32 {
            42
        }
    }

    #[constructor]
    fn constructor(ref self: ContractState) {
        self.set_value(0);
    }

    #[abi(embed_v0)]
    impl ImplicitInternalContract of super::IImplicitInternalContract<ContractState> {
        fn add(ref self: ContractState, nb: u32) {
            self.set_value(self.value.read() + nb);
        }
        fn get_value(self: @ContractState) -> u32 {
            self.value.read()
        }
        fn get_const(self: @ContractState) -> u32 {
            self.get_const()
        }
    }
}

Remix 中尝试这个合约。

Last change: 2023-11-26, commit: 35ec815