Web3课程汇集

第四节:如何从 Go 开发顺利转型 Web3

主要是前端开发/全栈开发,需求最大~

很多L1,都是基于cosmos-sdk开发的


账户 分为 外部账户(有公/私钥) 和 合约账户(只有公钥)

中间语言Yul/Yul+

zan.top 也是个节点&水龙头服务

https://zan.top/faucet



区块头里面 三棵树—> 常问的面试题

<以太坊的技术与实现> 这本书



如何用geth查询最新的区块高度?

要使用 Geth 查询最新的区块高度,你可以通过命令行界面(CLI)或 JavaScript 控制台来实现。以下是两种方法:

方法一:使用命令行

  1. 启动 Geth 节点。

  2. 在命令行中,输入以下命令:

    1
    geth attach

    这将连接到运行中的 Geth 节点。

  3. 在 Geth JavaScript 控制台中,输入以下命令:

    1
    eth.blockNumber

    这会返回最新的区块高度。

方法二:使用 RPC 接口

如果你已启用 RPC 接口,可以通过以下方式查询:

  1. 发送一个 JSON-RPC 请求到 Geth 节点。可以使用 curl 命令:

    1
    curl -X POST --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' -H "Content-Type: application/json" http://localhost:8545
  2. 这将返回最新的区块高度,以十六进制格式显示,你需要将其转换为十进制。

示例输出

无论使用哪种方法,返回的结果都是类似这样的:

1
2
3
4
5
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x10d4f"
}

其中 "result" 字段的值是最新区块高度的十六进制表示。你可以将其转换为十进制数。



1. 如何在go代码中用geth查询最新的区块高度?

在 Go 代码中使用 Geth 查询最新的区块高度,你需要使用 go-ethereum 包。以下是一个简单的示例,演示如何连接到 Geth 节点并获取最新的区块高度。

步骤

  1. 安装 go-ethereum 包

    首先,确保你已经安装了 go-ethereum。你可以使用以下命令安装:

    1
    go get github.com/ethereum/go-ethereum
  2. 编写代码

    创建一个新的 Go 文件,例如 main.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
    package main

    import (
    "context"
    "fmt"
    "log"

    "github.com/ethereum/go-ethereum/rpc"
    )

    func main() {
    // 连接到 Geth 节点
    client, err := rpc.DialContext(context.Background(), "http://localhost:8545")
    if err != nil {
    log.Fatalf("Failed to connect to the Ethereum client: %v", err)
    }

    // 查询最新区块高度
    var blockNumber hexutil.Big
    err = client.CallContext(context.Background(), &blockNumber, "eth_blockNumber")
    if err != nil {
    log.Fatalf("Failed to get block number: %v", err)
    }

    // 打印最新区块高度
    fmt.Printf("Latest block number: %s\n", blockNumber.String())
    }
  3. 运行代码

    确保 Geth 节点正在运行并且监听在 http://localhost:8545。然后在终端中运行以下命令:

    1
    go run main.go

说明

  • 代码中使用 rpc.DialContext 连接到 Geth 节点。
  • 通过 client.CallContext 调用 eth_blockNumber 方法来获取最新的区块高度。
  • 返回的区块高度是以十六进制格式表示的,使用 hexutil.Big 类型进行处理。

这样,你就可以在 Go 代码中成功查询到最新的区块高度。


可以在https://zan.top/service/apikeys/2c33d502-7158-4e79-922f-b0d98e9a8dbb/started 创建

235c92fe56e1494a84dd9e851340f623

https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623

代码在 /Users/fliter/geth-lab

go mod tidy时下载的依赖:

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
go: finding module for package github.com/ethereum/go-ethereum/rpc
go: found github.com/ethereum/go-ethereum/rpc in github.com/ethereum/go-ethereum v1.14.12
go: downloading github.com/Microsoft/go-winio v0.6.2
go: downloading github.com/deckarep/golang-set/v2 v2.6.0
go: downloading github.com/gorilla/websocket v1.4.2
go: downloading github.com/davecgh/go-spew v1.1.1
go: downloading github.com/holiman/uint256 v1.3.1
go: downloading golang.org/x/crypto v0.22.0
go: downloading github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible
go: downloading golang.org/x/sys v0.22.0
go: downloading golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
go: downloading github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9
go: downloading github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1
go: downloading github.com/crate-crypto/go-kzg-4844 v1.0.0
go: downloading github.com/ethereum/c-kzg-4844 v1.0.0
go: downloading github.com/StackExchange/wmi v1.2.1
go: downloading github.com/tklauser/go-sysconf v0.3.12
go: downloading github.com/stretchr/testify v1.9.0
go: downloading github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c
go: downloading golang.org/x/sync v0.7.0
go: downloading github.com/go-ole/go-ole v1.3.0
go: downloading github.com/tklauser/numcpus v0.6.1
go: downloading github.com/pmezard/go-difflib v1.0.0
go: downloading gopkg.in/yaml.v3 v3.0.1
go: downloading github.com/consensys/gnark-crypto v0.12.1



