etherscan-lite 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|