使用go与智能合约交互之函数选择器调用

go与智能合约交互的方式有很多种,其中一种方式可以在不知道合约源码的情况下进行调用,接下来让我们一起学习一下。

 1、首先我们安装一下go-ethereum

go get -u github.com/ethereum/go-ethereum

2、新建main.go文件,添加依赖

import (
	"context"
	"crypto/ecdsa"
	"fmt"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethclient"
	"math/big"
	"os"
)

3、定义常量

const (
	privateKey      = "你的钱包私钥"
	contractAddress = "调用合约地址"
	toAddress       = "接收转账地址" //这里我使用transfer方法作为案例,所以需要一个接收转账地址
)

4、定义调用函数

func transfer(client *ethclient.Client, privateKey, toAddress, contract string) (string, error) {}

4.1、先从私钥推导出公钥,再从公钥推导出钱包地址

	//从私钥推导出 公钥
	privateKeyECDSA, err := crypto.HexToECDSA(privateKey)
	if err != nil {
		fmt.Println("crypto.HexToECDSA error ,", err)
		return "", err
	}
	publicKey := privateKeyECDSA.Public()
	publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
	if !ok {
		fmt.Println("publicKeyECDSA error ,", err)
		return "", err
	}
	//从公钥推导出钱包地址
	fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
	fmt.Println("钱包地址:", fromAddress.Hex())

4.2、构造请求参数

    var data []byte
    methodName := crypto.Keccak256([]byte("transfer(address,uint256)"))[:4]
    paddedToAddress := common.LeftPadBytes(common.HexToAddress(toAddress).Bytes(), 32)
    amount, _ := new(big.Int).SetString("100000000000000000000", 10)
    paddedAmount := common.LeftPadBytes(amount.Bytes(), 32)
    data = append(data, methodName...)
    data = append(data, paddedToAddress...)
    data = append(data, paddedAmount...)

methodName :这个就是我们想要调用的合约方法的函数选择器,这个定义的含义就是 用keccak256方法对调用方法(不包含定义字段和空格)进行加密,并取前4个字节,示例格式:0xa9059cbb

paddedToAddress :是先将toAddress转成address类型,然后用0在左侧填充到32位,示例格式:0000000000000000000000002228e53c4642dedae43f498eeda78b23571b84d8

amount :定义了一个 10进制的大数,也就是我们需要转账的金额,这里是 1000 * 10^18,这个要看转账token定义的decimal是多少位

paddedAmount:paddedToAddress一样,也是用0在左侧填充到32位,示例格式:0000000000000000000000000000000000000000000000056bc75e2d63100000

最后再将methodName、paddedToAddress、paddedAmount追加到字节数组 组成最终的data参数

4.3、构造交易对象

    //获取nonce
	nonce, err := client.NonceAt(context.Background(), fromAddress, nil)
	if err != nil {
		return "", err
	}
	//获取小费
	gasTipCap, _ := client.SuggestGasTipCap(context.Background())
	//transfer 默认是 使用 21000 gas
	gas := uint64(100000)
	//最大gas fee
	gasFeeCap := big.NewInt(38694000460)

	contractAddress := common.HexToAddress(contract)
	//创建交易
	tx := types.NewTx(&types.DynamicFeeTx{
		Nonce:     nonce,
		GasTipCap: gasTipCap,
		GasFeeCap: gasFeeCap,
		Gas:       gas,
		To:        &contractAddress,
		Value:     big.NewInt(0),
		Data:      data,
	})

这里我们用了DynamicFeeTx结构体来构建交易对象,它主要是支持EIP-1559协议可以动态设置Max Priority(矿工小费)以及Max Gas Fee(最大gas费用)

其中Value,表示原生币要转账的数量(比如我们在eth主网,那就是代币要转账的eth数量)

4.4、交易签名/发送交易

    // 获取当前区块链的ChainID
	chainID, err := client.ChainID(context.Background())
	if err != nil {
		fmt.Println("获取ChainID失败:", err)
		return "", err
	}

	fmt.Println("当前区块链的ChainID:", chainID)
	//创建签名者
	signer := types.NewLondonSigner(chainID)
	//对交易进行签名
	signTx, err := types.SignTx(tx, signer, privateKeyECDSA)
	if err != nil {
		return "", err
	}
	//发送交易
	err = client.SendTransaction(context.Background(), signTx)
	if err != nil {
		return "", err
	}

因为我们使用的是DynamicFeeTx创建交易对象,所以这里 signer我们需要使用NewLondonSigner来构建

4.5、main函数里来调用函数

func main() {
	client, err := ethclient.Dial("区块链rpc地址")
	if err != nil {
		fmt.Println("ethclient.Dial error : ", err)
		os.Exit(0)
	}
	tx, err := transfer(client, privateKey, toAddress, contractAddress)
	if err != nil {
		fmt.Println("transfer error : ", err)
		os.Exit(0)
	}

	fmt.Println("transfer tx : ", tx)

}

区块链rpc地址 填入你要调用的链的具体节点地址,如果没有可以通过 INFURA 进行创建

5、执行main方法

使用go与智能合约交互之函数选择器调用_第1张图片

我这里使用的以太坊的 goerli测试链 进行测试的,看上面我们的代码已经成功执行了,让我们去区块链浏览器了看一下

 使用go与智能合约交互之函数选择器调用_第2张图片

 使用go与智能合约交互之函数选择器调用_第3张图片

可以看到区块链已经确认了我们的本次交易

本次教程,我们学会了如何使用go在不知道合约源码的情况下进行合约方法调用,如果在学习的过程中有任何问题可以在公众号给我留言,看到我会第一时间回复你的,另外公众号也会不定期分享关于区块链、web3的前沿信息,感兴趣的朋友可以保持关注

 请关注公众号:外柏叁布道者(web3_preacher,回复 “go合约调用” 领取完整代码

你可能感兴趣的:(使用go开发区块链,golang,智能合约,开发语言,区块链,web3)