etherscan-lite 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +3 -0
- data/Manifest.txt +8 -0
- data/README.md +355 -0
- data/Rakefile +32 -0
- data/lib/etherscan-lite/account.rb +100 -0
- data/lib/etherscan-lite/base.rb +57 -0
- data/lib/etherscan-lite/version.rb +22 -0
- data/lib/etherscan-lite.rb +53 -0
- metadata +105 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8268ce22467ea0136543b35e4595ff60b51e009dd7d60559f3cf858541ed1e24
|
4
|
+
data.tar.gz: 66da1fc606dd316d7640e8e45dc99fc0ea7bd81a4c61cbfa6003707ac3a4b334
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3a2ce94118461adce95f7fd3b3992f44c89f0f479b28e145eb2cc0c0d76e4a5fa78d11a3e603b6a4f871a548c9e1349c5908d0931e3a2067ee5082faf730a88c
|
7
|
+
data.tar.gz: 26c59cb4af1fcfd8b0454964748762d60ea466d3b9fd2e9736789564f841e4fef054a353ed5b2ebabc10bc5e06f116f61db75f362b1a91a1a7de4b15c3489f86
|
data/CHANGELOG.md
ADDED
data/Manifest.txt
ADDED
data/README.md
ADDED
@@ -0,0 +1,355 @@
|
|
1
|
+
# Etherscan Lite
|
2
|
+
|
3
|
+
etherscan-lite - light-weight machinery / helper for the Etherscan (blockchain) JSON HTTP API / web services (note: API key sign-up required)
|
4
|
+
|
5
|
+
* home :: [github.com/rubycocos/blockchain](https://github.com/rubycocos/blockchain)
|
6
|
+
* bugs :: [github.com/rubycocos/blockchain/issues](https://github.com/rubycocos/blockchain/issues)
|
7
|
+
* gem :: [rubygems.org/gems/etherscan-lite](https://rubygems.org/gems/etherscan-lite)
|
8
|
+
* rdoc :: [rubydoc.info/gems/etherscan-lite](http://rubydoc.info/gems/etherscan-lite)
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
|
14
|
+
|
15
|
+
### Step 0 - Setup - Configure ETHERSCAN API Key
|
16
|
+
|
17
|
+
|
18
|
+
The etherscan lite machinery will (auto-magically) lookup
|
19
|
+
the `ETHERSCAN_KEY` environment variable
|
20
|
+
or will load a dotenv file (`.env`) in the working / current directory
|
21
|
+
or use in your script:
|
22
|
+
|
23
|
+
``` ruby
|
24
|
+
Etherscan.config.key = 'YOUR_API_KEY_HERE'
|
25
|
+
|
26
|
+
# or
|
27
|
+
|
28
|
+
Etherscan.configure do |config|
|
29
|
+
config.key = 'YOUR_API_KEY_HERE'
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
|
34
|
+
### Etherscan API Recipes
|
35
|
+
|
36
|
+
Let's try the "official" recipes from the Eherscan API docu
|
37
|
+
|
38
|
+
- Get All USDT Transfers from Binance
|
39
|
+
- Get the Latest Moonbird Non-Fungible Token (NFT) Transfers
|
40
|
+
- List ETH deposits to Arbitrum Bridge
|
41
|
+
|
42
|
+
|
43
|
+
### Get All USDT Transfers from Binance
|
44
|
+
|
45
|
+
see <https://docs.etherscan.io/recipes/get-all-usdt-transfers-from-binance>
|
46
|
+
|
47
|
+
|
48
|
+
``` ruby
|
49
|
+
require 'etherscan-lite'
|
50
|
+
|
51
|
+
USDT_ADDRESS = '0xdac17f958d2ee523a2206206994597c13d831ec7'
|
52
|
+
BINANCE_HOT_WALLET = '0xdfd5293d8e347dfe59e90efd55b2956a1343963d'
|
53
|
+
|
54
|
+
data = Etherscan.tokentx( address: BINANCE_HOT_WALLET,
|
55
|
+
contractaddress: USDT_ADDRESS )
|
56
|
+
pp data
|
57
|
+
```
|
58
|
+
|
59
|
+
resulting in:
|
60
|
+
|
61
|
+
``` json
|
62
|
+
[{"blockNumber"=>"16191306",
|
63
|
+
"timeStamp"=>"1671121931",
|
64
|
+
"hash"=>"0x77361870fdc3046f7c24cabafa7185a84d60f4fa12aef8363e8520fbdd003cc7",
|
65
|
+
"nonce"=>"4866500",
|
66
|
+
"blockHash"=>"0x1f5d2e10774bd5473257ad0f47d08b3e523e3baace6f0218bce8aab62e90ec67",
|
67
|
+
"from"=>"0xdfd5293d8e347dfe59e90efd55b2956a1343963d",
|
68
|
+
"contractAddress"=>"0xdac17f958d2ee523a2206206994597c13d831ec7",
|
69
|
+
"to"=>"0x40fbc37ff0e4d3f900b867f2ca48ae6aba77c854",
|
70
|
+
"value"=>"495264069",
|
71
|
+
"tokenName"=>"Tether USD",
|
72
|
+
"tokenSymbol"=>"USDT",
|
73
|
+
"tokenDecimal"=>"6",
|
74
|
+
"transactionIndex"=>"44",
|
75
|
+
"gas"=>"207128",
|
76
|
+
"gasPrice"=>"31567202036",
|
77
|
+
"gasUsed"=>"63197",
|
78
|
+
"cumulativeGasUsed"=>"5207555",
|
79
|
+
"input"=>"deprecated",
|
80
|
+
"confirmations"=>"3"},
|
81
|
+
{"blockNumber"=>"16191304",
|
82
|
+
"timeStamp"=>"1671121907",
|
83
|
+
"hash"=>"0xd3d529d0d420e38680ad9066a5d62434a04b01e94b00b81fc5fea303afbda076",
|
84
|
+
"nonce"=>"4866498",
|
85
|
+
"blockHash"=>"0x9b2dfbfd068c90546c7572bc059cd790e12eb6b9f9b21a3c7c33e0abd8d69d6c",
|
86
|
+
"from"=>"0xdfd5293d8e347dfe59e90efd55b2956a1343963d",
|
87
|
+
"contractAddress"=>"0xdac17f958d2ee523a2206206994597c13d831ec7",
|
88
|
+
"to"=>"0xf7140bb010da74a191e3c98f801e596937f177fb",
|
89
|
+
"value"=>"4496800000",
|
90
|
+
"tokenName"=>"Tether USD",
|
91
|
+
"tokenSymbol"=>"USDT",
|
92
|
+
"tokenDecimal"=>"6",
|
93
|
+
"transactionIndex"=>"57",
|
94
|
+
"gas"=>"207128",
|
95
|
+
"gasPrice"=>"32759178674",
|
96
|
+
"gasUsed"=>"46109",
|
97
|
+
"cumulativeGasUsed"=>"3775818",
|
98
|
+
"input"=>"deprecated",
|
99
|
+
"confirmations"=>"5"},
|
100
|
+
...
|
101
|
+
]
|
102
|
+
```
|
103
|
+
|
104
|
+
and let's pretty print the data (records):
|
105
|
+
|
106
|
+
``` ruby
|
107
|
+
data.each_with_index do |h,i|
|
108
|
+
timestamp = Time.at( h['timeStamp'].to_i ).utc
|
109
|
+
|
110
|
+
decimal = h['tokenDecimal'].to_i
|
111
|
+
value = h['value'].to_i
|
112
|
+
|
113
|
+
major = value / (10**decimal)
|
114
|
+
minor = value % (10**decimal)
|
115
|
+
|
116
|
+
print " [#{i}] #{timestamp} - "
|
117
|
+
print "#{h['tokenName']} (#{h['tokenSymbol']}) "
|
118
|
+
print "%6d.%0#{decimal}d" % [major, minor]
|
119
|
+
print " (#{value}) - "
|
120
|
+
print "from: #{h['from'][0..10]} "
|
121
|
+
print "to: #{h['to'][0..10]} - "
|
122
|
+
print "txid: #{h['hash'][0..8]}"
|
123
|
+
print "\n"
|
124
|
+
end
|
125
|
+
```
|
126
|
+
|
127
|
+
resulting in:
|
128
|
+
|
129
|
+
```
|
130
|
+
[0] 2022-12-15 16:32:11 UTC - Tether USD (USDT) 495.264069 (495264069) - from: 0xdfd5293d8 to: 0x40fbc37ff - txid: 0x7736187
|
131
|
+
[1] 2022-12-15 16:31:47 UTC - Tether USD (USDT) 4496.800000 (4496800000) - from: 0xdfd5293d8 to: 0xf7140bb01 - txid: 0xd3d529d
|
132
|
+
[2] 2022-12-15 16:31:11 UTC - Tether USD (USDT) 1496.800000 (1496800000) - from: 0xdfd5293d8 to: 0xcab0e46b1 - txid: 0x0b7986d
|
133
|
+
[3] 2022-12-15 16:31:11 UTC - Tether USD (USDT) 122.800000 (122800000) - from: 0xdfd5293d8 to: 0xcc38c0e6f - txid: 0x8894af7
|
134
|
+
[4] 2022-12-15 16:30:35 UTC - Tether USD (USDT) 22953.971400 (22953971400) - from: 0xdfd5293d8 to: 0xccb95ec69 - txid: 0x0bb6b75
|
135
|
+
[5] 2022-12-15 16:30:11 UTC - Tether USD (USDT) 254.743920 (254743920) - from: 0xdfd5293d8 to: 0x68f2a6311 - txid: 0xf691bed
|
136
|
+
[6] 2022-12-15 16:29:35 UTC - Tether USD (USDT) 548.950317 (548950317) - from: 0xdfd5293d8 to: 0xaa00cd50e - txid: 0x847854b
|
137
|
+
[7] 2022-12-15 16:29:11 UTC - Tether USD (USDT) 33667.697868 (33667697868) - from: 0xdfd5293d8 to: 0xcfb27a23f - txid: 0x7a2390d
|
138
|
+
[8] 2022-12-15 16:28:59 UTC - Tether USD (USDT) 48126.270731 (48126270731) - from: 0xdfd5293d8 to: 0x09857b83a - txid: 0x0653035
|
139
|
+
[9] 2022-12-15 16:28:35 UTC - Tether USD (USDT) 15996.800000 (15996800000) - from: 0xdfd5293d8 to: 0xd8d6ffe34 - txid: 0xb02d04b
|
140
|
+
```
|
141
|
+
|
142
|
+
|
143
|
+
### Get the Latest Moonbird Non-Fungible Token (NFT) Transfers
|
144
|
+
|
145
|
+
see <https://docs.etherscan.io/recipes/get-the-latest-moonbird-nft-transfers>
|
146
|
+
|
147
|
+
``` ruby
|
148
|
+
require 'etherscan-lite'
|
149
|
+
|
150
|
+
MOONBIRDS_ADDRESS = '0x23581767a106ae21c074b2276D25e5C3e136a68b'
|
151
|
+
|
152
|
+
data = Etherscan.tokennfttx( contractaddress: MOONBIRDS_ADDRESS )
|
153
|
+
pp data
|
154
|
+
```
|
155
|
+
|
156
|
+
resulting in:
|
157
|
+
|
158
|
+
``` json
|
159
|
+
[{"blockNumber"=>"16191303",
|
160
|
+
"timeStamp"=>"1671121895",
|
161
|
+
"hash"=>"0xf049e3247e19e2eca1971f6daa38e7310bf2705b7da6347b9801122eef57f30e",
|
162
|
+
"nonce"=>"16348",
|
163
|
+
"blockHash"=>"0x2ec6abfc229cb61b7a851d9e078e93681634cf0b2b3390a54f6fa21e8d10cd04",
|
164
|
+
"from"=>"0x8ae57a027c63fca8070d1bf38622321de8004c67",
|
165
|
+
"contractAddress"=>"0x23581767a106ae21c074b2276d25e5c3e136a68b",
|
166
|
+
"to"=>"0xdc3276739390e3fdf7929056593d2ce316ebcfa8",
|
167
|
+
"tokenID"=>"2934",
|
168
|
+
"tokenName"=>"Moonbirds",
|
169
|
+
"tokenSymbol"=>"MOONBIRD",
|
170
|
+
"tokenDecimal"=>"0",
|
171
|
+
"transactionIndex"=>"150",
|
172
|
+
"gas"=>"168819",
|
173
|
+
"gasPrice"=>"30350829601",
|
174
|
+
"gasUsed"=>"64019",
|
175
|
+
"cumulativeGasUsed"=>"16664047",
|
176
|
+
"input"=>"deprecated",
|
177
|
+
"confirmations"=>"25"},
|
178
|
+
{"blockNumber"=>"16191297",
|
179
|
+
"timeStamp"=>"1671121823",
|
180
|
+
"hash"=>"0xb341b32b2c8904733c05648f67c09c99602a22b454f6f99b68746eb204c8f235",
|
181
|
+
"nonce"=>"4310",
|
182
|
+
"blockHash"=>"0x8774a12b660e59586ae94af1670362d2c73d09c94230f236859548ae0768f387",
|
183
|
+
"from"=>"0x8bc110db7029197c3621bea8092ab1996d5dd7be",
|
184
|
+
"contractAddress"=>"0x23581767a106ae21c074b2276d25e5c3e136a68b",
|
185
|
+
"to"=>"0x6ce2eb1c3006850ebbb97499f1a25b8ce6c01a44",
|
186
|
+
"tokenID"=>"9836",
|
187
|
+
"tokenName"=>"Moonbirds",
|
188
|
+
"tokenSymbol"=>"MOONBIRD",
|
189
|
+
"tokenDecimal"=>"0",
|
190
|
+
"transactionIndex"=>"15",
|
191
|
+
"gas"=>"3576346",
|
192
|
+
"gasPrice"=>"35958543341",
|
193
|
+
"gasUsed"=>"2751035",
|
194
|
+
"cumulativeGasUsed"=>"3999647",
|
195
|
+
"input"=>"deprecated",
|
196
|
+
"confirmations"=>"31"},
|
197
|
+
...
|
198
|
+
]
|
199
|
+
```
|
200
|
+
|
201
|
+
and let's pretty print the data (records):
|
202
|
+
|
203
|
+
|
204
|
+
``` ruby
|
205
|
+
data.each_with_index do |h,i|
|
206
|
+
timestamp = Time.at( h['timeStamp'].to_i ).utc
|
207
|
+
|
208
|
+
print " [#{i}] #{timestamp} - "
|
209
|
+
print "#{h['tokenName']} #{h['tokenID']} - "
|
210
|
+
print "from: #{h['from'][0..10]} "
|
211
|
+
print "to: #{h['to'][0..10]} - "
|
212
|
+
print "txid: #{h['hash'][0..8]}"
|
213
|
+
print "\n"
|
214
|
+
end
|
215
|
+
```
|
216
|
+
|
217
|
+
resulting in:
|
218
|
+
|
219
|
+
```
|
220
|
+
[0] 2022-12-15 16:31:35 UTC - Moonbirds 2934 - from: 0x8ae57a027 to: 0xdc3276739 - txid: 0xf049e32
|
221
|
+
[1] 2022-12-15 16:30:23 UTC - Moonbirds 9836 - from: 0x8bc110db7 to: 0x6ce2eb1c3 - txid: 0xb341b32
|
222
|
+
[2] 2022-12-15 16:30:23 UTC - Moonbirds 9378 - from: 0x8bc110db7 to: 0x6ce2eb1c3 - txid: 0xb341b32
|
223
|
+
[3] 2022-12-15 16:30:23 UTC - Moonbirds 9059 - from: 0x8bc110db7 to: 0x6ce2eb1c3 - txid: 0xb341b32
|
224
|
+
[4] 2022-12-15 16:30:23 UTC - Moonbirds 8199 - from: 0x8bc110db7 to: 0x6ce2eb1c3 - txid: 0xb341b32
|
225
|
+
[5] 2022-12-15 16:30:23 UTC - Moonbirds 7800 - from: 0x8bc110db7 to: 0x6ce2eb1c3 - txid: 0xb341b32
|
226
|
+
[6] 2022-12-15 16:30:23 UTC - Moonbirds 5952 - from: 0x8bc110db7 to: 0x6ce2eb1c3 - txid: 0xb341b32
|
227
|
+
[7] 2022-12-15 16:30:23 UTC - Moonbirds 5868 - from: 0x8bc110db7 to: 0x6ce2eb1c3 - txid: 0xb341b32
|
228
|
+
[8] 2022-12-15 16:30:23 UTC - Moonbirds 5853 - from: 0x8bc110db7 to: 0x6ce2eb1c3 - txid: 0xb341b32
|
229
|
+
[9] 2022-12-15 16:30:23 UTC - Moonbirds 501 - from: 0x8bc110db7 to: 0x6ce2eb1c3 - txid: 0xb341b32
|
230
|
+
```
|
231
|
+
|
232
|
+
|
233
|
+
|
234
|
+
### List ETH deposits to Arbitrum Bridge
|
235
|
+
|
236
|
+
see <https://docs.etherscan.io/recipes/list-eth-deposits-to-arbitrum-bridge>
|
237
|
+
|
238
|
+
|
239
|
+
``` ruby
|
240
|
+
require 'etherscan-lite'
|
241
|
+
|
242
|
+
ARBITRUM_DELAYED_INBOX = '0x4dbd4fc535ac27206064b68ffcf827b0a60bab3f'
|
243
|
+
|
244
|
+
data = Etherscan.txlist( address: ARBITRUM_DELAYED_INBOX )
|
245
|
+
pp data
|
246
|
+
```
|
247
|
+
|
248
|
+
resulting in:
|
249
|
+
|
250
|
+
|
251
|
+
``` json
|
252
|
+
[{"blockNumber"=>"16191330",
|
253
|
+
"timeStamp"=>"1671122219",
|
254
|
+
"hash"=>"0xea692b153ec048322dd6dc0a42fba45a0f06b2bd0e6888c7e42edbc629689f00",
|
255
|
+
"nonce"=>"998",
|
256
|
+
"blockHash"=>"0x3c3a23b78fd1522f9f9ed5a1fc45d5a7d1d71327961c77d164c0eeb1e72b4322",
|
257
|
+
"transactionIndex"=>"244",
|
258
|
+
"from"=>"0xae4705dc0816ee6d8a13f1c72780ec5021915fed",
|
259
|
+
"to"=>"0x4dbd4fc535ac27206064b68ffcf827b0a60bab3f",
|
260
|
+
"value"=>"420690000000000000",
|
261
|
+
"gas"=>"92219",
|
262
|
+
"gasPrice"=>"26218969764",
|
263
|
+
"isError"=>"0",
|
264
|
+
"txreceipt_status"=>"1",
|
265
|
+
"input"=>"0x439370b1",
|
266
|
+
"contractAddress"=>"",
|
267
|
+
"cumulativeGasUsed"=>"18496407",
|
268
|
+
"gasUsed"=>"91261",
|
269
|
+
"confirmations"=>"16",
|
270
|
+
"methodId"=>"0x439370b1",
|
271
|
+
"functionName"=>"depositEth()"},
|
272
|
+
{"blockNumber"=>"16191327",
|
273
|
+
"timeStamp"=>"1671122183",
|
274
|
+
"hash"=>"0x8a82fc0e7ac1fb588f1ee248810d518bc03dfb4e938160c6502f949fcc16054c",
|
275
|
+
"nonce"=>"2",
|
276
|
+
"blockHash"=>"0xb533b2cd157369414839c58b74319bf32400dd6521b5d945eb7ac405d0600203",
|
277
|
+
"transactionIndex"=>"78",
|
278
|
+
"from"=>"0x338b8d83e644689a0ea90f04e0efa144fccfb3c7",
|
279
|
+
"to"=>"0x4dbd4fc535ac27206064b68ffcf827b0a60bab3f",
|
280
|
+
"value"=>"19000000000000000",
|
281
|
+
"gas"=>"92219",
|
282
|
+
"gasPrice"=>"29492008048",
|
283
|
+
"isError"=>"0",
|
284
|
+
"txreceipt_status"=>"1",
|
285
|
+
"input"=>"0x439370b1",
|
286
|
+
"contractAddress"=>"",
|
287
|
+
"cumulativeGasUsed"=>"7020870",
|
288
|
+
"gasUsed"=>"91261",
|
289
|
+
"confirmations"=>"19",
|
290
|
+
"methodId"=>"0x439370b1",
|
291
|
+
"functionName"=>"depositEth()"},
|
292
|
+
...
|
293
|
+
]
|
294
|
+
```
|
295
|
+
|
296
|
+
and let's pretty print the data (records):
|
297
|
+
|
298
|
+
|
299
|
+
``` ruby
|
300
|
+
data.each_with_index do |h,i|
|
301
|
+
timestamp = Time.at( h['timeStamp'].to_i ).utc
|
302
|
+
|
303
|
+
## note: ether (ETH) uses 18 decimal
|
304
|
+
## e.g. 0.000000000000000001 (= 1 wei)
|
305
|
+
decimal = 18
|
306
|
+
value = h['value'].to_i
|
307
|
+
|
308
|
+
major = value / (10**decimal)
|
309
|
+
minor = value % (10**decimal)
|
310
|
+
|
311
|
+
print " [#{i}] #{timestamp} - "
|
312
|
+
print "#{h['functionName']} "
|
313
|
+
print "%3d.%0#{decimal}d" % [major, minor]
|
314
|
+
print " (#{value}) - "
|
315
|
+
print "from: #{h['from'][0..10]} "
|
316
|
+
print "to: #{h['to'][0..10]} - "
|
317
|
+
print "txid: #{h['hash'][0..8]}"
|
318
|
+
print "\n"
|
319
|
+
end
|
320
|
+
```
|
321
|
+
|
322
|
+
resulting in:
|
323
|
+
|
324
|
+
```
|
325
|
+
[0] 2022-12-15 16:36:59 UTC - depositEth() 0.420690000000000000 (420690000000000000) - from: 0xae4705dc0 to: 0x4dbd4fc53 - txid: 0xea692b1
|
326
|
+
[1] 2022-12-15 16:36:23 UTC - depositEth() 0.019000000000000000 (19000000000000000) - from: 0x338b8d83e to: 0x4dbd4fc53 - txid: 0x8a82fc0
|
327
|
+
[2] 2022-12-15 16:35:23 UTC - depositEth() 0.040000000000000000 (40000000000000000) - from: 0x63e1c7edc to: 0x4dbd4fc53 - txid: 0x46bc422
|
328
|
+
[3] 2022-12-15 16:34:23 UTC - depositEth() 0.003330000000000000 (3330000000000000) - from: 0xe29abe7f8 to: 0x4dbd4fc53 - txid: 0x2fbd49e
|
329
|
+
[4] 2022-12-15 16:34:23 UTC - depositEth() 0.022398548608559353 (22398548608559353) - from: 0x3dbcf6a3d to: 0x4dbd4fc53 - txid: 0xc311e3f
|
330
|
+
[5] 2022-12-15 16:32:23 UTC - depositEth() 0.195713000000000000 (195713000000000000) - from: 0xc7099c3ed to: 0x4dbd4fc53 - txid: 0x4a2f2e4
|
331
|
+
[6] 2022-12-15 16:31:23 UTC - depositEth() 0.100000000000000000 (100000000000000000) - from: 0x78cea29ac to: 0x4dbd4fc53 - txid: 0xedc3793
|
332
|
+
[7] 2022-12-15 16:28:35 UTC - depositEth() 2.406000000000000000 (2406000000000000000) - from: 0xa59192967 to: 0x4dbd4fc53 - txid: 0xde20917
|
333
|
+
[8] 2022-12-15 16:28:23 UTC - depositEth() 0.030000000000000000 (30000000000000000) - from: 0x03a64c941 to: 0x4dbd4fc53 - txid: 0xc813c01
|
334
|
+
[9] 2022-12-15 16:27:35 UTC - depositEth() 0.004000000000000000 (4000000000000000) - from: 0x614d071bf to: 0x4dbd4fc53 - txid: 0xb24df57
|
335
|
+
```
|
336
|
+
|
337
|
+
and so on.
|
338
|
+
|
339
|
+
|
340
|
+
|
341
|
+
|
342
|
+
|
343
|
+
|
344
|
+
## License
|
345
|
+
|
346
|
+
The scripts are dedicated to the public domain.
|
347
|
+
Use it as you please with no restrictions whatsoever.
|
348
|
+
|
349
|
+
|
350
|
+
## Questions? Comments?
|
351
|
+
|
352
|
+
|
353
|
+
Post them on the [D.I.Y. Punk (Pixel) Art reddit](https://old.reddit.com/r/DIYPunkArt). Thanks.
|
354
|
+
|
355
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'hoe'
|
2
|
+
require './lib/etherscan-lite/version.rb'
|
3
|
+
|
4
|
+
|
5
|
+
Hoe.spec 'etherscan-lite' do
|
6
|
+
|
7
|
+
self.version = EtherscanLite::VERSION
|
8
|
+
|
9
|
+
self.summary = "etherscan-lite - light-weight machinery / helper for the Etherscan (blockchain) JSON HTTP API / web services (note: API key sign-up required)"
|
10
|
+
self.description = summary
|
11
|
+
|
12
|
+
self.urls = { home: 'https://github.com/rubycocos/blockchain' }
|
13
|
+
|
14
|
+
self.author = 'Gerald Bauer'
|
15
|
+
self.email = 'wwwmake@googlegroups.com'
|
16
|
+
|
17
|
+
# switch extension to .markdown for gihub formatting
|
18
|
+
self.readme_file = 'README.md'
|
19
|
+
self.history_file = 'CHANGELOG.md'
|
20
|
+
|
21
|
+
self.extra_deps = [
|
22
|
+
['cocos'],
|
23
|
+
]
|
24
|
+
|
25
|
+
self.licenses = ['Public Domain']
|
26
|
+
|
27
|
+
self.spec_extras = {
|
28
|
+
required_ruby_version: '>= 2.3'
|
29
|
+
}
|
30
|
+
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Etherscan
|
2
|
+
|
3
|
+
## Get a list of 'Normal' Transactions By Address
|
4
|
+
## Returns the list of transactions performed by an address,
|
5
|
+
## with optional pagination.
|
6
|
+
## see https://docs.etherscan.io/api-endpoints/accounts#get-a-list-of-normal-transactions-by-address
|
7
|
+
def self.txlist_url( address:,
|
8
|
+
startblock: 0,
|
9
|
+
endblock: 99999999,
|
10
|
+
page: 1,
|
11
|
+
offset: 10,
|
12
|
+
sort: 'desc' )
|
13
|
+
|
14
|
+
src = "#{BASE}?module=account&action=txlist" +
|
15
|
+
"&address=#{address}" +
|
16
|
+
"&startblock=#{startblock}" +
|
17
|
+
"&endblock=#{endblock}" +
|
18
|
+
"&page=#{page}" +
|
19
|
+
"&offset=#{offset}" +
|
20
|
+
"&sort=#{sort}" +
|
21
|
+
"&apikey=#{config.key}"
|
22
|
+
src
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.txlist( **kwargs )
|
26
|
+
call( txlist_url( **kwargs ) )
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
## Get a list of 'ERC20 - Token Transfer Events' by Address
|
31
|
+
## Returns the list of ERC-20 tokens transferred by an address,
|
32
|
+
## with optional filtering by token contract.
|
33
|
+
## Usage:
|
34
|
+
## - ERC-20 transfers from an address, specify the address parameter
|
35
|
+
## - ERC-20 transfers from a contract address, specify the contract address parameter
|
36
|
+
## - ERC-20 transfers from an address filtered by a token contract, specify both address and contract address parameters.
|
37
|
+
##
|
38
|
+
## see https://docs.etherscan.io/api-endpoints/accounts#get-a-list-of-erc20-token-transfer-events-by-address
|
39
|
+
def self.tokentx_url( address: nil,
|
40
|
+
contractaddress: nil,
|
41
|
+
startblock: 0,
|
42
|
+
endblock: 99999999,
|
43
|
+
page: 1,
|
44
|
+
offset: 10,
|
45
|
+
sort: 'desc' )
|
46
|
+
|
47
|
+
src = "#{BASE}?module=account&action=tokentx" +
|
48
|
+
"&startblock=#{startblock}" +
|
49
|
+
"&endblock=#{endblock}" +
|
50
|
+
"&page=#{page}" +
|
51
|
+
"&offset=#{offset}" +
|
52
|
+
"&sort=#{sort}" +
|
53
|
+
"&apikey=#{config.key}"
|
54
|
+
|
55
|
+
## optional
|
56
|
+
src += "&address=#{address}" if address
|
57
|
+
src += "&contractaddress=#{contractaddress}" if contractaddress
|
58
|
+
src
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.tokentx( **kwargs )
|
62
|
+
call( tokentx_url( **kwargs ) )
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
## Get a list of 'ERC721 - Token Transfer Events' by Address
|
67
|
+
## Returns the list of ERC-721 ( NFT ) tokens transferred by an address,
|
68
|
+
## with optional filtering by token contract.
|
69
|
+
## Usage:
|
70
|
+
## - ERC-721 transfers from an address, specify the address parameter
|
71
|
+
## - ERC-721 transfers from a contract address, specify the contract address parameter
|
72
|
+
## - ERC-721 transfers from an address filtered by a token contract, specify both address and contract address parameters.
|
73
|
+
##
|
74
|
+
## see https://docs.etherscan.io/api-endpoints/accounts#get-a-list-of-erc721-token-transfer-events-by-address
|
75
|
+
def self.tokennfttx_url( address: nil,
|
76
|
+
contractaddress: nil,
|
77
|
+
startblock: 0,
|
78
|
+
endblock: 99999999,
|
79
|
+
page: 1,
|
80
|
+
offset: 10,
|
81
|
+
sort: 'desc' )
|
82
|
+
|
83
|
+
src = "#{BASE}?module=account&action=tokennfttx" +
|
84
|
+
"&startblock=#{startblock}" +
|
85
|
+
"&endblock=#{endblock}" +
|
86
|
+
"&page=#{page}" +
|
87
|
+
"&offset=#{offset}" +
|
88
|
+
"&sort=#{sort}" +
|
89
|
+
"&apikey=#{config.key}"
|
90
|
+
|
91
|
+
## optional
|
92
|
+
src += "&address=#{address}" if address
|
93
|
+
src += "&contractaddress=#{contractaddress}" if contractaddress
|
94
|
+
src
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.tokennfttx( **kwargs )
|
98
|
+
call( tokennfttx_url( **kwargs ) )
|
99
|
+
end
|
100
|
+
end # module Etherscan
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Etherscan
|
2
|
+
BASE = 'https://api.etherscan.io/api'
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
def self.call( src ) ## get response as (parsed) json (hash table)
|
8
|
+
uri = URI.parse( src )
|
9
|
+
|
10
|
+
http = Net::HTTP.new( uri.host, uri.port )
|
11
|
+
|
12
|
+
puts "[debug] GET #{uri.request_uri} uri=#{uri}"
|
13
|
+
|
14
|
+
headers = {
|
15
|
+
# 'User-Agent' => "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36",
|
16
|
+
'User-Agent' => "ruby v#{RUBY_VERSION}",
|
17
|
+
}
|
18
|
+
|
19
|
+
|
20
|
+
request = Net::HTTP::Get.new( uri.request_uri, headers )
|
21
|
+
if uri.instance_of? URI::HTTPS
|
22
|
+
http.use_ssl = true
|
23
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
24
|
+
end
|
25
|
+
|
26
|
+
response = http.request( request )
|
27
|
+
|
28
|
+
if response.code == '200'
|
29
|
+
puts "#{response.code} #{response.message} - content_type: #{response.content_type}, content_length: #{response.content_length}"
|
30
|
+
|
31
|
+
text = response.body.to_s
|
32
|
+
text = text.force_encoding( Encoding::UTF_8 )
|
33
|
+
|
34
|
+
data = JSON.parse( text )
|
35
|
+
data
|
36
|
+
|
37
|
+
## note: "unwrap" result - and auto-check status/message e.g.
|
38
|
+
## {"status"=>"1",
|
39
|
+
## "message"=>"OK",
|
40
|
+
## "result"=> ..
|
41
|
+
## }
|
42
|
+
if data['status'] == '1' && data['message'] == 'OK'
|
43
|
+
puts "#{data['status']} #{data['message']}"
|
44
|
+
data['result']
|
45
|
+
else
|
46
|
+
puts "!! ETHERSCAN API ERROR:"
|
47
|
+
puts "#{data['status']} #{data['message']}"
|
48
|
+
exit 1
|
49
|
+
end
|
50
|
+
else
|
51
|
+
puts "!! ERROR:"
|
52
|
+
puts "#{response.code} #{response.message}"
|
53
|
+
exit 1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end # module Etherscan
|
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module EtherscanLite
|
4
|
+
MAJOR = 0
|
5
|
+
MINOR = 0
|
6
|
+
PATCH = 1
|
7
|
+
VERSION = [MAJOR,MINOR,PATCH].join('.')
|
8
|
+
|
9
|
+
def self.version
|
10
|
+
VERSION
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.banner
|
14
|
+
"etherscan-lite/#{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}] in (#{root})"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.root
|
18
|
+
File.expand_path( File.dirname(File.dirname(File.dirname(__FILE__))) )
|
19
|
+
end
|
20
|
+
|
21
|
+
end # module EtherscanLite
|
22
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'cocos'
|
2
|
+
|
3
|
+
|
4
|
+
### todo/fix:
|
5
|
+
## move .env loader to
|
6
|
+
## cocos - why? why not?
|
7
|
+
def load_env( path='./.env' )
|
8
|
+
if File.exist?( path )
|
9
|
+
puts "==> loading .env settings..."
|
10
|
+
env = read_yaml( path )
|
11
|
+
puts " applying .env settings... (merging into ENV)"
|
12
|
+
pp env
|
13
|
+
env.each do |k,v|
|
14
|
+
ENV[k] ||= v
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
load_env
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
## our own code
|
24
|
+
require_relative 'etherscan-lite/version'
|
25
|
+
|
26
|
+
### add (shared) "global" config
|
27
|
+
module Etherscan
|
28
|
+
class Configuration
|
29
|
+
|
30
|
+
#######################
|
31
|
+
## accessors
|
32
|
+
## todo/check - change to apikey or api_key or such - why? why not?
|
33
|
+
def key() @key ||= ENV['ETHERSCAN_KEY']; end
|
34
|
+
def key=(value) @key = value; end
|
35
|
+
end # class Configuration
|
36
|
+
|
37
|
+
|
38
|
+
## lets you use
|
39
|
+
## Ethersan.configure do |config|
|
40
|
+
## config.key = 'xxxx'
|
41
|
+
## end
|
42
|
+
def self.configure() yield( config ); end
|
43
|
+
def self.config() @config ||= Configuration.new; end
|
44
|
+
end # module Etherscan
|
45
|
+
|
46
|
+
|
47
|
+
require_relative 'etherscan-lite/base'
|
48
|
+
require_relative 'etherscan-lite/account'
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
puts EtherscanLite.banner # say hello
|
53
|
+
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: etherscan-lite
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gerald Bauer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-12-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: cocos
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rdoc
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.0'
|
34
|
+
- - "<"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '7'
|
37
|
+
type: :development
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '4.0'
|
44
|
+
- - "<"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '7'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: hoe
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '3.23'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '3.23'
|
61
|
+
description: 'etherscan-lite - light-weight machinery / helper for the Etherscan (blockchain)
|
62
|
+
JSON HTTP API / web services (note: API key sign-up required)'
|
63
|
+
email: wwwmake@googlegroups.com
|
64
|
+
executables: []
|
65
|
+
extensions: []
|
66
|
+
extra_rdoc_files:
|
67
|
+
- CHANGELOG.md
|
68
|
+
- Manifest.txt
|
69
|
+
- README.md
|
70
|
+
files:
|
71
|
+
- CHANGELOG.md
|
72
|
+
- Manifest.txt
|
73
|
+
- README.md
|
74
|
+
- Rakefile
|
75
|
+
- lib/etherscan-lite.rb
|
76
|
+
- lib/etherscan-lite/account.rb
|
77
|
+
- lib/etherscan-lite/base.rb
|
78
|
+
- lib/etherscan-lite/version.rb
|
79
|
+
homepage: https://github.com/rubycocos/blockchain
|
80
|
+
licenses:
|
81
|
+
- Public Domain
|
82
|
+
metadata: {}
|
83
|
+
post_install_message:
|
84
|
+
rdoc_options:
|
85
|
+
- "--main"
|
86
|
+
- README.md
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '2.3'
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
requirements: []
|
100
|
+
rubygems_version: 3.3.7
|
101
|
+
signing_key:
|
102
|
+
specification_version: 4
|
103
|
+
summary: 'etherscan-lite - light-weight machinery / helper for the Etherscan (blockchain)
|
104
|
+
JSON HTTP API / web services (note: API key sign-up required)'
|
105
|
+
test_files: []
|