在 Web3 后端开发中,abigen 是一个至关重要的工具。它能根据 Solidity 合约生成的 ABI(应用二进制接口)自动生成 Go 语言代码,让你像调用普通 Go 函数一样调用智能合约。
以下是详细的 abigen 使用教程。
第一步:安装 abigen 工具
abigen 是 go-ethereum 项目的一部分。你可以通过以下命令安装:
# 安装最新版 abigen
go install github.com/ethereum/go-ethereum/cmd/abigen@latest
验证安装:
在终端输入 abigen --version。如果看到版本号,说明安装成功。
注意:如果提示找不到命令,请确保你的 $GOPATH/bin 已添加到系统的 PATH 环境变量中。
第二步:准备 Solidity 合约
创建一个简单的合约文件 SimpleStorage.sol:
// SPDX-License-Identifier: MIT
pragma uint256;
pragma solidity ^0.8.0;
contract SimpleStorage {
uint256 private data;
event DataStored(uint256 newValue);
function set(uint256 x) public {
data = x;
emit DataStored(x);
}
function get() public view returns (uint256) {
return data;
}
}
第三步:获取 ABI 和 Bytecode
要生成 Go 代码,你需要两个东西:
- ABI: 描述合约有哪些函数。
- Bin (Bytecode): 合约的编译代码(如果你需要通过 Go 部署合约的话)。
方法 A:使用 solc 编译器(本地)
solc --abi --bin SimpleStorage.sol -o build
方法 B:使用 Remix IDE(最简单)
- 将代码粘贴到 Remix。
- 编译合约。
- 在 "Compilation Details" 中点击 ABI 和 Bytecode 的复制按钮,分别存为
SimpleStorage.abi和SimpleStorage.bin。
第四步:使用 abigen 生成 Go 绑定
假设你现在有了 SimpleStorage.abi 和 SimpleStorage.bin,运行以下命令:
abigen --abi SimpleStorage.abi --bin SimpleStorage.bin --pkg store --type SimpleStorage --out storage.go
参数解释:
--abi: 指定 ABI 文件路径。--bin: 指定 Bin 文件路径(可选,仅调用合约不部署时可不加)。--pkg: 指定生成的 Go 代码的包名(这里设为store)。--type: 指定生成的 Go 结构体的名称。--out: 指定输出的文件名。
生成成功后,你会看到一个几百行的 storage.go 文件,里面包含了 DeploySimpleStorage、Set、Get 等函数。
第五步:在 Go 代码中调用(实战例子)
现在我们要写一个 main.go 来调用这个生成的 storage.go。为了确保能跑通,我们连接到你之前的 Sepolia 测试网。
目录结构:
.
├── SimpleStorage.abi
├── SimpleStorage.bin
├── store/
│ └── storage.go // abigen 生成的文件
├── main.go
└── .env
main.go 实现代码:
package main
import (
"context"
"fmt"
"log"
"math/big"
"os"
"go-wallet-lite/store" // 替换为你的项目路径/store
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/joho/godotenv"
)
func main() {
godotenv.Load()
// 1. 连接 Sepolia 节点
client, err := ethclient.Dial(os.Getenv("RPC_URL"))
if err != nil {
log.Fatal(err)
}
// 2. 准备合约地址
// 这是一个已经在 Sepolia 上部署好的测试合约地址(如果没有,可以换成你自己的)
contractAddr := common.HexToAddress("0x7de680214a1f335165c63e903b1e77983636f72a")
// 3. 实例化合约
instance, err := store.NewSimpleStorage(contractAddr, client)
if err != nil {
log.Fatal(err)
}
// 4. 调用 Read 方法 (Get)
// 查询合约里存的数字
value, err := instance.Get(&bind.CallOpts{})
if err != nil {
log.Fatal(err)
}
fmt.Printf("当前合约存储的值: %s\n", value.String())
// 5. 调用 Write 方法 (Set)
// 注意:写操作需要私钥签名,会消耗 Gas
/*
privateKey, err := crypto.HexToECDSA(os.Getenv("PRIVATE_KEY"))
auth, _ := bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(11155111)) // Sepolia ChainID
tx, err := instance.Set(auth, big.NewInt(666)) // 将值设为 666
if err != nil {
log.Fatal(err)
}
fmt.Printf("交易已发送,Hash: %s\n", tx.Hash().Hex())
*/
}
常见坑点总结
- 包名不一致:
abigen生成时指定的--pkg store必须和文件夹名称store一致,否则 Go 找不到。 - ABI 更新不及时:如果你修改了 Solidity 代码,必须重新生成 ABI 并重新运行
abigen,否则调用时会报错(方法哈希不匹配)。 - 大数处理:Solidity 的
uint256在 Go 中对应的是*big.Int,不能直接用int,必须使用math/big库。 - ChainID:在做“写操作”时,
NewKeyedTransactorWithChainID里的 ChainID 必须传对(Sepolia 是11155111,主网是1)。
总结
abigen 的工作流就是:写合约 -> 拿 ABI -> 跑 abigen -> 在 Go 中像调包一样调合约。
建议尝试: 你可以先把 Get 方法跑通(不需要私钥),然后再尝试用私钥跑通 Set 方法。需要我教你如何在 Go 里安全地加载私钥吗?