go: downloading github.com/bits-and-blooms/bitset v1.13.0
go: downloading github.com/mmcloughlin/addchain v0.4.0
go: downloading github.com/consensys/bavard v0.1.13
go: downloading github.com/supranational/blst v0.3.13
go: downloading rsc.io/tmplfunc v0.0.3


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
package main

import (
"context"
"fmt"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/ethclient"
"log"

"github.com/ethereum/go-ethereum/rpc"
)

func main() {
// 连接到 Geth 节点
client, err := rpc.DialContext(context.Background(), "https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")
if err != nil {
log.Fatalf("Failed to connect to the Ethereum client: %v", err)
}

// 查询最新区块高度
var blockNumber hexutil.Big
err = client.CallContext(context.Background(), &blockNumber, "eth_blockNumber")
if err != nil {
log.Fatalf("Failed to get block number: %v", err)
}

// 打印最新区块高度
fmt.Printf("Latest block number: %s\n", blockNumber.String())

// 或者:

client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

latesBlockNumber, err := client2.BlockNumber(context.Background())

if err != nil {
log.Fatal(err)
}
// 打印最新区块高度
fmt.Printf("Latest block number: %d\n", latesBlockNumber)

}


两种方式~

第一种poe提供的,打印出来的是16进制

第二种是这个up主写的,十进制

两者可能不一样,因为区块涨的很快?



2. 查询某个区块的详情

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func queryBlockInfo() {

client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

blockInfo, err := client2.BlockByNumber(context.Background(), big.NewInt(21300304))

if err != nil {
log.Fatal(err)
}
// 打印某个区块的详情
fmt.Printf("区块详情: %#v\n", blockInfo)

fmt.Println()

for _, tx := range blockInfo.Transactions() {
fmt.Printf("交易哈希信息:%s\n", tx.Hash().Hex())
}

}


查询某个交易哈希与回执

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

func queryTxAndReceipt() {

client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

ctx := context.Background()

tx, _, err := client2.TransactionByHash(ctx, common.HexToHash("0x246bc6b7d134819f75e428f03a3e029d6eb09d5dca2cb00b76f68894d4a166d9"))

if err != nil {
log.Fatal(err)
}

fmt.Printf("tx:%+v\n", tx)

receipt, err := client2.TransactionReceipt(ctx, common.HexToHash("0x246bc6b7d134819f75e428f03a3e029d6eb09d5dca2cb00b76f68894d4a166d9"))

if err != nil {
log.Fatal(err)
}
// 打印回执
fmt.Printf("receipt: %#v\n", receipt)

}

查询当前gas费


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

func queryGasPrice() {
client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

ctx := context.Background()

gasPrice, err := client2.SuggestGasPrice(ctx)
if err != nil {
log.Fatal(err)
}
// 打印gasPrice
fmt.Printf("gasPrice: %#v\n", gasPrice)

}


创建账户

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
func queryGasPrice() {
client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

ctx := context.Background()

gasPrice, err := client2.SuggestGasPrice(ctx)
if err != nil {
log.Fatal(err)
}
// 打印gasPrice
fmt.Printf("gasPrice: %#v\n", gasPrice)

}

func createAccount() {
priKey, err := crypto.GenerateKey()
if err != nil {
log.Fatal(err)
}

priKeyBytes := crypto.FromECDSA(priKey)

//priKey: "17a8932fbf2f1c6afed1e49b0dd780bc606dec602aefe60d051c58d12b3bf721"
fmt.Printf("priKey: %#v\n", common.Bytes2Hex(priKeyBytes))

}

恢复账户

通过私钥得到公钥,再通过公钥计算出地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

func loadAccount() {
priKey, err := crypto.ToECDSA(common.Hex2Bytes("17a8932fbf2f1c6afed1e49b0dd780bc606dec602aefe60d051c58d12b3bf721"))

if err != nil {
log.Fatal(err)
}

publicKey := priKey.Public()

publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)

if !ok {
log.Fatal("断言失败")
}

publicBytes := crypto.FromECDSAPub(publicKeyECDSA)
fmt.Println(hexutil.Encode(publicBytes[4:])) //0x2fbc49556fe31b7cbbcfac0647e05950554ecaa89154b68b762d5cf30b5f51fee0d5504fa22eb60fe17ac7e5f0cb79c07059f9d5535d0161eded9d04be

