---
title: "什么是智能合约的 ABI？"
description: "开发者示例与用法"
---

# 什么是智能合约的 ABI？

智能合约的应用二进制接口（ABI）使合约能够与外部应用程序及其他智能合约进行通信和交互。从外部来源接收数据，对于完成应用程序和用户的目标至关重要。

在传统 Web 开发中，应用程序与服务器之间通过 API（应用程序接口）进行数据交流。服务器作为集中化的信息来源，按请求向应用程序提供数据。

在区块链上，不存在这种数据的集中化。节点本质上充当服务器的角色，智能合约则是链上"托管"的函数。链外的应用程序（以及其他智能合约）需要一种方式来与链上的智能合约通信。这正是 ABI 发挥作用的地方。

## **为什么需要 ABI？**

在详细介绍 ABI 是什么之前，先了解一下我们为什么需要它。

智能合约是 [EVM（以太坊虚拟机）](https://www.alchemy.com/overviews/what-is-the-ethereum-virtual-machine-evm) 的核心应用。智能合约的作用是在满足合约中定义的特定条件时执行交易。这些条件可以是链上或链下的事件。智能合约使用 [Solidity](https://www.alchemy.com/overviews/solidity) 等高级语言编写，但它们以二进制格式的可执行字节码形式存储在 EVM 上。

<ImageBlock
  src="https://media.alchemy.com/1703767018-evm-executable-bytecode.jpeg"
  alt="智能合约代码以可执行字节码形式存储在 EVM 上的示意图"
  width={1600}
  height={916}
  caption="EVM 上的可执行字节码"
/>

由于这些字节码并非人类可读，需要经过解释才能理解。ABI 使编写智能合约的人能够在用 Javascript 等高级语言编写的 Web 应用程序与 EVM 所理解的字节码之间进行通信。

## **什么是 ABI？**

与其 Web2 领域的表亲 API 类似，ABI 充当函数选择器的角色，定义了智能合约中可被调用执行的具体方法。这些具体方法及其相关联的数据类型被列在一个生成的 JSON RPC 文件中。

<ImageBlock
  src="https://media.alchemy.com/1703767166-abi-function-selector.png"
  alt="ABI 作为智能合约方法函数选择器的示意图"
  width={760}
  height={484}
  caption="ABI 函数选择器"
/>

与 API 不同，我们不能直接以 JSON 格式向智能合约发送请求并期待响应，因为合约只能以字节码进行通信。为了将其转换为 EVM 能理解的内容，这些信息需要通过 ABI 编码进行编码。这些编码包括函数签名和变量声明，使 EVM 能够准确知道要在智能合约中执行哪个函数。

<ImageBlock
  src="https://media.alchemy.com/1703767249-abi-encoding.png"
  alt="ABI 编码将函数调用转换为 EVM 字节码的示例"
  width={1362}
  height={280}
  caption="ABI 编码"
/>

响应结果同样以字节码形式返回，因此在被 Web 应用程序处理之前也需要经过解释。使用字节码作为响应的优势在于，我们可以预期调用合约函数后会返回某种特定的结构。

## **如何使用 ABI？**

### 生成

如果你使用 Hardhat/Truffle 之类的工具，或 [Remix](https://remix.ethereum.org/#optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.7+commit.e28d00a7.js) 之类的 IDE，合约 ABI 会自动为你生成。你也可以通过使用 [Solidity Compiler NPM 包](https://www.npmjs.com/package/solc) 手动创建 ABI。安装该包后，可以在终端中运行 '`solcjs contractname.sol --abi`' 命令。如果执行成功，将生成一个 .abi 文件。

现在你已经有了一个生成的 ABI，我们来看看这个文件中的一些要素：

<ImageBlock
  src="https://media.alchemy.com/1703767374-generated-contract-abi.png"
  alt="生成的智能合约 ABI JSON 文件示例"
  width={1600}
  height={730}
  caption="生成的合约 ABI"
/>

### **执行**

由于 ABI 承担着 EVM 字节码与网站 Javascript 之间解释器的角色，因此在你想要执行智能合约的任何函数时都需要用到它。除了 ABI 之外，还需要合约在区块链上的地址。下面是一段简短的 Javascript 代码，展示了具体的操作方式：

<ImageBlock
  src="https://media.alchemy.com/1703767477-executing-abi.png"
  alt="使用 ABI 和地址执行合约函数的 JavaScript 代码片段"
  width={1600}
  height={880}
  caption="执行 ABI"
/>

如果你想查找一个已部署合约的 ABI，可以通过在 [Etherscan](https://www.alchemy.com/dapps/etherscan) 上搜索该合约的地址来找到。例如[这个例子](https://etherscan.io/address/0xb4eaf48bd7f72356e1019c157e91b81a1c541073#code)：

<ImageBlock
  src="https://media.alchemy.com/1703767569-abi-of-already-deployed-contract.png"
  alt="Etherscan 合约页面展示已部署合约的 ABI"
  width={1600}
  height={315}
  caption="已部署合约的 ABI"
/>

### 编码

由于所有通信都以字节码进行，很难指望开发者自己去编码这些消息。幸运的是，像 Remix 这样常用的编译器也可以为你处理编码。这些编码遵循特定的模式，因此通过查阅 [ABI 规范](https://docs.soliditylang.org/en/v0.8.11/abi-spec.html)，可以更好地了解其运作方式。

前四个字节是函数签名，指明了智能合约中正在执行的函数类型。一个常见的函数标识符是 a9059cbb，它表示这是一个 [ERC20](https://www.alchemy.com/overviews/erc20-solidity) 转账操作。这里有一个函数签名的[数据库目录](https://www.4byte.directory/)，可供进一步查阅。

<ImageBlock
  src="https://media.alchemy.com/1703767678-function-hashes.png"
  alt="ABI 函数签名哈希示例，包括 ERC20 的 transfer 选择器"
  width={1069}
  height={418}
  caption="ABI 函数哈希"
/>

从第五个字节开始，是参数的编码部分。响应遵循类似的结构，但不包含函数签名。

## **结论**

ABI 常常是使用智能合约时容易被忽视的一个方面，但它在这项技术的可用性方面扮演着重要角色。通过学习 [智能合约教程](https://www.alchemy.com/docs/how-to-deploy-a-smart-contract-to-the-sepolia-testnet) 进行实践，是理解这个默默工作的核心组件、并应用所学知识的好方法。
