├── .gitignore
├── .golangci.yaml
├── LICENSE
├── Makefile
├── README.md
├── assets
└── img
│ └── Ethereum-icon-purple.svg
├── client
├── client_test.go
├── convert.go
├── convert_test.go
├── evm.go
├── evm_test.go
├── interface.go
├── pool.go
├── pool_test.go
├── solana.go
└── solana_test.go
├── consts
├── abis.go
└── chain.go
├── erc
└── erc20
│ ├── erc20.go
│ └── erc20.json
├── go.mod
├── go.sum
├── model
├── client
│ ├── conf.go
│ └── default.go
└── solana
│ └── rpc.go
└── pkg
├── otel
└── metrics.go
├── pk
└── signer.go
└── wjson
└── json.go
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/go,intellij+all,visualstudiocode
3 | # Edit at https://www.gitignore.io/?templates=go,intellij+all,visualstudiocode
4 |
5 | ### Go ###
6 | # Binaries for programs and plugins
7 | *.exe
8 | *.exe~
9 | *.dll
10 | *.so
11 | *.dylib
12 | # MacOS data file
13 | .DS_store
14 | # Test binary, built with `go test -c`
15 | *.test
16 |
17 | # Output of the go coverage tool, specifically when used with LiteIDE
18 | *.out
19 |
20 | # Dependency directories (remove the comment below to include it)
21 | # vendor/
22 |
23 | ### Go Patch ###
24 | /vendor/
25 | /Godeps/
26 |
27 | ### Intellij+all ###
28 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
29 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
30 |
31 | # User-specific stuff
32 | .idea/**/workspace.xml
33 | .idea/**/tasks.xml
34 | .idea/**/usage.statistics.xml
35 | .idea/**/dictionaries
36 | .idea/**/shelf
37 |
38 | # Generated files
39 | .idea/**/contentModel.xml
40 |
41 | # Sensitive or high-churn files
42 | .idea/**/dataSources/
43 | .idea/**/dataSources.ids
44 | .idea/**/dataSources.local.xml
45 | .idea/**/sqlDataSources.xml
46 | .idea/**/dynamic.xml
47 | .idea/**/uiDesigner.xml
48 | .idea/**/dbnavigator.xml
49 |
50 | # Gradle
51 | .idea/**/gradle.xml
52 | .idea/**/libraries
53 |
54 | # Gradle and Maven with auto-import
55 | # When using Gradle or Maven with auto-import, you should exclude module files,
56 | # since they will be recreated, and may cause churn. Uncomment if using
57 | # auto-import.
58 | # .idea/modules.xml
59 | # .idea/*.iml
60 | # .idea/modules
61 | # *.iml
62 | # *.ipr
63 |
64 | # CMake
65 | cmake-build-*/
66 |
67 | # Mongo Explorer plugin
68 | .idea/**/mongoSettings.xml
69 |
70 | # File-based project format
71 | *.iws
72 |
73 | # IntelliJ
74 | out/
75 |
76 | # mpeltonen/sbt-idea plugin
77 | .idea_modules/
78 |
79 | # JIRA plugin
80 | atlassian-ide-plugin.xml
81 |
82 | # Cursive Clojure plugin
83 | .idea/replstate.xml
84 |
85 | # Crashlytics plugin (for Android Studio and IntelliJ)
86 | com_crashlytics_export_strings.xml
87 | crashlytics.properties
88 | crashlytics-build.properties
89 | fabric.properties
90 |
91 | # Editor-based Rest Client
92 | .idea/httpRequests
93 |
94 | # Android studio 3.1+ serialized cache file
95 | .idea/caches/build_file_checksums.ser
96 |
97 | ### Intellij+all Patch ###
98 | # Ignores the whole .idea folder and all .iml files
99 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
100 |
101 | .idea/
102 |
103 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
104 |
105 | *.iml
106 | modules.xml
107 | .idea/misc.xml
108 | *.ipr
109 |
110 | # Sonarlint plugin
111 | .idea/sonarlint
112 |
113 | ### VisualStudioCode ###
114 | .vscode/*
115 | !.vscode/settings.json
116 | !.vscode/tasks.json
117 | !.vscode/launch.json
118 | !.vscode/extensions.json
119 |
120 | ### VisualStudioCode Patch ###
121 | # Ignore all local history of files
122 | .history
123 |
124 | # End of https://www.gitignore.io/api/go,intellij+all,visualstudiocode
125 |
126 | *.pem
127 | .agollo
128 | *.log
129 | **/kube-config
130 |
131 | # Test
132 | test/geth/data/*
133 | test/geth/log/*
134 |
--------------------------------------------------------------------------------
/.golangci.yaml:
--------------------------------------------------------------------------------
1 | # This file configures github.com/golangci/golangci-lint.
2 |
3 | run:
4 | timeout: 20m
5 | tests: true
6 | # default is true. Enables skipping of directories:
7 | # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
8 | skip-dirs-use-default: true
9 | skip-files:
10 | - core/genesis_alloc.go
11 |
12 | linters:
13 | disable-all: true
14 | enable:
15 | - goconst
16 | - goimports
17 | - gosimple
18 | - govet
19 | - ineffassign
20 | - misspell
21 | - unconvert
22 | - typecheck
23 | - unused
24 | - staticcheck
25 | - bidichk
26 | - durationcheck
27 | - exportloopref
28 | - whitespace
29 |
30 | # - structcheck # lots of false positives
31 | # - errcheck #lot of false positives
32 | # - contextcheck
33 | # - errchkjson # lots of false positives
34 | # - errorlint # this check crashes
35 | # - exhaustive # silly check
36 | # - makezero # false positives
37 | # - nilerr # several intentional
38 |
39 | linters-settings:
40 | gofmt:
41 | simplify: true
42 | goconst:
43 | min-len: 3 # minimum length of string constant
44 | min-occurrences: 6 # minimum number of occurrences
45 |
46 | issues:
47 | exclude-rules:
48 | - path: crypto/bn256/cloudflare/optate.go
49 | linters:
50 | - deadcode
51 | - staticcheck
52 | - path: internal/build/pgp.go
53 | text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.'
54 | - path: core/vm/contracts.go
55 | text: 'SA1019: "golang.org/x/crypto/ripemd160" is deprecated: RIPEMD-160 is a legacy hash and should not be used for new applications.'
56 | - path: accounts/usbwallet/trezor.go
57 | text: 'SA1019: "github.com/golang/protobuf/proto" is deprecated: Use the "google.golang.org/protobuf/proto" package instead.'
58 | - path: accounts/usbwallet/trezor/
59 | text: 'SA1019: "github.com/golang/protobuf/proto" is deprecated: Use the "google.golang.org/protobuf/proto" package instead.'
60 | exclude:
61 | - 'SA1019: event.TypeMux is deprecated: use Feed'
62 | - 'SA1019: strings.Title is deprecated'
63 | - 'SA1019: strings.Title has been deprecated since Go 1.18 and an alternative has been available since Go 1.0: The rule Title uses for word boundaries does not handle Unicode punctuation properly. Use golang.org/x/text/cases instead.'
64 | - 'SA1029: should not use built-in type string as key for value'
65 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | all: node
2 | @echo "all"
3 |
4 | node:
5 | geth \
6 | -datadir test/geth/data \
7 | --dev \
8 | --ws \
9 | --http \
10 | --mine \
11 | --metrics \
12 | --pprof \
13 | --graphql \
14 | --http.api admin,eth,debug,miner,net,txpool,personal,web3 \
15 | console 2 >> test/geth/log/geth.log
16 |
17 | console:
18 | geth attach test/geth/data/geth.ipc
19 | lint:
20 | golangci-lint run ./...
21 | clean:
22 | rm -rf test/geth/data
23 | init:
24 | geth \
25 | -datadir test/geth/data \
26 | --dev \
27 | --ws \
28 | --http \
29 | --mine \
30 | --http.api admin,eth,debug,miner,net,txpool,personal,web3 \
31 | init test/geth/genesis.json
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
Web3 Go
9 |
10 |
11 | Ethereum Dapp Go API, inspired by
12 | web3.js .
13 |
14 | Report Bug
15 | ·
16 | Pull Request
17 |
18 |
19 |
20 | [](https://github.com/kylesliu/web3-go)
21 | [](https://github.com/kylesliu/web3-go/blob/main/LICENSE)
22 |
23 | ## Introduction
24 |
25 | This is the Ethereum [Golang API](https://github.com/kylesliu/web3-go) which connects to the Generic [JSON-RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) spec.
26 |
27 | You need to run a local or remote Ethereum node to use this library.
28 |
29 | Here is an open source case [Web3 Studio](https://web3-studio.leek.dev/d/demo/web3-studio) reference under.
30 |
31 |
32 |
33 |
34 |
35 |
36 | ### Client
37 |
38 |
39 | ```bash
40 | export WEB3_GO_DEV_KEY_1="YOU_EVM_PRIVATE_KEY 1"
41 | export WEB3_GO_DEV_KEY_2="YOU_EVM_PRIVATE_KEY 1"
42 | ```
43 |
44 | ```bash
45 | go get github.com/6boris/web3-go
46 | ```
47 |
48 |
49 | ```go
50 | package main
51 |
52 | import (
53 | "context"
54 | "fmt"
55 | "github.com/6boris/web3-go/client"
56 | clientModel "github.com/6boris/web3-go/model/client"
57 | "github.com/6boris/web3-go/pkg/pk"
58 | "github.com/ethereum/go-ethereum/common"
59 | "github.com/shopspring/decimal"
60 | "math/big"
61 | "os"
62 | )
63 |
64 | func main() {
65 | ctx := context.Background()
66 | evmSigners := make([]*clientModel.ConfEvmChainSigner, 0)
67 | for _, v := range []string{"WEB3_GO_DEV_KEY_1", "WEB3_GO_DEV_KEY_1"} {
68 | signer, loopErr := pk.TransformPkToEvmSigner(os.Getenv(v))
69 | if loopErr != nil {
70 | continue
71 | }
72 | evmSigners = append(evmSigners, signer)
73 | }
74 | ec, err := client.NewEvmClient(&clientModel.ConfEvmChainClient{
75 | TransportURL: "https://1rpc.io/matic",
76 | GasFeeRate: decimal.NewFromFloat(2),
77 | GasLimitRate: decimal.NewFromFloat(1.5),
78 | Signers: evmSigners,
79 | })
80 |
81 | nativeTx, err := ec.SendTransactionSimple(
82 | ctx,
83 | ec.GetAllSinners()[0], ec.GetAllSinners()[1],
84 | big.NewInt(1),
85 | )
86 | if err != nil {
87 | panic(err)
88 | }
89 | fmt.Println(fmt.Sprintf("Native Token Tx: %s", nativeTx.Hash()))
90 |
91 | erc20Tx, err := ec.ERC20Transfer(
92 | ctx,
93 | common.HexToAddress("0xc2132D05D31c914a87C6611C10748AEb04B58e8F"),
94 | ec.GetAllSinners()[0], ec.GetAllSinners()[1],
95 | decimal.NewFromFloat(0.000001).Mul(decimal.New(1, int32(6))).BigInt(),
96 | )
97 | if err != nil {
98 | panic(err)
99 | }
100 | fmt.Println(fmt.Sprintf("USDT Token Tx: %s", erc20Tx.Hash()))
101 | }
102 | /*
103 | Output:
104 | Native Token Tx: 0xf3aa0e634357a222c39e8.......8f1a7e7d313db71827c3
105 | USDT Token Tx: 0xedd54d9e6bd3738880cd55........21aa69f06dba1e011625
106 | */
107 | ```
108 |
109 | ## Development Trips
110 | - [X] Client
111 | - [ ] Base Method
112 | - [X] eth_chainId
113 | - [X] web3_clientVersion
114 | - [X] eth_gasPrice
115 | - [X] eth_blockNumber
116 | - [X] eth_getBalance
117 | - [ ] ...
118 | - [ ] Middleware
119 | - [X] LoadBalance
120 | - [X] Metrics
121 | - [ ] Grafana
122 | - [ ] CircuitBreaker
123 | - [ ] Business Cases
124 | - [ ] Web3 Studio
125 | - [ ] Other ...
126 |
127 |
128 |
129 | ## Community
130 |
131 | - [web3.js](https://github.com/ChainSafe/web3.js) Ethereum JavaScript API.
132 | - [Web3j](https://github.com/web3j/web3j) Web3 Java Ethereum Ðapp API.
133 | - [Web3.py](https://github.com/ethereum/web3.py) A Python library for interacting with Ethereum.
134 |
135 | ## Provider
136 | - https://public.blockpi.io/
137 |
138 |
139 | ## Dev tool
140 |
141 | - [JSON RPC](https://www.jsonrpc.org/specification) Defining the JSON RPC specification.
142 | - [Go Ethereum](https://github.com/ethereum/go-ethereum) Official Golang implementation of the Ethereum protocol.
143 | - [Ethereum 1.0 API](https://github.com/ethereum/eth1.0-apis) Ethereum JSON-RPC Specification.
144 |
--------------------------------------------------------------------------------
/assets/img/Ethereum-icon-purple.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/client/client_test.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "context"
5 | "os"
6 | "testing"
7 |
8 | clientModel "github.com/6boris/web3-go/model/client"
9 | "github.com/6boris/web3-go/pkg/pk"
10 | "github.com/shopspring/decimal"
11 | )
12 |
13 | var (
14 | testCtx context.Context
15 | testPool *Pool
16 | testEvmEthClient *EvmClient
17 | testEvmPolygonClient *EvmClient
18 | testSolanaClient *SolanaClient
19 | )
20 |
21 | func TestMain(m *testing.M) {
22 | var err error
23 | evmSigners := make([]*clientModel.ConfEvmChainSigner, 0)
24 | for _, v := range []string{"WEB3_GO_DEV_KEY_1", "WEB3_GO_DEV_KEY_1"} {
25 | signer, loopErr := pk.TransformPkToEvmSigner(os.Getenv(v))
26 | if loopErr != nil {
27 | continue
28 | }
29 | evmSigners = append(evmSigners, signer)
30 | }
31 | testEvmEthClient, err = NewEvmClient(&clientModel.ConfEvmChainClient{TransportURL: "https://1rpc.io/eth"})
32 | if err != nil {
33 | panic(err)
34 | }
35 | testEvmPolygonClient, err = NewEvmClient(&clientModel.ConfEvmChainClient{
36 | TransportURL: "https://1rpc.io/matic",
37 | GasFeeRate: decimal.NewFromFloat(2),
38 | GasLimitMax: decimal.NewFromInt(30000000),
39 | GasLimitRate: decimal.NewFromFloat(1.5),
40 | Signers: evmSigners,
41 | })
42 | if err != nil {
43 | panic(err)
44 | }
45 | testSolanaClient, err = NewSolanaClient(&clientModel.ConfSolanaClient{
46 | TransportURL: "https://api.mainnet-beta.solana.com",
47 | IsDev: true,
48 | })
49 | if err != nil {
50 | panic(err)
51 | }
52 | testPool = NewPool(clientModel.GetDefaultConfPool())
53 | testCtx = context.TODO()
54 | // Before Test
55 | code := m.Run()
56 | // After Test
57 | os.Exit(code)
58 | }
59 |
--------------------------------------------------------------------------------
/client/convert.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "fmt"
5 | "math/big"
6 | "net/http"
7 | "strconv"
8 |
9 | "github.com/6boris/web3-go/consts"
10 | clientModel "github.com/6boris/web3-go/model/client"
11 | "github.com/6boris/web3-go/model/solana"
12 | "github.com/ethereum/go-ethereum/common"
13 | "github.com/gin-gonic/gin"
14 | )
15 |
16 | type GinMethodConvert struct {
17 | pool *Pool
18 | }
19 |
20 | func PromHandler(handler http.Handler) gin.HandlerFunc {
21 | return func(c *gin.Context) {
22 | handler.ServeHTTP(c.Writer, c.Request)
23 | }
24 | }
25 |
26 | func NewGinMethodConvert(conf *clientModel.ConfPool) *GinMethodConvert {
27 | g := &GinMethodConvert{}
28 | g.pool = NewPool(conf)
29 | return g
30 | }
31 |
32 | func (g *GinMethodConvert) _convertGinHandler(ctx *gin.Context) {
33 | req := &clientModel.EvmCallProxyRequest{}
34 | err := ctx.BindJSON(req)
35 | if err != nil {
36 | ctx.JSON(400, clientModel.ErrReply{Code: 400, Reason: "PARAMS_ERR", Message: err.Error()})
37 | return
38 | }
39 | evmClient := g.pool.GetEvmClient(req.ChainID)
40 | if req.ChainID > 0 && evmClient == nil {
41 | ctx.JSON(400, clientModel.ErrReply{Code: 400, Reason: "PARAMS_ERR", Message: "Not have enable client"})
42 | return
43 | }
44 | switch req.Method {
45 | case consts.EvmMethodChainID:
46 | g._convertEvmChainID(ctx, req, evmClient)
47 | case consts.EvmMethodSuggestGasTipCap:
48 | g._convertEvmGasPrice(ctx, req, evmClient)
49 | case consts.EvmMethodBlockNumber:
50 | g._convertEvmBlockNumber(ctx, req, evmClient)
51 | case consts.EvmMethodBalanceAt:
52 | g._convertEvmGetBalance(ctx, req, evmClient)
53 | default:
54 | ctx.JSON(400, clientModel.ErrReply{Code: 400, Reason: "PARAMS_ERR", Message: fmt.Sprintf("Not support this method:%s", req.Method)})
55 | return
56 | }
57 | }
58 |
59 | // eth_chainId https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_chainId
60 | func (g *GinMethodConvert) _convertEvmChainID(ctx *gin.Context, req *clientModel.EvmCallProxyRequest, client *EvmClient) {
61 | resp := &clientModel.EvmCallProxyReply{
62 | ID: req.ID,
63 | JsonRpc: req.JsonRpc,
64 | }
65 | ethResp, err := client.ChainID(ctx)
66 | if err != nil {
67 | ctx.JSON(500, &clientModel.ErrReply{Code: 500, Reason: "ETH_ERR", Message: err.Error(), Metadata: map[string]string{"transport_url": client.GetTransportURL()}})
68 | return
69 | }
70 | resp.Result = fmt.Sprintf("0x%s", ethResp.Text(16))
71 | ctx.JSON(http.StatusOK, resp)
72 | }
73 |
74 | // eth_gasPrice https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gasprice
75 | func (g *GinMethodConvert) _convertEvmGasPrice(ctx *gin.Context, req *clientModel.EvmCallProxyRequest, client *EvmClient) {
76 | resp := &clientModel.EvmCallProxyReply{
77 | ID: req.ID,
78 | JsonRpc: req.JsonRpc,
79 | }
80 | ethResp, err := client.SuggestGasPrice(ctx)
81 | if err != nil {
82 | ctx.JSON(500, &clientModel.ErrReply{Code: 500, Reason: "ETH_ERR", Message: err.Error(), Metadata: map[string]string{"transport_url": client.GetTransportURL()}})
83 | return
84 | }
85 |
86 | resp.Result = ethResp
87 | ctx.JSON(http.StatusOK, resp)
88 | }
89 |
90 | // eth_blockNumber https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_blocknumber
91 | func (g *GinMethodConvert) _convertEvmBlockNumber(ctx *gin.Context, req *clientModel.EvmCallProxyRequest, client *EvmClient) {
92 | resp := &clientModel.EvmCallProxyReply{
93 | ID: req.ID,
94 | JsonRpc: req.JsonRpc,
95 | }
96 | ethResp, err := client.BlockNumber(ctx)
97 | if err != nil {
98 | ctx.JSON(500, &clientModel.ErrReply{Code: 500, Reason: "ETH_ERR", Message: err.Error(), Metadata: map[string]string{"transport_url": client.GetTransportURL()}})
99 | return
100 | }
101 | resp.Result = fmt.Sprintf("0x%s", big.NewInt(int64(ethResp)).Text(16))
102 | ctx.JSON(http.StatusOK, resp)
103 | }
104 |
105 | // eth_getBalance https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getbalance
106 | func (g *GinMethodConvert) _convertEvmGetBalance(ctx *gin.Context, req *clientModel.EvmCallProxyRequest, client *EvmClient) {
107 | resp := &clientModel.EvmCallProxyReply{
108 | ID: req.ID,
109 | JsonRpc: req.JsonRpc,
110 | }
111 |
112 | account := req.Params[0].(string)
113 | var blockNumber *big.Int
114 | if len(req.Params) > 2 {
115 | blockStr, ok := req.Params[1].(string)
116 | if ok {
117 | block, err := strconv.ParseInt(blockStr, 10, 64)
118 | if err == nil {
119 | blockNumber = big.NewInt(block)
120 | }
121 | }
122 | }
123 | ethResp, err := client.BalanceAt(ctx, common.HexToAddress(account), blockNumber)
124 | if err != nil {
125 | ctx.JSON(500, &clientModel.ErrReply{Code: 500, Reason: "ETH_ERR", Message: err.Error(), Metadata: map[string]string{"transport_url": client.GetTransportURL()}})
126 | return
127 | }
128 | resp.Result = fmt.Sprintf("0x%s", ethResp.Text(16))
129 | ctx.JSON(http.StatusOK, resp)
130 | }
131 |
132 | func (g *GinMethodConvert) _convertSolanaHandler(ctx *gin.Context) {
133 | req := &clientModel.SolanaCallProxyRequest{}
134 | err := ctx.BindJSON(req)
135 | if err != nil {
136 | ctx.JSON(400, clientModel.ErrReply{Code: 400, Reason: "PARAMS_ERR", Message: err.Error()})
137 | return
138 | }
139 | solanaClient := g.pool.GetSolanaClient(req.ChainEnv)
140 | if solanaClient == nil {
141 | ctx.JSON(400, clientModel.ErrReply{Code: 400, Reason: "PARAMS_ERR", Message: "Not have enable client"})
142 | return
143 | }
144 | switch req.Method {
145 | case consts.SolanaMethodGetBalance:
146 | g._convertSolanaGetBalance(ctx, req, solanaClient)
147 | default:
148 | ctx.JSON(400, clientModel.ErrReply{Code: 400, Reason: "PARAMS_ERR", Message: fmt.Sprintf("Not support this method:%s", req.Method)})
149 | return
150 | }
151 | }
152 |
153 | func (g *GinMethodConvert) _convertSolanaGetBalance(ctx *gin.Context, req *clientModel.SolanaCallProxyRequest, client *SolanaClient) {
154 | resp := &clientModel.EvmCallProxyReply{
155 | ID: req.ID,
156 | JsonRpc: req.JsonRpc,
157 | }
158 |
159 | account := req.Params[0].(string)
160 | callResp, err := client.GetBalance(ctx, &solana.GetBalanceRequest{
161 | Account: account,
162 | })
163 | if err != nil {
164 | ctx.JSON(500, &clientModel.ErrReply{Code: 500, Reason: "ETH_ERR", Message: err.Error(), Metadata: map[string]string{"transport_url": client.TransportURL}})
165 | return
166 | }
167 | resp.Result = callResp.Value
168 | ctx.JSON(http.StatusOK, resp)
169 | }
170 |
--------------------------------------------------------------------------------
/client/convert_test.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "strconv"
5 | "testing"
6 |
7 | "github.com/6boris/web3-go/consts"
8 | clientModel "github.com/6boris/web3-go/model/client"
9 | "github.com/ethereum/go-ethereum/common"
10 | "github.com/gin-gonic/gin"
11 | "github.com/imroc/req/v3"
12 | "github.com/prometheus/client_golang/prometheus/promhttp"
13 | "github.com/stretchr/testify/assert"
14 | )
15 |
16 | func Test_Convert_Server(t *testing.T) {
17 | t.Run("Start Server", func(t *testing.T) {
18 | app := gin.New()
19 | app.GET("/metrics", PromHandler(promhttp.Handler()))
20 | app.POST("/evm", NewGinMethodConvert(clientModel.GetDefaultConfPool())._convertGinHandler)
21 | app.POST("/solana", NewGinMethodConvert(clientModel.GetDefaultConfPool())._convertSolanaHandler)
22 | _ = app.Run(":8545")
23 | })
24 | }
25 |
26 | func Test_Convert_Unite(t *testing.T) {
27 | cases := []struct {
28 | name string
29 | url string
30 | params interface{}
31 | expect string
32 | }{
33 | {
34 | "EVM", "http://127.0.0.1:8545/evm",
35 | map[string]interface{}{"chain_id": 1, "method": consts.EvmMethodChainID, "params": []interface{}{}},
36 | "EVM",
37 | },
38 | {
39 | "EVM", "http://127.0.0.1:8545/evm",
40 | map[string]interface{}{"chain_id": 1, "method": consts.EvmMethodSuggestGasTipCap, "params": []interface{}{}},
41 | "",
42 | },
43 | {
44 | "EVM", "http://127.0.0.1:8545/evm",
45 | map[string]interface{}{"chain_id": 1, "method": consts.EvmMethodBlockNumber, "params": []interface{}{}},
46 | "",
47 | },
48 | {
49 | "EVM", "http://127.0.0.1:8545/evm",
50 | map[string]interface{}{"chain_id": 1, "method": consts.EvmMethodBalanceAt, "params": []interface{}{common.HexToAddress("0xcDd37Ada79F589c15bD4f8fD2083dc88E34A2af2")}},
51 | "",
52 | },
53 | {
54 | "SOLANA", "http://127.0.0.1:8545/solana",
55 | map[string]interface{}{"chain_env": consts.ChainEnvMainnet, "method": consts.SolanaMethodGetBalance, "params": []interface{}{"5EhGYUyQNrxgUbuYF4vbL2SZDT6RMfhq3yjeyevvULeC"}},
56 | "",
57 | },
58 | }
59 | t.Run("Unite Case", func(t *testing.T) {
60 | for i, c := range cases {
61 | t.Run(c.name+" "+strconv.Itoa(i+1), func(t *testing.T) {
62 | _, err := req.C().DevMode().R().SetBody(c.params).Post(c.url)
63 | assert.Nil(t, err)
64 | })
65 | }
66 | })
67 | }
68 |
--------------------------------------------------------------------------------
/client/evm.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "context"
5 | "crypto/ecdsa"
6 | "errors"
7 | "math/big"
8 | "strings"
9 | "time"
10 |
11 | "github.com/6boris/web3-go/consts"
12 | "github.com/6boris/web3-go/erc/erc20"
13 | clientModel "github.com/6boris/web3-go/model/client"
14 | "github.com/6boris/web3-go/pkg/otel"
15 | "github.com/ethereum/go-ethereum"
16 | "github.com/ethereum/go-ethereum/accounts/abi/bind"
17 | "github.com/ethereum/go-ethereum/common"
18 | "github.com/ethereum/go-ethereum/core/types"
19 | "github.com/ethereum/go-ethereum/ethclient"
20 | "github.com/ethereum/go-ethereum/rpc"
21 | "github.com/google/uuid"
22 | "github.com/shopspring/decimal"
23 | "go.opentelemetry.io/otel/attribute"
24 | "go.opentelemetry.io/otel/metric"
25 | )
26 |
27 | type EvmClient struct {
28 | ethClient *ethclient.Client
29 | rpcClient *rpc.Client
30 | _signers []*clientModel.ConfEvmChainSigner
31 | _gasLimitMax decimal.Decimal
32 | _gasFeeRate decimal.Decimal
33 | _gasLimitRate decimal.Decimal
34 | _clientID string
35 | _appID string
36 | _zone string
37 | _cluster string
38 | _ethChainID int64
39 | _ethChainName string
40 | _ethChainEnv string
41 | _provider string
42 | _transportURL string
43 | }
44 |
45 | func NewEvmClient(conf *clientModel.ConfEvmChainClient) (*EvmClient, error) {
46 | var err error
47 | ec := &EvmClient{
48 | _clientID: strings.ReplaceAll(uuid.NewString(), "-", ""),
49 | _provider: conf.Provider,
50 | _transportURL: conf.TransportURL,
51 | _gasFeeRate: conf.GasFeeRate,
52 | _gasLimitRate: conf.GasLimitRate,
53 | _gasLimitMax: conf.GasLimitMax,
54 | }
55 |
56 | if ec._gasFeeRate == decimal.Zero {
57 | ec._gasFeeRate = decimal.NewFromFloat(1.1)
58 | }
59 | if ec._gasLimitRate == decimal.Zero {
60 | ec._gasLimitRate = decimal.NewFromFloat(2)
61 | }
62 | if ec._gasLimitMax == decimal.Zero {
63 | ec._gasLimitMax = decimal.NewFromFloat(30000000)
64 | }
65 | ec._signers = conf.Signers
66 |
67 | ec.ethClient, err = ethclient.Dial(conf.TransportURL)
68 | if err != nil {
69 | return nil, err
70 | }
71 | ec.rpcClient, err = rpc.Dial(conf.TransportURL)
72 | if err != nil {
73 | return nil, err
74 | }
75 |
76 | return ec, nil
77 | }
78 |
79 | func (ec *EvmClient) _getSinnerPrivateKey(account common.Address) (*ecdsa.PrivateKey, error) {
80 | for _, v := range ec._signers {
81 | if v.PublicAddress.String() == account.String() {
82 | return v.PrivateKey, nil
83 | }
84 | }
85 | return nil, errors.New("signer not config")
86 | }
87 | func (ec *EvmClient) _beforeHooks(ctx context.Context, meta *clientModel.Metadata) {
88 | _ = ctx
89 | meta.StartAt = time.Now()
90 | }
91 | func (ec *EvmClient) _afterHooks(ctx context.Context, meta *clientModel.Metadata) {
92 | otel.MetricsWeb3RequestCounter.Add(ctx, 1, metric.WithAttributes(
93 | attribute.Key("client_id").String(ec._clientID),
94 | attribute.Key("app_id").String(ec._appID),
95 | attribute.Key("zone").String(ec._appID),
96 | attribute.Key("cluster").String(ec._cluster),
97 | attribute.Key("chain_id").Int64(ec._ethChainID),
98 | attribute.Key("chain_name").String(ec._ethChainName),
99 | attribute.Key("chain_env").String(ec._ethChainEnv),
100 | attribute.Key("provider").String(ec._provider),
101 | attribute.Key("abi_method").String(meta.CallMethod),
102 | attribute.Key("status").String(meta.Status),
103 | ))
104 | otel.MetricsWeb3RequestHistogram.Record(ctx, time.Since(meta.StartAt).Milliseconds(), metric.WithAttributes(
105 | attribute.Key("client_id").String(ec._clientID),
106 | attribute.Key("app_id").String(ec._appID),
107 | attribute.Key("zone").String(ec._appID),
108 | attribute.Key("cluster").String(ec._cluster),
109 | attribute.Key("chain_id").Int64(ec._ethChainID),
110 | attribute.Key("chain_env").String(ec._ethChainEnv),
111 | attribute.Key("chain_name").String(ec._ethChainName),
112 | attribute.Key("provider").String(ec._provider),
113 | attribute.Key("abi_method").String(meta.CallMethod),
114 | ))
115 | }
116 | func (ec *EvmClient) _getTransactOpts(ctx context.Context, signer common.Address, to common.Address, dataHex string) (*bind.TransactOpts, error) {
117 | msgSignerPk, err := ec._getSinnerPrivateKey(signer)
118 | if err != nil {
119 | return nil, err
120 | }
121 | nonce, err := ec.PendingNonceAt(context.Background(), signer)
122 | if err != nil {
123 | return nil, err
124 | }
125 | gasPrice, err := ec.SuggestGasPrice(context.Background())
126 | if err != nil {
127 | return nil, err
128 | }
129 | chainID, err := ec.ChainID(context.Background())
130 | if err != nil {
131 | return nil, err
132 | }
133 | estimateGas, err := ec.ethClient.EstimateGas(ctx, ethereum.CallMsg{
134 | From: signer,
135 | To: &to,
136 | Gas: uint64(ec._gasLimitMax.BigInt().Int64()),
137 | Value: big.NewInt(0),
138 | Data: common.Hex2Bytes(dataHex),
139 | })
140 | if err != nil {
141 | return nil, err
142 | }
143 | opts, err := bind.NewKeyedTransactorWithChainID(msgSignerPk, chainID)
144 | if err != nil {
145 | return nil, err
146 | }
147 | opts.Nonce = big.NewInt(int64(nonce))
148 | opts.Value = big.NewInt(0)
149 | opts.GasLimit = 0
150 | opts.GasPrice = decimal.NewFromBigInt(gasPrice, 0).Mul(ec._gasFeeRate).BigInt()
151 | opts.Context = ctx
152 | if estimateGas > 0 && !ec._gasLimitRate.IsZero() {
153 | opts.GasLimit = decimal.NewFromInt(int64(estimateGas)).Mul(ec._gasLimitRate).BigInt().Uint64()
154 | }
155 | if !ec._gasLimitMax.IsZero() && opts.GasLimit > uint64(ec._gasLimitMax.BigInt().Int64()) {
156 | opts.GasLimit = uint64(ec._gasLimitMax.BigInt().Int64())
157 | }
158 | return opts, nil
159 | }
160 | func (ec *EvmClient) _getCallOpts(ctx context.Context) (*bind.CallOpts, error) {
161 | opts := &bind.CallOpts{
162 | Context: ctx,
163 | }
164 | return opts, nil
165 | }
166 |
167 | func (ec *EvmClient) Close() {
168 | ec.ethClient.Close()
169 | ec.rpcClient.Close()
170 | }
171 | func (ec *EvmClient) GetAllSinners() []common.Address {
172 | data := make([]common.Address, 0)
173 | for _, v := range ec._signers {
174 | data = append(data, v.PublicAddress)
175 | }
176 | return data
177 | }
178 | func (ec *EvmClient) GetTransportURL() string {
179 | return ec._transportURL
180 | }
181 |
182 | func (ec *EvmClient) BlockByHash(ctx context.Context, blockHash common.Hash) (*types.Block, error) {
183 | abiMethod := consts.EvmMethodBlockByHash
184 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
185 | ec._beforeHooks(ctx, meta)
186 | defer func() {
187 | ec._afterHooks(ctx, meta)
188 | }()
189 | result, err := ec.ethClient.BlockByHash(ctx, blockHash)
190 | if err != nil {
191 | meta.Status = consts.AbiCallStatusFail
192 | }
193 | return result, err
194 | }
195 | func (ec *EvmClient) BlockByNumber(ctx context.Context, blockNumber *big.Int) (*types.Block, error) {
196 | abiMethod := consts.EvmMethodBlockByNumber
197 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
198 | ec._beforeHooks(ctx, meta)
199 | defer func() {
200 | ec._afterHooks(ctx, meta)
201 | }()
202 | result, err := ec.ethClient.BlockByNumber(ctx, blockNumber)
203 | if err != nil {
204 | meta.Status = consts.AbiCallStatusFail
205 | }
206 | return result, err
207 | }
208 | func (ec *EvmClient) HeaderByHash(ctx context.Context, blockHash common.Hash) (*types.Header, error) {
209 | abiMethod := consts.EvmMethodHeaderByHash
210 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
211 | ec._beforeHooks(ctx, meta)
212 | defer func() {
213 | ec._afterHooks(ctx, meta)
214 | }()
215 | result, err := ec.ethClient.HeaderByHash(ctx, blockHash)
216 | if err != nil {
217 | meta.Status = consts.AbiCallStatusFail
218 | }
219 | return result, err
220 | }
221 | func (ec *EvmClient) HeaderByNumber(ctx context.Context, blockNumber *big.Int) (*types.Header, error) {
222 | abiMethod := consts.EvmMethodHeaderByNumber
223 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
224 | ec._beforeHooks(ctx, meta)
225 | defer func() {
226 | ec._afterHooks(ctx, meta)
227 | }()
228 | result, err := ec.ethClient.HeaderByNumber(ctx, blockNumber)
229 | if err != nil {
230 | meta.Status = consts.AbiCallStatusFail
231 | }
232 | return result, err
233 | }
234 | func (ec *EvmClient) TransactionCount(ctx context.Context, blockHash common.Hash) (uint, error) {
235 | abiMethod := consts.EvmMethodTransactionCount
236 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
237 | ec._beforeHooks(ctx, meta)
238 | defer func() {
239 | ec._afterHooks(ctx, meta)
240 | }()
241 | result, err := ec.ethClient.TransactionCount(ctx, blockHash)
242 | if err != nil {
243 | meta.Status = consts.AbiCallStatusFail
244 | }
245 | return result, err
246 | }
247 | func (ec *EvmClient) TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error) {
248 | abiMethod := consts.EvmMethodTransactionInBlock
249 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
250 | ec._beforeHooks(ctx, meta)
251 | defer func() {
252 | ec._afterHooks(ctx, meta)
253 | }()
254 | result, err := ec.ethClient.TransactionInBlock(ctx, blockHash, index)
255 | if err != nil {
256 | meta.Status = consts.AbiCallStatusFail
257 | }
258 | return result, err
259 | }
260 | func (ec *EvmClient) TransactionByHash(ctx context.Context, blockHash common.Hash) (*types.Transaction, bool, error) {
261 | abiMethod := consts.EvmMethodTransactionByHash
262 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
263 | ec._beforeHooks(ctx, meta)
264 | defer func() {
265 | ec._afterHooks(ctx, meta)
266 | }()
267 | result, isPending, err := ec.ethClient.TransactionByHash(ctx, blockHash)
268 | if err != nil {
269 | meta.Status = consts.AbiCallStatusFail
270 | }
271 | return result, isPending, err
272 | }
273 | func (ec *EvmClient) TransactionReceipt(ctx context.Context, blockHash common.Hash) (*types.Receipt, error) {
274 | abiMethod := consts.EvmMethodTransactionReceipt
275 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
276 | ec._beforeHooks(ctx, meta)
277 | defer func() {
278 | ec._afterHooks(ctx, meta)
279 | }()
280 | result, err := ec.ethClient.TransactionReceipt(ctx, blockHash)
281 | if err != nil {
282 | meta.Status = consts.AbiCallStatusFail
283 | }
284 | return result, err
285 | }
286 |
287 | func (ec *EvmClient) SendTransaction(ctx context.Context, tx *types.Transaction) error {
288 | abiMethod := consts.EvmMethodSendTransaction
289 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
290 | ec._beforeHooks(ctx, meta)
291 | defer func() {
292 | ec._afterHooks(ctx, meta)
293 | }()
294 | err := ec.ethClient.SendTransaction(ctx, tx)
295 | if err != nil {
296 | meta.Status = consts.AbiCallStatusFail
297 | }
298 | return err
299 | }
300 | func (ec *EvmClient) SendTransactionSimple(ctx context.Context, signer common.Address, to common.Address, value *big.Int) (*types.Transaction, error) {
301 | abiMethod := consts.EvmMethodSendTransaction
302 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
303 | ec._beforeHooks(ctx, meta)
304 | defer func() {
305 | ec._afterHooks(ctx, meta)
306 | }()
307 | msgSignerPk, err := ec._getSinnerPrivateKey(signer)
308 | if err != nil {
309 | return nil, err
310 | }
311 | opts, err := ec._getTransactOpts(ctx, signer, to, "0x")
312 | if err != nil {
313 | return nil, err
314 | }
315 | chainID, err := ec.ChainID(context.Background())
316 | if err != nil {
317 | return nil, err
318 | }
319 | signedTx, err := types.SignNewTx(msgSignerPk, types.NewEIP155Signer(chainID), &types.LegacyTx{
320 | To: &to,
321 | Nonce: opts.Nonce.Uint64(),
322 | Value: value,
323 | Gas: opts.GasLimit,
324 | GasPrice: opts.GasPrice,
325 | })
326 | if err != nil {
327 | return nil, err
328 | }
329 | err = ec.ethClient.SendTransaction(ctx, signedTx)
330 | if err != nil {
331 | meta.Status = consts.AbiCallStatusFail
332 | }
333 | return signedTx, err
334 | }
335 |
336 | func (ec *EvmClient) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) {
337 | abiMethod := consts.EvmMethodBalanceAt
338 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
339 | ec._beforeHooks(ctx, meta)
340 | defer func() {
341 | ec._afterHooks(ctx, meta)
342 | }()
343 | result, err := ec.ethClient.BalanceAt(ctx, account, blockNumber)
344 | if err != nil {
345 | meta.Status = consts.AbiCallStatusFail
346 | }
347 | return result, err
348 | }
349 | func (ec *EvmClient) StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) {
350 | abiMethod := consts.EvmMethodStorageAt
351 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
352 | ec._beforeHooks(ctx, meta)
353 | defer func() {
354 | ec._afterHooks(ctx, meta)
355 | }()
356 | result, err := ec.ethClient.StorageAt(ctx, account, key, blockNumber)
357 | if err != nil {
358 | meta.Status = consts.AbiCallStatusFail
359 | }
360 | return result, err
361 | }
362 | func (ec *EvmClient) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) {
363 | abiMethod := consts.EvmMethodCodeAt
364 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
365 | ec._beforeHooks(ctx, meta)
366 | defer func() {
367 | ec._afterHooks(ctx, meta)
368 | }()
369 | result, err := ec.ethClient.CodeAt(ctx, account, blockNumber)
370 | if err != nil {
371 | meta.Status = consts.AbiCallStatusFail
372 | }
373 | return result, err
374 | }
375 | func (ec *EvmClient) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) {
376 | abiMethod := consts.EvmMethodNonceAt
377 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
378 | ec._beforeHooks(ctx, meta)
379 | defer func() {
380 | ec._afterHooks(ctx, meta)
381 | }()
382 | result, err := ec.ethClient.NonceAt(ctx, account, blockNumber)
383 | if err != nil {
384 | meta.Status = consts.AbiCallStatusFail
385 | }
386 | return result, err
387 | }
388 |
389 | func (ec *EvmClient) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
390 | abiMethod := consts.EvmMethodSuggestGasPrice
391 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
392 | ec._beforeHooks(ctx, meta)
393 | defer func() {
394 | ec._afterHooks(ctx, meta)
395 | }()
396 | result, err := ec.ethClient.SuggestGasPrice(ctx)
397 | if err != nil {
398 | meta.Status = consts.AbiCallStatusFail
399 | }
400 | return result, err
401 | }
402 | func (ec *EvmClient) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
403 | abiMethod := consts.EvmMethodSuggestGasTipCap
404 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
405 | ec._beforeHooks(ctx, meta)
406 | defer func() {
407 | ec._afterHooks(ctx, meta)
408 | }()
409 | result, err := ec.ethClient.SuggestGasTipCap(ctx)
410 | if err != nil {
411 | meta.Status = consts.AbiCallStatusFail
412 | }
413 | return result, err
414 | }
415 | func (ec *EvmClient) FeeHistory(ctx context.Context, blockCount uint64, lastBlock *big.Int, rewardPercentiles []float64) (*ethereum.FeeHistory, error) {
416 | abiMethod := consts.EvmMethodFeeHistory
417 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
418 | ec._beforeHooks(ctx, meta)
419 | defer func() {
420 | ec._afterHooks(ctx, meta)
421 | }()
422 | result, err := ec.ethClient.FeeHistory(ctx, blockCount, lastBlock, rewardPercentiles)
423 | if err != nil {
424 | meta.Status = consts.AbiCallStatusFail
425 | }
426 | return result, err
427 | }
428 | func (ec *EvmClient) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error) {
429 | abiMethod := consts.EvmMethodEstimateGas
430 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
431 | ec._beforeHooks(ctx, meta)
432 | defer func() {
433 | ec._afterHooks(ctx, meta)
434 | }()
435 | result, err := ec.ethClient.EstimateGas(ctx, msg)
436 | if err != nil {
437 | meta.Status = consts.AbiCallStatusFail
438 | }
439 | return result, err
440 | }
441 |
442 | func (ec *EvmClient) PendingBalanceAt(ctx context.Context, account common.Address) (*big.Int, error) {
443 | abiMethod := consts.EvmMethodPendingBalanceAtp
444 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
445 | ec._beforeHooks(ctx, meta)
446 | defer func() {
447 | ec._afterHooks(ctx, meta)
448 | }()
449 | result, err := ec.ethClient.PendingBalanceAt(ctx, account)
450 | if err != nil {
451 | meta.Status = consts.AbiCallStatusFail
452 | }
453 | return result, err
454 | }
455 | func (ec *EvmClient) PendingStorageAt(ctx context.Context, account common.Address, key common.Hash) ([]byte, error) {
456 | abiMethod := consts.EvmMethodPendingStorageAt
457 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
458 | ec._beforeHooks(ctx, meta)
459 | defer func() {
460 | ec._afterHooks(ctx, meta)
461 | }()
462 | result, err := ec.ethClient.PendingStorageAt(ctx, account, key)
463 | if err != nil {
464 | meta.Status = consts.AbiCallStatusFail
465 | }
466 | return result, err
467 | }
468 | func (ec *EvmClient) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) {
469 | abiMethod := consts.EvmMethodPendingCodeAt
470 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
471 | ec._beforeHooks(ctx, meta)
472 | defer func() {
473 | ec._afterHooks(ctx, meta)
474 | }()
475 | result, err := ec.ethClient.PendingCodeAt(ctx, account)
476 | if err != nil {
477 | meta.Status = consts.AbiCallStatusFail
478 | }
479 | return result, err
480 | }
481 | func (ec *EvmClient) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) {
482 | abiMethod := consts.EvmMethodPendingNonceAt
483 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
484 | ec._beforeHooks(ctx, meta)
485 | defer func() {
486 | ec._afterHooks(ctx, meta)
487 | }()
488 | result, err := ec.ethClient.PendingNonceAt(ctx, account)
489 | if err != nil {
490 | meta.Status = consts.AbiCallStatusFail
491 | }
492 | return result, err
493 | }
494 | func (ec *EvmClient) PendingTransactionCount(ctx context.Context) (uint, error) {
495 | abiMethod := consts.EvmMethodPendingTransactionCount
496 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
497 | ec._beforeHooks(ctx, meta)
498 | defer func() {
499 | ec._afterHooks(ctx, meta)
500 | }()
501 | result, err := ec.ethClient.PendingTransactionCount(ctx)
502 | if err != nil {
503 | meta.Status = consts.AbiCallStatusFail
504 | }
505 | return result, err
506 | }
507 |
508 | func (ec *EvmClient) BlockNumber(ctx context.Context) (uint64, error) {
509 | abiMethod := consts.EvmMethodBlockNumber
510 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
511 | ec._beforeHooks(ctx, meta)
512 | defer func() {
513 | ec._afterHooks(ctx, meta)
514 | }()
515 | result, err := ec.ethClient.BlockNumber(ctx)
516 | if err != nil {
517 | meta.Status = consts.AbiCallStatusFail
518 | }
519 | return result, err
520 | }
521 | func (ec *EvmClient) ChainID(ctx context.Context) (*big.Int, error) {
522 | abiMethod := consts.EvmMethodChainID
523 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
524 | ec._beforeHooks(ctx, meta)
525 | defer func() {
526 | ec._afterHooks(ctx, meta)
527 | }()
528 | result, err := ec.ethClient.ChainID(ctx)
529 | if err != nil {
530 | meta.Status = consts.AbiCallStatusFail
531 | }
532 | return result, err
533 | }
534 | func (ec *EvmClient) NetworkID(ctx context.Context) (*big.Int, error) {
535 | abiMethod := consts.EvmMethodNetworkID
536 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
537 | ec._beforeHooks(ctx, meta)
538 | defer func() {
539 | ec._afterHooks(ctx, meta)
540 | }()
541 | result, err := ec.ethClient.NetworkID(ctx)
542 | if err != nil {
543 | meta.Status = consts.AbiCallStatusFail
544 | }
545 | return result, err
546 | }
547 |
548 | func (ec *EvmClient) ERC20Name(ctx context.Context, token common.Address) (string, error) {
549 | abiMethod := consts.EvmErc20MethodName
550 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
551 | ec._beforeHooks(ctx, meta)
552 | defer func() {
553 | ec._afterHooks(ctx, meta)
554 | }()
555 | inst, err := erc20.NewERC20(token, ec.ethClient)
556 | if err != nil {
557 | return "", err
558 | }
559 | opts, err := ec._getCallOpts(ctx)
560 | if err != nil {
561 | return "", err
562 | }
563 | callResp, err := inst.Name(opts)
564 | if err != nil {
565 | return "", err
566 | }
567 | return callResp, nil
568 | }
569 | func (ec *EvmClient) ERC20Symbol(ctx context.Context, token common.Address) (string, error) {
570 | abiMethod := consts.EvmErc20MethodSymbol
571 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
572 | ec._beforeHooks(ctx, meta)
573 | defer func() {
574 | ec._afterHooks(ctx, meta)
575 | }()
576 | inst, err := erc20.NewERC20(token, ec.ethClient)
577 | if err != nil {
578 | return "", err
579 | }
580 | opts, err := ec._getCallOpts(ctx)
581 | if err != nil {
582 | return "", err
583 | }
584 | callResp, err := inst.Symbol(opts)
585 | if err != nil {
586 | return "", err
587 | }
588 | return callResp, nil
589 | }
590 | func (ec *EvmClient) ERC20Decimals(ctx context.Context, token common.Address) (uint8, error) {
591 | abiMethod := consts.EvmErc20MethodDecimals
592 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
593 | ec._beforeHooks(ctx, meta)
594 | defer func() {
595 | ec._afterHooks(ctx, meta)
596 | }()
597 | inst, err := erc20.NewERC20(token, ec.ethClient)
598 | if err != nil {
599 | return 0, err
600 | }
601 | opts, err := ec._getCallOpts(ctx)
602 | if err != nil {
603 | return 0, err
604 | }
605 | callResp, err := inst.Decimals(opts)
606 | if err != nil {
607 | return 0, err
608 | }
609 | return callResp, nil
610 | }
611 | func (ec *EvmClient) ERC20BalanceOf(ctx context.Context, token common.Address, account common.Address) (*big.Int, error) {
612 | abiMethod := consts.EvmErc20MethodBalanceOf
613 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
614 | ec._beforeHooks(ctx, meta)
615 | defer func() {
616 | ec._afterHooks(ctx, meta)
617 | }()
618 | inst, err := erc20.NewERC20(token, ec.ethClient)
619 | if err != nil {
620 | return big.NewInt(0), err
621 | }
622 | opts, err := ec._getCallOpts(ctx)
623 | if err != nil {
624 | return big.NewInt(0), err
625 | }
626 | callResp, err := inst.BalanceOf(opts, account)
627 | if err != nil {
628 | return big.NewInt(0), err
629 | }
630 | return callResp, nil
631 | }
632 | func (ec *EvmClient) ERC20TotalSupply(ctx context.Context, token common.Address) (*big.Int, error) {
633 | abiMethod := consts.EvmErc20MethodTotalSupply
634 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
635 | ec._beforeHooks(ctx, meta)
636 | defer func() {
637 | ec._afterHooks(ctx, meta)
638 | }()
639 | inst, err := erc20.NewERC20(token, ec.ethClient)
640 | if err != nil {
641 | return big.NewInt(0), err
642 | }
643 | opts, err := ec._getCallOpts(ctx)
644 | if err != nil {
645 | return big.NewInt(0), err
646 | }
647 | callResp, err := inst.TotalSupply(opts)
648 | if err != nil {
649 | return big.NewInt(0), err
650 | }
651 | return callResp, nil
652 | }
653 | func (ec *EvmClient) ERC20Transfer(ctx context.Context, token common.Address, signer common.Address, to common.Address, value *big.Int) (*types.Transaction, error) {
654 | abiMethod := consts.EvmErc20MethodTransfer
655 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
656 | ec._beforeHooks(ctx, meta)
657 | defer func() {
658 | ec._afterHooks(ctx, meta)
659 | }()
660 | inst, err := erc20.NewERC20(token, ec.ethClient)
661 | if err != nil {
662 | return nil, err
663 | }
664 | abi, err := erc20.ERC20MetaData.GetAbi()
665 | if err != nil {
666 | return nil, err
667 | }
668 | abiData, err := abi.Pack("transfer", to, value)
669 | if err != nil {
670 | return nil, err
671 | }
672 |
673 | opts, err := ec._getTransactOpts(ctx, signer, token, common.Bytes2Hex(abiData))
674 | if err != nil {
675 | return nil, err
676 | }
677 | callResp, err := inst.Transfer(opts, to, value)
678 | if err != nil {
679 | return nil, err
680 | }
681 |
682 | return callResp, nil
683 | }
684 | func (ec *EvmClient) ERC20Approve(ctx context.Context, token common.Address, signer common.Address, to common.Address, value *big.Int) (*types.Transaction, error) {
685 | abiMethod := consts.EvmErc20MethodApprove
686 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
687 | ec._beforeHooks(ctx, meta)
688 | defer func() {
689 | ec._afterHooks(ctx, meta)
690 | }()
691 | inst, err := erc20.NewERC20(token, ec.ethClient)
692 | if err != nil {
693 | return nil, err
694 | }
695 | abi, err := erc20.ERC20MetaData.GetAbi()
696 | if err != nil {
697 | return nil, err
698 | }
699 | abiData, err := abi.Pack("transfer", to, value)
700 | if err != nil {
701 | return nil, err
702 | }
703 | opts, err := ec._getTransactOpts(ctx, signer, token, common.Bytes2Hex(abiData))
704 | if err != nil {
705 | return nil, err
706 | }
707 | callResp, err := inst.Approve(opts, to, value)
708 | if err != nil {
709 | return nil, err
710 | }
711 | return callResp, nil
712 | }
713 | func (ec *EvmClient) ERC20IncreaseAllowance(ctx context.Context, token common.Address, signer common.Address, to common.Address, value *big.Int) (*types.Transaction, error) {
714 | abiMethod := consts.EvmErc20MethodIncreaseAllowance
715 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
716 | ec._beforeHooks(ctx, meta)
717 | defer func() {
718 | ec._afterHooks(ctx, meta)
719 | }()
720 | inst, err := erc20.NewERC20(token, ec.ethClient)
721 | if err != nil {
722 | return nil, err
723 | }
724 | abi, err := erc20.ERC20MetaData.GetAbi()
725 | if err != nil {
726 | return nil, err
727 | }
728 | abiData, err := abi.Pack("transfer", to, value)
729 | if err != nil {
730 | return nil, err
731 | }
732 | opts, err := ec._getTransactOpts(ctx, signer, token, common.Bytes2Hex(abiData))
733 | if err != nil {
734 | return nil, err
735 | }
736 | callResp, err := inst.IncreaseAllowance(opts, to, value)
737 | if err != nil {
738 | return nil, err
739 | }
740 | return callResp, nil
741 | }
742 | func (ec *EvmClient) ERC20DecreaseAllowance(ctx context.Context, token common.Address, signer common.Address, to common.Address, value *big.Int) (*types.Transaction, error) {
743 | abiMethod := consts.EvmErc20MethodDecreaseAllowance
744 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
745 | ec._beforeHooks(ctx, meta)
746 | defer func() {
747 | ec._afterHooks(ctx, meta)
748 | }()
749 | inst, err := erc20.NewERC20(token, ec.ethClient)
750 | if err != nil {
751 | return nil, err
752 | }
753 | abi, err := erc20.ERC20MetaData.GetAbi()
754 | if err != nil {
755 | return nil, err
756 | }
757 | abiData, err := abi.Pack("transfer", to, value)
758 | if err != nil {
759 | return nil, err
760 | }
761 | opts, err := ec._getTransactOpts(ctx, signer, token, common.Bytes2Hex(abiData))
762 | if err != nil {
763 | return nil, err
764 | }
765 | callResp, err := inst.DecreaseAllowance(opts, to, value)
766 | if err != nil {
767 | return nil, err
768 | }
769 | return callResp, nil
770 | }
771 | func (ec *EvmClient) ERC20Allowance(ctx context.Context, token common.Address, owner common.Address, spender common.Address) (*big.Int, error) {
772 | abiMethod := consts.EvmErc20MethodAllowance
773 | meta := &clientModel.Metadata{CallMethod: abiMethod, Status: consts.AbiCallStatusSuccess}
774 | ec._beforeHooks(ctx, meta)
775 | defer func() {
776 | ec._afterHooks(ctx, meta)
777 | }()
778 | inst, err := erc20.NewERC20(token, ec.ethClient)
779 | if err != nil {
780 | return big.NewInt(0), err
781 | }
782 | opts, err := ec._getCallOpts(ctx)
783 | if err != nil {
784 | return big.NewInt(0), err
785 | }
786 | callResp, err := inst.Allowance(opts, owner, spender)
787 | if err != nil {
788 | return big.NewInt(0), err
789 | }
790 | return callResp, nil
791 | }
792 |
--------------------------------------------------------------------------------
/client/evm_test.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "context"
5 | "crypto/ecdsa"
6 | "fmt"
7 | "math/big"
8 | "os"
9 | "testing"
10 |
11 | "github.com/6boris/web3-go/pkg/wjson"
12 | "github.com/davecgh/go-spew/spew"
13 | "github.com/ethereum/go-ethereum"
14 | "github.com/ethereum/go-ethereum/common"
15 | "github.com/ethereum/go-ethereum/core/types"
16 | "github.com/ethereum/go-ethereum/crypto"
17 | "github.com/shopspring/decimal"
18 | "github.com/stretchr/testify/assert"
19 | )
20 |
21 | func TestNewEvmClient(t *testing.T) {
22 | testAccount := common.HexToAddress("0xf15689636571dba322b48E9EC9bA6cFB3DF818e1")
23 | testBlockHash := common.HexToHash("0x21e0118bd8618a14632f82e1445c1f178cfab5bbd2debf1eb3338886ced75e15")
24 | testBlockNumber := big.NewInt(19454574)
25 | testTxHash := common.HexToHash("0xb382be540032c6751b97cb623ff2bbcd0f1da2a386c4a75f7e561ce4ebefb787")
26 | testEvmPolygonUSDTAddress := common.HexToAddress("0xc2132D05D31c914a87C6611C10748AEb04B58e8F")
27 | t.Run("BlockByHash", func(t *testing.T) {
28 | blockInfo, err := testEvmEthClient.BlockByHash(testCtx, testBlockHash)
29 | assert.Nil(t, err)
30 | spew.Dump(blockInfo)
31 | })
32 | t.Run("BlockByNumber", func(t *testing.T) {
33 | blockInfo, err := testEvmEthClient.BlockByNumber(testCtx, testBlockNumber)
34 | assert.Nil(t, err)
35 | spew.Dump(blockInfo)
36 | })
37 | t.Run("HeaderByHash", func(t *testing.T) {
38 | headerInfo, err := testEvmEthClient.HeaderByHash(testCtx, testBlockHash)
39 | assert.Nil(t, err)
40 | spew.Dump(headerInfo)
41 | })
42 | t.Run("HeaderByNumber", func(t *testing.T) {
43 | headerInfo, err := testEvmEthClient.HeaderByNumber(testCtx, testBlockNumber)
44 | assert.Nil(t, err)
45 | spew.Dump(headerInfo)
46 | })
47 | t.Run("TransactionCount", func(t *testing.T) {
48 | txCount, err := testEvmEthClient.TransactionCount(testCtx, testBlockHash)
49 | assert.Nil(t, err)
50 | spew.Dump(txCount)
51 | })
52 | t.Run("TransactionInBlock", func(t *testing.T) {
53 | txCount, err := testEvmEthClient.TransactionInBlock(testCtx, testBlockHash, 1)
54 | assert.Nil(t, err)
55 | spew.Dump(txCount)
56 | })
57 | t.Run("TransactionByHash", func(t *testing.T) {
58 | txInfo, isPending, err := testEvmEthClient.TransactionByHash(testCtx, testTxHash)
59 | assert.Nil(t, err)
60 | spew.Dump(isPending)
61 | spew.Dump(txInfo)
62 | })
63 | t.Run("TransactionReceipt", func(t *testing.T) {
64 | txInfo, err := testEvmEthClient.TransactionReceipt(testCtx, testTxHash)
65 | assert.Nil(t, err)
66 | spew.Dump(txInfo)
67 | })
68 | t.Run("SendTransaction_Native_Token", func(t *testing.T) {
69 | privateKey, err := crypto.HexToECDSA(os.Getenv("WEB3_GO_DEV_KEY_2"))
70 | assert.Nil(t, err)
71 | publicKey := privateKey.Public()
72 | publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
73 | assert.Nil(t, err)
74 | sendAccount := crypto.PubkeyToAddress(*publicKeyECDSA)
75 |
76 | chainID, err := testEvmPolygonClient.ChainID(context.Background())
77 | assert.Nil(t, err)
78 |
79 | nonce, err := testEvmPolygonClient.PendingNonceAt(context.Background(), sendAccount)
80 | assert.Nil(t, err)
81 |
82 | gasLimit := uint64(21000)
83 | value := decimal.New(1, 0).BigInt()
84 | gasPrice, err := testEvmPolygonClient.SuggestGasPrice(testCtx)
85 | gasPrice = decimal.NewFromBigInt(gasPrice, 0).
86 | Mul(decimal.NewFromFloat(2)).BigInt()
87 | assert.Nil(t, err)
88 | signedTx, err := types.SignNewTx(privateKey, types.NewEIP155Signer(chainID), &types.LegacyTx{
89 | To: &sendAccount,
90 | Nonce: nonce,
91 | Value: value,
92 | Gas: gasLimit,
93 | GasPrice: gasPrice,
94 | })
95 | assert.Nil(t, err)
96 |
97 | err = testEvmPolygonClient.SendTransaction(context.Background(), signedTx)
98 | assert.Nil(t, err)
99 | fmt.Println(wjson.StructToJsonStringWithIndent(map[string]interface{}{
100 | "chain_id": chainID,
101 | "sendAccount": sendAccount,
102 | "toAccount": sendAccount,
103 | "nonce": nonce,
104 | "gas_limit": gasLimit,
105 | "value": value,
106 | "gas_price": decimal.NewFromBigInt(gasPrice, -9),
107 | "tx_hash": signedTx.Hash().String(),
108 | }, "", " "))
109 | })
110 | t.Run("SendTransactionSimple", func(t *testing.T) {
111 | tx, err := testEvmPolygonClient.SendTransactionSimple(
112 | testCtx,
113 | testEvmPolygonClient.GetAllSinners()[0],
114 | testEvmPolygonClient.GetAllSinners()[1],
115 | decimal.NewFromFloat(0.00001).Mul(decimal.New(1, 18)).BigInt(),
116 | )
117 | assert.Nil(t, err)
118 | spew.Dump(tx.Hash())
119 | })
120 | t.Run("BalanceAt", func(t *testing.T) {
121 | accountBalance, err := testEvmEthClient.BalanceAt(testCtx, testAccount, nil)
122 | assert.Nil(t, err)
123 | spew.Dump(decimal.NewFromBigInt(accountBalance, -18))
124 | })
125 | t.Run("StorageAt", func(t *testing.T) {
126 | storageBytes, err := testEvmEthClient.StorageAt(
127 | testCtx, testAccount,
128 | common.HexToHash(""), big.NewInt(19454700),
129 | )
130 | assert.Nil(t, err)
131 | spew.Dump(storageBytes)
132 | })
133 | t.Run("CodeAt", func(t *testing.T) {
134 | codeBytes, err := testEvmEthClient.CodeAt(
135 | testCtx, common.HexToAddress("0xdAC17F958D2ee523a2206206994597C13D831ec7"),
136 | big.NewInt(19454700),
137 | )
138 | assert.Nil(t, err)
139 | spew.Dump(codeBytes)
140 | })
141 | t.Run("NonceAt", func(t *testing.T) {
142 | nonceAt, err := testEvmEthClient.NonceAt(
143 | testCtx, testAccount,
144 | big.NewInt(19454700),
145 | )
146 | assert.Nil(t, err)
147 | spew.Dump(nonceAt)
148 | })
149 | t.Run("SuggestGasPrice", func(t *testing.T) {
150 | gasPrice, err := testEvmEthClient.SuggestGasPrice(testCtx)
151 | assert.Nil(t, err)
152 | spew.Dump(decimal.NewFromBigInt(gasPrice, -18))
153 | })
154 | t.Run("SuggestGasTipCap", func(t *testing.T) {
155 | gasPrice, err := testEvmEthClient.SuggestGasTipCap(testCtx)
156 | assert.Nil(t, err)
157 | spew.Dump(decimal.NewFromBigInt(gasPrice, -18))
158 | })
159 | t.Run("FeeHistory", func(t *testing.T) {
160 | feeHistory, err := testEvmEthClient.FeeHistory(testCtx,
161 | 2,
162 | testBlockNumber,
163 | []float64{0.008912678667376286},
164 | )
165 | assert.Nil(t, err)
166 | spew.Dump(feeHistory)
167 | })
168 | t.Run("EstimateGas", func(t *testing.T) {
169 | msg := ethereum.CallMsg{
170 | From: testAccount,
171 | To: &common.Address{},
172 | Gas: 21000,
173 | Value: big.NewInt(1),
174 | }
175 | gasInfo, err := testEvmEthClient.EstimateGas(testCtx, msg)
176 | assert.Nil(t, err)
177 | spew.Dump(gasInfo)
178 | })
179 | t.Run("PendingBalanceAt", func(t *testing.T) {
180 | accountInfo, err := testEvmEthClient.PendingBalanceAt(testCtx, testAccount)
181 | assert.Nil(t, err)
182 | spew.Dump(decimal.NewFromBigInt(accountInfo, -18))
183 | })
184 | t.Run("PendingStorageAt", func(t *testing.T) {
185 | storageBytes, err := testEvmEthClient.PendingStorageAt(
186 | testCtx, testAccount,
187 | common.HexToHash(""),
188 | )
189 | assert.Nil(t, err)
190 | spew.Dump(storageBytes)
191 | })
192 | t.Run("PendingCodeAt", func(t *testing.T) {
193 | codeBytes, err := testEvmEthClient.PendingCodeAt(
194 | testCtx, common.HexToAddress("0xdAC17F958D2ee523a2206206994597C13D831ec7"),
195 | )
196 | assert.Nil(t, err)
197 | spew.Dump(codeBytes)
198 | })
199 | t.Run("PendingNonceAt", func(t *testing.T) {
200 | nonceAt, err := testEvmEthClient.PendingNonceAt(
201 | testCtx, testAccount,
202 | )
203 | assert.Nil(t, err)
204 | spew.Dump(nonceAt)
205 | })
206 | t.Run("PendingTransactionCount", func(t *testing.T) {
207 | pendingTxCount, err := testEvmEthClient.PendingTransactionCount(testCtx)
208 | assert.Nil(t, err)
209 | spew.Dump(pendingTxCount)
210 | })
211 | t.Run("BlockNumber", func(t *testing.T) {
212 | blockNumber, err := testEvmEthClient.BlockNumber(testCtx)
213 | assert.Nil(t, err)
214 | spew.Dump(blockNumber)
215 | })
216 | t.Run("ChainID", func(t *testing.T) {
217 | chanID, err := testEvmEthClient.ChainID(testCtx)
218 | assert.Nil(t, err)
219 | spew.Dump(chanID)
220 | })
221 | t.Run("ERC20Name", func(t *testing.T) {
222 | tokenName, err := testEvmPolygonClient.ERC20Name(testCtx, testEvmPolygonUSDTAddress)
223 | assert.Nil(t, err)
224 | spew.Dump(tokenName)
225 | })
226 | t.Run("ERC20Symbol", func(t *testing.T) {
227 | tokenSymbol, err := testEvmPolygonClient.ERC20Symbol(testCtx, testEvmPolygonUSDTAddress)
228 | assert.Nil(t, err)
229 | spew.Dump(tokenSymbol)
230 | })
231 | t.Run("ERC20Decimals", func(t *testing.T) {
232 | tokenDecimals, err := testEvmPolygonClient.ERC20Decimals(testCtx, testEvmPolygonUSDTAddress)
233 | assert.Nil(t, err)
234 | spew.Dump(tokenDecimals)
235 | })
236 | t.Run("ERC20BalanceOf", func(t *testing.T) {
237 | tokenDecimals, err := testEvmPolygonClient.ERC20Decimals(testCtx, testEvmPolygonUSDTAddress)
238 | assert.Nil(t, err)
239 |
240 | tokenBalance, err := testEvmPolygonClient.ERC20BalanceOf(testCtx,
241 | testEvmPolygonUSDTAddress,
242 | testEvmPolygonUSDTAddress)
243 | assert.Nil(t, err)
244 | spew.Dump(decimal.NewFromBigInt(tokenBalance, -int32(tokenDecimals)))
245 | })
246 | t.Run("ERC20TotalSupply", func(t *testing.T) {
247 | tokenSymbol, err := testEvmPolygonClient.ERC20Symbol(testCtx, testEvmPolygonUSDTAddress)
248 | assert.Nil(t, err)
249 |
250 | tokenDecimals, err := testEvmPolygonClient.ERC20Decimals(testCtx, testEvmPolygonUSDTAddress)
251 | assert.Nil(t, err)
252 |
253 | tokenBalance, err := testEvmPolygonClient.ERC20TotalSupply(testCtx, testEvmPolygonUSDTAddress)
254 | assert.Nil(t, err)
255 | fmt.Printf("TotalSupply:%s %s\n",
256 | decimal.NewFromBigInt(tokenBalance, -int32(tokenDecimals)).String(), tokenSymbol)
257 | })
258 | t.Run("ERC20Transfer", func(t *testing.T) {
259 | tokenDecimals, err := testEvmPolygonClient.ERC20Decimals(testCtx, testEvmPolygonUSDTAddress)
260 | assert.Nil(t, err)
261 | txInfo, err := testEvmPolygonClient.ERC20Transfer(
262 | testCtx,
263 | testEvmPolygonUSDTAddress,
264 | testEvmPolygonClient.GetAllSinners()[0],
265 | testEvmPolygonClient.GetAllSinners()[1],
266 | decimal.NewFromFloat(0.00001).Mul(decimal.New(1, int32(tokenDecimals))).BigInt(),
267 | )
268 | assert.Nil(t, err)
269 | fmt.Println(txInfo.Hash().String())
270 | })
271 | t.Run("ERC20Approve", func(t *testing.T) {
272 | tokenDecimals, err := testEvmPolygonClient.ERC20Decimals(testCtx, testEvmPolygonUSDTAddress)
273 | assert.Nil(t, err)
274 |
275 | txInfo, err := testEvmPolygonClient.ERC20Approve(
276 | testCtx,
277 | testEvmPolygonUSDTAddress,
278 | testEvmPolygonClient.GetAllSinners()[0], testEvmPolygonClient.GetAllSinners()[1],
279 | decimal.NewFromFloat(0.00001).Mul(decimal.New(1, int32(tokenDecimals))).BigInt(),
280 | )
281 | assert.Nil(t, err)
282 | fmt.Println("ERC20Approve", txInfo.Hash().String())
283 | })
284 | t.Run("ERC20IncreaseAllowance", func(t *testing.T) {
285 | tokenDecimals, err := testEvmPolygonClient.ERC20Decimals(testCtx, testEvmPolygonUSDTAddress)
286 | assert.Nil(t, err)
287 |
288 | txInfo, err := testEvmPolygonClient.ERC20IncreaseAllowance(
289 | testCtx,
290 | testEvmPolygonUSDTAddress,
291 | testEvmPolygonClient.GetAllSinners()[0], testEvmPolygonClient.GetAllSinners()[1],
292 | decimal.NewFromFloat(0.00001).Mul(decimal.New(1, int32(tokenDecimals))).BigInt(),
293 | )
294 | assert.Nil(t, err)
295 | fmt.Println("ERC20Approve", txInfo.Hash().String())
296 | })
297 | t.Run("ERC20DecreaseAllowance", func(t *testing.T) {
298 | tokenDecimals, err := testEvmPolygonClient.ERC20Decimals(testCtx, testEvmPolygonUSDTAddress)
299 | assert.Nil(t, err)
300 |
301 | txInfo, err := testEvmPolygonClient.ERC20DecreaseAllowance(
302 | testCtx,
303 | testEvmPolygonUSDTAddress,
304 | testEvmPolygonClient.GetAllSinners()[0], testEvmPolygonClient.GetAllSinners()[1],
305 | decimal.NewFromFloat(0.00001).Mul(decimal.New(1, int32(tokenDecimals))).BigInt(),
306 | )
307 | assert.Nil(t, err)
308 | fmt.Println("ERC20Approve", txInfo.Hash().String())
309 | })
310 | t.Run("ERC20Allowance", func(t *testing.T) {
311 | tokenSymbol, err := testEvmPolygonClient.ERC20Symbol(testCtx, testEvmPolygonUSDTAddress)
312 | assert.Nil(t, err)
313 |
314 | tokenDecimals, err := testEvmPolygonClient.ERC20Decimals(testCtx, testEvmPolygonUSDTAddress)
315 | assert.Nil(t, err)
316 |
317 | tokenAllowance, err := testEvmPolygonClient.ERC20Allowance(
318 | testCtx,
319 | testEvmPolygonUSDTAddress,
320 | testEvmPolygonClient.GetAllSinners()[0], testEvmPolygonClient.GetAllSinners()[1],
321 | )
322 | assert.Nil(t, err)
323 | fmt.Printf("ERC20Allowance:%s %s\n",
324 | decimal.NewFromBigInt(tokenAllowance, -int32(tokenDecimals)).String(), tokenSymbol)
325 | })
326 | }
327 |
--------------------------------------------------------------------------------
/client/interface.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "context"
5 | "math/big"
6 |
7 | "github.com/ethereum/go-ethereum"
8 | "github.com/ethereum/go-ethereum/common"
9 | "github.com/ethereum/go-ethereum/core/types"
10 | )
11 |
12 | type EvmClientInterface interface {
13 |
14 | // Geth ChainReader
15 |
16 | BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
17 | BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error)
18 | HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)
19 | HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
20 | TransactionCount(ctx context.Context, blockHash common.Hash) (uint, error)
21 | TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error)
22 |
23 | // Geth TransactionReader
24 |
25 | TransactionByHash(ctx context.Context, txHash common.Hash) (tx *types.Transaction, isPending bool, err error)
26 | TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
27 | SendTransaction(ctx context.Context, tx *types.Transaction) error
28 |
29 | // Geth ChainStateReader
30 |
31 | BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error)
32 | StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error)
33 | CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error)
34 | NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error)
35 |
36 | // Geth Gas
37 |
38 | SuggestGasPrice(ctx context.Context) (*big.Int, error)
39 | SuggestGasTipCap(ctx context.Context) (*big.Int, error)
40 | FeeHistory(ctx context.Context, blockCount uint64, lastBlock *big.Int, rewardPercentiles []float64) (*ethereum.FeeHistory, error)
41 | EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error)
42 |
43 | // Geth PendingStateReader
44 | PendingBalanceAt(ctx context.Context, account common.Address) (*big.Int, error)
45 | PendingStorageAt(ctx context.Context, account common.Address, key common.Hash) ([]byte, error)
46 | PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error)
47 | PendingNonceAt(ctx context.Context, account common.Address) (uint64, error)
48 | PendingTransactionCount(ctx context.Context) (uint, error)
49 |
50 | // Geth Other
51 |
52 | BlockNumber(ctx context.Context) (uint64, error)
53 | ChainID(ctx context.Context) (*big.Int, error)
54 | }
55 |
56 | type SolanaClientInterface interface {
57 | }
58 |
--------------------------------------------------------------------------------
/client/pool.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "github.com/6boris/web3-go/model/client"
5 | "github.com/go-kratos/aegis/circuitbreaker"
6 | "github.com/go-kratos/aegis/circuitbreaker/sre"
7 | )
8 |
9 | type Pool struct {
10 | conf *client.ConfPool
11 | // clients map[int64]map[string]*Client
12 | breakerGroup *circuitbreaker.CircuitBreaker
13 | _evmClients map[int64]map[string]*EvmClient
14 | _solanaClients map[string]*SolanaClient
15 | }
16 |
17 | // func init() {
18 | // //exporter, err := prometheus.New()
19 | // //if err != nil {
20 | // // log.Fatal(err)
21 | // //}
22 | // //provider := metricSdk.NewMeterProvider(metricSdk.WithReader(exporter))
23 | // //meter := provider.Meter("metrics", metric.WithInstrumentationVersion(runtime.Version()))
24 | // m1, err := global.Meter("web3.go").Int64Counter("web3_abi_call", metric.WithDescription("Web3 Gateway abi call counter"))
25 | // if err != nil {
26 | // panic(err)
27 | // }
28 | // m2, err := global.Meter("web3.go").Int64Histogram("web3_abi_call", metric.WithDescription("Web3 Gateway abi call hist"))
29 | // if err != nil {
30 | // panic(err)
31 | // }
32 | // MetricsWeb3RequestCounter = m1
33 | // MetricsWeb3RequestHistogram = m2
34 | //
35 | //}
36 |
37 | func NewPool(conf *client.ConfPool) *Pool {
38 | p := &Pool{
39 | conf: conf,
40 | _solanaClients: map[string]*SolanaClient{},
41 | }
42 | b := sre.NewBreaker()
43 | p.breakerGroup = &b
44 |
45 | p._evmClients = make(map[int64]map[string]*EvmClient, 0)
46 | for _, chain := range conf.EvmChains {
47 | if _, ok := p._evmClients[chain.ChainID]; !ok {
48 | p._evmClients[chain.ChainID] = make(map[string]*EvmClient, 0)
49 | }
50 | for _, c := range chain.Clients {
51 | if c.TransportSchema == "https" {
52 | tmpC, err := NewEvmClient(c)
53 | tmpC._appID = conf.AppID
54 | tmpC._zone = conf.Zone
55 | tmpC._cluster = conf.Cluster
56 | tmpC._ethChainID = chain.ChainID
57 | tmpC._ethChainName = chain.ChainName
58 | tmpC._ethChainEnv = chain.ChainEnv
59 | if err != nil {
60 | panic(err)
61 | } else {
62 | p._evmClients[chain.ChainID][tmpC._clientID] = tmpC
63 | }
64 | }
65 | }
66 | }
67 | for _, c := range p.conf.SolanaChains {
68 | loopClient, loopErr := NewSolanaClient(c)
69 | if loopErr == nil {
70 | p._solanaClients[loopClient.ClientID] = loopClient
71 | }
72 | }
73 | return p
74 | }
75 |
76 | func (p *Pool) GetEvmClient(chainID int64) *EvmClient {
77 | if clientMap, ok := p._evmClients[chainID]; ok {
78 | if len(clientMap) > 0 {
79 | for _, val := range clientMap {
80 | return val
81 | }
82 | }
83 | }
84 | return nil
85 | }
86 | func (p *Pool) GetSolanaClient(chainEnv string) *SolanaClient {
87 | if len(p._solanaClients) == 0 {
88 | return nil
89 | }
90 | for _, v := range p._solanaClients {
91 | if v.ChainEnv == chainEnv {
92 | return v
93 | }
94 | }
95 | return nil
96 | }
97 |
--------------------------------------------------------------------------------
/client/pool_test.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "context"
5 | "crypto/ecdsa"
6 | "fmt"
7 | "log"
8 | "testing"
9 |
10 | "github.com/6boris/web3-go/consts"
11 | "github.com/6boris/web3-go/model/solana"
12 | "github.com/davecgh/go-spew/spew"
13 | "github.com/ethereum/go-ethereum/crypto"
14 | "github.com/shopspring/decimal"
15 | "github.com/stretchr/testify/assert"
16 | )
17 |
18 | func Test_Unite_Pool(t *testing.T) {
19 | chainID := int64(1)
20 | t.Run("ChainID", func(t *testing.T) {
21 | for i := 0; i < 50; i++ {
22 | resp, err := testPool.GetEvmClient(chainID).ChainID(testCtx)
23 | assert.Nil(t, err)
24 | spew.Dump(resp)
25 | }
26 | })
27 | t.Run("BlockNumber", func(t *testing.T) {
28 | chainCase := []int64{
29 | 1, 5, 11155111, // Ethereum
30 | 56, 97, // Bsc
31 | 137, 80001, // Polygon
32 | 250, 4002, // Fantom
33 | 10, 420, // Optimistic
34 | }
35 | for _, c := range chainCase {
36 | resp, err := testPool.GetEvmClient(c).BlockNumber(testCtx)
37 | assert.Nil(t, err)
38 | fmt.Println(fmt.Printf("ChainID:%d BlockNumber:%d", c, resp))
39 | }
40 | })
41 | t.Run("Evm_SendTransaction", func(t *testing.T) {
42 |
43 | privateKey, err := crypto.HexToECDSA("fad9c8855b740a0b7ed4c221dbad0f33a83a49cad6b3fe8d5817ac83d38b6a19")
44 | if err != nil {
45 | log.Fatal(err)
46 | }
47 | publicKey := privateKey.Public()
48 | publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
49 | if !ok {
50 | log.Fatal("error casting public key to ECDSA")
51 | }
52 | testAccount := crypto.PubkeyToAddress(*publicKeyECDSA)
53 | fmt.Println("testAccount", testAccount)
54 | testChainID := int64(137)
55 | nonce, err := testPool.GetEvmClient(testChainID).PendingNonceAt(testCtx, testAccount)
56 | assert.Nil(t, err)
57 | fmt.Println("Nonce:", nonce)
58 | //value := big.NewInt(1000000000000000000)
59 | //gasLimit := uint64(21000)
60 | gasPrice, err := testPool.GetEvmClient(testChainID).SuggestGasPrice(context.Background())
61 | assert.Nil(t, err)
62 | fmt.Println("gasPrice:", gasPrice)
63 |
64 | //err := testPool.GetEvmClient(137).SendTransaction(testCtx, nil)
65 | //assert.Nil(t, err)
66 | })
67 | t.Run("Evm_ChainID", func(t *testing.T) {
68 | resp, err := testPool.GetEvmClient(1).ChainID(testCtx)
69 | assert.Nil(t, err)
70 | spew.Dump(resp)
71 | })
72 | t.Run("Evm_SuggestGasTipCap", func(t *testing.T) {
73 | gasPrice, err := testPool.GetEvmClient(1).SuggestGasTipCap(testCtx)
74 | assert.Nil(t, err)
75 | spew.Dump(decimal.NewFromBigInt(gasPrice, -18))
76 | })
77 |
78 | t.Run("Solana_GetBalance", func(t *testing.T) {
79 | resp, err := testPool.GetSolanaClient(consts.ChainEnvMainnet).GetBalance(testCtx, &solana.GetBalanceRequest{Account: "5EhGYUyQNrxgUbuYF4vbL2SZDT6RMfhq3yjeyevvULeC"})
80 | assert.Nil(t, err)
81 | spew.Dump(resp)
82 | })
83 | }
84 |
--------------------------------------------------------------------------------
/client/solana.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | "errors"
7 | "fmt"
8 | "strings"
9 | "time"
10 |
11 | clientModel "github.com/6boris/web3-go/model/client"
12 | "github.com/6boris/web3-go/model/solana"
13 | "github.com/google/uuid"
14 | "github.com/imroc/req/v3"
15 | "github.com/shopspring/decimal"
16 | "github.com/tidwall/gjson"
17 | )
18 |
19 | type SolanaClient struct {
20 | HttpClient *req.Client
21 | ClientID string
22 | AppID string
23 | Zone string
24 | Cluster string
25 | ChainEnv string
26 | Provider string
27 | TransportURL string
28 | }
29 |
30 | func NewSolanaClient(conf *clientModel.ConfSolanaClient) (*SolanaClient, error) {
31 | client := &SolanaClient{
32 | ClientID: strings.ReplaceAll(uuid.NewString(), "-", ""),
33 | Provider: conf.Provider,
34 | TransportURL: conf.TransportURL,
35 | ChainEnv: conf.ChainEnv,
36 | }
37 | client.HttpClient = req.C().
38 | SetBaseURL(conf.TransportURL).
39 | WrapRoundTripFunc(func(rt req.RoundTripper) req.RoundTripFunc {
40 | return func(req *req.Request) (resp *req.Response, err error) {
41 | // before request
42 | // ...
43 | resp, err = rt.RoundTrip(req)
44 | // after response
45 | // ...
46 | return
47 | }
48 | }).
49 | SetTimeout(20 * time.Second)
50 | if conf.IsDev {
51 | client.HttpClient.DevMode()
52 | }
53 |
54 | return client, nil
55 | }
56 |
57 | func (sc *SolanaClient) GetAccountInfo(ctx context.Context, request *solana.GetAccountInfoRequest) (*solana.GetAccountInfoReply, error) {
58 | reply := &solana.GetAccountInfoReply{}
59 | response, err := sc.HttpClient.
60 | R().
61 | SetContext(ctx).
62 | SetBody(map[string]interface{}{
63 | "jsonrpc": "2.0", "id": 1,
64 | "method": "getAccountInfo",
65 | "params": []interface{}{
66 | request.Account,
67 | map[string]string{
68 | "encoding": "base58",
69 | },
70 | },
71 | }).
72 | Post("")
73 | if err != nil {
74 | return nil, err
75 | }
76 | if gjson.GetBytes(response.Bytes(), "error").String() != "" {
77 | return nil, errors.New(gjson.GetBytes(response.Bytes(), "error.message").String())
78 | }
79 | err = json.Unmarshal([]byte(gjson.GetBytes(response.Bytes(), "result").String()), &reply)
80 | if err != nil {
81 | return nil, err
82 | }
83 | return reply, nil
84 | }
85 | func (sc *SolanaClient) GetVersion(ctx context.Context) (*solana.GetVersionReply, error) {
86 | reply := &solana.GetVersionReply{}
87 | response, err := sc.HttpClient.
88 | R().
89 | SetContext(ctx).
90 | SetBody(map[string]interface{}{
91 | "jsonrpc": "2.0", "id": 1,
92 | "method": "getVersion",
93 | }).
94 | Post("")
95 | if err != nil {
96 | return nil, err
97 | }
98 | if gjson.GetBytes(response.Bytes(), "error").String() != "" {
99 | return nil, errors.New(gjson.GetBytes(response.Bytes(), "error.message").String())
100 | }
101 | reply.FeatureSet = gjson.GetBytes(response.Bytes(), "result.feature-set").String()
102 | reply.SolanaCore = gjson.GetBytes(response.Bytes(), "result.solana-core").String()
103 | return reply, nil
104 | }
105 | func (sc *SolanaClient) GetBalance(ctx context.Context, request *solana.GetBalanceRequest) (*solana.GetBalanceReply, error) {
106 | //callMethod := consts.SolanaMethodGetBalance
107 | reply := &solana.GetBalanceReply{}
108 | response, err := sc.HttpClient.
109 | R().
110 | SetContext(ctx).
111 | SetBody(map[string]interface{}{
112 | "jsonrpc": "2.0", "id": 1,
113 | "method": "getBalance",
114 | "params": []string{request.Account},
115 | }).
116 | Post("")
117 | if err != nil {
118 | return nil, err
119 | }
120 | if gjson.GetBytes(response.Bytes(), "error").String() != "" {
121 | return nil, errors.New(gjson.GetBytes(response.Bytes(), "error.message").String())
122 | }
123 | err = json.Unmarshal([]byte(gjson.GetBytes(response.Bytes(), "result.context").String()), &reply.Context)
124 | if err != nil {
125 | return nil, err
126 | }
127 | reply.Value, err = decimal.NewFromString(gjson.GetBytes(response.Bytes(), "result.value").String())
128 | if err != nil {
129 | return nil, err
130 | }
131 | reply.Value = reply.Value.Div(decimal.New(1, 9))
132 | return reply, nil
133 | }
134 | func (sc *SolanaClient) GetTokenAccountBalance(ctx context.Context, request *solana.GetTokenAccountBalanceRequest) (*solana.GetTokenAccountBalanceReply, error) {
135 | reply := &solana.GetTokenAccountBalanceReply{}
136 | response, err := sc.HttpClient.
137 | SetBaseURL(sc.TransportURL).
138 | R().
139 | SetContext(ctx).
140 | SetBody(map[string]interface{}{
141 | "jsonrpc": "2.0", "id": 1,
142 | "method": "getTokenAccountBalance",
143 | "params": []string{request.Account},
144 | }).
145 | Post("")
146 | if err != nil {
147 | return nil, err
148 | }
149 | if gjson.GetBytes(response.Bytes(), "error").String() != "" {
150 | return nil, errors.New(gjson.GetBytes(response.Bytes(), "error.message").String())
151 | }
152 | err = json.Unmarshal([]byte(gjson.GetBytes(response.Bytes(), "result.context").String()), &reply.Context)
153 | if err != nil {
154 | return nil, err
155 | }
156 | reply.Amount, err = decimal.NewFromString(gjson.GetBytes(response.Bytes(), "result.value.amount").String())
157 | if err != nil {
158 | return nil, err
159 | }
160 | reply.Decimals, err = decimal.NewFromString(gjson.GetBytes(response.Bytes(), "result.value.decimals").String())
161 | if err != nil {
162 | return nil, err
163 | }
164 | reply.UIAmount, err = decimal.NewFromString(gjson.GetBytes(response.Bytes(), "result.value.uiAmount").String())
165 | if err != nil {
166 | return nil, err
167 | }
168 | reply.UIAmountString, err = decimal.NewFromString(gjson.GetBytes(response.Bytes(), "result.value.uiAmountString").String())
169 | if err != nil {
170 | return nil, err
171 | }
172 | return reply, nil
173 | }
174 | func (sc *SolanaClient) GetBlockHeight(ctx context.Context) (int64, error) {
175 | response, err := sc.HttpClient.
176 | R().
177 | SetContext(ctx).
178 | SetBody(map[string]interface{}{
179 | "jsonrpc": "2.0", "id": 1,
180 | "method": "getBlockHeight",
181 | }).
182 | Post("")
183 | if err != nil {
184 | return 0, err
185 | }
186 | if gjson.GetBytes(response.Bytes(), "error").String() != "" {
187 | return 0, errors.New(gjson.GetBytes(response.Bytes(), "error.message").String())
188 | }
189 | return gjson.GetBytes(response.Bytes(), "result").Int(), nil
190 | }
191 | func (sc *SolanaClient) GetBlockTime(ctx context.Context, blockNumber int64) (int64, error) {
192 | response, err := sc.HttpClient.
193 | R().
194 | SetContext(ctx).
195 | SetBody(map[string]interface{}{
196 | "jsonrpc": "2.0", "id": 1,
197 | "method": "getBlockTime",
198 | "params": []interface{}{blockNumber},
199 | }).
200 | Post("")
201 | if err != nil {
202 | return 0, err
203 | }
204 | if gjson.GetBytes(response.Bytes(), "error").String() != "" {
205 | return 0, errors.New(gjson.GetBytes(response.Bytes(), "error.message").String())
206 | }
207 | return gjson.GetBytes(response.Bytes(), "result").Int(), nil
208 | }
209 | func (sc *SolanaClient) GetBlock(ctx context.Context, request *solana.GetBlockRequest) (*solana.GetBlockReply, error) {
210 | //callMethod := consts.SolanaMethodGetBalance
211 | reply := &solana.GetBlockReply{}
212 | response, err := sc.HttpClient.
213 | R().
214 | SetContext(ctx).
215 | SetBody(map[string]interface{}{
216 | "jsonrpc": "2.0", "id": 1,
217 | "method": "getBlock",
218 | "params": []interface{}{
219 | request.Slot,
220 | map[string]interface{}{
221 | "encoding": request.Encoding,
222 | "transactionDetails": request.TransactionDetails,
223 | "rewards": request.Rewards,
224 | },
225 | },
226 | }).
227 | Post("")
228 | if err != nil {
229 | return nil, err
230 | }
231 | if gjson.GetBytes(response.Bytes(), "error").String() != "" {
232 | return nil, errors.New(gjson.GetBytes(response.Bytes(), "error.message").String())
233 | }
234 | //err = json.Unmarshal([]byte(gjson.GetBytes(response.Bytes(), "result.context").String()), &reply.Context)
235 | //if err != nil {
236 | // return nil, err
237 | //}
238 | return reply, nil
239 | }
240 | func (sc *SolanaClient) GetClusterNodes(ctx context.Context) ([]*solana.ClusterNodesItem, error) {
241 | //callMethod := consts.SolanaMethodGetBalance
242 | reply := make([]*solana.ClusterNodesItem, 0)
243 | response, err := sc.HttpClient.
244 | R().
245 | SetContext(ctx).
246 | SetBody(map[string]interface{}{
247 | "jsonrpc": "2.0", "id": 1,
248 | "method": "getClusterNodes",
249 | }).
250 | Post("")
251 | if err != nil {
252 | return nil, err
253 | }
254 | if gjson.GetBytes(response.Bytes(), "error").String() != "" {
255 | return nil, errors.New(gjson.GetBytes(response.Bytes(), "error.message").String())
256 | }
257 | gjson.GetBytes(response.Bytes(), "result").ForEach(func(key, value gjson.Result) bool {
258 | fmt.Println(key, value.String())
259 | item := &solana.ClusterNodesItem{}
260 | if loopErr := json.Unmarshal([]byte(value.String()), item); loopErr == nil {
261 | reply = append(reply, item)
262 | }
263 | return true
264 | })
265 | return reply, nil
266 | }
267 |
--------------------------------------------------------------------------------
/client/solana_test.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/6boris/web3-go/model/solana"
7 | "github.com/davecgh/go-spew/spew"
8 | "github.com/stretchr/testify/assert"
9 | )
10 |
11 | func TestSolana_Unite_GetAccountInfo(t *testing.T) {
12 | t.Run("Contract_USDT", func(t *testing.T) {
13 | reply, err := testSolanaClient.GetAccountInfo(testCtx,
14 | &solana.GetAccountInfoRequest{Account: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"},
15 | )
16 | assert.Nil(t, err)
17 | spew.Dump(reply)
18 | })
19 | t.Run("User_Common", func(t *testing.T) {
20 | reply, err := testSolanaClient.GetAccountInfo(testCtx,
21 | &solana.GetAccountInfoRequest{Account: "Hw161dCAE9VBtbTo3EgbzwLdvVxNnEpiqqAJw7q38BYE"},
22 | )
23 | assert.Nil(t, err)
24 | spew.Dump(reply)
25 | })
26 | }
27 |
28 | func TestSolana_Unite_GetBalance(t *testing.T) {
29 | t.Run("Demo", func(t *testing.T) {
30 | reply, err := testSolanaClient.GetBalance(testCtx,
31 | &solana.GetBalanceRequest{Account: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"},
32 | )
33 | assert.Nil(t, err)
34 | spew.Dump(reply)
35 | })
36 | }
37 |
38 | func TestSolana_Unite_GetVersion(t *testing.T) {
39 | t.Run("Demo", func(t *testing.T) {
40 | reply, err := testSolanaClient.GetVersion(testCtx)
41 | assert.Nil(t, err)
42 | spew.Dump(reply)
43 | })
44 | }
45 |
46 | func TestSolana_Unite_GetTokenAccountBalance(t *testing.T) {
47 | t.Run("SLND", func(t *testing.T) {
48 | reply, err := testSolanaClient.GetTokenAccountBalance(testCtx,
49 | &solana.GetTokenAccountBalanceRequest{Account: "3Lz6rCrXdLybFiuJGJnEjv6Z2XtCh5n4proPGP2aBkA1"})
50 | assert.Nil(t, err)
51 | spew.Dump(reply)
52 | })
53 | t.Run("TNSR", func(t *testing.T) {
54 | reply, err := testSolanaClient.GetTokenAccountBalance(testCtx,
55 | &solana.GetTokenAccountBalanceRequest{Account: "5FhnYa75QKfMkPjBCrM7iucf2wMBNzHE2chyyTUfJEqj"})
56 | assert.Nil(t, err)
57 | spew.Dump(reply)
58 | })
59 | }
60 |
61 | func TestSolana_Unite_GetBlockHeight(t *testing.T) {
62 | t.Run("Demo", func(t *testing.T) {
63 | reply, err := testSolanaClient.GetBlockHeight(testCtx)
64 | assert.Nil(t, err)
65 | spew.Dump(reply)
66 | })
67 | }
68 |
69 | func TestSolana_Unite_GetBlockTime(t *testing.T) {
70 | t.Run("Demo", func(t *testing.T) {
71 | blockHeight, err := testSolanaClient.GetBlockHeight(testCtx)
72 | assert.Nil(t, err)
73 | reply, err := testSolanaClient.GetBlockTime(testCtx, blockHeight)
74 | assert.Nil(t, err)
75 | spew.Dump(reply)
76 | })
77 | }
78 |
79 | func TestSolana_Unite_GetBlock(t *testing.T) {
80 | t.Run("Demo", func(t *testing.T) {
81 | reply, err := testSolanaClient.GetBlock(testCtx, &solana.GetBlockRequest{
82 | Slot: 430,
83 | Encoding: "base58",
84 | TransactionDetails: "full",
85 | Rewards: false,
86 | })
87 | assert.Nil(t, err)
88 | spew.Dump(reply)
89 | })
90 | }
91 |
92 | func TestSolana_Unite_GetClusterNodes(t *testing.T) {
93 | t.Run("Demo", func(t *testing.T) {
94 | reply, err := testSolanaClient.GetClusterNodes(testCtx)
95 | assert.Nil(t, err)
96 | spew.Dump(reply)
97 | spew.Dump(len(reply))
98 | })
99 | }
100 |
--------------------------------------------------------------------------------
/consts/abis.go:
--------------------------------------------------------------------------------
1 | package consts
2 |
3 | const (
4 | AbiCallStatusSuccess = "SUCCESS"
5 | AbiCallStatusFail = "FAILED"
6 |
7 | EvmMethodBlockByHash = "EVM_BlockByHash"
8 | EvmMethodBlockByNumber = "EVM_BlockByNumber"
9 | EvmMethodHeaderByHash = "EVM_HeaderByHash"
10 | EvmMethodHeaderByNumber = "EVM_HeaderByNumber"
11 | EvmMethodTransactionCount = "EVM_TransactionCount"
12 | EvmMethodTransactionInBlock = "EVM_TransactionInBlock"
13 | EvmMethodTransactionByHash = "EVM_TransactionByHash"
14 | EvmMethodTransactionReceipt = "EVM_TransactionReceipt"
15 | EvmMethodSendTransaction = "EVM_SendTransaction"
16 | EvmMethodBalanceAt = "EVM_BalanceAt"
17 | EvmMethodStorageAt = "EVM_StorageAt"
18 | EvmMethodCodeAt = "EVM_CodeAt"
19 | EvmMethodNonceAt = "EVM_NonceAt"
20 | EvmMethodSuggestGasPrice = "EVM_SuggestGasPrice"
21 | EvmMethodSuggestGasTipCap = "EVM_SuggestGasTipCap"
22 | EvmMethodFeeHistory = "EVM_FeeHistory"
23 | EvmMethodEstimateGas = "EVM_EstimateGas"
24 | EvmMethodPendingBalanceAtp = "EVM_PendingBalanceAt"
25 | EvmMethodPendingStorageAt = "EVM_PendingStorageAt"
26 | EvmMethodPendingCodeAt = "EVM_PendingCodeAt"
27 | EvmMethodPendingNonceAt = "EVM_PendingNonceAt"
28 | EvmMethodPendingTransactionCount = "EVM_PendingTransactionCount"
29 | EvmMethodBlockNumber = "EVM_BlockNumber"
30 | EvmMethodChainID = "EVM_ChainID"
31 | EvmMethodNetworkID = "EVM_NetworkID"
32 | EvmErc20MethodBalanceOf = "EVM_ERC20_BalanceOf"
33 | EvmErc20MethodName = "EVM_ERC20_Name"
34 | EvmErc20MethodDecimals = "EVM_ERC20_Decimals"
35 | EvmErc20MethodSymbol = "EVM_ERC20_Symbol"
36 | EvmErc20MethodTotalSupply = "EVM_ERC20_TotalSupply"
37 | EvmErc20MethodTransfer = "EVM_ERC20_Transfer"
38 | EvmErc20MethodApprove = "EVM_ERC20_Approve"
39 | EvmErc20MethodIncreaseAllowance = "EVM_ERC20_IncreaseAllowance"
40 | EvmErc20MethodDecreaseAllowance = "EVM_ERC20_DecreaseAllowance"
41 | EvmErc20MethodAllowance = "EVM_ERC20_Allowance"
42 |
43 | SolanaMethodGetBalance = "SOLANA_GetBalance"
44 | SolanaMethodGetTokenAccountBalance = "SOLANA_GetTokenAccountBalance"
45 | )
46 |
--------------------------------------------------------------------------------
/consts/chain.go:
--------------------------------------------------------------------------------
1 | package consts
2 |
3 | const (
4 | ChainEnvMainnet = "Mainnet"
5 | ChainEnvTestnet = "Testnet"
6 | ChainEnvDevnet = "Devnet"
7 | )
8 |
--------------------------------------------------------------------------------
/erc/erc20/erc20.go:
--------------------------------------------------------------------------------
1 | // Code generated - DO NOT EDIT.
2 | // This file is a generated binding and any manual changes will be lost.
3 |
4 | package erc20
5 |
6 | import (
7 | "errors"
8 | "math/big"
9 | "strings"
10 |
11 | ethereum "github.com/ethereum/go-ethereum"
12 | "github.com/ethereum/go-ethereum/accounts/abi"
13 | "github.com/ethereum/go-ethereum/accounts/abi/bind"
14 | "github.com/ethereum/go-ethereum/common"
15 | "github.com/ethereum/go-ethereum/core/types"
16 | "github.com/ethereum/go-ethereum/event"
17 | )
18 |
19 | // Reference imports to suppress errors if they are not otherwise used.
20 | var (
21 | _ = errors.New
22 | _ = big.NewInt
23 | _ = strings.NewReader
24 | _ = ethereum.NotFound
25 | _ = bind.Bind
26 | _ = common.Big1
27 | _ = types.BloomLookup
28 | _ = event.NewSubscription
29 | _ = abi.ConvertType
30 | )
31 |
32 | // ERC20MetaData contains all meta data concerning the ERC20 contract.
33 | var ERC20MetaData = &bind.MetaData{
34 | ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"allowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"ERC20InsufficientAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"ERC20InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"approver\",\"type\":\"address\"}],\"name\":\"ERC20InvalidApprover\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"ERC20InvalidReceiver\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"ERC20InvalidSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"ERC20InvalidSpender\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
35 | }
36 |
37 | // ERC20ABI is the input ABI used to generate the binding from.
38 | // Deprecated: Use ERC20MetaData.ABI instead.
39 | var ERC20ABI = ERC20MetaData.ABI
40 |
41 | // ERC20 is an auto generated Go binding around an Ethereum contract.
42 | type ERC20 struct {
43 | ERC20Caller // Read-only binding to the contract
44 | ERC20Transactor // Write-only binding to the contract
45 | ERC20Filterer // Log filterer for contract events
46 | }
47 |
48 | // ERC20Caller is an auto generated read-only Go binding around an Ethereum contract.
49 | type ERC20Caller struct {
50 | contract *bind.BoundContract // Generic contract wrapper for the low level calls
51 | }
52 |
53 | // ERC20Transactor is an auto generated write-only Go binding around an Ethereum contract.
54 | type ERC20Transactor struct {
55 | contract *bind.BoundContract // Generic contract wrapper for the low level calls
56 | }
57 |
58 | // ERC20Filterer is an auto generated log filtering Go binding around an Ethereum contract events.
59 | type ERC20Filterer struct {
60 | contract *bind.BoundContract // Generic contract wrapper for the low level calls
61 | }
62 |
63 | // ERC20Session is an auto generated Go binding around an Ethereum contract,
64 | // with pre-set call and transact options.
65 | type ERC20Session struct {
66 | Contract *ERC20 // Generic contract binding to set the session for
67 | CallOpts bind.CallOpts // Call options to use throughout this session
68 | TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
69 | }
70 |
71 | // ERC20CallerSession is an auto generated read-only Go binding around an Ethereum contract,
72 | // with pre-set call options.
73 | type ERC20CallerSession struct {
74 | Contract *ERC20Caller // Generic contract caller binding to set the session for
75 | CallOpts bind.CallOpts // Call options to use throughout this session
76 | }
77 |
78 | // ERC20TransactorSession is an auto generated write-only Go binding around an Ethereum contract,
79 | // with pre-set transact options.
80 | type ERC20TransactorSession struct {
81 | Contract *ERC20Transactor // Generic contract transactor binding to set the session for
82 | TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
83 | }
84 |
85 | // ERC20Raw is an auto generated low-level Go binding around an Ethereum contract.
86 | type ERC20Raw struct {
87 | Contract *ERC20 // Generic contract binding to access the raw methods on
88 | }
89 |
90 | // ERC20CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
91 | type ERC20CallerRaw struct {
92 | Contract *ERC20Caller // Generic read-only contract binding to access the raw methods on
93 | }
94 |
95 | // ERC20TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
96 | type ERC20TransactorRaw struct {
97 | Contract *ERC20Transactor // Generic write-only contract binding to access the raw methods on
98 | }
99 |
100 | // NewERC20 creates a new instance of ERC20, bound to a specific deployed contract.
101 | func NewERC20(address common.Address, backend bind.ContractBackend) (*ERC20, error) {
102 | contract, err := bindERC20(address, backend, backend, backend)
103 | if err != nil {
104 | return nil, err
105 | }
106 | return &ERC20{ERC20Caller: ERC20Caller{contract: contract}, ERC20Transactor: ERC20Transactor{contract: contract}, ERC20Filterer: ERC20Filterer{contract: contract}}, nil
107 | }
108 |
109 | // NewERC20Caller creates a new read-only instance of ERC20, bound to a specific deployed contract.
110 | func NewERC20Caller(address common.Address, caller bind.ContractCaller) (*ERC20Caller, error) {
111 | contract, err := bindERC20(address, caller, nil, nil)
112 | if err != nil {
113 | return nil, err
114 | }
115 | return &ERC20Caller{contract: contract}, nil
116 | }
117 |
118 | // NewERC20Transactor creates a new write-only instance of ERC20, bound to a specific deployed contract.
119 | func NewERC20Transactor(address common.Address, transactor bind.ContractTransactor) (*ERC20Transactor, error) {
120 | contract, err := bindERC20(address, nil, transactor, nil)
121 | if err != nil {
122 | return nil, err
123 | }
124 | return &ERC20Transactor{contract: contract}, nil
125 | }
126 |
127 | // NewERC20Filterer creates a new log filterer instance of ERC20, bound to a specific deployed contract.
128 | func NewERC20Filterer(address common.Address, filterer bind.ContractFilterer) (*ERC20Filterer, error) {
129 | contract, err := bindERC20(address, nil, nil, filterer)
130 | if err != nil {
131 | return nil, err
132 | }
133 | return &ERC20Filterer{contract: contract}, nil
134 | }
135 |
136 | // bindERC20 binds a generic wrapper to an already deployed contract.
137 | func bindERC20(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
138 | parsed, err := ERC20MetaData.GetAbi()
139 | if err != nil {
140 | return nil, err
141 | }
142 | return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
143 | }
144 |
145 | // Call invokes the (constant) contract method with params as input values and
146 | // sets the output to result. The result type might be a single field for simple
147 | // returns, a slice of interfaces for anonymous returns and a struct for named
148 | // returns.
149 | func (_ERC20 *ERC20Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
150 | return _ERC20.Contract.ERC20Caller.contract.Call(opts, result, method, params...)
151 | }
152 |
153 | // Transfer initiates a plain transaction to move funds to the contract, calling
154 | // its default method if one is available.
155 | func (_ERC20 *ERC20Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
156 | return _ERC20.Contract.ERC20Transactor.contract.Transfer(opts)
157 | }
158 |
159 | // Transact invokes the (paid) contract method with params as input values.
160 | func (_ERC20 *ERC20Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
161 | return _ERC20.Contract.ERC20Transactor.contract.Transact(opts, method, params...)
162 | }
163 |
164 | // Call invokes the (constant) contract method with params as input values and
165 | // sets the output to result. The result type might be a single field for simple
166 | // returns, a slice of interfaces for anonymous returns and a struct for named
167 | // returns.
168 | func (_ERC20 *ERC20CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
169 | return _ERC20.Contract.contract.Call(opts, result, method, params...)
170 | }
171 |
172 | // Transfer initiates a plain transaction to move funds to the contract, calling
173 | // its default method if one is available.
174 | func (_ERC20 *ERC20TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
175 | return _ERC20.Contract.contract.Transfer(opts)
176 | }
177 |
178 | // Transact invokes the (paid) contract method with params as input values.
179 | func (_ERC20 *ERC20TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
180 | return _ERC20.Contract.contract.Transact(opts, method, params...)
181 | }
182 |
183 | // Allowance is a free data retrieval call binding the contract method 0xdd62ed3e.
184 | //
185 | // Solidity: function allowance(address owner, address spender) view returns(uint256)
186 | func (_ERC20 *ERC20Caller) Allowance(opts *bind.CallOpts, owner common.Address, spender common.Address) (*big.Int, error) {
187 | var out []interface{}
188 | err := _ERC20.contract.Call(opts, &out, "allowance", owner, spender)
189 |
190 | if err != nil {
191 | return *new(*big.Int), err
192 | }
193 |
194 | out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
195 |
196 | return out0, err
197 |
198 | }
199 |
200 | // Allowance is a free data retrieval call binding the contract method 0xdd62ed3e.
201 | //
202 | // Solidity: function allowance(address owner, address spender) view returns(uint256)
203 | func (_ERC20 *ERC20Session) Allowance(owner common.Address, spender common.Address) (*big.Int, error) {
204 | return _ERC20.Contract.Allowance(&_ERC20.CallOpts, owner, spender)
205 | }
206 |
207 | // Allowance is a free data retrieval call binding the contract method 0xdd62ed3e.
208 | //
209 | // Solidity: function allowance(address owner, address spender) view returns(uint256)
210 | func (_ERC20 *ERC20CallerSession) Allowance(owner common.Address, spender common.Address) (*big.Int, error) {
211 | return _ERC20.Contract.Allowance(&_ERC20.CallOpts, owner, spender)
212 | }
213 |
214 | // BalanceOf is a free data retrieval call binding the contract method 0x70a08231.
215 | //
216 | // Solidity: function balanceOf(address account) view returns(uint256)
217 | func (_ERC20 *ERC20Caller) BalanceOf(opts *bind.CallOpts, account common.Address) (*big.Int, error) {
218 | var out []interface{}
219 | err := _ERC20.contract.Call(opts, &out, "balanceOf", account)
220 |
221 | if err != nil {
222 | return *new(*big.Int), err
223 | }
224 |
225 | out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
226 |
227 | return out0, err
228 |
229 | }
230 |
231 | // BalanceOf is a free data retrieval call binding the contract method 0x70a08231.
232 | //
233 | // Solidity: function balanceOf(address account) view returns(uint256)
234 | func (_ERC20 *ERC20Session) BalanceOf(account common.Address) (*big.Int, error) {
235 | return _ERC20.Contract.BalanceOf(&_ERC20.CallOpts, account)
236 | }
237 |
238 | // BalanceOf is a free data retrieval call binding the contract method 0x70a08231.
239 | //
240 | // Solidity: function balanceOf(address account) view returns(uint256)
241 | func (_ERC20 *ERC20CallerSession) BalanceOf(account common.Address) (*big.Int, error) {
242 | return _ERC20.Contract.BalanceOf(&_ERC20.CallOpts, account)
243 | }
244 |
245 | // Decimals is a free data retrieval call binding the contract method 0x313ce567.
246 | //
247 | // Solidity: function decimals() view returns(uint8)
248 | func (_ERC20 *ERC20Caller) Decimals(opts *bind.CallOpts) (uint8, error) {
249 | var out []interface{}
250 | err := _ERC20.contract.Call(opts, &out, "decimals")
251 |
252 | if err != nil {
253 | return *new(uint8), err
254 | }
255 |
256 | out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8)
257 |
258 | return out0, err
259 |
260 | }
261 |
262 | // Decimals is a free data retrieval call binding the contract method 0x313ce567.
263 | //
264 | // Solidity: function decimals() view returns(uint8)
265 | func (_ERC20 *ERC20Session) Decimals() (uint8, error) {
266 | return _ERC20.Contract.Decimals(&_ERC20.CallOpts)
267 | }
268 |
269 | // Decimals is a free data retrieval call binding the contract method 0x313ce567.
270 | //
271 | // Solidity: function decimals() view returns(uint8)
272 | func (_ERC20 *ERC20CallerSession) Decimals() (uint8, error) {
273 | return _ERC20.Contract.Decimals(&_ERC20.CallOpts)
274 | }
275 |
276 | // Name is a free data retrieval call binding the contract method 0x06fdde03.
277 | //
278 | // Solidity: function name() view returns(string)
279 | func (_ERC20 *ERC20Caller) Name(opts *bind.CallOpts) (string, error) {
280 | var out []interface{}
281 | err := _ERC20.contract.Call(opts, &out, "name")
282 |
283 | if err != nil {
284 | return *new(string), err
285 | }
286 |
287 | out0 := *abi.ConvertType(out[0], new(string)).(*string)
288 |
289 | return out0, err
290 |
291 | }
292 |
293 | // Name is a free data retrieval call binding the contract method 0x06fdde03.
294 | //
295 | // Solidity: function name() view returns(string)
296 | func (_ERC20 *ERC20Session) Name() (string, error) {
297 | return _ERC20.Contract.Name(&_ERC20.CallOpts)
298 | }
299 |
300 | // Name is a free data retrieval call binding the contract method 0x06fdde03.
301 | //
302 | // Solidity: function name() view returns(string)
303 | func (_ERC20 *ERC20CallerSession) Name() (string, error) {
304 | return _ERC20.Contract.Name(&_ERC20.CallOpts)
305 | }
306 |
307 | // Symbol is a free data retrieval call binding the contract method 0x95d89b41.
308 | //
309 | // Solidity: function symbol() view returns(string)
310 | func (_ERC20 *ERC20Caller) Symbol(opts *bind.CallOpts) (string, error) {
311 | var out []interface{}
312 | err := _ERC20.contract.Call(opts, &out, "symbol")
313 |
314 | if err != nil {
315 | return *new(string), err
316 | }
317 |
318 | out0 := *abi.ConvertType(out[0], new(string)).(*string)
319 |
320 | return out0, err
321 |
322 | }
323 |
324 | // Symbol is a free data retrieval call binding the contract method 0x95d89b41.
325 | //
326 | // Solidity: function symbol() view returns(string)
327 | func (_ERC20 *ERC20Session) Symbol() (string, error) {
328 | return _ERC20.Contract.Symbol(&_ERC20.CallOpts)
329 | }
330 |
331 | // Symbol is a free data retrieval call binding the contract method 0x95d89b41.
332 | //
333 | // Solidity: function symbol() view returns(string)
334 | func (_ERC20 *ERC20CallerSession) Symbol() (string, error) {
335 | return _ERC20.Contract.Symbol(&_ERC20.CallOpts)
336 | }
337 |
338 | // TotalSupply is a free data retrieval call binding the contract method 0x18160ddd.
339 | //
340 | // Solidity: function totalSupply() view returns(uint256)
341 | func (_ERC20 *ERC20Caller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) {
342 | var out []interface{}
343 | err := _ERC20.contract.Call(opts, &out, "totalSupply")
344 |
345 | if err != nil {
346 | return *new(*big.Int), err
347 | }
348 |
349 | out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
350 |
351 | return out0, err
352 |
353 | }
354 |
355 | // TotalSupply is a free data retrieval call binding the contract method 0x18160ddd.
356 | //
357 | // Solidity: function totalSupply() view returns(uint256)
358 | func (_ERC20 *ERC20Session) TotalSupply() (*big.Int, error) {
359 | return _ERC20.Contract.TotalSupply(&_ERC20.CallOpts)
360 | }
361 |
362 | // TotalSupply is a free data retrieval call binding the contract method 0x18160ddd.
363 | //
364 | // Solidity: function totalSupply() view returns(uint256)
365 | func (_ERC20 *ERC20CallerSession) TotalSupply() (*big.Int, error) {
366 | return _ERC20.Contract.TotalSupply(&_ERC20.CallOpts)
367 | }
368 |
369 | // Approve is a paid mutator transaction binding the contract method 0x095ea7b3.
370 | //
371 | // Solidity: function approve(address spender, uint256 value) returns(bool)
372 | func (_ERC20 *ERC20Transactor) Approve(opts *bind.TransactOpts, spender common.Address, value *big.Int) (*types.Transaction, error) {
373 | return _ERC20.contract.Transact(opts, "approve", spender, value)
374 | }
375 |
376 | // Approve is a paid mutator transaction binding the contract method 0x095ea7b3.
377 | //
378 | // Solidity: function approve(address spender, uint256 value) returns(bool)
379 | func (_ERC20 *ERC20Session) Approve(spender common.Address, value *big.Int) (*types.Transaction, error) {
380 | return _ERC20.Contract.Approve(&_ERC20.TransactOpts, spender, value)
381 | }
382 |
383 | // Approve is a paid mutator transaction binding the contract method 0x095ea7b3.
384 | //
385 | // Solidity: function approve(address spender, uint256 value) returns(bool)
386 | func (_ERC20 *ERC20TransactorSession) Approve(spender common.Address, value *big.Int) (*types.Transaction, error) {
387 | return _ERC20.Contract.Approve(&_ERC20.TransactOpts, spender, value)
388 | }
389 |
390 | // DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7.
391 | //
392 | // Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool)
393 | func (_ERC20 *ERC20Transactor) DecreaseAllowance(opts *bind.TransactOpts, spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) {
394 | return _ERC20.contract.Transact(opts, "decreaseAllowance", spender, subtractedValue)
395 | }
396 |
397 | // DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7.
398 | //
399 | // Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool)
400 | func (_ERC20 *ERC20Session) DecreaseAllowance(spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) {
401 | return _ERC20.Contract.DecreaseAllowance(&_ERC20.TransactOpts, spender, subtractedValue)
402 | }
403 |
404 | // DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7.
405 | //
406 | // Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool)
407 | func (_ERC20 *ERC20TransactorSession) DecreaseAllowance(spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) {
408 | return _ERC20.Contract.DecreaseAllowance(&_ERC20.TransactOpts, spender, subtractedValue)
409 | }
410 |
411 | // IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351.
412 | //
413 | // Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool)
414 | func (_ERC20 *ERC20Transactor) IncreaseAllowance(opts *bind.TransactOpts, spender common.Address, addedValue *big.Int) (*types.Transaction, error) {
415 | return _ERC20.contract.Transact(opts, "increaseAllowance", spender, addedValue)
416 | }
417 |
418 | // IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351.
419 | //
420 | // Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool)
421 | func (_ERC20 *ERC20Session) IncreaseAllowance(spender common.Address, addedValue *big.Int) (*types.Transaction, error) {
422 | return _ERC20.Contract.IncreaseAllowance(&_ERC20.TransactOpts, spender, addedValue)
423 | }
424 |
425 | // IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351.
426 | //
427 | // Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool)
428 | func (_ERC20 *ERC20TransactorSession) IncreaseAllowance(spender common.Address, addedValue *big.Int) (*types.Transaction, error) {
429 | return _ERC20.Contract.IncreaseAllowance(&_ERC20.TransactOpts, spender, addedValue)
430 | }
431 |
432 | // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb.
433 | //
434 | // Solidity: function transfer(address to, uint256 value) returns(bool)
435 | func (_ERC20 *ERC20Transactor) Transfer(opts *bind.TransactOpts, to common.Address, value *big.Int) (*types.Transaction, error) {
436 | return _ERC20.contract.Transact(opts, "transfer", to, value)
437 | }
438 |
439 | // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb.
440 | //
441 | // Solidity: function transfer(address to, uint256 value) returns(bool)
442 | func (_ERC20 *ERC20Session) Transfer(to common.Address, value *big.Int) (*types.Transaction, error) {
443 | return _ERC20.Contract.Transfer(&_ERC20.TransactOpts, to, value)
444 | }
445 |
446 | // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb.
447 | //
448 | // Solidity: function transfer(address to, uint256 value) returns(bool)
449 | func (_ERC20 *ERC20TransactorSession) Transfer(to common.Address, value *big.Int) (*types.Transaction, error) {
450 | return _ERC20.Contract.Transfer(&_ERC20.TransactOpts, to, value)
451 | }
452 |
453 | // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd.
454 | //
455 | // Solidity: function transferFrom(address from, address to, uint256 value) returns(bool)
456 | func (_ERC20 *ERC20Transactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) {
457 | return _ERC20.contract.Transact(opts, "transferFrom", from, to, value)
458 | }
459 |
460 | // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd.
461 | //
462 | // Solidity: function transferFrom(address from, address to, uint256 value) returns(bool)
463 | func (_ERC20 *ERC20Session) TransferFrom(from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) {
464 | return _ERC20.Contract.TransferFrom(&_ERC20.TransactOpts, from, to, value)
465 | }
466 |
467 | // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd.
468 | //
469 | // Solidity: function transferFrom(address from, address to, uint256 value) returns(bool)
470 | func (_ERC20 *ERC20TransactorSession) TransferFrom(from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) {
471 | return _ERC20.Contract.TransferFrom(&_ERC20.TransactOpts, from, to, value)
472 | }
473 |
474 | // ERC20ApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the ERC20 contract.
475 | type ERC20ApprovalIterator struct {
476 | Event *ERC20Approval // Event containing the contract specifics and raw log
477 |
478 | contract *bind.BoundContract // Generic contract to use for unpacking event data
479 | event string // Event name to use for unpacking event data
480 |
481 | logs chan types.Log // Log channel receiving the found contract events
482 | sub ethereum.Subscription // Subscription for errors, completion and termination
483 | done bool // Whether the subscription completed delivering logs
484 | fail error // Occurred error to stop iteration
485 | }
486 |
487 | // Next advances the iterator to the subsequent event, returning whether there
488 | // are any more events found. In case of a retrieval or parsing error, false is
489 | // returned and Error() can be queried for the exact failure.
490 | func (it *ERC20ApprovalIterator) Next() bool {
491 | // If the iterator failed, stop iterating
492 | if it.fail != nil {
493 | return false
494 | }
495 | // If the iterator completed, deliver directly whatever's available
496 | if it.done {
497 | select {
498 | case log := <-it.logs:
499 | it.Event = new(ERC20Approval)
500 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
501 | it.fail = err
502 | return false
503 | }
504 | it.Event.Raw = log
505 | return true
506 |
507 | default:
508 | return false
509 | }
510 | }
511 | // Iterator still in progress, wait for either a data or an error event
512 | select {
513 | case log := <-it.logs:
514 | it.Event = new(ERC20Approval)
515 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
516 | it.fail = err
517 | return false
518 | }
519 | it.Event.Raw = log
520 | return true
521 |
522 | case err := <-it.sub.Err():
523 | it.done = true
524 | it.fail = err
525 | return it.Next()
526 | }
527 | }
528 |
529 | // Error returns any retrieval or parsing error occurred during filtering.
530 | func (it *ERC20ApprovalIterator) Error() error {
531 | return it.fail
532 | }
533 |
534 | // Close terminates the iteration process, releasing any pending underlying
535 | // resources.
536 | func (it *ERC20ApprovalIterator) Close() error {
537 | it.sub.Unsubscribe()
538 | return nil
539 | }
540 |
541 | // ERC20Approval represents a Approval event raised by the ERC20 contract.
542 | type ERC20Approval struct {
543 | Owner common.Address
544 | Spender common.Address
545 | Value *big.Int
546 | Raw types.Log // Blockchain specific contextual infos
547 | }
548 |
549 | // FilterApproval is a free log retrieval operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925.
550 | //
551 | // Solidity: event Approval(address indexed owner, address indexed spender, uint256 value)
552 | func (_ERC20 *ERC20Filterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, spender []common.Address) (*ERC20ApprovalIterator, error) {
553 |
554 | var ownerRule []interface{}
555 | for _, ownerItem := range owner {
556 | ownerRule = append(ownerRule, ownerItem)
557 | }
558 | var spenderRule []interface{}
559 | for _, spenderItem := range spender {
560 | spenderRule = append(spenderRule, spenderItem)
561 | }
562 |
563 | logs, sub, err := _ERC20.contract.FilterLogs(opts, "Approval", ownerRule, spenderRule)
564 | if err != nil {
565 | return nil, err
566 | }
567 | return &ERC20ApprovalIterator{contract: _ERC20.contract, event: "Approval", logs: logs, sub: sub}, nil
568 | }
569 |
570 | // WatchApproval is a free log subscription operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925.
571 | //
572 | // Solidity: event Approval(address indexed owner, address indexed spender, uint256 value)
573 | func (_ERC20 *ERC20Filterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *ERC20Approval, owner []common.Address, spender []common.Address) (event.Subscription, error) {
574 |
575 | var ownerRule []interface{}
576 | for _, ownerItem := range owner {
577 | ownerRule = append(ownerRule, ownerItem)
578 | }
579 | var spenderRule []interface{}
580 | for _, spenderItem := range spender {
581 | spenderRule = append(spenderRule, spenderItem)
582 | }
583 |
584 | logs, sub, err := _ERC20.contract.WatchLogs(opts, "Approval", ownerRule, spenderRule)
585 | if err != nil {
586 | return nil, err
587 | }
588 | return event.NewSubscription(func(quit <-chan struct{}) error {
589 | defer sub.Unsubscribe()
590 | for {
591 | select {
592 | case log := <-logs:
593 | // New log arrived, parse the event and forward to the user
594 | event := new(ERC20Approval)
595 | if err := _ERC20.contract.UnpackLog(event, "Approval", log); err != nil {
596 | return err
597 | }
598 | event.Raw = log
599 |
600 | select {
601 | case sink <- event:
602 | case err := <-sub.Err():
603 | return err
604 | case <-quit:
605 | return nil
606 | }
607 | case err := <-sub.Err():
608 | return err
609 | case <-quit:
610 | return nil
611 | }
612 | }
613 | }), nil
614 | }
615 |
616 | // ParseApproval is a log parse operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925.
617 | //
618 | // Solidity: event Approval(address indexed owner, address indexed spender, uint256 value)
619 | func (_ERC20 *ERC20Filterer) ParseApproval(log types.Log) (*ERC20Approval, error) {
620 | event := new(ERC20Approval)
621 | if err := _ERC20.contract.UnpackLog(event, "Approval", log); err != nil {
622 | return nil, err
623 | }
624 | event.Raw = log
625 | return event, nil
626 | }
627 |
628 | // ERC20TransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the ERC20 contract.
629 | type ERC20TransferIterator struct {
630 | Event *ERC20Transfer // Event containing the contract specifics and raw log
631 |
632 | contract *bind.BoundContract // Generic contract to use for unpacking event data
633 | event string // Event name to use for unpacking event data
634 |
635 | logs chan types.Log // Log channel receiving the found contract events
636 | sub ethereum.Subscription // Subscription for errors, completion and termination
637 | done bool // Whether the subscription completed delivering logs
638 | fail error // Occurred error to stop iteration
639 | }
640 |
641 | // Next advances the iterator to the subsequent event, returning whether there
642 | // are any more events found. In case of a retrieval or parsing error, false is
643 | // returned and Error() can be queried for the exact failure.
644 | func (it *ERC20TransferIterator) Next() bool {
645 | // If the iterator failed, stop iterating
646 | if it.fail != nil {
647 | return false
648 | }
649 | // If the iterator completed, deliver directly whatever's available
650 | if it.done {
651 | select {
652 | case log := <-it.logs:
653 | it.Event = new(ERC20Transfer)
654 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
655 | it.fail = err
656 | return false
657 | }
658 | it.Event.Raw = log
659 | return true
660 |
661 | default:
662 | return false
663 | }
664 | }
665 | // Iterator still in progress, wait for either a data or an error event
666 | select {
667 | case log := <-it.logs:
668 | it.Event = new(ERC20Transfer)
669 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
670 | it.fail = err
671 | return false
672 | }
673 | it.Event.Raw = log
674 | return true
675 |
676 | case err := <-it.sub.Err():
677 | it.done = true
678 | it.fail = err
679 | return it.Next()
680 | }
681 | }
682 |
683 | // Error returns any retrieval or parsing error occurred during filtering.
684 | func (it *ERC20TransferIterator) Error() error {
685 | return it.fail
686 | }
687 |
688 | // Close terminates the iteration process, releasing any pending underlying
689 | // resources.
690 | func (it *ERC20TransferIterator) Close() error {
691 | it.sub.Unsubscribe()
692 | return nil
693 | }
694 |
695 | // ERC20Transfer represents a Transfer event raised by the ERC20 contract.
696 | type ERC20Transfer struct {
697 | From common.Address
698 | To common.Address
699 | Value *big.Int
700 | Raw types.Log // Blockchain specific contextual infos
701 | }
702 |
703 | // FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef.
704 | //
705 | // Solidity: event Transfer(address indexed from, address indexed to, uint256 value)
706 | func (_ERC20 *ERC20Filterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*ERC20TransferIterator, error) {
707 |
708 | var fromRule []interface{}
709 | for _, fromItem := range from {
710 | fromRule = append(fromRule, fromItem)
711 | }
712 | var toRule []interface{}
713 | for _, toItem := range to {
714 | toRule = append(toRule, toItem)
715 | }
716 |
717 | logs, sub, err := _ERC20.contract.FilterLogs(opts, "Transfer", fromRule, toRule)
718 | if err != nil {
719 | return nil, err
720 | }
721 | return &ERC20TransferIterator{contract: _ERC20.contract, event: "Transfer", logs: logs, sub: sub}, nil
722 | }
723 |
724 | // WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef.
725 | //
726 | // Solidity: event Transfer(address indexed from, address indexed to, uint256 value)
727 | func (_ERC20 *ERC20Filterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *ERC20Transfer, from []common.Address, to []common.Address) (event.Subscription, error) {
728 |
729 | var fromRule []interface{}
730 | for _, fromItem := range from {
731 | fromRule = append(fromRule, fromItem)
732 | }
733 | var toRule []interface{}
734 | for _, toItem := range to {
735 | toRule = append(toRule, toItem)
736 | }
737 |
738 | logs, sub, err := _ERC20.contract.WatchLogs(opts, "Transfer", fromRule, toRule)
739 | if err != nil {
740 | return nil, err
741 | }
742 | return event.NewSubscription(func(quit <-chan struct{}) error {
743 | defer sub.Unsubscribe()
744 | for {
745 | select {
746 | case log := <-logs:
747 | // New log arrived, parse the event and forward to the user
748 | event := new(ERC20Transfer)
749 | if err := _ERC20.contract.UnpackLog(event, "Transfer", log); err != nil {
750 | return err
751 | }
752 | event.Raw = log
753 |
754 | select {
755 | case sink <- event:
756 | case err := <-sub.Err():
757 | return err
758 | case <-quit:
759 | return nil
760 | }
761 | case err := <-sub.Err():
762 | return err
763 | case <-quit:
764 | return nil
765 | }
766 | }
767 | }), nil
768 | }
769 |
770 | // ParseTransfer is a log parse operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef.
771 | //
772 | // Solidity: event Transfer(address indexed from, address indexed to, uint256 value)
773 | func (_ERC20 *ERC20Filterer) ParseTransfer(log types.Log) (*ERC20Transfer, error) {
774 | event := new(ERC20Transfer)
775 | if err := _ERC20.contract.UnpackLog(event, "Transfer", log); err != nil {
776 | return nil, err
777 | }
778 | event.Raw = log
779 | return event, nil
780 | }
781 |
--------------------------------------------------------------------------------
/erc/erc20/erc20.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "inputs": [],
4 | "stateMutability": "nonpayable",
5 | "type": "constructor"
6 | },
7 | {
8 | "inputs": [
9 | {
10 | "internalType": "address",
11 | "name": "spender",
12 | "type": "address"
13 | },
14 | {
15 | "internalType": "uint256",
16 | "name": "allowance",
17 | "type": "uint256"
18 | },
19 | {
20 | "internalType": "uint256",
21 | "name": "needed",
22 | "type": "uint256"
23 | }
24 | ],
25 | "name": "ERC20InsufficientAllowance",
26 | "type": "error"
27 | },
28 | {
29 | "inputs": [
30 | {
31 | "internalType": "address",
32 | "name": "sender",
33 | "type": "address"
34 | },
35 | {
36 | "internalType": "uint256",
37 | "name": "balance",
38 | "type": "uint256"
39 | },
40 | {
41 | "internalType": "uint256",
42 | "name": "needed",
43 | "type": "uint256"
44 | }
45 | ],
46 | "name": "ERC20InsufficientBalance",
47 | "type": "error"
48 | },
49 | {
50 | "inputs": [
51 | {
52 | "internalType": "address",
53 | "name": "approver",
54 | "type": "address"
55 | }
56 | ],
57 | "name": "ERC20InvalidApprover",
58 | "type": "error"
59 | },
60 | {
61 | "inputs": [
62 | {
63 | "internalType": "address",
64 | "name": "receiver",
65 | "type": "address"
66 | }
67 | ],
68 | "name": "ERC20InvalidReceiver",
69 | "type": "error"
70 | },
71 | {
72 | "inputs": [
73 | {
74 | "internalType": "address",
75 | "name": "sender",
76 | "type": "address"
77 | }
78 | ],
79 | "name": "ERC20InvalidSender",
80 | "type": "error"
81 | },
82 | {
83 | "inputs": [
84 | {
85 | "internalType": "address",
86 | "name": "spender",
87 | "type": "address"
88 | }
89 | ],
90 | "name": "ERC20InvalidSpender",
91 | "type": "error"
92 | },
93 | {
94 | "anonymous": false,
95 | "inputs": [
96 | {
97 | "indexed": true,
98 | "internalType": "address",
99 | "name": "owner",
100 | "type": "address"
101 | },
102 | {
103 | "indexed": true,
104 | "internalType": "address",
105 | "name": "spender",
106 | "type": "address"
107 | },
108 | {
109 | "indexed": false,
110 | "internalType": "uint256",
111 | "name": "value",
112 | "type": "uint256"
113 | }
114 | ],
115 | "name": "Approval",
116 | "type": "event"
117 | },
118 | {
119 | "anonymous": false,
120 | "inputs": [
121 | {
122 | "indexed": true,
123 | "internalType": "address",
124 | "name": "from",
125 | "type": "address"
126 | },
127 | {
128 | "indexed": true,
129 | "internalType": "address",
130 | "name": "to",
131 | "type": "address"
132 | },
133 | {
134 | "indexed": false,
135 | "internalType": "uint256",
136 | "name": "value",
137 | "type": "uint256"
138 | }
139 | ],
140 | "name": "Transfer",
141 | "type": "event"
142 | },
143 | {
144 | "inputs": [
145 | {
146 | "internalType": "address",
147 | "name": "owner",
148 | "type": "address"
149 | },
150 | {
151 | "internalType": "address",
152 | "name": "spender",
153 | "type": "address"
154 | }
155 | ],
156 | "name": "allowance",
157 | "outputs": [
158 | {
159 | "internalType": "uint256",
160 | "name": "",
161 | "type": "uint256"
162 | }
163 | ],
164 | "stateMutability": "view",
165 | "type": "function"
166 | },
167 | {
168 | "inputs": [
169 | {
170 | "internalType": "address",
171 | "name": "spender",
172 | "type": "address"
173 | },
174 | {
175 | "internalType": "uint256",
176 | "name": "value",
177 | "type": "uint256"
178 | }
179 | ],
180 | "name": "approve",
181 | "outputs": [
182 | {
183 | "internalType": "bool",
184 | "name": "",
185 | "type": "bool"
186 | }
187 | ],
188 | "stateMutability": "nonpayable",
189 | "type": "function"
190 | },
191 | {
192 | "inputs": [
193 | {
194 | "internalType": "address",
195 | "name": "account",
196 | "type": "address"
197 | }
198 | ],
199 | "name": "balanceOf",
200 | "outputs": [
201 | {
202 | "internalType": "uint256",
203 | "name": "",
204 | "type": "uint256"
205 | }
206 | ],
207 | "stateMutability": "view",
208 | "type": "function"
209 | },
210 | {
211 | "inputs": [],
212 | "name": "decimals",
213 | "outputs": [
214 | {
215 | "internalType": "uint8",
216 | "name": "",
217 | "type": "uint8"
218 | }
219 | ],
220 | "stateMutability": "view",
221 | "type": "function"
222 | },
223 | {
224 | "inputs": [],
225 | "name": "name",
226 | "outputs": [
227 | {
228 | "internalType": "string",
229 | "name": "",
230 | "type": "string"
231 | }
232 | ],
233 | "stateMutability": "view",
234 | "type": "function"
235 | },
236 | {
237 | "inputs": [],
238 | "name": "symbol",
239 | "outputs": [
240 | {
241 | "internalType": "string",
242 | "name": "",
243 | "type": "string"
244 | }
245 | ],
246 | "stateMutability": "view",
247 | "type": "function"
248 | },
249 | {
250 | "inputs": [],
251 | "name": "totalSupply",
252 | "outputs": [
253 | {
254 | "internalType": "uint256",
255 | "name": "",
256 | "type": "uint256"
257 | }
258 | ],
259 | "stateMutability": "view",
260 | "type": "function"
261 | },
262 | {
263 | "inputs": [
264 | {
265 | "internalType": "address",
266 | "name": "to",
267 | "type": "address"
268 | },
269 | {
270 | "internalType": "uint256",
271 | "name": "value",
272 | "type": "uint256"
273 | }
274 | ],
275 | "name": "transfer",
276 | "outputs": [
277 | {
278 | "internalType": "bool",
279 | "name": "",
280 | "type": "bool"
281 | }
282 | ],
283 | "stateMutability": "nonpayable",
284 | "type": "function"
285 | },
286 | {
287 | "inputs": [
288 | {
289 | "internalType": "address",
290 | "name": "from",
291 | "type": "address"
292 | },
293 | {
294 | "internalType": "address",
295 | "name": "to",
296 | "type": "address"
297 | },
298 | {
299 | "internalType": "uint256",
300 | "name": "value",
301 | "type": "uint256"
302 | }
303 | ],
304 | "name": "transferFrom",
305 | "outputs": [
306 | {
307 | "internalType": "bool",
308 | "name": "",
309 | "type": "bool"
310 | }
311 | ],
312 | "stateMutability": "nonpayable",
313 | "type": "function"
314 | },
315 | {
316 | "inputs": [
317 | {
318 | "internalType": "address",
319 | "name": "spender",
320 | "type": "address"
321 | },
322 | {
323 | "internalType": "uint256",
324 | "name": "addedValue",
325 | "type": "uint256"
326 | }
327 | ],
328 | "name": "increaseAllowance",
329 | "outputs": [
330 | {
331 | "internalType": "bool",
332 | "name": "",
333 | "type": "bool"
334 | }
335 | ],
336 | "stateMutability": "nonpayable",
337 | "type": "function"
338 | },
339 | {
340 | "inputs": [
341 | {
342 | "internalType": "address",
343 | "name": "spender",
344 | "type": "address"
345 | },
346 | {
347 | "internalType": "uint256",
348 | "name": "subtractedValue",
349 | "type": "uint256"
350 | }
351 | ],
352 | "name": "decreaseAllowance",
353 | "outputs": [
354 | {
355 | "internalType": "bool",
356 | "name": "",
357 | "type": "bool"
358 | }
359 | ],
360 | "stateMutability": "nonpayable",
361 | "type": "function"
362 | }
363 | ]
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/6boris/web3-go
2 |
3 | go 1.22
4 |
5 | require (
6 | github.com/davecgh/go-spew v1.1.1
7 | github.com/ethereum/go-ethereum v1.14.0
8 | github.com/gin-gonic/gin v1.9.1
9 | github.com/go-kratos/aegis v0.2.0
10 | github.com/google/uuid v1.6.0
11 | github.com/imroc/req/v3 v3.43.3
12 | github.com/prometheus/client_golang v1.19.0
13 | github.com/shopspring/decimal v1.4.0
14 | github.com/stretchr/testify v1.9.0
15 | github.com/tidwall/gjson v1.17.1
16 | go.opentelemetry.io/otel v1.25.0
17 | go.opentelemetry.io/otel/exporters/prometheus v0.47.0
18 | go.opentelemetry.io/otel/metric v1.25.0
19 | go.opentelemetry.io/otel/sdk/metric v1.25.0
20 | )
21 |
22 | require (
23 | github.com/Microsoft/go-winio v0.6.2 // indirect
24 | github.com/andybalholm/brotli v1.1.0 // indirect
25 | github.com/beorn7/perks v1.0.1 // indirect
26 | github.com/bits-and-blooms/bitset v1.13.0 // indirect
27 | github.com/btcsuite/btcd/btcec/v2 v2.3.3 // indirect
28 | github.com/bytedance/sonic v1.11.6 // indirect
29 | github.com/cespare/xxhash/v2 v2.3.0 // indirect
30 | github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
31 | github.com/chenzhuoyu/iasm v0.9.1 // indirect
32 | github.com/cloudflare/circl v1.3.7 // indirect
33 | github.com/consensys/bavard v0.1.13 // indirect
34 | github.com/consensys/gnark-crypto v0.12.1 // indirect
35 | github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect
36 | github.com/deckarep/golang-set/v2 v2.6.0 // indirect
37 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
38 | github.com/ethereum/c-kzg-4844 v1.0.1 // indirect
39 | github.com/fsnotify/fsnotify v1.7.0 // indirect
40 | github.com/gabriel-vasile/mimetype v1.4.3 // indirect
41 | github.com/gin-contrib/sse v0.1.0 // indirect
42 | github.com/go-logr/logr v1.4.1 // indirect
43 | github.com/go-logr/stdr v1.2.2 // indirect
44 | github.com/go-ole/go-ole v1.3.0 // indirect
45 | github.com/go-playground/locales v0.14.1 // indirect
46 | github.com/go-playground/universal-translator v0.18.1 // indirect
47 | github.com/go-playground/validator/v10 v10.19.0 // indirect
48 | github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
49 | github.com/goccy/go-json v0.10.2 // indirect
50 | github.com/google/pprof v0.0.0-20240422182052-72c8669ad3e7 // indirect
51 | github.com/gorilla/websocket v1.5.1 // indirect
52 | github.com/hashicorp/errwrap v1.1.0 // indirect
53 | github.com/hashicorp/go-multierror v1.1.1 // indirect
54 | github.com/holiman/uint256 v1.2.4 // indirect
55 | github.com/json-iterator/go v1.1.12 // indirect
56 | github.com/klauspost/compress v1.17.8 // indirect
57 | github.com/klauspost/cpuid/v2 v2.2.7 // indirect
58 | github.com/leodido/go-urn v1.4.0 // indirect
59 | github.com/mattn/go-isatty v0.0.20 // indirect
60 | github.com/mmcloughlin/addchain v0.4.0 // indirect
61 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
62 | github.com/modern-go/reflect2 v1.0.2 // indirect
63 | github.com/onsi/ginkgo/v2 v2.17.1 // indirect
64 | github.com/pelletier/go-toml/v2 v2.2.1 // indirect
65 | github.com/pmezard/go-difflib v1.0.0 // indirect
66 | github.com/prometheus/client_model v0.6.1 // indirect
67 | github.com/prometheus/common v0.53.0 // indirect
68 | github.com/prometheus/procfs v0.14.0 // indirect
69 | github.com/quic-go/qpack v0.4.0 // indirect
70 | github.com/quic-go/quic-go v0.42.0 // indirect
71 | github.com/refraction-networking/utls v1.6.4 // indirect
72 | github.com/shirou/gopsutil v3.21.11+incompatible // indirect
73 | github.com/supranational/blst v0.3.11 // indirect
74 | github.com/tidwall/match v1.1.1 // indirect
75 | github.com/tidwall/pretty v1.2.1 // indirect
76 | github.com/tklauser/go-sysconf v0.3.13 // indirect
77 | github.com/tklauser/numcpus v0.7.0 // indirect
78 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
79 | github.com/ugorji/go/codec v1.2.12 // indirect
80 | github.com/yusufpapurcu/wmi v1.2.4 // indirect
81 | go.opentelemetry.io/otel/sdk v1.25.0 // indirect
82 | go.opentelemetry.io/otel/trace v1.25.0 // indirect
83 | go.uber.org/mock v0.4.0 // indirect
84 | golang.org/x/arch v0.7.0 // indirect
85 | golang.org/x/crypto v0.22.0 // indirect
86 | golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
87 | golang.org/x/mod v0.17.0 // indirect
88 | golang.org/x/net v0.24.0 // indirect
89 | golang.org/x/sync v0.7.0 // indirect
90 | golang.org/x/sys v0.19.0 // indirect
91 | golang.org/x/text v0.14.0 // indirect
92 | golang.org/x/tools v0.20.0 // indirect
93 | google.golang.org/protobuf v1.33.0 // indirect
94 | gopkg.in/yaml.v3 v3.0.1 // indirect
95 | rsc.io/tmplfunc v0.0.3 // indirect
96 | )
97 |
98 | replace (
99 | github.com/bytedance/sonic => github.com/bytedance/sonic v1.11.2
100 | github.com/crate-crypto/go-kzg-4844 => github.com/crate-crypto/go-kzg-4844 v0.7.0
101 | )
102 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
2 | github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
3 | github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
4 | github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
5 | github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40=
6 | github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o=
7 | github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
8 | github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
9 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
10 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
11 | github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
12 | github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
13 | github.com/btcsuite/btcd/btcec/v2 v2.3.3 h1:6+iXlDKE8RMtKsvK0gshlXIuPbyWM/h84Ensb7o3sC0=
14 | github.com/btcsuite/btcd/btcec/v2 v2.3.3/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
15 | github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
16 | github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
17 | github.com/bytedance/sonic v1.11.2 h1:ywfwo0a/3j9HR8wsYGWsIWl2mvRsI950HyoxiBERw5A=
18 | github.com/bytedance/sonic v1.11.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
19 | github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
20 | github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
21 | github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
22 | github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
23 | github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
24 | github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
25 | github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
26 | github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0=
27 | github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
28 | github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
29 | github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
30 | github.com/cockroachdb/errors v1.8.1 h1:A5+txlVZfOqFBDa4mGz2bUWSp0aHElvHX2bKkdbQu+Y=
31 | github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac=
32 | github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY=
33 | github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
34 | github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvDmeyi+l/FS/VtA00IWvjeFvjen1m1l1A=
35 | github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo=
36 | github.com/cockroachdb/redact v1.0.8 h1:8QG/764wK+vmEYoOlfobpe12EQcS81ukx/a4hdVMxNw=
37 | github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
38 | github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM=
39 | github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ=
40 | github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
41 | github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
42 | github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ=
43 | github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
44 | github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M=
45 | github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY=
46 | github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
47 | github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
48 | github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ=
49 | github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs=
50 | github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA=
51 | github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc=
52 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
53 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
54 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
55 | github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM=
56 | github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
57 | github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
58 | github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
59 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
60 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
61 | github.com/ethereum/c-kzg-4844 v1.0.1 h1:pGixCbGizcVKSwoV70ge48+PrbB+iSKs2rjgfE4yJmQ=
62 | github.com/ethereum/c-kzg-4844 v1.0.1/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
63 | github.com/ethereum/go-ethereum v1.13.15 h1:U7sSGYGo4SPjP6iNIifNoyIAiNjrmQkz6EwQG+/EZWo=
64 | github.com/ethereum/go-ethereum v1.13.15/go.mod h1:TN8ZiHrdJwSe8Cb6x+p0hs5CxhJZPbqB7hHkaUXcmIU=
65 | github.com/ethereum/go-ethereum v1.14.0 h1:xRWC5NlB6g1x7vNy4HDBLuqVNbtLrc7v8S6+Uxim1LU=
66 | github.com/ethereum/go-ethereum v1.14.0/go.mod h1:1STrq471D0BQbCX9He0hUj4bHxX2k6mt5nOQJhDNOJ8=
67 | github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA=
68 | github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
69 | github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
70 | github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
71 | github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
72 | github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
73 | github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI=
74 | github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
75 | github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE=
76 | github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc=
77 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
78 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
79 | github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
80 | github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
81 | github.com/go-kratos/aegis v0.2.0 h1:dObzCDWn3XVjUkgxyBp6ZeWtx/do0DPZ7LY3yNSJLUQ=
82 | github.com/go-kratos/aegis v0.2.0/go.mod h1:v0R2m73WgEEYB3XYu6aE2WcMwsZkJ/Rzuf5eVccm7bI=
83 | github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
84 | github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
85 | github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
86 | github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
87 | github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
88 | github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
89 | github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
90 | github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
91 | github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
92 | github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
93 | github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
94 | github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
95 | github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
96 | github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
97 | github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4=
98 | github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
99 | github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
100 | github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
101 | github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
102 | github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
103 | github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
104 | github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
105 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
106 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
107 | github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
108 | github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
109 | github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
110 | github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
111 | github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk=
112 | github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
113 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
114 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
115 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
116 | github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
117 | github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
118 | github.com/google/pprof v0.0.0-20240416155748-26353dc0451f h1:WpZiq8iqvGjJ3m3wzAVKL6+0vz7VkE79iSy9GII00II=
119 | github.com/google/pprof v0.0.0-20240416155748-26353dc0451f/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
120 | github.com/google/pprof v0.0.0-20240422182052-72c8669ad3e7 h1:3q13T5NW3mlTJZM6B5UAsf2N5NYFbYWIyI3W8DlvBDU=
121 | github.com/google/pprof v0.0.0-20240422182052-72c8669ad3e7/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
122 | github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
123 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
124 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
125 | github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
126 | github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
127 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
128 | github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
129 | github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
130 | github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE=
131 | github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0=
132 | github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
133 | github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
134 | github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6wn4Ej8vjuVGxeHdan+bRb2ebyv4=
135 | github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc=
136 | github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
137 | github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
138 | github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU=
139 | github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
140 | github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
141 | github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
142 | github.com/imroc/req/v3 v3.43.3 h1:WdZhpUev9THtuwEZsW2LOYacl12fm7IkB7OgACv40+k=
143 | github.com/imroc/req/v3 v3.43.3/go.mod h1:SQIz5iYop16MJxbo8ib+4LnostGCok8NQf8ToyQc2xA=
144 | github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
145 | github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
146 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
147 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
148 | github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
149 | github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
150 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
151 | github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
152 | github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
153 | github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
154 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
155 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
156 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
157 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
158 | github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
159 | github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
160 | github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
161 | github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
162 | github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
163 | github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
164 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
165 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
166 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
167 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
168 | github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
169 | github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
170 | github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
171 | github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
172 | github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A=
173 | github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
174 | github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
175 | github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
176 | github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
177 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
178 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
179 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
180 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
181 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
182 | github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
183 | github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
184 | github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8=
185 | github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
186 | github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
187 | github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
188 | github.com/pelletier/go-toml/v2 v2.2.1 h1:9TA9+T8+8CUCO2+WYnDLCgrYi9+omqKXyjDtosvtEhg=
189 | github.com/pelletier/go-toml/v2 v2.2.1/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
190 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
191 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
192 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
193 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
194 | github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
195 | github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
196 | github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
197 | github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
198 | github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE=
199 | github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U=
200 | github.com/prometheus/procfs v0.14.0 h1:Lw4VdGGoKEZilJsayHf0B+9YgLGREba2C6xr+Fdfq6s=
201 | github.com/prometheus/procfs v0.14.0/go.mod h1:XL+Iwz8k8ZabyZfMFHPiilCniixqQarAy5Mu67pHlNQ=
202 | github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
203 | github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
204 | github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM=
205 | github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
206 | github.com/refraction-networking/utls v1.6.4 h1:aeynTroaYn7y+mFtqv8D0bQ4bw0y9nJHneGxJ7lvRDM=
207 | github.com/refraction-networking/utls v1.6.4/go.mod h1:2VL2xfiqgFAZtJKeUTlf+PSYFs3Eu7km0gCtXJ3m8zs=
208 | github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
209 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
210 | github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
211 | github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
212 | github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
213 | github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
214 | github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
215 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
216 | github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
217 | github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
218 | github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
219 | github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
220 | github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA=
221 | github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg=
222 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
223 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
224 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
225 | github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
226 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
227 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
228 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
229 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
230 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
231 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
232 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
233 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
234 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
235 | github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4=
236 | github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
237 | github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
238 | github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
239 | github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
240 | github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
241 | github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
242 | github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
243 | github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
244 | github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
245 | github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
246 | github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4=
247 | github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0=
248 | github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4=
249 | github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY=
250 | github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
251 | github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
252 | github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
253 | github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
254 | github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
255 | github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
256 | github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
257 | github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
258 | github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
259 | github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
260 | github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
261 | github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
262 | go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k=
263 | go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg=
264 | go.opentelemetry.io/otel/exporters/prometheus v0.47.0 h1:OL6yk1Z/pEGdDnrBbxSsH+t4FY1zXfBRGd7bjwhlMLU=
265 | go.opentelemetry.io/otel/exporters/prometheus v0.47.0/go.mod h1:xF3N4OSICZDVbbYZydz9MHFro1RjmkPUKEvar2utG+Q=
266 | go.opentelemetry.io/otel/metric v1.25.0 h1:LUKbS7ArpFL/I2jJHdJcqMGxkRdxpPHE0VU/D4NuEwA=
267 | go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s=
268 | go.opentelemetry.io/otel/sdk v1.25.0 h1:PDryEJPC8YJZQSyLY5eqLeafHtG+X7FWnf3aXMtxbqo=
269 | go.opentelemetry.io/otel/sdk v1.25.0/go.mod h1:oFgzCM2zdsxKzz6zwpTZYLLQsFwc+K0daArPdIhuxkw=
270 | go.opentelemetry.io/otel/sdk/metric v1.25.0 h1:7CiHOy08LbrxMAp4vWpbiPcklunUshVpAvGBrdDRlGw=
271 | go.opentelemetry.io/otel/sdk/metric v1.25.0/go.mod h1:LzwoKptdbBBdYfvtGCzGwk6GWMA3aUzBOwtQpR6Nz7o=
272 | go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM=
273 | go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I=
274 | go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
275 | go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
276 | golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
277 | golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
278 | golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
279 | golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
280 | golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
281 | golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY=
282 | golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
283 | golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
284 | golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
285 | golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
286 | golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
287 | golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
288 | golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
289 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
290 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
291 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
292 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
293 | golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
294 | golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
295 | golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
296 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
297 | golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
298 | golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
299 | golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
300 | golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
301 | google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
302 | google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
303 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
304 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
305 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
306 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
307 | gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
308 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
309 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
310 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
311 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
312 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
313 | nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
314 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
315 | rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
316 | rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=
317 |
--------------------------------------------------------------------------------
/model/client/conf.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "crypto/ecdsa"
5 | "time"
6 |
7 | "github.com/shopspring/decimal"
8 |
9 | "github.com/ethereum/go-ethereum/common"
10 | )
11 |
12 | type ConfPool struct {
13 | AppID string `yaml:"app_id" json:"app_id"`
14 | Zone string `yaml:"zone" json:"zone"`
15 | Cluster string `yaml:"cluster" json:"cluster"`
16 | EvmChains map[int64]*ConfEvmChainInfo `yaml:"evm_chains" json:"evm_chains"`
17 | SolanaChains []*ConfSolanaClient `yaml:"solana_chains" json:"solana_chains"`
18 | }
19 | type ConfEvmChainInfo struct {
20 | ChainID int64 `yaml:"chain_id" json:"chain_id"`
21 | ChainName string `yaml:"chain_name" json:"chain_name"`
22 | ChainEnv string `yaml:"chain_env" json:"chain_env"`
23 | OfficialWebsite string `yaml:"official_website_url" json:"official_website"`
24 | ExplorerURL string `yaml:"explorer_url" json:"explorer_url"`
25 | Faucets []string `yaml:"faucets" json:"faucets"`
26 | Clients []*ConfEvmChainClient `yaml:"clients" json:"clients"`
27 | }
28 | type ConfEvmChainClient struct {
29 | ClientID string `yaml:"client_id" json:"client_id"`
30 | Provider string `yaml:"provider" json:"provider"`
31 | ProviderWebsite string `yaml:"provider_website" json:"provider_website"`
32 | TransportSchema string `yaml:"transport_schema" json:"transport_schema"`
33 | TransportURL string `yaml:"transport_url" json:"transport_url"`
34 | GasFeeRate decimal.Decimal `yaml:"gas_fee_rate" json:"gas_fee_rate"`
35 | GasLimitRate decimal.Decimal `yaml:"gas_limit_rate" json:"gas_limit_rate"`
36 | GasLimitMax decimal.Decimal `yaml:"gas_limit_max" json:"gas_limit_max"`
37 | Signers []*ConfEvmChainSigner `yaml:"signers" json:"signers"`
38 | }
39 |
40 | type ConfEvmChainSigner struct {
41 | PublicAddress common.Address `json:"public_address"`
42 | PrivateKey *ecdsa.PrivateKey `json:"-"`
43 | }
44 | type ConfEvmChain struct {
45 | ChainID int64 `yaml:"chain_id" json:"chain_id"`
46 | ChainName string `yaml:"chain_name" json:"chain_name"`
47 | ChainEnv string `yaml:"chain_env" json:"chain_env"`
48 | OfficialWebsite string `yaml:"official_website_url" json:"official_website"`
49 | ExplorerURL string `yaml:"explorer_url" json:"explorer_url"`
50 | Faucets []string `yaml:"faucets" json:"faucets"`
51 | Clients []*ConfClient `yaml:"clients" json:"clients"`
52 | }
53 |
54 | type ConfClient struct {
55 | ClientID string `yaml:"client_id" json:"client_id"`
56 | Provider string `yaml:"provider" json:"provider"`
57 | ProviderWebsite string `yaml:"provider_website" json:"provider_website"`
58 | TransportSchema string `yaml:"transport_schema" json:"transport_schema"`
59 | TransportURL string `yaml:"transport_url" json:"transport_url"`
60 | }
61 | type ConfEvmClient struct {
62 | ClientID string `yaml:"client_id" json:"client_id"`
63 | Provider string `yaml:"provider" json:"provider"`
64 | ProviderWebsite string `yaml:"provider_website" json:"provider_website"`
65 | TransportSchema string `yaml:"transport_schema" json:"transport_schema"`
66 | TransportURL string `yaml:"transport_url" json:"transport_url"`
67 | }
68 | type ConfSolanaClient struct {
69 | ClientID string `yaml:"client_id" json:"client_id"`
70 | Provider string `yaml:"provider" json:"provider"`
71 | TransportSchema string `yaml:"transport_schema" json:"transport_schema"`
72 | ChainEnv string `yaml:"chain_env" json:"chain_env"`
73 | TransportURL string `yaml:"transport_url" json:"transport_url"`
74 | IsDev bool `yaml:"is_dev" json:"is_dev"`
75 | }
76 |
77 | type Metadata struct {
78 | CallMethod string `yaml:"call_method" json:"call_method"`
79 | StartAt time.Time `yaml:"start_at" json:"start_at"`
80 | Status string `yaml:"status" json:"status"`
81 | }
82 |
83 | type EvmCallProxyRequest struct {
84 | ChainID int64 `json:"chain_id"`
85 | ID int64 `json:"id"`
86 | JsonRpc string `json:"jsonrpc"`
87 | Method string `json:"method"`
88 | Params []interface{} `json:"params"`
89 | }
90 | type SolanaCallProxyRequest struct {
91 | ChainEnv string `json:"chain_env"`
92 | ID int64 `json:"id"`
93 | JsonRpc string `json:"jsonrpc"`
94 | Method string `json:"method"`
95 | Params []interface{} `json:"params"`
96 | }
97 |
98 | type EvmCallProxyReply struct {
99 | ID int64 `json:"id"`
100 | JsonRpc string `json:"json_rpc"`
101 | Result interface{} `json:"result"`
102 | }
103 | type ErrReply struct {
104 | Code int64 `json:"code"`
105 | Reason string `json:"reason"`
106 | Message string `json:"message"`
107 | Metadata map[string]string `json:"metadata,omitempty"`
108 | }
109 |
--------------------------------------------------------------------------------
/model/client/default.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import "github.com/6boris/web3-go/consts"
4 |
5 | func GetDefaultConfPool() *ConfPool {
6 | conf := &ConfPool{
7 | AppID: "web3.app_id.default",
8 | Zone: "web3.zone.default",
9 | Cluster: "web3.cluster.default",
10 | SolanaChains: []*ConfSolanaClient{
11 | {
12 | ClientID: "",
13 | Provider: "",
14 | ChainEnv: consts.ChainEnvTestnet,
15 | TransportSchema: "http",
16 | TransportURL: "https://api.testnet.solana.com",
17 | },
18 | {
19 | ClientID: "",
20 | Provider: "",
21 | ChainEnv: consts.ChainEnvDevnet,
22 | TransportSchema: "http",
23 | TransportURL: "https://api.devnet.solana.com",
24 | },
25 | {
26 | ClientID: "",
27 | Provider: "",
28 | ChainEnv: consts.ChainEnvMainnet,
29 | TransportSchema: "http",
30 | TransportURL: "https://api.mainnet-beta.solana.com",
31 | },
32 | },
33 | EvmChains: map[int64]*ConfEvmChainInfo{
34 | 1: {
35 | ChainID: 1,
36 | ChainName: "Ethereum Mainnet",
37 | ChainEnv: consts.ChainEnvMainnet,
38 | OfficialWebsite: "https://ethereum.org",
39 | ExplorerURL: "https://etherscan.io",
40 | Faucets: []string{},
41 | Clients: []*ConfEvmChainClient{
42 | {Provider: "LlamaNodes", ProviderWebsite: "https://llamanodes.com", TransportSchema: "https", TransportURL: "https://eth.llamarpc.com"},
43 | {Provider: "OMNIA", ProviderWebsite: "https://omniatech.io", TransportSchema: "https", TransportURL: "https://endpoints.omniatech.io/v1/eth/mainnet/public"},
44 | {Provider: "Ankr", ProviderWebsite: "https://www.ankr.com", TransportSchema: "https", TransportURL: "https://rpc.ankr.com/eth"},
45 | {Provider: "PublicNode", ProviderWebsite: "https://ethereum.publicnode.com", TransportSchema: "https", TransportURL: "https://ethereum.publicnode.com"},
46 | {Provider: "1RPC", ProviderWebsite: "https://www.1rpc.io", TransportSchema: "https", TransportURL: "https://1rpc.io/eth"},
47 | {Provider: "MEV Blocker", ProviderWebsite: "https://mevblocker.io", TransportSchema: "https", TransportURL: "https://rpc.mevblocker.io"},
48 | {Provider: "FlashBots", ProviderWebsite: "https://www.flashbots.net", TransportSchema: "https", TransportURL: "https://rpc.flashbots.net"},
49 | {Provider: "CloudFlare", ProviderWebsite: "https://www.cloudflare.com/web3", TransportSchema: "https", TransportURL: "https://cloudflare-eth.com"},
50 | {Provider: "SecureRpc", ProviderWebsite: "https://securerpc.com", TransportSchema: "https", TransportURL: "https://api.securerpc.com/v1"},
51 | {Provider: "BlockPI", ProviderWebsite: "https://public.blockpi.io", TransportSchema: "https", TransportURL: "https://ethereum.blockpi.network/v1/rpc/public"},
52 | {Provider: "Payload.De", ProviderWebsite: "https://payload.de", TransportSchema: "https", TransportURL: "https://rpc.payload.de"},
53 | {Provider: "Alchemy", ProviderWebsite: "https://www.alchemy.com", TransportSchema: "https", TransportURL: "https://eth-mainnet.g.alchemy.com/v2/demo"},
54 | {Provider: "GasHawk", ProviderWebsite: "https://gashawk.io", TransportSchema: "https", TransportURL: "https://core.gashawk.io/rpc"},
55 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://rpc.mevblocker.io"},
56 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://core.gashawk.io/rpc"},
57 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://eth.api.onfinality.io/public"},
58 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://eth-rpc.gateway.pokt.network"},
59 | },
60 | },
61 | 11155111: {
62 | ChainID: 11155111,
63 | ChainName: "Ethereum Sepolia",
64 | ChainEnv: consts.ChainEnvTestnet,
65 | OfficialWebsite: "https://ethereum.org",
66 | ExplorerURL: "https://sepolia.etherscan.io",
67 | Faucets: []string{},
68 | Clients: []*ConfEvmChainClient{
69 | {Provider: "BlockPI", ProviderWebsite: "https://public.blockpi.io/", TransportSchema: "https", TransportURL: "https://ethereum-sepolia.blockpi.network/v1/rpc/public"},
70 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://eth-sepolia.public.blastapi.io"},
71 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://rpc2.sepolia.org"},
72 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://rpc.sepolia.org"},
73 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://eth-sepolia-public.unifra.io"},
74 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://endpoints.omniatech.io/v1/eth/sepolia/public"},
75 | },
76 | },
77 | 5: {
78 | ChainID: 5,
79 | ChainName: "Ethereum Goerli",
80 | ChainEnv: consts.ChainEnvTestnet,
81 | OfficialWebsite: "https://ethereum.org",
82 | ExplorerURL: "https://goerli.etherscan.io",
83 | Faucets: []string{},
84 | Clients: []*ConfEvmChainClient{
85 | {Provider: "BlockPI", ProviderWebsite: "https://public.blockpi.io/", TransportSchema: "https", TransportURL: "https://goerli.blockpi.network/v1/rpc/public"},
86 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://rpc.ankr.com/eth_goerli"},
87 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://eth-goerli.public.blastapi.io"},
88 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://eth-goerli.g.alchemy.com/v2/demo"},
89 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://goerli.blockpi.network/v1/rpc/public"},
90 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://eth-goerli.api.onfinality.io/public"},
91 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://rpc.goerli.eth.gateway.fm"},
92 | },
93 | },
94 | 137: {
95 | ChainID: 137,
96 | ChainName: "Polygon PoS Chain",
97 | ChainEnv: consts.ChainEnvMainnet,
98 | OfficialWebsite: "https://polygon.technology",
99 | ExplorerURL: "https://polygonscan.com",
100 | Faucets: []string{},
101 | Clients: []*ConfEvmChainClient{
102 | {Provider: "LlamaNodes", ProviderWebsite: "https://llamanodes.com", TransportSchema: "https", TransportURL: "https://polygon.llamarpc.com"},
103 | {Provider: "Ankr", ProviderWebsite: "https://polygon-rpc.com", TransportSchema: "https", TransportURL: "https://polygon-rpc.com"},
104 | {Provider: "QuickNode", ProviderWebsite: "https://www.quicknode.com", TransportSchema: "https", TransportURL: "https://rpc-mainnet.matic.quiknode.pro"},
105 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://rpc-mainnet.matic.network"},
106 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://rpc.ankr.com/polygon"},
107 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://1rpc.io/matic"},
108 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://poly-rpc.gateway.pokt.network"},
109 | },
110 | },
111 | 80001: {
112 | ChainID: 80001,
113 | ChainName: "Polygon PoS Chain Testnet",
114 | ChainEnv: consts.ChainEnvTestnet,
115 | OfficialWebsite: "https://polygon.technology",
116 | ExplorerURL: "https://mumbai.polygonscan.com",
117 | Faucets: []string{},
118 | Clients: []*ConfEvmChainClient{
119 | {Provider: "BlockPI", ProviderWebsite: "https://public.blockpi.io/", TransportSchema: "https", TransportURL: "https://polygon-mumbai.blockpi.network/v1/rpc/public"},
120 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://rpc-mumbai.maticvigil.com"},
121 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://polygon-testnet.public.blastapi.io"},
122 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://matic-mumbai.chainstacklabs.com"},
123 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://rpc.ankr.com/polygon_mumbai"},
124 | },
125 | },
126 | 10: {
127 | ChainID: 10,
128 | ChainName: "Optimism",
129 | ChainEnv: consts.ChainEnvMainnet,
130 | OfficialWebsite: "https://www.optimism.io",
131 | ExplorerURL: "https://optimistic.etherscan.io",
132 | Faucets: []string{},
133 | Clients: []*ConfEvmChainClient{
134 | {Provider: "BlockPI", ProviderWebsite: "https://public.blockpi.io/", TransportSchema: "https", TransportURL: "https://optimism.blockpi.network/v1/rpc/public"},
135 | {Provider: "Alchemy", ProviderWebsite: "https://www.alchemy.com/", TransportSchema: "https", TransportURL: "https://mainnet.optimism.io"},
136 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://optimism-mainnet.public.blastapi.io"},
137 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://rpc.ankr.com/optimism"},
138 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://1rpc.io/op"},
139 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://optimism.blockpi.network/v1/rpc/public"},
140 | },
141 | },
142 | 420: {
143 | ChainID: 420,
144 | ChainName: "Optimism Goerli",
145 | ChainEnv: consts.ChainEnvTestnet,
146 | OfficialWebsite: "https://www.optimism.io",
147 | ExplorerURL: "https://goerli-explorer.optimism.io",
148 | Faucets: []string{},
149 | Clients: []*ConfEvmChainClient{
150 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://optimism-goerli.public.blastapi.io"},
151 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://goerli.optimism.io"},
152 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://opt-goerli.g.alchemy.com/v2/demo"},
153 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://endpoints.omniatech.io/v1/op/goerli/public"},
154 | },
155 | },
156 | 42161: {
157 | ChainID: 42161,
158 | ChainName: "Arbitrum One",
159 | ChainEnv: consts.ChainEnvMainnet,
160 | OfficialWebsite: "https://arbitrum.io",
161 | ExplorerURL: "https://arbiscan.io",
162 | Faucets: []string{},
163 | Clients: []*ConfEvmChainClient{
164 | {Provider: "BlockPI", ProviderWebsite: "https://public.blockpi.io/", TransportSchema: "https", TransportURL: "https://arbitrum.blockpi.network/v1/rpc/public"},
165 | {Provider: "Ankr", ProviderWebsite: "https://www.ankr.com", TransportSchema: "https", TransportURL: "https://rpc.ankr.com/arbitrum"},
166 | {Provider: "Arbitrum", ProviderWebsite: "https://arbitrum.io", TransportSchema: "https", TransportURL: "https://arb1.arbitrum.io/rpc"},
167 | },
168 | },
169 | 42170: {
170 | ChainID: 42170,
171 | ChainName: "Arbitrum Nova",
172 | ChainEnv: consts.ChainEnvTestnet,
173 | OfficialWebsite: "https://arbitrum.io",
174 | ExplorerURL: "https://nova.arbiscan.io",
175 | Faucets: []string{},
176 | Clients: []*ConfEvmChainClient{
177 | {Provider: "Arbitrum", ProviderWebsite: "https://developer.arbitrum.io/public-chains", TransportSchema: "https", TransportURL: "https://nova.arbitrum.io/rpc"},
178 | },
179 | },
180 | 421613: {
181 | ChainID: 421613,
182 | ChainName: "Arbitrum Goerli",
183 | ChainEnv: consts.ChainEnvTestnet,
184 | OfficialWebsite: "https://arbitrum.io",
185 | ExplorerURL: "https://goerli.arbiscan.io",
186 | Faucets: []string{},
187 | Clients: []*ConfEvmChainClient{
188 | {Provider: "Arbitrum", ProviderWebsite: "https://developer.arbitrum.io/public-chains", TransportSchema: "https", TransportURL: "https://goerli-rollup.arbitrum.io/rpc"},
189 | },
190 | },
191 | 43113: {
192 | ChainID: 43113,
193 | ChainName: "Avalanche Fuji",
194 | ChainEnv: consts.ChainEnvMainnet,
195 | OfficialWebsite: "https://www.avax.network",
196 | ExplorerURL: "https://testnet.snowtrace.io",
197 | Faucets: []string{},
198 | Clients: []*ConfEvmChainClient{
199 | {Provider: "Ankr", ProviderWebsite: "https://developer.arbitrum.io/public-chains", TransportSchema: "https", TransportURL: "https://rpc.ankr.com/avalanche_fuji"},
200 | },
201 | },
202 | 43114: {
203 | ChainID: 43114,
204 | ChainName: "Avalanche Fuji",
205 | ChainEnv: consts.ChainEnvTestnet,
206 | OfficialWebsite: "https://www.avax.network",
207 | ExplorerURL: "https://testnet.snowtrace.io",
208 | Faucets: []string{},
209 | Clients: []*ConfEvmChainClient{
210 | {Provider: "Arbitrum", ProviderWebsite: "https://developer.arbitrum.io/public-chains", TransportSchema: "https", TransportURL: "https://rpc.ankr.com/avalanche"},
211 | },
212 | },
213 |
214 | 100: {
215 | ChainID: 100,
216 | ChainName: "Gnosis",
217 | ChainEnv: consts.ChainEnvMainnet,
218 | OfficialWebsite: "https://www.gnosis.io",
219 | ExplorerURL: "https://testnet.snowtrace.io",
220 | Faucets: []string{},
221 | Clients: []*ConfEvmChainClient{
222 | {Provider: "BlockPI", ProviderWebsite: "https://blockscout.com/xdai/mainnet", TransportSchema: "https", TransportURL: "https://gnosis.blockpi.network/v1/rpc/public"},
223 | },
224 | },
225 | 56: {
226 | ChainID: 56,
227 | ChainName: "BNB Smart Chain",
228 | ChainEnv: consts.ChainEnvMainnet,
229 | OfficialWebsite: "https://bscscan.com",
230 | ExplorerURL: "https://bscscan.com",
231 | Faucets: []string{},
232 | Clients: []*ConfEvmChainClient{
233 | {Provider: "BlockPI", ProviderWebsite: "https://public.blockpi.io/", TransportSchema: "https", TransportURL: "https://bsc.blockpi.network/v1/rpc/public"},
234 | },
235 | },
236 | 97: {
237 | ChainID: 97,
238 | ChainName: "BSC Testnet",
239 | ChainEnv: consts.ChainEnvTestnet,
240 | OfficialWebsite: "https://bscscan.com",
241 | ExplorerURL: "https://testnet.bscscan.com",
242 | Faucets: []string{},
243 | Clients: []*ConfEvmChainClient{
244 | {Provider: "Blast", ProviderWebsite: "https://blastapi.io", TransportSchema: "https", TransportURL: "https://bsc-testnet.public.blastapi.io"},
245 | },
246 | },
247 | 250: {
248 | ChainID: 250,
249 | ChainName: "Fantom Mainnet",
250 | ChainEnv: consts.ChainEnvMainnet,
251 | OfficialWebsite: "",
252 | ExplorerURL: "",
253 | Faucets: []string{},
254 | Clients: []*ConfEvmChainClient{
255 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://rpc.fantom.network"},
256 | },
257 | },
258 | 4002: {
259 | ChainID: 4002,
260 | ChainName: "Fantom Testnet",
261 | ChainEnv: consts.ChainEnvTestnet,
262 | OfficialWebsite: "",
263 | ExplorerURL: "",
264 | Faucets: []string{},
265 | Clients: []*ConfEvmChainClient{
266 | {Provider: "Other", ProviderWebsite: "", TransportSchema: "https", TransportURL: "https://rpc.ankr.com/fantom_testnet"},
267 | },
268 | },
269 | },
270 | }
271 | return conf
272 | }
273 |
--------------------------------------------------------------------------------
/model/solana/rpc.go:
--------------------------------------------------------------------------------
1 | package solana
2 |
3 | import "github.com/shopspring/decimal"
4 |
5 | type ContextItem struct {
6 | ApiVersion string `json:"apiVersion"`
7 | Slot int64 `json:"slot"`
8 | }
9 | type AccountInfoItem struct {
10 | Lamports decimal.Decimal `json:"lamports"`
11 | Owner string `json:"owner"`
12 | Executable bool `json:"executable"`
13 | RentEpoch decimal.Decimal `json:"rentEpoch"`
14 | Space decimal.Decimal `json:"space"`
15 | Data []string `json:"data"`
16 | }
17 |
18 | type GetAccountInfoRequest struct {
19 | Account string `json:"account"`
20 | }
21 | type GetAccountInfoReply struct {
22 | Context *ContextItem `json:"context"`
23 | Value *AccountInfoItem `json:"value"`
24 | }
25 |
26 | type GetVersionRequest struct{}
27 | type GetVersionReply struct {
28 | FeatureSet string `json:"feature_set"`
29 | SolanaCore string `json:"solana_core"`
30 | }
31 |
32 | type GetBalanceRequest struct {
33 | Account string `json:"account"`
34 | }
35 | type GetBalanceReply struct {
36 | Context *ContextItem `json:"context"`
37 | Value decimal.Decimal `json:"value"`
38 | }
39 |
40 | type GetTokenAccountBalanceRequest struct {
41 | Account string `json:"account"`
42 | }
43 | type GetTokenAccountBalanceReply struct {
44 | Context *ContextItem `json:"context"`
45 | Amount decimal.Decimal `json:"amount"`
46 | Decimals decimal.Decimal `json:"decimals"`
47 | UIAmount decimal.Decimal `json:"ui_amount"`
48 | UIAmountString decimal.Decimal `json:"ui_amount_string"`
49 | }
50 |
51 | type GetBlockHeightRequest struct {
52 | }
53 | type GetBlockHeightReply struct {
54 | BlockHeight int64 `json:"block_height"`
55 | }
56 |
57 | type GetBlockRequest struct {
58 | Slot int64 `json:"slot"`
59 | Encoding string `json:"encoding"`
60 | TransactionDetails string `json:"transaction_details"`
61 | Rewards bool `json:"rewards"`
62 | }
63 | type GetBlockReply struct {
64 | Context *ContextItem `json:"context"`
65 | Value decimal.Decimal `json:"value"`
66 | }
67 |
68 | type ClusterNodesItem struct {
69 | Gossip string `json:"gossip"`
70 | PubKey string `json:"pubkey"`
71 | RPC string `json:"rpc"`
72 | TPU string `json:"tpu"`
73 | Version string `json:"version"`
74 | }
75 |
--------------------------------------------------------------------------------
/pkg/otel/metrics.go:
--------------------------------------------------------------------------------
1 | package otel
2 |
3 | import (
4 | otelProm "go.opentelemetry.io/otel/exporters/prometheus"
5 | otelMetrics "go.opentelemetry.io/otel/metric"
6 | metricSdk "go.opentelemetry.io/otel/sdk/metric"
7 | )
8 |
9 | var MetricsWeb3RequestCounter otelMetrics.Int64Counter
10 | var MetricsWeb3RequestHistogram otelMetrics.Int64Histogram
11 |
12 | func init() {
13 | opts := []otelProm.Option{
14 | otelProm.WithoutTargetInfo(),
15 | }
16 | exporter, err := otelProm.New(opts...)
17 | if err != nil {
18 | panic(err)
19 | }
20 | provider := metricSdk.NewMeterProvider(metricSdk.WithReader(exporter))
21 | meter := provider.Meter("Web3 Go")
22 | m1, err := meter.Int64Counter("web3_abi_call", otelMetrics.WithDescription("Web3 Gateway abi call counter"))
23 | if err != nil {
24 | panic(err)
25 | }
26 |
27 | m2, err := meter.Int64Histogram("web3_abi_call", otelMetrics.WithDescription("Web3 Gateway abi call hist"))
28 | if err != nil {
29 | panic(err)
30 | }
31 |
32 | MetricsWeb3RequestCounter = m1
33 | MetricsWeb3RequestHistogram = m2
34 | }
35 |
--------------------------------------------------------------------------------
/pkg/pk/signer.go:
--------------------------------------------------------------------------------
1 | package pk
2 |
3 | import (
4 | "crypto/ecdsa"
5 | "errors"
6 |
7 | clientModel "github.com/6boris/web3-go/model/client"
8 | "github.com/ethereum/go-ethereum/crypto"
9 | )
10 |
11 | func TransformPkToEvmSigner(privateKey string) (*clientModel.ConfEvmChainSigner, error) {
12 | signer := &clientModel.ConfEvmChainSigner{}
13 | pk, err := crypto.HexToECDSA(privateKey)
14 | if err != nil {
15 | return nil, err
16 | }
17 | publicKey := pk.Public()
18 | publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
19 | if !ok {
20 | return nil, errors.New("TransformPkToEvmSigner Failed")
21 | }
22 | signer.PrivateKey = pk
23 | signer.PublicAddress = crypto.PubkeyToAddress(*publicKeyECDSA)
24 | return signer, err
25 | }
26 |
--------------------------------------------------------------------------------
/pkg/wjson/json.go:
--------------------------------------------------------------------------------
1 | package wjson
2 |
3 | import "encoding/json"
4 |
5 | func StructToJsonString(data interface{}) string {
6 | dataB, err := json.Marshal(data)
7 | if err != nil {
8 | return ""
9 | }
10 | return string(dataB)
11 | }
12 |
13 | func StructToJsonStringWithIndent(data interface{}, prefix, indent string) string {
14 | dataB, err := json.MarshalIndent(data, prefix, indent)
15 | if err != nil {
16 | return ""
17 | }
18 | return string(dataB)
19 | }
20 |
--------------------------------------------------------------------------------