当前位置:   article > 正文

使用go与智能合约交互之abi调用_go abi

go abi

上一篇文章,我们讲解了go如何使用函数选择器的方式进行智能合约的调用,接下来让我们一起学习一下如何使用abi的方式进行智能合约的调用

本系列课程:

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

第二节:使用go与智能合约交互之abi调用

第三节:使用go与智能合约交互之使用abigen生成合约go文件进行调用

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

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


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

  1. import (
  2.     "context"
  3.     "crypto/ecdsa"
  4.     "fmt"
  5.     "github.com/ethereum/go-ethereum/common"
  6.     "github.com/ethereum/go-ethereum/core/types"
  7.     "github.com/ethereum/go-ethereum/crypto"
  8.     "github.com/ethereum/go-ethereum/ethclient"
  9.     "math/big"
  10.     "os"
  11. )


3、定义常量

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


4、定义调用函数

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


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

  1.  //从私钥推导出 公钥
  2.     privateKeyECDSA, err := crypto.HexToECDSA(privateKey)
  3.     if err != nil {
  4.         fmt.Println("crypto.HexToECDSA error ,", err)
  5.         return "", err
  6.     }
  7.     publicKey := privateKeyECDSA.Public()
  8.     publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
  9.     if !ok {
  10.         fmt.Println("publicKeyECDSA error ,", err)
  11.         return "", err
  12.     }
  13.     //从公钥推导出钱包地址
  14.     fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
  15.     fmt.Println("钱包地址:", fromAddress.Hex())

4.2、构造请求参数

这里就跟使用函数选择器的方式不一样了,也是本篇文章的重点介绍内容

4.2.1、准备好合约的abi文件 abi.json

不会获取合约abi文件 可以关注公众号:外柏叁布道者(web3_preacher给我留言

  1. [
  2. {
  3. "inputs": [],
  4. "stateMutability": "nonpayable",
  5. "type": "constructor"
  6. },
  7. {
  8. "anonymous": false,
  9. "inputs": [
  10. {
  11. "indexed": true,
  12. "internalType": "address",
  13. "name": "owner",
  14. "type": "address"
  15. },
  16. {
  17. "indexed": true,
  18. "internalType": "address",
  19. "name": "spender",
  20. "type": "address"
  21. },
  22. {
  23. "indexed": false,
  24. "internalType": "uint256",
  25. "name": "value",
  26. "type": "uint256"
  27. }
  28. ],
  29. "name": "Approval",
  30. "type": "event"
  31. },
  32. .....
  33. ]
4.2.2、读取abi文件
  1. //读取abi文件
  2. abiData, err := os.ReadFile("./part2/abi.json")
  3. if err != nil {
  4. fmt.Println("os.ReadFile error ,", err)
  5. return "", err
  6. }
4.2.3、将abi数据转成合约abi对象
  1. contractAbi, err := abi.JSON(bytes.NewReader(abiData))
  2. if err != nil {
  3. fmt.Println("abi.JSON error ,", err)
  4. return "", err
  5. }
4.2.4、合约abi对象打包要调用的方法和参数
  1. amount, _ := new(big.Int).SetString("100000000000000000000", 10)
  2. data, err := contractAbi.Pack("transfer", common.HexToAddress(toAddress), amount)
  3. if err != nil {
  4. fmt.Println("contractAbi.Pack error ,", err)
  5. return "", err
  6. }

实际上这步操作跟我们第一章里讲到的代码(见下面)的作用是一样的,有兴趣的朋友,可以自行阅读一下contractAbi.Pack这个方法的源码

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

4.3、构造交易对象

  1. //获取nonce
  2. nonce, err := client.NonceAt(context.Background(), fromAddress, nil)
  3. if err != nil {
  4. return "", err
  5. }
  6. //获取小费
  7. gasTipCap, _ := client.SuggestGasTipCap(context.Background())
  8. //transfer 默认是 使用 21000 gas
  9. gas := uint64(100000)
  10. //最大gas fee
  11. gasFeeCap := big.NewInt(38694000460)
  12. contractAddress := common.HexToAddress(contract)
  13. //创建交易
  14. tx := types.NewTx(&types.DynamicFeeTx{
  15. Nonce: nonce,
  16. GasTipCap: gasTipCap,
  17. GasFeeCap: gasFeeCap,
  18. Gas: gas,
  19. To: &contractAddress,
  20. Value: big.NewInt(0),
  21. Data: data,
  22. })

4.4、交易签名/发送交易

  1. // 获取当前区块链的ChainID
  2. chainID, err := client.ChainID(context.Background())
  3. if err != nil {
  4. fmt.Println("获取ChainID失败:", err)
  5. return "", err
  6. }
  7. fmt.Println("当前区块链的ChainID:", chainID)
  8. //创建签名者
  9. signer := types.NewLondonSigner(chainID)
  10. //对交易进行签名
  11. signTx, err := types.SignTx(tx, signer, privateKeyECDSA)
  12. if err != nil {
  13. return "", err
  14. }
  15. //发送交易
  16. err = client.SendTransaction(context.Background(), signTx)
  17. if err != nil {
  18. return "", err
  19. }

4.5、main函数里来调用函数

  1. func main() {
  2. client, err := ethclient.Dial("https://goerli.infura.io/v3/3214cac49d354e48ad196cdfcefae1f8")
  3. if err != nil {
  4. fmt.Println("ethclient.Dial error : ", err)
  5. os.Exit(0)
  6. }
  7. tx, err := transfer(client, privateKey, toAddress, contractAddress)
  8. if err != nil {
  9. fmt.Println("transfer error : ", err)
  10. os.Exit(0)
  11. }
  12. fmt.Println("使用go调用智能合约第二讲:transfer tx : ", tx)
  13. }

 5、执行main方法

 我们的代码已经成功执行了,让我们去区块链浏览器了看一下

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

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/900061
推荐阅读
相关标签
  

闽ICP备14008679号