接口和分发器
本节介绍 OpenZeppelin Contracts for Cairo 提供的接口,并解释其背后的设计选择。
接口可以在 interface
子模块下的模块树中找到,例如 token::erc20::interface
。例如:
use openzeppelin_token::erc20::interface::IERC20;
或者
use openzeppelin_token::erc20::interface::ERC20ABI;
为了简单起见,我们将使用 ERC20 作为示例,但相同的概念适用于其他模块。 |
接口 traits
该库提供了三种类型的 traits 来实现或与合约交互:
标准 traits
这些 traits 与预定义的接口(例如标准)相关联。 它仅包括接口中定义的函数,并且是与兼容合约交互的标准方式。
#[starknet::interface]
pub trait IERC20<TState> {
fn total_supply(self: @TState) -> u256;
fn balance_of(self: @TState, account: ContractAddress) -> u256;
fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256;
fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool;
fn transfer_from(
ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256
) -> bool;
fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool;
}
ABI traits
它们描述了合约的完整接口。这对于与此库提供的预设合约交互非常有用,例如 ERC20 预设,它包括来自不同 traits 的函数,例如 IERC20
和 IERC20Camel
。
该库为大多数组件提供了一个 ABI trait,它提供了所有外部函数签名,即使大多数时候不需要同时实现所有这些签名。当与实现该组件的合约交互时,这可能会有所帮助,而不是定义新的 dispatcher。 |
#[starknet::interface]
pub trait ERC20ABI<TState> {
// IERC20
fn total_supply(self: @TState) -> u256;
fn balance_of(self: @TState, account: ContractAddress) -> u256;
fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256;
fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool;
fn transfer_from(
ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256
) -> bool;
fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool;
// IERC20Metadata
fn name(self: @TState) -> ByteArray;
fn symbol(self: @TState) -> ByteArray;
fn decimals(self: @TState) -> u8;
// IERC20CamelOnly
fn totalSupply(self: @TState) -> u256;
fn balanceOf(self: @TState, account: ContractAddress) -> u256;
fn transferFrom(
ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256
) -> bool;
}
Dispatcher traits
使用 #[starknet::interface]
注释的 traits 会自动生成一个 dispatcher,该 dispatcher 可用于与实现给定接口的合约进行交互。可以通过将 Dispatcher
和 DispatcherTrait
后缀附加到 trait 名称来导入它们,如下所示:
use openzeppelin_token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait};
其他类型的 dispatchers 也是从带注释的 trait 自动生成的。有关更多信息,请参见 Cairo 书籍的 与另一个合约交互 部分。
在示例中,IERC20Dispatcher 用于与合约交互,但 IERC20DispatcherTrait 需要在作用域内才能使函数可用。
|
双重接口
camelCase 函数已弃用,仅为了向后兼容而维护。
建议仅将 snake_case 接口与合约和组件一起使用。camelCase 函数将在
未来的版本中删除。
|
按照 伟大接口迁移 计划,我们向所有预先存在的 camelCase
合约添加了 snake_case
函数,目的是最终放弃对后者的支持。
简而言之,该库提供了两种类型的接口和实用程序来处理它们:
-
camelCase
接口,这是我们到目前为止一直在使用的接口。 -
snake_case
接口,这是我们正在迁移到的接口。
这意味着目前我们的大多数合约都实现了 双重接口。例如,ERC20 预设合约公开了 transferFrom
、transfer_from
、balanceOf
、balance_of
等。
双重接口适用于 OpenZeppelin Contracts for Cairo 早期版本 (v0.6.1 及以下) 中存在的所有外部函数。 |
IERC20
ERC20 接口 trait 的默认版本公开了 snake_case
函数:
#[starknet::interface]
pub trait IERC20<TState> {
fn name(self: @TState) -> ByteArray;
fn symbol(self: @TState) -> ByteArray;
fn decimals(self: @TState) -> u8;
fn total_supply(self: @TState) -> u256;
fn balance_of(self: @TState, account: ContractAddress) -> u256;
fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256;
fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool;
fn transfer_from(
ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256
) -> bool;
fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool;
}
IERC20Camel
最重要的是,该库还提供了相同接口的 camelCase
版本:
#[starknet::interface]
pub trait IERC20Camel<TState> {
fn name(self: @TState) -> ByteArray;
fn symbol(self: @TState) -> ByteArray;
fn decimals(self: @TState) -> u8;
fn totalSupply(self: @TState) -> u256;
fn balanceOf(self: @TState, account: ContractAddress) -> u256;
fn allowance(self: @TState, owner: ContractAddress, spender: ContractAddress) -> u256;
fn transfer(ref self: TState, recipient: ContractAddress, amount: u256) -> bool;
fn transferFrom(
ref self: TState, sender: ContractAddress, recipient: ContractAddress, amount: u256
) -> bool;
fn approve(ref self: TState, spender: ContractAddress, amount: u256) -> bool;
}