address := crypto.PubkeyToAddress(*publicKeyECDSA).Hex()
fmt.Println(address) // 0x607e1E37B2117E2775E45923b6300e5B5C3F0238

}

查询余额

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

func queryBalance() {

client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

ctx := context.Background()

fromAccount := common.HexToAddress("0x62F70A36AA049d965521b2528186EC799aBd80Ed")

fmt.Printf("address: %s\n", fromAccount.Hex()) //address: 0x62F70A36AA049d965521b2528186EC799aBd80Ed

balance, err := client2.BalanceAt(ctx, fromAccount, nil) //balance: 2557245377255309

if err != nil {
log.Fatal(err)
}

fmt.Printf("balance: %s\n", balance.String()) //balance: 2557245377255309

}

这个实用啊!

10的负18次方


eth转账

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

func transfer() {

client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

ctx := context.Background()

fromAccount := common.HexToAddress("账号1(要转出的账号地址)")
fmt.Printf("address: %s\n", fromAccount.Hex())

toAccount := common.HexToAddress("账号1(要转出的账号地址)")
fmt.Printf("address: %s\n", fromAccount.Hex())

value := big.NewInt(1e15) //0.001 eth

nonce, err := client2.PendingNonceAt(ctx, fromAccount)

if err != nil {
log.Fatal(err)
}

var gasLimit uint64 = 21000

gasPrice, err := client2.SuggestGasPrice(ctx)
if err != nil {
log.Fatal(err)
}

var data []byte

tx := types.NewTransaction(nonce, toAccount, value, gasLimit, gasPrice, data)

chainID, err := client2.ChainID(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("chainID: %s\n", chainID.String())

privKey, err := crypto.ToECDSA(common.Hex2Bytes("私钥"))
if err != nil {
log.Fatal(err)
}

signer := types.NewEIP155Signer(chainID)

signedTx, err := types.SignTx(tx, signer, privKey)
if err != nil {
log.Fatal(err)
}

err = client2.SendTransaction(ctx, signedTx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("交易哈希: %s\n", signedTx.Hash().Hex())

// 可以换成测试网的节点,以及账号,领取一点测试币,最后交易成功了能在以太坊测试网浏览器上查
}


开发实战5 之 部署智能合约(ERC20)

有很多种方式,此处用geth最原生的方式 (和转账交易差不多啊~)

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

func deployERC20() {

client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

ctx := context.Background()

fromAccount := common.HexToAddress("账号1(要转出的账号地址)")
fmt.Printf("address: %s\n", fromAccount.Hex())

value := big.NewInt(0)

nonce, err := client2.PendingNonceAt(ctx, fromAccount)

if err != nil {
log.Fatal(err)
}

var gasLimit uint64 = 3000000

gasPrice, err := client2.SuggestGasPrice(ctx)
if err != nil {
log.Fatal(err)
}

var data []byte = common.Hex2Bytes("你的token_code")

tx := types.NewContractCreation(nonce, value, gasLimit, gasPrice, data)

chainID, err := client2.ChainID(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("chainID: %s\n", chainID.String())

privKey, err := crypto.ToECDSA(common.Hex2Bytes("私钥"))
if err != nil {
log.Fatal(err)
}

signer := types.NewEIP155Signer(chainID)

signedTx, err := types.SignTx(tx, signer, privKey)
if err != nil {
log.Fatal(err)
}

err = client2.SendTransaction(ctx, signedTx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("交易哈希: %s\n", signedTx.Hash().Hex())

// 可以换成测试网的节点,以及账号,领取一点测试币,最后交易成功了能在以太坊测试网浏览器上查
}

开发实战5 之 查询code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

func queryCode() {

client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

ctx := context.Background()

contractAccount := common.HexToAddress("上一步得到的合约地址(其实就是to的那个地址)")

fmt.Printf("address: %s\n", contractAccount.Hex())

code, err := client2.CodeAt(ctx, contractAccount, nil)

if err != nil {
log.Fatal(err)
}

fmt.Printf("balance: %s\n", common.Bytes2Hex(code))
}

开发实战6 之 使用abigen生成合约文件

abigen命令,能通过一个xxx.abi生成一个xxx.go文件

开发实战6 之 调用智能合约(查询ERC20余额)

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

func queryERC20Balance() {

client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

//ctx := context.Background()

fromAccount := common.HexToAddress("账号1(要转出的账号地址)")
fmt.Printf("address: %s\n", fromAccount.Hex())

// geth也不知道你要调用哪个合约,这个合约里有哪些方法了..需要调用abi生成的go文件

myTokenCaller, err := my_token.NewMyTokenCaller(fromAccount, client2)

if err != nil {
log.Fatal(err)
}

balance, err := myTokenCaller.BalanceOf(nil, fromAccount)

if err != nil {
log.Fatal(err)
}

fmt.Printf("balance: %s\n", balance.String())

}

开发实战7 之 调用智能合约(ERC20转账)

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

func transferERC20() {

client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

ctx := context.Background()

fromAccount := common.HexToAddress("账号1(要转出的账号地址)")
fmt.Printf("address: %s\n", fromAccount.Hex())

constractAccount := common.HexToAddress("合约地址")
fmt.Printf("address: %s\n", constractAccount.Hex())

value := big.NewInt(0)

nonce, err := client2.PendingNonceAt(ctx, fromAccount)

if err != nil {
log.Fatal(err)
}

var gasLimit uint64 = 30000 //调合约的话一般要几十万

gasPrice, err := client2.SuggestGasPrice(ctx)
if err != nil {
log.Fatal(err)
}

myToken, err := my_token.NewMyToken(constractAccount, client2)
if err != nil {
log.Fatal(err)
}

chainID, err := client2.ChainID(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("chainID: %s\n", chainID.String())

privKey, err := crypto.ToECDSA(common.Hex2Bytes("私钥"))
if err != nil {
log.Fatal(err)
}

auth, err := bind.NewKeyedTransactorWithChainID(privKey, chainID)
if err != nil {
log.Fatal(err)
}

auth.Nonce = big.NewInt(int64(nonce))
auth.Value = value
auth.GasLimit = gasLimit
auth.GasPrice = gasPrice

signedTx, err := myToken.Transfer(auth, toaAccount, big.NewInt(5000000))
if err != nil {
log.Fatal(err)
}

}

开发实战8 – 查询Transfer日志

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

func queryERC20Logs() {

client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

ctx := context.Background()

fromAccount := common.HexToAddress("账号1(要转出的账号地址)")
fmt.Printf("address: %s\n", fromAccount.Hex())

constractAccount := common.HexToAddress("合约地址")
fmt.Printf("address: %s\n", constractAccount.Hex())

query := &bind.FilterOpts{Start: 7089380, End: nil, Context: ctx}

myTokenFilterer, err := my_token.NewMyTokenFilterer(constractAccount, client2)

txIterator, err := my_token.NewMyTokenFilterer(query, nil, nil)
if err != nil {
log.Fatal(err)
}

for txIterator.Next() {
fmt.Printf("from: %s\n", txIterator.Event.From.Hex())
fmt.Printf("to: %s\n", txIterator.Event.To.Hex())
fmt.Printf("value: %s\n", txIterator.Event.Value.String())

}

}




完整代码:

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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
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/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
"log"
"math/big"
)

func main() {

//queryLatestBlockNumber() // 查询最新的区块高度
//fmt.Println()
//
//queryBlockInfo() // 查询区块详情

//queryTxAndReceipt() // 查询交易哈希与回执
//queryGasPrice() // 查询当前gas费

// createAccount() // 创建账号
// loadAccount() // 恢复(导入)账号

// queryBalance() //查询余额

transfer() // 转账
deployERC20() // 部署合约
queryCode() // 查询code

queryERC20Balance()
}

func queryLatestBlockNumber() {
// 连接到 Geth 节点
client, err := rpc.DialContext(context.Background(), "https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")
if err != nil {
log.Fatalf("Failed to connect to the Ethereum client: %v", err)
}

// 查询最新区块高度
var blockNumber hexutil.Big
err = client.CallContext(context.Background(), &blockNumber, "eth_blockNumber")
if err != nil {
log.Fatalf("Failed to get block number: %v", err)
}

// 打印最新区块高度
fmt.Printf("Latest block number: %s\n", blockNumber.String())

// 或者:

client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

latestBlockNumber, err := client2.BlockNumber(context.Background())

if err != nil {
log.Fatal(err)
}
// 打印最新区块高度
fmt.Printf("Latest block number: %d\n", latestBlockNumber)

}

func queryBlockInfo() {

client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

blockInfo, err := client2.BlockByNumber(context.Background(), big.NewInt(21300304))

if err != nil {
log.Fatal(err)
}
// 打印某个区块的详情
fmt.Printf("区块详情: %#v\n", blockInfo)

fmt.Println()

for _, tx := range blockInfo.Transactions() {
fmt.Printf("交易哈希信息:%s\n", tx.Hash().Hex())
}

}

func queryTxAndReceipt() {

client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

ctx := context.Background()

tx, _, err := client2.TransactionByHash(ctx, common.HexToHash("0x246bc6b7d134819f75e428f03a3e029d6eb09d5dca2cb00b76f68894d4a166d9"))

if err != nil {
log.Fatal(err)
}

fmt.Printf("tx:%+v\n", tx)

receipt, err := client2.TransactionReceipt(ctx, common.HexToHash("0x246bc6b7d134819f75e428f03a3e029d6eb09d5dca2cb00b76f68894d4a166d9"))

if err != nil {
log.Fatal(err)
}
// 打印回执
fmt.Printf("receipt: %#v\n", receipt)

}

func queryGasPrice() {
client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

ctx := context.Background()

gasPrice, err := client2.SuggestGasPrice(ctx)
if err != nil {
log.Fatal(err)
}
// 打印gasPrice
fmt.Printf("gasPrice: %#v\n", gasPrice)

}

func createAccount() {
priKey, err := crypto.GenerateKey()
if err != nil {
log.Fatal(err)
}

priKeyBytes := crypto.FromECDSA(priKey)

//priKey: "17a8932fbf2f1c6afed1e49b0dd780bc606dec602aefe60d051c58d12b3bf721"
fmt.Printf("priKey: %#v\n", common.Bytes2Hex(priKeyBytes))

}

func loadAccount() {
priKey, err := crypto.ToECDSA(common.Hex2Bytes("17a8932fbf2f1c6afed1e49b0dd780bc606dec602aefe60d051c58d12b3bf721"))

if err != nil {
log.Fatal(err)
}

publicKey := priKey.Public()

publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)

if !ok {
log.Fatal("断言失败")
}

publicBytes := crypto.FromECDSAPub(publicKeyECDSA)
fmt.Println(hexutil.Encode(publicBytes[4:])) //0x2fbc49556fe31b7cbbcfac0647e05950554ecaa89154b68b762d5cf30b5f51fee0d5504fa22eb60fe17ac7e5f0cb79c07059f9d5535d0161eded9d04be

address := crypto.PubkeyToAddress(*publicKeyECDSA).Hex()
fmt.Println(address) // 0x607e1E37B2117E2775E45923b6300e5B5C3F0238

}

func queryBalance() {

client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

ctx := context.Background()

fromAccount := common.HexToAddress("0x62F70A36AA049d965521b2528186EC799aBd80Ed")

fmt.Printf("address: %s\n", fromAccount.Hex()) //address: 0x62F70A36AA049d965521b2528186EC799aBd80Ed

balance, err := client2.BalanceAt(ctx, fromAccount, nil) //balance: 2557245377255309

if err != nil {
log.Fatal(err)
}

fmt.Printf("balance: %s\n", balance.String()) //balance: 2557245377255309

}

func transfer() {

client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

ctx := context.Background()

fromAccount := common.HexToAddress("账号1(要转出的账号地址)")
fmt.Printf("address: %s\n", fromAccount.Hex())

toAccount := common.HexToAddress("账号1(要转出的账号地址)")
fmt.Printf("address: %s\n", fromAccount.Hex())

value := big.NewInt(1e15) //0.001 eth

nonce, err := client2.PendingNonceAt(ctx, fromAccount)

if err != nil {
log.Fatal(err)
}

var gasLimit uint64 = 21000

gasPrice, err := client2.SuggestGasPrice(ctx)
if err != nil {
log.Fatal(err)
}

var data []byte

tx := types.NewTransaction(nonce, toAccount, value, gasLimit, gasPrice, data)

chainID, err := client2.ChainID(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("chainID: %s\n", chainID.String())

privKey, err := crypto.ToECDSA(common.Hex2Bytes("私钥"))
if err != nil {
log.Fatal(err)
}

signer := types.NewEIP155Signer(chainID)

signedTx, err := types.SignTx(tx, signer, privKey)
if err != nil {
log.Fatal(err)
}

err = client2.SendTransaction(ctx, signedTx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("交易哈希: %s\n", signedTx.Hash().Hex())

// 可以换成测试网的节点,以及账号,领取一点测试币,最后交易成功了能在以太坊测试网浏览器上查
}

func deployERC20() {

client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

ctx := context.Background()

fromAccount := common.HexToAddress("账号1(要转出的账号地址)")
fmt.Printf("address: %s\n", fromAccount.Hex())

value := big.NewInt(0)

nonce, err := client2.PendingNonceAt(ctx, fromAccount)

if err != nil {
log.Fatal(err)
}

var gasLimit uint64 = 3000000

gasPrice, err := client2.SuggestGasPrice(ctx)
if err != nil {
log.Fatal(err)
}

var data []byte = common.Hex2Bytes("你的token_code")

tx := types.NewContractCreation(nonce, value, gasLimit, gasPrice, data)

chainID, err := client2.ChainID(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("chainID: %s\n", chainID.String())

privKey, err := crypto.ToECDSA(common.Hex2Bytes("私钥"))
if err != nil {
log.Fatal(err)
}

signer := types.NewEIP155Signer(chainID)

signedTx, err := types.SignTx(tx, signer, privKey)
if err != nil {
log.Fatal(err)
}

err = client2.SendTransaction(ctx, signedTx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("交易哈希: %s\n", signedTx.Hash().Hex())

// 可以换成测试网的节点,以及账号,领取一点测试币,最后交易成功了能在以太坊测试网浏览器上查
}

func queryCode() {

client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

ctx := context.Background()

contractAccount := common.HexToAddress("上一步得到的合约地址(其实就是to的那个地址)")

fmt.Printf("address: %s\n", contractAccount.Hex())

code, err := client2.CodeAt(ctx, contractAccount, nil)

if err != nil {
log.Fatal(err)
}

fmt.Printf("balance: %s\n", common.Bytes2Hex(code))
}

func queryERC20Balance() {

client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

//ctx := context.Background()

fromAccount := common.HexToAddress("账号1(要转出的账号地址)")
fmt.Printf("address: %s\n", fromAccount.Hex())

// geth也不知道你要调用哪个合约,这个合约里有哪些方法了..需要调用abi生成的go文件

myTokenCaller, err := my_token.NewMyTokenCaller(fromAccount, client2)

if err != nil {
log.Fatal(err)
}

balance, err := myTokenCaller.BalanceOf(nil, fromAccount)

if err != nil {
log.Fatal(err)
}

fmt.Printf("balance: %s\n", balance.String())

}

func transferERC20() {

client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

ctx := context.Background()

fromAccount := common.HexToAddress("账号1(要转出的账号地址)")
fmt.Printf("address: %s\n", fromAccount.Hex())

constractAccount := common.HexToAddress("合约地址")
fmt.Printf("address: %s\n", constractAccount.Hex())

value := big.NewInt(0)

nonce, err := client2.PendingNonceAt(ctx, fromAccount)

if err != nil {
log.Fatal(err)
}

var gasLimit uint64 = 30000 //调合约的话一般要几十万

gasPrice, err := client2.SuggestGasPrice(ctx)
if err != nil {
log.Fatal(err)
}

myToken, err := my_token.NewMyToken(constractAccount, client2)
if err != nil {
log.Fatal(err)
}

chainID, err := client2.ChainID(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("chainID: %s\n", chainID.String())

privKey, err := crypto.ToECDSA(common.Hex2Bytes("私钥"))
if err != nil {
log.Fatal(err)
}

auth, err := bind.NewKeyedTransactorWithChainID(privKey, chainID)
if err != nil {
log.Fatal(err)
}

auth.Nonce = big.NewInt(int64(nonce))
auth.Value = value
auth.GasLimit = gasLimit
auth.GasPrice = gasPrice

signedTx, err := myToken.Transfer(auth, toaAccount, big.NewInt(5000000))
if err != nil {
log.Fatal(err)
}

}

func queryERC20Logs() {

client2, err := ethclient.Dial("https://api.zan.top/node/v1/eth/mainnet/235c92fe56e1494a84dd9e851340f623")

if err != nil {
log.Fatal(err)
}

ctx := context.Background()

fromAccount := common.HexToAddress("账号1(要转出的账号地址)")
fmt.Printf("address: %s\n", fromAccount.Hex())

constractAccount := common.HexToAddress("合约地址")
fmt.Printf("address: %s\n", constractAccount.Hex())

query := &bind.FilterOpts{Start: 7089380, End: nil, Context: ctx}

myTokenFilterer, err := my_token.NewMyTokenFilterer(constractAccount, client2)

txIterator, err := my_token.NewMyTokenFilterer(query, nil, nil)
if err != nil {
log.Fatal(err)
}

for txIterator.Next() {
fmt.Printf("from: %s\n", txIterator.Event.From.Hex())
fmt.Printf("to: %s\n", txIterator.Event.To.Hex())
fmt.Printf("value: %s\n", txIterator.Event.Value.String())

}

}



第三节:如何从 Java 开发顺利转型 Web3

https://mp.weixin.qq.com/s/PM7lcLAXNPBLPPT48-c4AQ



第二节:如何从 前端 开发顺利转型 Web3

是个东北的老哥,有点意思~

okx要到深圳或香港

bitget 远程/吉隆坡

币安 迪拜



react和ts是基操

vue用的较少

可以用cosmos搭建自己的一个区块链

Solidity去哦是本身很简单,关键是要保证后期安全和使用起来省钱

ethers.js是和区块链交互的~

ethers.js 要和metamask等钱包连起来,会提供一个叫provider的全局变量,再用这个provider调合约,就这么点事儿.

ethers.js 就是连接合约和钱包的桥梁,承上启下的作用

最早是web3.js



v3,v4,v5都是breakchanges, 爱用不用,不做兼容…

ethers.js 的几大模块:

生态库: TypeChains

连接钱包:

  • web3-react

  • wagmi


ui组件库

  • rainbowkit

  • connectkit 官网是 family.so?


upwork平台可以接单

5000u 是底牌

不要玩合约!



Web3 招聘平台 SmartDeer

纯老外, next.js, cloudflare,aws

最后是这哥们的微信~ yzjmydream




Web3进阶必备|01.如何分析一条公链

公链的传统架构,6层:

zero knowledge proof 的公链 –> oasis lab / Aleo, 以及zk四小龙

环签名 —> solana POH

从2015年开始,公链的技术架构几乎没有啥创新了~


分片和有向无环图 是两种比较成功的技术

分片: Near

有向无环图(DAG, 替代传统区块链的数据结构,允许更高效的交易确认和处理): Hashgraph,conflux 的底层用了这个



不过比较有特色的公链都是在激励层做文章,改动相对少,而且用户也买账

谈到一条公链,大家也会首先想到其共识机制,如eth的pos, solana是poh

eos是dpos, 不仅影响tps,也定义了该公链的社会制度,关系到治理方式和去中心化程度

大家对eos口诛笔伐, dPOS将超级节点的权利无限放大, 与中心化相违背



Ton用的智能合约的语言叫FunC




algorand , mina


网站:

sosovalue


0x 开头的eth地址,内部分两种,外部账户(EOA,类似银行账户,存放eth)和合约账户(CA,存放智能合约)

合约账户,合约地址,0x开头,40位,和外部账户长得一模一样

有三种交易类型

github.com/hitadao




做市商 这个角色


https://www.bilibili.com/video/BV1Lh1XYaEie/?spm_id_from=333.1245.0.0

ip号段,主要就是指ipv4的前两段,比如 43.11.4.5, 就是 43.11

https://ipjiance.cn/

ip质量检查

https://ipjiance.com/




Ledger、Trezor


读懂「做市商」是怎么玩的:

https://www.bilibili.com/video/BV1yS421R7Xg/

不仅限于币圈, 股票啥的市场也有这东西

小盘子很容易操控价格…
https://www.bilibili.com/video/BV1M22iY3E8x/


国内专门做工具的: https://mct.xyz/

https://www.bilibili.com/video/BV1HJ4m1T7an

The All-in-one Toolbox For Crypto Adventure 专注开发 WEB3 效率工具 - https://github.com/mctxyz

空投/白名单中奖查询: https://mct.xyz/whitelist



行业领先的Web3工具平台 GTokenTool.Com

冷钱包不接触网络,所以会很安全~




【撸毛人必备的工具网站汇总——建议收藏】

一、撸毛多开
ads指纹浏览器
ads可以淘宝搜索“ads指纹浏览器”购买,差不多100个一个月200块,比正常的购买优惠很多
https://share.adspower.net/2pb8EB
三件套以及ip购买,量大优惠,推荐一个实惠靠谱的朋友,成本可大大降低
微信:oxalin_13
谷歌,推特,discord三件套购买
https://lumao1688.com
接码平台SMS-BUS
http://sms-bus.com
接码平台5sim
http://5sim.net/zh
接码平台SMS-active
http://sms-activate.org/cn

二、查询空投项目网站
1、可能空投的项目
https://airdropking.io/en/
2、筛选正在进行和即将结束的空投
http://Airdrops.io
3、带空投评级功能
http://99airdrops.com
4、包含多个领域的空投
http://airdropalert.com
5、查询最新空投
https://dropsearn.com/airdrops/
6、发现早期项目空投
https://alphadrops.net/alpha
7、网友自建的一个空投项目汇总网站,好用一点但没必要
https://earn3.me/?referral_code=Gh9odPeu
8、查询未领取的空投
https://earni.fi/account

三、空投检索聚合器
1、EVM地址空投聚合查询
https://portfolio.metamask.io/explore
https://daylight.xyz https://earni.fi
https://earndrop.io
2、EVM和Sol生态空投聚合查询
https://solana-airdrop-checker.solworks.dev
3、sol生态空投查询
https://app.streamflow.finance/airdrop
4、Cosmos生态空投聚合查询
https://cosmos.leapwallet.io/airdrops
5、多生态空投聚合查询,看下自己有没有符合要求的,可以去登记空投
https://unicorn.meme/dashboard#airdrop

四、币圈工具汇总平台
1、Dexnav工具集合
https://dexnav.com
2、PANEWS数据导航
https://panewslab.com/zh/tools
3、Foresightnews工具集合
https://foresightnews.pro/tools
4、http://ki.bi工具集合
https://lu.ki.bi
5、自己之前闲着没事也整理了一点常用的网站工具,感兴趣的话可以看看!
https://docs.google.com/spreadsheets/d/1Bgips7WwmPOExwmiLCax7UneAS6hhZwV3wpzsr6yI3Q/edit#gid=1250204698

五、融资查询网站
融资信息:http://rootdata.com
融资信息:http://icoanalytics.org
融资信息:http://crypto-fundraising.info
融资信息:http://chainbroker.io
融资信息:http://crunchbase.com
融资信息:http://gstatic.com/generate_204
融资信息:http://airtable.com

六、推特、Discord、Telegram三款翻译工具
1、推特网页直接翻译,还支持PDF,YouTube等视频双语字幕翻译
https://chromewebstore.google.com/detail/%E6%B2%89%E6%B5%B8%E5%BC%8F%E7%BF%BB%E8%AF%91-%E7%BD%91%E9%A1%B5%E7%BF%BB%E8%AF%91%E6%8F%92%E4%BB%B6-pdf%E7%BF%BB%E8%AF%91-%E5%85%8D%E8%B4%B9/bpoadfkcbjbfhfodiogcnhhhpibjhbnh?hl=zh-CN
2、Discord翻译插件指南
https://mirror.xyz/0x7471e603a5e90136d678C919884048B227f5ba5D/6OaA9z8ae-2YVuCl5Jsl6N5SSdjvKf4nZAleoKalrGM
3、Telegram简体中文语言包
https://t.me/setlanguage/classic-zh-cn
Telegram繁体中文语言包
https://t.me/setlanguage/zh-hant-beta



经过我遴选后:

https://airdropalert.com/zh-CN/farm/

https://airdrops.io/

https://www.alphadrops.net/alpha 赞!! 这个一定要看

https://earn3.app/airdrops/all 赞!! 这个一定要看

http://cryptorank.io/drophunting





dapplearning 上面不错的课程

https://dapplearning.org/sharing?pageNo=11&searchType=theme&key= !!!!!!

uniswap:

Uniswap V3:白皮书解读 | Dapp Learning

Uniswap V3:代码解析 1 | Dapp Learning

Uniswap V3:代码解析 2 | Dapp Learning

Uniswap V3:SDK 代码解析 | Dapp Learning

Uniswap V2 前端代码解析 | Dapp Learning

UniswapV3:前端分享-Interface解析 | Dapp Learning

[科普]由浅入深理解uniswapV3原理 | Dapp Learning

UniswapV3 拓展分享 | Dapp Learning

基于 Uniswap V4 Hooks 的 TWAMM-p2


aave & compound:

AAVE分享:白皮书解读 | Dapp Learning

AAVE分享:合约代码解析 | Dapp Learning

Compound 分享:白皮书解读 | Dapp Learning

Compound分享:智能合约源码分析 | Dapp Learning

Compound分享:Dao治理模块解读 | Dapp Learning



FileCoin白皮书解读 | Dapp Learning

MonoX 攻击事件分析与复现 | Dapp Learning

EVM源码解析 | Dapp Learning

Sushi 源码解读

使用 foundry 框架加速智能合约开发( Part 1 ) truffle -> hardhat -> foundry -> 秃头了

Chainlink 原理剖析 ( part 1 )

来寻找Ethermint链增发漏洞

跨链技术

FileCoin技术与生态介绍

MEV101 https://www.google.com.hk/search?q=MEV101&oq=MEV101

Chainlink CCIP跨链协议

用trampoline开发AA钱包

WalletConnect 技术分享

revm 源码解析-p2

https://www.youtube.com/watch?v=hfkFBROx0lY —> https://t.me/SignalPlus_Official

flashbots 技术架构及其实现原理 —> https://typical-rowboat-3b5.notion.site/Flashbots-fc1b14c01f784c14b47e894388ab5957

备份:https://www.notion.so/Flashbots-218f85c2016380dd82a7f7e538f9eb97 imcusg

智能合约安全分析工具使用演示





中国人着迷的Filecoin 海外无人问津 原因是什么?(POC系列1)

再看Filecoin官方和创始人Juan Benet的Twitter,回应者极少,宣布测试网上线的重要Twitter只有7个评论,粉丝数量也有严重的刷量嫌疑。CryptoMiso显示技术社区的活跃度也很低,过去12个月Github提交代码数在百名以外

https://www.google.com/search?q=CryptoMiso&sourceid=chrome&ie=UTF-8

我去!

CryptoMiso - Ranking cryptocurrencies based on Github …

https://www.cryptomiso.com

CryptoMiso is a web service ranking cryptocurrencies based on the commit history of their most popular Github repository.

我按着这个来提交代码不就行了 哈哈哈哈