1、关于开发环境搭建配置等可参考之前的文章 2、部署合约代码erc20.js
const hre = require("hardhat");
async function main() {
const CONTRACT = await hre.ethers.getContractFactory("ERC20");
const contract = await CONTRACT.deploy();
await contract.init("ERC20Name","ERC20Symbol");
console.log("name:",contract.name(),"symbol:",contract.symbol());
await contract.deployed();
console.log(`contract deployed to ${contract.address}`);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
3、启动并上链
#切换到智能合约项目位置
npx hardhat node
#新开一个窗口,确保localhost已经在hardhat.config.js中配置了,可查看第一步链接对照
npx hardhat run scripts/erc.js --network localhost
4、新建一个文件夹,存放go项目,完成mod初始化等
完整go项目文件目录
5、拷贝智能合约compile产生的ABI,在新文件夹中新建一个erc20.json文件
文章来源地址https://www.toymoban.com/news/detail-503299.html
6、安装abigen
go get github.com/ethereum/go-ethereum
#切换路径 cd $GOPATH/pkg/mod/github.com/ethereum/go-ethereum@v1.10.25
sudo make && make devtools
#测试安装
abigen --help
7、将ABI生成GO文件
abigen --abi erc20.json -pkg json -type erc20 --out erc20.go
8、编写调用文件 main.go
package main
import (
"context"
"crypto/ecdsa"
"fmt"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"math/big"
"mysolidity/json"
)
func main() {
//合约地址
contractAddress := "0x5FbDB2315678afecb367f032d93F642f64180aa3"
//连接本地的以太坊私链(一定要保证本地以太坊私链已经启动)
conn, err := ethclient.Dial("http://127.0.0.1:8545")
fmt.Println("connect to local node...", conn)
if err != nil {
fmt.Errorf("could not connect to local node: %v", err)
return
}
//创建合约
erc20, err := json.NewErc20(common.HexToAddress(contractAddress), conn)
if err != nil {
fmt.Errorf("failed to instantiate a Token contract: %v", err)
return
}
fmt.Println("contract token:", erc20)
//调用合约查询方法
name, err := erc20.Name(&bind.CallOpts{
Pending: false,
From: common.Address{},
BlockNumber: nil,
Context: nil,
})
if err != nil {
fmt.Errorf("name:%v", err)
return
}
symbol, err := erc20.Symbol(&bind.CallOpts{
Pending: false,
From: common.Address{},
BlockNumber: nil,
Context: nil,
})
if err != nil {
fmt.Errorf("name:%v", err)
return
}
fmt.Println("name:", name, "symbol:", symbol)
//查询第一个账户余额
b, err := erc20.BalanceOf(&bind.CallOpts{
Pending: false,
From: common.Address{},
BlockNumber: nil,
Context: nil,
}, common.HexToAddress("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"))//启动node默认生成的第1个账户地址
if err != nil {
fmt.Errorf("BalanceOf:%v", err)
return
}
fmt.Println("first balance:", b)
第一个账户给第二个账户转账
//私钥,需要生成签名
privateKey, err := crypto.HexToECDSA("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80")//私钥注意去掉ox,这是启动node默认生成的第1个账户的私钥
if err != nil {
fmt.Errorf("err:%v\n", err)
return
}
publicKey := privateKey.Public()
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
fmt.Errorf("cannot assert type: publicKey is not of type *ecdsa.PublicKey")
return
}
fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
nonce, err := conn.PendingNonceAt(context.Background(), fromAddress)
if err != nil {
fmt.Errorf("%v", err)
return
}
gasPrice, err := conn.SuggestGasPrice(context.Background())
if err != nil {
fmt.Errorf("%v", err)
return
}
//chainID
id, err := conn.ChainID(context.Background())
if err != nil {
return
}
fmt.Println("chainID:", id)
auth, _ := bind.NewKeyedTransactorWithChainID(privateKey, id)
auth.Nonce = big.NewInt(int64(nonce))
auth.Value = big.NewInt(10)
auth.GasLimit = uint64(300000)
auth.GasPrice = gasPrice
tx, err := erc20.Transfer(&bind.TransactOpts{
Signer: auth.Signer,
From: fromAddress,
GasLimit: auth.GasLimit,
GasPrice: auth.GasPrice,
Context: nil,
}, common.HexToAddress("0x70997970C51812dc3A010C7d01b50e0d17dc79C8"), big.NewInt(8))
if err != nil {
fmt.Errorf("transfer:%v", err)
return
}
fmt.Println("tx.GasPrice():", tx.GasPrice())
//查询两个账户余额
b, err = erc20.BalanceOf(&bind.CallOpts{From: fromAddress}, common.HexToAddress("0x70997970C51812dc3A010C7d01b50e0d17dc79C8"))//启动node默认生成的第2个账户地址
if err != nil {
fmt.Errorf("BalanceOf:%v", err)
return
}
fmt.Println("second balance:", b)
b, err = erc20.BalanceOf(&bind.CallOpts{From: fromAddress}, fromAddress)
if err != nil {
fmt.Errorf("BalanceOf:%v", err)
return
}
fmt.Println("first balance:", b)
}
9、查询事件日志(完整开发的一般流程,在链端开发智能合约后,由前端使用web3.js等进行交互,后端通过查询事件日志修改数据库信息展示)
package main
import (
"context"
"fmt"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"math/big"
"mysolidity/json"
)
func main() {
//合约地址
contractAddress := common.HexToAddress("0x5FbDB2315678afecb367f032d93F642f64180aa3")
//websocket监听
client, err := ethclient.Dial("ws://127.0.0.1:8545/ws")
if err != nil {
fmt.Errorf("could not connect to local node: %v", err)
return
}
query := ethereum.FilterQuery{
FromBlock: big.NewInt(1), //生产环境中,从0开始,查询后修改区块记录,下一次就从后一个有记录的区块数开始
ToBlock: big.NewInt(100),
Addresses: []common.Address{
contractAddress,
},
}
erc20, _ := json.NewErc20(contractAddress, client)
logs, err := client.FilterLogs(context.Background(), query)
if err != nil {
fmt.Errorf("err:%v\n", err)
return
}
for _, vLog := range logs {
if len(vLog.Topics) == 0 {
continue
}
event := vLog.Topics[0].Hex()
if event == TransferEvent() { //对对应的事件进行对应的处理
fmt.Println(vLog.Data)
data, err := erc20.ParseTransfer(vLog)
if err != nil {
fmt.Errorf("err:%v\n", err)
continue
}
fmt.Println(data.From.Hex(), data.To.Hex(), data.Value.Int64(), data.Raw.Data)
}
}
}
func TransferEvent() string {
event := crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)")).Hex()
return event
}
10、测试结果(main.go为最后一次运行结果)
文章来源:https://www.toymoban.com/news/detail-503299.html
到了这里,关于在本地以太坊私链上,使用go调用智能合约,获取事件日志的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!