如何从Go调用智能合约的视图函数?

问题描述 投票:0回答:1

无法在网上找到上述问题的解决方案,因此将其发布在这里: 对于 golang,我们需要使用 go-ethereum 包来执行智能合约相关操作。它类似于我们在 javascript 中用于智能合约操作的 ethers.js。

import (
    "encoding/hex"
    "encoding/json"
    "github.com/ethereum/go-ethereum/accounts/abi"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/common/hexutil"
    "github.com/ethereum/go-ethereum/rpc"
)
// Connect to the Ethereum client
    client, err := rpc.Dial("<rpc_node_url>")
    if err != nil {
        fmt.Println("unable to create client due to error:  %s", err)
    }
    defer client.Close()

    // Address of the smart contract
    contractAddress := "<contract_address_here>"

    // abi of the function to be executed
    contractABI := []byte(`<function_abi_here>`)

    // parsing ABI of the function to be executed
    parsedABI := abi.ABI{}
    err = json.Unmarshal(contractABI, &parsedABI)
    if err != nil {
        fmt.Println("error while unmarshaling abi: %s", err)
    }

    inputData, err := parsedABI.Pack("<function_name_here>", <args_comma_seperated_here>)
    if err != nil {
        fmt.Println("unable to pack input data due to error: %s", err)
    }

    var invokeResponse string

    // Call a view function of the smart contract
    err = client.Call(&invokeResponse, "eth_call", map[string]interface{}{
        "to":   contractAddress,
        "data": hex.EncodeToString(inputData),
    }, "latest")
    if err != nil {
        fmt.Println("unable to call contract due to error: %s", err)
    }

    // Decode the hex response into bytes
    data, err := hexutil.Decode(invokeResponse)
    if err != nil {
        fmt.Println("unable to decode invoke hex response due to error: %s", err)
    }
    var resp responseStruct
    err = parsedABI.UnpackIntoInterface(&resp, "<function_name_here>", data)
    if err != nil {
        fmt.Println("unable to unpack invoke response due to error: %s", err)
    }

在网上找不到上述问题的解决方案,正在考虑直接使用一些包来解决

go ethereum blockchain go-ethereum
1个回答
0
投票

这只是一个非常快速的答案,但应该可以满足您的需求。这是一个对 erc20 合约调用“balanceOf”的函数:

func ERC20GetBalanceOf(ctx context.Context, client *ethclient.Client, erc20Abi *abi.ABI, tokenAddr *common.Address,
    queryAddr *common.Address) (*big.Int, error) {
    balanceData, err := erc20Abi.Pack("balanceOf", queryAddr)
    if err != nil {
        return nil, fmt.Errorf("error packing balanceOf data %w", err)
    }
    balanceMsg := ethereum.CallMsg{
        To:   tokenAddr,
        Data: balanceData,
    }
    balanceResult, err := client.CallContract(ctx, balanceMsg, nil)
    if err != nil {
        return nil, fmt.Errorf("error calling balanceOf function: %w", err)
    }
    balance, err := erc20Abi.Unpack("balanceOf", balanceResult)
    if err != nil {
        return nil, fmt.Errorf("error unpacking balanceOf result: %w", err)
    }
    return balance[0].(*big.Int), nil
}

当然,如果您正确遵循

client.Call
中的幕后操作,您可以使用较低级别的调用,例如
client.CallContract(ctx, balanceMsg, nil)

但我相信我给您的是最常见的方法,无需生成 abi 绑定函数,如 goethereumbook

中所述
© www.soinside.com 2019 - 2024. All rights reserved.