etherscan-lite 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,3 @@
1
+ ### 0.0.1 / 2022-12-15
2
+
3
+ * Everything is new. First release
data/Manifest.txt ADDED
@@ -0,0 +1,8 @@
1
+ CHANGELOG.md
2
+ Manifest.txt
3
+ README.md
4
+ Rakefile
5
+ lib/etherscan-lite.rb
6
+ lib/etherscan-lite/account.rb
7
+ lib/etherscan-lite/base.rb
8
+ lib/etherscan-lite/version.rb
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: []