第1节:编译部署合约
小白入门:https://github.com/dukedaily/solidity-expert ,欢迎star转发,文末加V入群。
职场进阶: https://dukeweb3.com
前置条件
- 已经安装golang;
- 准备好bsc testnet的rpc,用于广播交易;
- 准备好bsc testnet的BNB,用于支付gas费;
- metamask 添加rpc:https://chainlist.org/zh/chain/97
- faucet:https://testnet.bnbchain.org/faucet-smart
- 浏览器:https://testnet.bscscan.com/
安装编译器
solc会对合约进行编译,生成:abi和bytecode
# Ubuntu
sudo snap install solc --edge
# MacOS
brew update
brew tap ethereum/ethereum
brew install solidity
安装abigen
abigen可以对abi进行编译,生成配套的go代码,从而支持我们进行后续开发。
go get -u github.com/ethereum/go-ethereum
cd $GOPATH/src/github.com/ethereum/go-ethereum/
make
make devtools
编写合约
创建工程:go mod init code,并创建文件contracts/Store.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity =0.8.15;
contract Store {
event ItemSet(bytes32 key, bytes32 value);
string public version;
mapping (bytes32 => bytes32) public items;
constructor(string memory _version) {
version = _version;
}
function setItem(bytes32 key, bytes32 value) external {
items[key] = value;
emit ItemSet(key, value);
}
}
编译合约
https://geth.ethereum.org/docs/tools/abigen
指定合约,生成abi和bin(bytecode),存放在metadata目录下,同时生成配套代码Store.go
# 1.通过.sol编译出abi
solc --abi --bin contracts/Store.sol -o metadata
# 2.通过abi编译出go文件
abigen --abi=metadata/Store.abi --bin=metadata/Store.bin --pkg=store --type Store --out=src/Store.go
# 4.安装go依赖包
go mod tidy
当前工程目录结构:
部署合约
创建部署文件main/deploy.go,准备部署到bsc testnet,chainid:56
package main
import (
"fmt"
"log"
utils "code/main/utils"
store "code/src"
"github.com/ethereum/go-ethereum/ethclient"
)
func main() {
client, err := ethclient.Dial(utils.BscTestnetRpc)
if err != nil {
log.Fatal(err)
}
auth := utils.Prepare(utils.HardhatPrivateKey, 0, client)
input := "1.0"
address, tx, instance, err := store.DeployStore(auth, client, input)
if err != nil {
log.Fatal(err)
}
// 0x587bf1bc96163e279d2ea1b27f3b41cc34b171c3
fmt.Println("address:", address.Hex())
// https://testnet.bscscan.com/tx/0x082186993e2786744366e2147827841dc02115439d9d3786ce39a1774209d38a
fmt.Println("tx hash:", tx.Hash().Hex())
_ = instance
}
main/utils/utils.go,为了方便开发,下面的私钥刻意暴露了出来,实际的代码中,应该使用环境变量,将私钥存放在.env文件中,请小心处理之,否则资产会被零元购
。
package utils
import (
"context"
"crypto/ecdsa"
"log"
"math/big"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
)
var (
BscTestnetRpc = "https://data-seed-prebsc-2-s1.binance.org:8545"
// address: 0xc783df8a850f42e7f7e57013759c285caa701eb6
HardhatPrivateKey = "c5e8f61d1ab959b397eecc0a37a6517b8e67a0e7cf1f4bce5591f3ed80199122"
)
func Prepare(privKey string, value int64, client *ethclient.Client) *bind.TransactOpts {
privateKey, err := crypto.HexToECDSA(privKey)
if err != nil {
log.Fatal(err)
}
publicKey := privateKey.Public()
publicKeECDSA, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
log.Fatal("invalid public key type")
}
fromAddress := crypto.PubkeyToAddress(*publicKeECDSA)
nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
if err != nil {
log.Fatal(err)
}
gasPrice, err := client.SuggestGasPrice(context.Background())
if err != nil {
log.Fatal(err)
}
// chainId := 56
// auth, _ := bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(int64(56)))
auth := bind.NewKeyedTransactor(privateKey)
auth.Nonce = big.NewInt(int64(nonce))
auth.Value = big.NewInt(value)
// auth.GasLimit = uint64(300000)
auth.GasPrice = gasPrice
return auth
}
执行结果,点击查看
总结
本文我们介绍了如何:创建与以太坊交互的客户端、编写合约、编译合约、与合约读写交互操作,有了这些基础准备后,下一节我们将介绍如何使用合约监听事件并与我们的世界杯项目进行结合,敬请期待!