abigen使用教程 - go版本

10 阅读3分钟

在 Web3 后端开发中,abigen 是一个至关重要的工具。它能根据 Solidity 合约生成的 ABI(应用二进制接口)自动生成 Go 语言代码,让你像调用普通 Go 函数一样调用智能合约。

以下是详细的 abigen 使用教程。


第一步:安装 abigen 工具

abigengo-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 代码,你需要两个东西:

  1. ABI: 描述合约有哪些函数。
  2. Bin (Bytecode): 合约的编译代码(如果你需要通过 Go 部署合约的话)。

方法 A:使用 solc 编译器(本地)

solc --abi --bin SimpleStorage.sol -o build

方法 B:使用 Remix IDE(最简单)

  1. 将代码粘贴到 Remix
  2. 编译合约。
  3. 在 "Compilation Details" 中点击 ABIBytecode 的复制按钮,分别存为 SimpleStorage.abiSimpleStorage.bin

第四步:使用 abigen 生成 Go 绑定

假设你现在有了 SimpleStorage.abiSimpleStorage.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 文件,里面包含了 DeploySimpleStorageSetGet 等函数。


第五步:在 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())
    */
}

常见坑点总结

  1. 包名不一致abigen 生成时指定的 --pkg store 必须和文件夹名称 store 一致,否则 Go 找不到。
  2. ABI 更新不及时:如果你修改了 Solidity 代码,必须重新生成 ABI 并重新运行 abigen,否则调用时会报错(方法哈希不匹配)。
  3. 大数处理:Solidity 的 uint256 在 Go 中对应的是 *big.Int,不能直接用 int,必须使用 math/big 库。
  4. ChainID:在做“写操作”时,NewKeyedTransactorWithChainID 里的 ChainID 必须传对(Sepolia 是 11155111,主网是 1)。

总结

abigen 的工作流就是:写合约 -> 拿 ABI -> 跑 abigen -> 在 Go 中像调包一样调合约。

建议尝试: 你可以先把 Get 方法跑通(不需要私钥),然后再尝试用私钥跑通 Set 方法。需要我教你如何在 Go 里安全地加载私钥吗?