合约接口和Trait生成
合约接口定义合约的结构和行为,充当合约的公共 ABI。它们列出了合约公开的所有函数签名。接口的详细说明可以参考 [Cairo之书](https://book.cairo-lang.org/ch99-01-02-a-simple-contract.html)。
在cairo中,要指定接口,您需要定义一个带有#[starknet::interface]
注释的特征,然后在合约中实现该特征。
当函数需要访问协定状态时,它必须具有类型为ContractState
的self
参数。这意味着接口特征中的相应函数签名也必须采用TContractState
类型作为参数。需要注意的是,合约接口中的每个函数都必须具有此类型为TContractState
的self
参数。
您可以使用#[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 中尝试这个合约。