-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy path16transferETH.go
100 lines (92 loc) · 3.42 KB
/
16transferETH.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package main
import (
"context"
"crypto/ecdsa"
"fmt"
"github.com/ethereum/go-ethereum"
"log"
"math/big"
"os"
"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"
)
func main() {
//0. 初始化客户端
client, err := ethclient.Dial("https://ropsten.infura.io/v3/28d5693e8bee4b58a61f0c627d62331e")
if err != nil {
log.Fatal(err)
}
// 1. 加载私钥
privateKey, err := crypto.HexToECDSA(os.Getenv("PRIVATE_KEY"))
if err != nil {
log.Fatal(err)
}
//之后我们需要获得帐户的随机数(nonce)。 每笔交易都需要一个nonce。 根据定义,nonce是仅使用一次的数字。 如果是发送交易的新帐户,则该随机数将为“0”。
//来自帐户的每个新事务都必须具有前一个nonce增加1的nonce。很难对所有nonce进行手动跟踪,
//于是ethereum客户端提供一个帮助方法PendingNonceAt,它将返回你应该使用的下一个nonce。
//该函数需要我们发送的帐户的公共地址 - 这个我们可以从私钥派生。
publicKey := privateKey.Public()
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
log.Fatal("cannot assert type: publicKey is not of type *ecdsa.PublicKey")
}
fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
fmt.Printf("from address: %s\n", common.HexToAddress(fromAddress.Hash().Hex()))
toAddress := common.HexToAddress("0xf1EEfEE62A8651c3772cd8D7ba9031b7029316f7")
fmt.Printf("to address: %s\n", common.HexToAddress(toAddress.Hash().Hex()))
// 2. 获得账户创建转账交易需要的的随机数nonce
nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
if err != nil {
log.Fatal(err)
}
fmt.Printf("nonce: %d\n", nonce)
// 3. 设置转账交易信息
// 转账1ETH
value := big.NewInt(1000000000000000000) // in wei (1 eth)
var data []byte
// 手动设置ETH转账的燃气应设上限为"40000”单位
//gasLimit := uint64(40000) // in units
//
// 也可根据data估算的gasLimit
gasLimit, err := client.EstimateGas(context.Background(), ethereum.CallMsg{
To: &toAddress,
Data: data,
})
if err != nil {
log.Fatal(err)
}
// 燃气价格总是根据市场需求和用户愿意支付的价格而波动的,因此对燃气价格进行硬编码有时并不理想。
// go-ethereum客户端提供SuggestGasPrice函数,用于根据'x'个先前块来获得平均燃气价格。
gasPrice, err := client.SuggestGasPrice(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Printf("SuggestGasPrice: %d\n", gasPrice)
tx := types.NewTx(&types.LegacyTx{
Nonce: nonce,
To: &toAddress,
Value: value,
Gas: gasLimit,
GasPrice: gasPrice,
Data: data,
})
//下一步是使用发件人的私钥对事务进行签名。 为此,我们调用SignTx方法,该方法接受一个未签名的事务和我们之前构造的私钥。
// SignTx方法需要EIP155签名者,这个也需要我们先从客户端拿到链ID。
chainID, err := client.NetworkID(context.Background())
if err != nil {
log.Fatal(err)
}
// 4. 使用私钥对转账交易签名
signedTx, err := types.SignTx(tx, types.LatestSignerForChainID(chainID), privateKey)
if err != nil {
log.Fatal(err)
}
// 5. 发布交易
err = client.SendTransaction(context.Background(), signedTx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("tx sent: %s\n", signedTx.Hash().Hex())
}