ABI和合约接口

区块链上的智能合约之间的跨合约互动是一种常见的做法,它使我们能够建立灵活的合约,相互对话。

在Starknet上实现这一点需要我们称之为接口的东西。

ABI - 应用二进制接口

在Starknet上,合约的 ABI 是合约函数和结构的 JSON 表示,使任何人(或任何其他合约)都能对其进行编码调用。它是一个蓝图,指示如何调用函数、以及它们所需的输入参数和格式。

虽然我们用高级Cairo语言编写智能合约逻辑,但它们在虚拟机上存储为二进制格式的可执行字节码。由于这种字节码不是人类可读的,因此需要解释才能理解。这就是 ABI 的作用所在,它定义了可以调用智能合约执行的特定方法。如果没有 ABI,外部参与者几乎不可能理解如何与合约交互。

ABI 通常用于 dApps 前端,使其能够正确格式化数据,使智能合约能够理解数据,反之亦然。当你通过 VoyagerStarkscan 等区块资源管理器与智能合约交互时,它们会使用合约的 ABI 来格式化你发送给合约的数据以及合约返回的数据。

接口

合约的接口是它公开的函数列表。 它指定了智能合约中包含的函数签名(名称、参数、可见性和返回值),但不包括函数体。

在Cairo中,合约接口是用 #[starknet::interface] 属性注解的 traits。如果你对 traits 还不熟悉,请查看专门介绍 traits 的章节。

一个重要的规范是,该trait必须是基于 TContractState 类型的泛型。函数访问想要合约存储空间必须基于此trait,这样函数才能读写合约。

注意:合约的构造函数不是接口的一部分。内部函数也不是接口的一部分。

下面是 ERC20 代币合约的接口示例。正如您所看到的,它是在 TContractState 类型上的泛型trait。view函数有一个类型为@TContractState的自参数,而 external 函数有一个类型为 ref self: TContractState.的自参数。

use starknet::ContractAddress;

#[starknet::interface]
trait IERC20<TContractState> {
    fn name(self: @TContractState) -> felt252;

    fn symbol(self: @TContractState) -> felt252;

    fn decimals(self: @TContractState) -> u8;

    fn total_supply(self: @TContractState) -> u256;

    fn balance_of(self: @TContractState, account: ContractAddress) -> u256;

    fn allowance(self: @TContractState, owner: ContractAddress, spender: ContractAddress) -> u256;

    fn transfer(ref self: TContractState, recipient: ContractAddress, amount: u256) -> bool;

    fn transfer_from(
        ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256
    ) -> bool;

    fn approve(ref self: TContractState, spender: ContractAddress, amount: u256) -> bool;
}

示例99-4:一个简单的ERC20接口

在下一章,我们将研究如何使用 合约调度器 ( dispatchers )、和 系统调用( syscalls ) 来调用其他智能合约。

Last change: 2023-11-15, commit: e18ad31