erc20 0.1.0 → 0.1.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 +4 -4
- data/.gitignore +5 -5
- data/.rultor.yml +1 -1
- data/Gemfile +10 -11
- data/Gemfile.lock +44 -153
- data/README.md +12 -12
- data/REUSE.toml +11 -1
- data/bin/erc20 +2 -2
- data/erc20.gemspec +2 -2
- data/lib/erc20/erc20.rb +3 -3
- data/lib/erc20/fake_wallet.rb +6 -3
- data/lib/erc20/wallet.rb +34 -17
- data/test/erc20/test_fake_wallet.rb +1 -1
- data/test/erc20/test_wallet.rb +12 -11
- data/test/test__helper.rb +1 -1
- metadata +5 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fbce7bc57948f9c8acfeec7c0af2cf67e70e2447e064040485e6868d466828dc
|
4
|
+
data.tar.gz: cc521c55db79dca85e58235c886172a7ca81cf0f59ee61f5c134cc888eb3db4c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c712231ba46caabca78b45e9be366c120e2f5275bc734c874f69c7306d1f961c7b7c3a5b8ae58341cb4d48776a91c5a8bc8ec2360dfcbc294d46ae329d9bf8a4
|
7
|
+
data.tar.gz: 7a074720cfec0773a6e4e0cc70fe07fde201ae9897cb395a2b91a84429683354b822bef0be10650290b554ffe59b150034a1ea320eed34a396d574267954c130
|
data/.gitignore
CHANGED
data/.rultor.yml
CHANGED
data/Gemfile
CHANGED
@@ -7,24 +7,23 @@ source 'https://rubygems.org'
|
|
7
7
|
gemspec
|
8
8
|
|
9
9
|
gem 'backtrace', '>0', require: false
|
10
|
-
gem 'cucumber', '9.
|
10
|
+
gem 'cucumber', '~>9.2', require: false
|
11
11
|
gem 'donce', '>0', require: false
|
12
12
|
gem 'faraday', '>0', require: false
|
13
13
|
gem 'loog', '>0', require: false
|
14
|
-
gem 'minitest', '5.25
|
15
|
-
gem 'minitest-reporters', '1.7
|
16
|
-
gem 'minitest-retry', '0.2
|
14
|
+
gem 'minitest', '~>5.25', require: false
|
15
|
+
gem 'minitest-reporters', '~>1.7', require: false
|
16
|
+
gem 'minitest-retry', '~>0.2', require: false
|
17
17
|
gem 'qbash', '>0', require: false
|
18
|
-
gem 'rake', '13.2
|
18
|
+
gem 'rake', '~>13.2', require: false
|
19
19
|
gem 'random-port', '>0', require: false
|
20
|
-
gem '
|
21
|
-
gem 'rubocop', '1.72.2', require: false
|
20
|
+
gem 'rubocop', '~>1.75', require: false
|
22
21
|
gem 'rubocop-minitest', '>0', require: false
|
23
22
|
gem 'rubocop-performance', '>0', require: false
|
24
23
|
gem 'rubocop-rake', '>0', require: false
|
25
24
|
gem 'rubocop-rspec', '>0', require: false
|
26
|
-
gem 'simplecov', '0.22
|
27
|
-
gem 'simplecov-cobertura', '2.1
|
28
|
-
gem 'threads', '0.4
|
25
|
+
gem 'simplecov', '~>0.22', require: false
|
26
|
+
gem 'simplecov-cobertura', '~>2.1', require: false
|
27
|
+
gem 'threads', '~>0.4', require: false
|
29
28
|
gem 'typhoeus', '>0', require: false
|
30
|
-
gem 'yard', '0.9
|
29
|
+
gem 'yard', '~>0.9', require: false
|
data/Gemfile.lock
CHANGED
@@ -12,82 +12,47 @@ PATH
|
|
12
12
|
GEM
|
13
13
|
remote: https://rubygems.org/
|
14
14
|
specs:
|
15
|
-
actionpack (8.0.1)
|
16
|
-
actionview (= 8.0.1)
|
17
|
-
activesupport (= 8.0.1)
|
18
|
-
nokogiri (>= 1.8.5)
|
19
|
-
rack (>= 2.2.4)
|
20
|
-
rack-session (>= 1.0.1)
|
21
|
-
rack-test (>= 0.6.3)
|
22
|
-
rails-dom-testing (~> 2.2)
|
23
|
-
rails-html-sanitizer (~> 1.6)
|
24
|
-
useragent (~> 0.16)
|
25
|
-
actionview (8.0.1)
|
26
|
-
activesupport (= 8.0.1)
|
27
|
-
builder (~> 3.1)
|
28
|
-
erubi (~> 1.11)
|
29
|
-
rails-dom-testing (~> 2.2)
|
30
|
-
rails-html-sanitizer (~> 1.6)
|
31
|
-
activesupport (8.0.1)
|
32
|
-
base64
|
33
|
-
benchmark (>= 0.3)
|
34
|
-
bigdecimal
|
35
|
-
concurrent-ruby (~> 1.0, >= 1.3.1)
|
36
|
-
connection_pool (>= 2.2.5)
|
37
|
-
drb
|
38
|
-
i18n (>= 1.6, < 2)
|
39
|
-
logger (>= 1.4.2)
|
40
|
-
minitest (>= 5.1)
|
41
|
-
securerandom (>= 0.3)
|
42
|
-
tzinfo (~> 2.0, >= 2.0.5)
|
43
|
-
uri (>= 0.13.1)
|
44
15
|
ansi (1.5.0)
|
45
|
-
ast (2.4.
|
16
|
+
ast (2.4.3)
|
46
17
|
backtrace (0.4.0)
|
47
18
|
base64 (0.2.0)
|
48
|
-
benchmark (0.4.0)
|
49
19
|
bigdecimal (3.1.9)
|
50
20
|
builder (3.3.0)
|
51
21
|
concurrent-ruby (1.3.5)
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
cucumber-ci-environment (~> 9.2, >= 9.2.0)
|
57
|
-
cucumber-core (~> 12.0)
|
22
|
+
cucumber (9.2.1)
|
23
|
+
builder (~> 3.2)
|
24
|
+
cucumber-ci-environment (> 9, < 11)
|
25
|
+
cucumber-core (> 13, < 14)
|
58
26
|
cucumber-cucumber-expressions (~> 17.0)
|
59
|
-
cucumber-gherkin (> 24, <
|
27
|
+
cucumber-gherkin (> 24, < 28)
|
60
28
|
cucumber-html-formatter (> 20.3, < 22)
|
61
29
|
cucumber-messages (> 19, < 25)
|
62
30
|
diff-lcs (~> 1.5)
|
63
|
-
mini_mime (~> 1.1
|
64
|
-
multi_test (~> 1.1
|
65
|
-
sys-uname (~> 1.2
|
66
|
-
cucumber-ci-environment (
|
67
|
-
cucumber-core (
|
68
|
-
cucumber-gherkin (>=
|
31
|
+
mini_mime (~> 1.1)
|
32
|
+
multi_test (~> 1.1)
|
33
|
+
sys-uname (~> 1.2)
|
34
|
+
cucumber-ci-environment (10.0.1)
|
35
|
+
cucumber-core (13.0.3)
|
36
|
+
cucumber-gherkin (>= 27, < 28)
|
69
37
|
cucumber-messages (>= 20, < 23)
|
70
|
-
cucumber-tag-expressions (
|
38
|
+
cucumber-tag-expressions (> 5, < 7)
|
71
39
|
cucumber-cucumber-expressions (17.1.0)
|
72
40
|
bigdecimal
|
73
|
-
cucumber-gherkin (
|
74
|
-
cucumber-messages (>= 19.1.4, <
|
41
|
+
cucumber-gherkin (27.0.0)
|
42
|
+
cucumber-messages (>= 19.1.4, < 23)
|
75
43
|
cucumber-html-formatter (21.9.0)
|
76
44
|
cucumber-messages (> 19, < 28)
|
77
45
|
cucumber-messages (22.0.0)
|
78
|
-
cucumber-tag-expressions (
|
79
|
-
|
80
|
-
diff-lcs (1.6.0)
|
46
|
+
cucumber-tag-expressions (6.1.2)
|
47
|
+
diff-lcs (1.6.1)
|
81
48
|
docile (1.4.1)
|
82
49
|
donce (0.1.0)
|
83
50
|
backtrace (> 0)
|
84
51
|
os (> 0)
|
85
52
|
qbash (> 0)
|
86
|
-
drb (2.2.1)
|
87
53
|
elapsed (0.0.1)
|
88
54
|
loog (> 0)
|
89
55
|
tago (> 0)
|
90
|
-
erubi (1.13.1)
|
91
56
|
eth (0.5.13)
|
92
57
|
forwardable (~> 1.3)
|
93
58
|
keccak (~> 1.3)
|
@@ -115,14 +80,7 @@ GEM
|
|
115
80
|
ffi (>= 1.15.5)
|
116
81
|
rake
|
117
82
|
forwardable (1.3.3)
|
118
|
-
|
119
|
-
concurrent-ruby (~> 1.0)
|
120
|
-
io-console (0.8.0)
|
121
|
-
irb (1.15.1)
|
122
|
-
pp (>= 0.6.0)
|
123
|
-
rdoc (>= 4.0.0)
|
124
|
-
reline (>= 0.4.2)
|
125
|
-
json (2.10.1)
|
83
|
+
json (2.10.2)
|
126
84
|
jsonrpc-client (0.1.4)
|
127
85
|
faraday
|
128
86
|
multi_json (>= 1.1.0)
|
@@ -130,14 +88,11 @@ GEM
|
|
130
88
|
konstructor (1.0.2)
|
131
89
|
language_server-protocol (3.17.0.4)
|
132
90
|
lint_roller (1.1.0)
|
133
|
-
logger (1.
|
134
|
-
loofah (2.24.0)
|
135
|
-
crass (~> 1.0.2)
|
136
|
-
nokogiri (>= 1.12.0)
|
91
|
+
logger (1.7.0)
|
137
92
|
loog (0.6.0)
|
138
93
|
mini_mime (1.1.5)
|
139
94
|
mini_portile2 (2.8.8)
|
140
|
-
minitest (5.25.
|
95
|
+
minitest (5.25.5)
|
141
96
|
minitest-reporters (1.7.1)
|
142
97
|
ansi
|
143
98
|
builder
|
@@ -149,56 +104,20 @@ GEM
|
|
149
104
|
multi_test (1.1.0)
|
150
105
|
net-http (0.6.0)
|
151
106
|
uri
|
152
|
-
nokogiri (1.18.3-arm64-darwin)
|
153
|
-
racc (~> 1.4)
|
154
|
-
nokogiri (1.18.3-x64-mingw-ucrt)
|
155
|
-
racc (~> 1.4)
|
156
|
-
nokogiri (1.18.3-x86_64-darwin)
|
157
|
-
racc (~> 1.4)
|
158
|
-
nokogiri (1.18.3-x86_64-linux-gnu)
|
159
|
-
racc (~> 1.4)
|
160
107
|
openssl (3.3.0)
|
161
108
|
os (1.1.4)
|
162
109
|
parallel (1.26.3)
|
163
|
-
parser (3.3.7.
|
110
|
+
parser (3.3.7.4)
|
164
111
|
ast (~> 2.4.1)
|
165
112
|
racc
|
166
|
-
pkg-config (1.
|
167
|
-
|
168
|
-
prettyprint
|
169
|
-
prettyprint (0.2.0)
|
170
|
-
psych (5.2.3)
|
171
|
-
date
|
172
|
-
stringio
|
113
|
+
pkg-config (1.6.0)
|
114
|
+
prism (1.4.0)
|
173
115
|
qbash (0.4.0)
|
174
116
|
backtrace (> 0)
|
175
117
|
elapsed (> 0)
|
176
118
|
loog (> 0)
|
177
119
|
tago (> 0)
|
178
120
|
racc (1.8.1)
|
179
|
-
rack (3.1.10)
|
180
|
-
rack-session (2.1.0)
|
181
|
-
base64 (>= 0.1.0)
|
182
|
-
rack (>= 3.0.0)
|
183
|
-
rack-test (2.2.0)
|
184
|
-
rack (>= 1.3)
|
185
|
-
rackup (2.2.1)
|
186
|
-
rack (>= 3)
|
187
|
-
rails-dom-testing (2.2.0)
|
188
|
-
activesupport (>= 5.0.0)
|
189
|
-
minitest
|
190
|
-
nokogiri (>= 1.6)
|
191
|
-
rails-html-sanitizer (1.6.2)
|
192
|
-
loofah (~> 2.21)
|
193
|
-
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
194
|
-
railties (8.0.1)
|
195
|
-
actionpack (= 8.0.1)
|
196
|
-
activesupport (= 8.0.1)
|
197
|
-
irb (~> 1.13)
|
198
|
-
rackup (>= 1.0.0)
|
199
|
-
rake (>= 12.2)
|
200
|
-
thor (~> 1.0, >= 1.2.2)
|
201
|
-
zeitwerk (~> 2.6)
|
202
121
|
rainbow (3.1.1)
|
203
122
|
rake (13.2.1)
|
204
123
|
random-port (0.7.5)
|
@@ -207,30 +126,9 @@ GEM
|
|
207
126
|
mini_portile2 (~> 2.8)
|
208
127
|
pkg-config (~> 1.5)
|
209
128
|
rubyzip (~> 2.3)
|
210
|
-
rdoc (6.12.0)
|
211
|
-
psych (>= 4.0.0)
|
212
129
|
regexp_parser (2.10.0)
|
213
|
-
reline (0.6.0)
|
214
|
-
io-console (~> 0.5)
|
215
130
|
rexml (3.4.1)
|
216
|
-
|
217
|
-
rspec-support (~> 3.13.0)
|
218
|
-
rspec-expectations (3.13.3)
|
219
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
220
|
-
rspec-support (~> 3.13.0)
|
221
|
-
rspec-mocks (3.13.2)
|
222
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
223
|
-
rspec-support (~> 3.13.0)
|
224
|
-
rspec-rails (7.1.1)
|
225
|
-
actionpack (>= 7.0)
|
226
|
-
activesupport (>= 7.0)
|
227
|
-
railties (>= 7.0)
|
228
|
-
rspec-core (~> 3.13)
|
229
|
-
rspec-expectations (~> 3.13)
|
230
|
-
rspec-mocks (~> 3.13)
|
231
|
-
rspec-support (~> 3.13)
|
232
|
-
rspec-support (3.13.2)
|
233
|
-
rubocop (1.72.2)
|
131
|
+
rubocop (1.75.2)
|
234
132
|
json (~> 2.3)
|
235
133
|
language_server-protocol (~> 3.17.0.2)
|
236
134
|
lint_roller (~> 1.1.0)
|
@@ -238,18 +136,19 @@ GEM
|
|
238
136
|
parser (>= 3.3.0.2)
|
239
137
|
rainbow (>= 2.2.2, < 4.0)
|
240
138
|
regexp_parser (>= 2.9.3, < 3.0)
|
241
|
-
rubocop-ast (>= 1.
|
139
|
+
rubocop-ast (>= 1.44.0, < 2.0)
|
242
140
|
ruby-progressbar (~> 1.7)
|
243
141
|
unicode-display_width (>= 2.4.0, < 4.0)
|
244
|
-
rubocop-ast (1.
|
245
|
-
parser (>= 3.3.
|
246
|
-
|
142
|
+
rubocop-ast (1.44.0)
|
143
|
+
parser (>= 3.3.7.2)
|
144
|
+
prism (~> 1.4)
|
145
|
+
rubocop-minitest (0.38.0)
|
247
146
|
lint_roller (~> 1.1)
|
248
|
-
rubocop (>= 1.
|
147
|
+
rubocop (>= 1.75.0, < 2.0)
|
249
148
|
rubocop-ast (>= 1.38.0, < 2.0)
|
250
|
-
rubocop-performance (1.
|
149
|
+
rubocop-performance (1.25.0)
|
251
150
|
lint_roller (~> 1.1)
|
252
|
-
rubocop (>= 1.
|
151
|
+
rubocop (>= 1.75.0, < 2.0)
|
253
152
|
rubocop-ast (>= 1.38.0, < 2.0)
|
254
153
|
rubocop-rake (0.7.1)
|
255
154
|
lint_roller (~> 1.1)
|
@@ -262,7 +161,6 @@ GEM
|
|
262
161
|
scrypt (3.0.8)
|
263
162
|
ffi-compiler (>= 1.0, < 2.0)
|
264
163
|
rake (>= 9, < 14)
|
265
|
-
securerandom (0.4.1)
|
266
164
|
simplecov (0.22.0)
|
267
165
|
docile (~> 1.1)
|
268
166
|
simplecov-html (~> 0.11)
|
@@ -273,29 +171,23 @@ GEM
|
|
273
171
|
simplecov-html (0.13.1)
|
274
172
|
simplecov_json_formatter (0.1.4)
|
275
173
|
slop (4.10.1)
|
276
|
-
stringio (3.1.5)
|
277
174
|
sys-uname (1.3.1)
|
278
175
|
ffi (~> 1.1)
|
279
|
-
tago (0.0
|
280
|
-
thor (1.3.2)
|
176
|
+
tago (0.1.0)
|
281
177
|
threads (0.4.1)
|
282
178
|
backtrace (~> 0)
|
283
179
|
concurrent-ruby (~> 1.0)
|
284
180
|
typhoeus (1.4.1)
|
285
181
|
ethon (>= 0.9.0)
|
286
|
-
tzinfo (2.0.6)
|
287
|
-
concurrent-ruby (~> 1.0)
|
288
182
|
unicode-display_width (3.1.4)
|
289
183
|
unicode-emoji (~> 4.0, >= 4.0.4)
|
290
184
|
unicode-emoji (4.0.4)
|
291
|
-
uri (1.0.
|
292
|
-
useragent (0.16.11)
|
185
|
+
uri (1.0.3)
|
293
186
|
websocket-driver (0.7.7)
|
294
187
|
base64
|
295
188
|
websocket-extensions (>= 0.1.0)
|
296
189
|
websocket-extensions (0.1.5)
|
297
190
|
yard (0.9.37)
|
298
|
-
zeitwerk (2.7.2)
|
299
191
|
|
300
192
|
PLATFORMS
|
301
193
|
arm64-darwin-22
|
@@ -308,28 +200,27 @@ PLATFORMS
|
|
308
200
|
|
309
201
|
DEPENDENCIES
|
310
202
|
backtrace (> 0)
|
311
|
-
cucumber (
|
203
|
+
cucumber (~> 9.2)
|
312
204
|
donce (> 0)
|
313
205
|
erc20!
|
314
206
|
faraday (> 0)
|
315
207
|
loog (> 0)
|
316
|
-
minitest (
|
317
|
-
minitest-reporters (
|
318
|
-
minitest-retry (
|
208
|
+
minitest (~> 5.25)
|
209
|
+
minitest-reporters (~> 1.7)
|
210
|
+
minitest-retry (~> 0.2)
|
319
211
|
qbash (> 0)
|
320
|
-
rake (
|
212
|
+
rake (~> 13.2)
|
321
213
|
random-port (> 0)
|
322
|
-
|
323
|
-
rubocop (= 1.72.2)
|
214
|
+
rubocop (~> 1.75)
|
324
215
|
rubocop-minitest (> 0)
|
325
216
|
rubocop-performance (> 0)
|
326
217
|
rubocop-rake (> 0)
|
327
218
|
rubocop-rspec (> 0)
|
328
|
-
simplecov (
|
329
|
-
simplecov-cobertura (
|
330
|
-
threads (
|
219
|
+
simplecov (~> 0.22)
|
220
|
+
simplecov-cobertura (~> 2.1)
|
221
|
+
threads (~> 0.4)
|
331
222
|
typhoeus (> 0)
|
332
|
-
yard (
|
223
|
+
yard (~> 0.9)
|
333
224
|
|
334
225
|
BUNDLED WITH
|
335
226
|
2.5.16
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# Ethereum ERC20 Manipulations in Ruby
|
2
2
|
|
3
3
|
[](http://www.rultor.com/p/yegor256/erc20)
|
4
4
|
[](https://www.jetbrains.com/ruby/)
|
@@ -12,9 +12,9 @@
|
|
12
12
|
[](https://github.com/yegor256/erc20/blob/master/LICENSE.txt)
|
13
13
|
|
14
14
|
This small Ruby [gem](https://rubygems.org/gems/erc20)
|
15
|
-
makes manipulations with [
|
16
|
-
as simple as
|
17
|
-
[JSON-RPC] and [WebSockets]
|
15
|
+
makes manipulations with [Ethereum] [ERC20] tokens
|
16
|
+
as simple as possible, when you have a provider of
|
17
|
+
[JSON-RPC] and [WebSockets] Ethereum APIs, such as
|
18
18
|
[Infura], [GetBlock], or [Alchemy]:
|
19
19
|
|
20
20
|
```ruby
|
@@ -44,10 +44,10 @@ w.accept(addresses) do |event|
|
|
44
44
|
end
|
45
45
|
```
|
46
46
|
|
47
|
-
|
47
|
+
You can also check ETH balance and send ETH transactions:
|
48
48
|
|
49
49
|
```ruby
|
50
|
-
# Check how many ETHs are
|
50
|
+
# Check how many ETHs are on the given address:
|
51
51
|
eth = w.eth_balance(address)
|
52
52
|
|
53
53
|
# Send a few ETHs to someone and get transaction hash:
|
@@ -91,7 +91,7 @@ w = ERC20::Wallet.new(
|
|
91
91
|
You can use [squid-proxy] [Docker] image to set up your own [HTTP proxy] server.
|
92
92
|
|
93
93
|
Of course, this library works with [Polygon], [Optimism],
|
94
|
-
and other
|
94
|
+
and other EVM compatible blockchains.
|
95
95
|
|
96
96
|
## How to use in command line
|
97
97
|
|
@@ -110,13 +110,13 @@ Then, run it:
|
|
110
110
|
erc20 --help
|
111
111
|
```
|
112
112
|
|
113
|
-
|
113
|
+
Usage should be straightforward. If you have questions, please submit an issue.
|
114
114
|
|
115
115
|
## How to use in tests
|
116
116
|
|
117
|
-
You can use `ERC20::FakeWallet` class that behaves exactly like
|
117
|
+
You can use the `ERC20::FakeWallet` class that behaves exactly like
|
118
118
|
`ERC20::Wallet`, but doesn't make any network connections to the provider.
|
119
|
-
|
119
|
+
Additionally, it records all requests sent to it:
|
120
120
|
|
121
121
|
```ruby
|
122
122
|
require 'erc20'
|
@@ -129,7 +129,7 @@ assert w.history.include?({ method: :pay, priv:, address:, amount: 42_000 })
|
|
129
129
|
|
130
130
|
Read
|
131
131
|
[these guidelines](https://www.yegor256.com/2014/04/15/github-guidelines.html).
|
132
|
-
Make sure
|
132
|
+
Make sure your build is green before you contribute
|
133
133
|
your pull request. You will need to have
|
134
134
|
[Ruby](https://www.ruby-lang.org/en/) 3.2+ and
|
135
135
|
[Bundler](https://bundler.io/) installed. Then:
|
@@ -142,7 +142,7 @@ bundle exec rake
|
|
142
142
|
If it's clean and you don't see any error messages, submit your pull request.
|
143
143
|
|
144
144
|
[gem]: https://github.com/rubygems/rubygems
|
145
|
-
[
|
145
|
+
[Ethereum]: https://en.wikipedia.org/wiki/Ethereum
|
146
146
|
[ERC20]: https://ethereum.org/en/developers/docs/standards/tokens/erc-20/
|
147
147
|
[JSON-RPC]: https://ethereum.org/en/developers/docs/apis/json-rpc/
|
148
148
|
[Websockets]: https://ethereum.org/en/developers/tutorials/using-websockets/
|
data/REUSE.toml
CHANGED
@@ -4,6 +4,10 @@
|
|
4
4
|
version = 1
|
5
5
|
[[annotations]]
|
6
6
|
path = [
|
7
|
+
"**.json",
|
8
|
+
"**.md",
|
9
|
+
"**.png",
|
10
|
+
"**.txt",
|
7
11
|
"**/*.csv",
|
8
12
|
"**/*.jpg",
|
9
13
|
"**/*.json",
|
@@ -13,13 +17,19 @@ path = [
|
|
13
17
|
"**/*.svg",
|
14
18
|
"**/*.txt",
|
15
19
|
"**/*.vm",
|
20
|
+
"**/.DS_Store",
|
16
21
|
"**/.gitignore",
|
22
|
+
"**/.gitleaksignore",
|
23
|
+
"**/.pdd",
|
17
24
|
"**/CNAME",
|
25
|
+
"**/Cargo.toml",
|
26
|
+
"**/Gemfile.lock",
|
27
|
+
".DS_Store",
|
18
28
|
".gitattributes",
|
19
29
|
".gitignore",
|
20
30
|
".gitleaksignore",
|
21
31
|
".pdd",
|
22
|
-
".
|
32
|
+
"Cargo.toml",
|
23
33
|
"Gemfile.lock",
|
24
34
|
"README.md",
|
25
35
|
"hardhat/.gitignore",
|
data/bin/erc20
CHANGED
@@ -18,7 +18,7 @@ begin
|
|
18
18
|
opts = Slop.parse(ARGV, strict: true, help: true) do |o|
|
19
19
|
o.banner = "Usage (#{ERC20::VERSION}): erc20 [options] command [args]
|
20
20
|
Commands are:
|
21
|
-
key: Generate a new
|
21
|
+
key: Generate a new Ethereum private key (64 symbols)
|
22
22
|
address: Turn private key into a public address (44 symbols)
|
23
23
|
price: Get current price of one gas unit, in gwei
|
24
24
|
pay: Send ERC20 payment
|
@@ -33,7 +33,7 @@ Options are:"
|
|
33
33
|
)
|
34
34
|
o.integer(
|
35
35
|
'--chain',
|
36
|
-
'
|
36
|
+
'Ethereum chain ID',
|
37
37
|
default: 1
|
38
38
|
)
|
39
39
|
o.string(
|
data/erc20.gemspec
CHANGED
@@ -12,12 +12,12 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.name = 'erc20'
|
13
13
|
s.version = ERC20::VERSION
|
14
14
|
s.license = 'MIT'
|
15
|
-
s.summary = 'Sending and receiving ERC20 tokens in
|
15
|
+
s.summary = 'Sending and receiving ERC20 tokens in Ethereum network'
|
16
16
|
s.description =
|
17
17
|
'A simple library for making ERC20 manipulations as easy as they ' \
|
18
18
|
'can be for cryptocurrency newbies: checking balance, sending payments, ' \
|
19
19
|
'and monitoring addresses for incoming payments. The library expects ' \
|
20
|
-
'
|
20
|
+
'Ethereum node to provide JSON RPC and Websockets API.'
|
21
21
|
s.authors = ['Yegor Bugayenko']
|
22
22
|
s.email = 'yegor256@gmail.com'
|
23
23
|
s.homepage = 'http://github.com/yegor256/erc20.rb'
|
data/lib/erc20/erc20.rb
CHANGED
@@ -3,9 +3,9 @@
|
|
3
3
|
# SPDX-FileCopyrightText: Copyright (c) 2025 Yegor Bugayenko
|
4
4
|
# SPDX-License-Identifier: MIT
|
5
5
|
|
6
|
-
# This module makes manipulations with
|
6
|
+
# This module makes manipulations with Ethereum ERC20 tokens
|
7
7
|
# as simple as they can be, if you have a provider of
|
8
|
-
# JSON-RPC and WebSockets
|
8
|
+
# JSON-RPC and WebSockets Ethereum APIs, for example
|
9
9
|
# Infura, GetBlock, or Alchemy.
|
10
10
|
#
|
11
11
|
# Start like this:
|
@@ -25,5 +25,5 @@
|
|
25
25
|
# License:: MIT
|
26
26
|
module ERC20
|
27
27
|
# Current version of the gem (changed by the +.rultor.yml+ on every release)
|
28
|
-
VERSION = '0.1.
|
28
|
+
VERSION = '0.1.1'
|
29
29
|
end
|
data/lib/erc20/fake_wallet.rb
CHANGED
@@ -91,9 +91,11 @@ class ERC20::FakeWallet
|
|
91
91
|
|
92
92
|
# Send a single ERC20 payment from a private address to a public one.
|
93
93
|
#
|
94
|
-
# @param [String]
|
95
|
-
# @param [String]
|
96
|
-
# @param [Integer]
|
94
|
+
# @param [String] priv Private key, in hex
|
95
|
+
# @param [String] address Public key, in hex
|
96
|
+
# @param [Integer] amount The amount of ERC20 tokens to send
|
97
|
+
# @param [Integer] gas_limit Optional gas limit
|
98
|
+
# @param [Integer] gas_price Optional gas price in gwei
|
97
99
|
# @return [String] Transaction hash
|
98
100
|
def pay(priv, address, amount, gas_limit: nil, gas_price: nil)
|
99
101
|
hex = TXN_HASH
|
@@ -106,6 +108,7 @@ class ERC20::FakeWallet
|
|
106
108
|
# @param [String] priv Private key, in hex
|
107
109
|
# @param [String] address Public key, in hex
|
108
110
|
# @param [Integer] amount The amount of ETHs to send
|
111
|
+
# @param [Integer] gas_price Optional gas price in gwei
|
109
112
|
# @return [String] Transaction hash
|
110
113
|
def eth_pay(priv, address, amount, gas_price: nil)
|
111
114
|
hex = TXN_HASH
|
data/lib/erc20/wallet.rb
CHANGED
@@ -12,7 +12,7 @@ require 'loog'
|
|
12
12
|
require 'uri'
|
13
13
|
require_relative 'erc20'
|
14
14
|
|
15
|
-
# A wallet with ERC20 tokens on
|
15
|
+
# A wallet with ERC20 tokens on Ethereum.
|
16
16
|
#
|
17
17
|
# Objects of this class are thread-safe.
|
18
18
|
#
|
@@ -64,7 +64,7 @@ class ERC20::Wallet
|
|
64
64
|
attr_reader :host, :port, :ssl, :chain, :contract, :ws_path, :http_path
|
65
65
|
|
66
66
|
# Constructor.
|
67
|
-
# @param [String] contract Hex of the contract in
|
67
|
+
# @param [String] contract Hex of the contract in Ethereum
|
68
68
|
# @param [Integer] chain The ID of the chain (1 for mainnet)
|
69
69
|
# @param [String] host The host to connect to
|
70
70
|
# @param [Integer] port TCP port to use
|
@@ -107,9 +107,9 @@ class ERC20::Wallet
|
|
107
107
|
|
108
108
|
# Get ERC20 balance of a public address (it's not the same as ETH balance!).
|
109
109
|
#
|
110
|
-
# An address in
|
111
|
-
# balance in ETH crypto. Another balance is the one kept by ERC20 contract
|
112
|
-
# in its own
|
110
|
+
# An address in Ethereum may have many balances. One of them is the main
|
111
|
+
# balance in ETH crypto. Another balance is the one kept by the ERC20 contract
|
112
|
+
# in its own ledger in root storage. This balance is checked by this method.
|
113
113
|
#
|
114
114
|
# @param [String] address Public key, in hex, starting from '0x'
|
115
115
|
# @return [Integer] Balance, in tokens
|
@@ -127,7 +127,7 @@ class ERC20::Wallet
|
|
127
127
|
|
128
128
|
# Get ETH balance of a public address.
|
129
129
|
#
|
130
|
-
# An address in
|
130
|
+
# An address in Ethereum may have many balances. One of them is the main
|
131
131
|
# balance in ETH crypto. This balance is checked by this method.
|
132
132
|
#
|
133
133
|
# @param [String] hex Public key, in hex, starting from '0x'
|
@@ -142,12 +142,12 @@ class ERC20::Wallet
|
|
142
142
|
b
|
143
143
|
end
|
144
144
|
|
145
|
-
# How
|
145
|
+
# How many gas units are required to send an ERC20 transaction.
|
146
146
|
#
|
147
|
-
# @param [String] from The
|
148
|
-
# @param [String] to
|
147
|
+
# @param [String] from The sending address, in hex
|
148
|
+
# @param [String] to The receiving address, in hex
|
149
149
|
# @param [Integer] amount How many ERC20 tokens to send
|
150
|
-
# @return [Integer]
|
150
|
+
# @return [Integer] Number of gas units required
|
151
151
|
def gas_estimate(from, to, amount)
|
152
152
|
raise 'Address can\'t be nil' unless from
|
153
153
|
raise 'Address must be a String' unless from.is_a?(String)
|
@@ -164,15 +164,33 @@ class ERC20::Wallet
|
|
164
164
|
end
|
165
165
|
|
166
166
|
# What is the price of gas unit in gwei?
|
167
|
+
#
|
168
|
+
# In Ethereum, gas is a unit that measures the computational work required to
|
169
|
+
# execute operations on the network. Every transaction and smart contract
|
170
|
+
# interaction consumes gas. Gas price is the amount of ETH you're willing to pay
|
171
|
+
# for each unit of gas, denominated in gwei (1 gwei = 0.000000001 ETH). Higher
|
172
|
+
# gas prices incentivize miners to include your transaction sooner, while lower
|
173
|
+
# prices may result in longer confirmation times.
|
174
|
+
#
|
167
175
|
# @return [Integer] Price of gas unit, in gwei (0.000000001 ETH)
|
168
176
|
def gas_price
|
169
|
-
|
177
|
+
block = jsonrpc.eth_getBlockByNumber('latest', false)
|
178
|
+
raise "Can't get gas price, try again later" if block.nil?
|
179
|
+
gwei = block['baseFeePerGas'].to_i(16)
|
170
180
|
@log.debug("The cost of one gas unit is #{gwei} gwei")
|
171
181
|
gwei
|
172
182
|
end
|
173
183
|
|
174
184
|
# Send a single ERC20 payment from a private address to a public one.
|
175
185
|
#
|
186
|
+
# ERC20 payments differ fundamentally from native ETH transfers. While ETH transfers
|
187
|
+
# simply move the cryptocurrency directly between addresses, ERC20 token transfers
|
188
|
+
# are actually interactions with a smart contract. When you transfer ERC20 tokens,
|
189
|
+
# you're not sending anything directly to another user - instead, you're calling
|
190
|
+
# the token contract's transfer function, which updates its internal ledger to
|
191
|
+
# decrease your balance and increase the recipient's balance. This requires more
|
192
|
+
# gas than ETH transfers since it involves executing contract code.
|
193
|
+
#
|
176
194
|
# @param [String] priv Private key, in hex
|
177
195
|
# @param [String] address Public key, in hex
|
178
196
|
# @param [Integer] amount The amount of ERC20 tokens to send
|
@@ -225,8 +243,7 @@ class ERC20::Wallet
|
|
225
243
|
#
|
226
244
|
# @param [String] priv Private key, in hex
|
227
245
|
# @param [String] address Public key, in hex
|
228
|
-
# @param [Integer] amount The amount of
|
229
|
-
# @param [Integer] limit How much gas you're ready to spend
|
246
|
+
# @param [Integer] amount The amount of ETH to send
|
230
247
|
# @param [Integer] price How much gas you pay per computation unit
|
231
248
|
# @return [String] Transaction hash
|
232
249
|
def eth_pay(priv, address, amount, price: gas_price)
|
@@ -272,7 +289,7 @@ class ERC20::Wallet
|
|
272
289
|
# +Thread.kill+.
|
273
290
|
#
|
274
291
|
# The array with the list of addresses (+addresses+) may change its
|
275
|
-
# content on-fly. The +accept()+ method will +
|
292
|
+
# content on-the-fly. The +accept()+ method will +eth_subscribe+ to the addresses
|
276
293
|
# that are added and will +eth_unsubscribe+ from those that are removed.
|
277
294
|
# Once we actually start listening, the +active+ array will be updated
|
278
295
|
# with the list of addresses.
|
@@ -291,8 +308,8 @@ class ERC20::Wallet
|
|
291
308
|
raise 'Addresses must respond to .to_a()' unless addresses.respond_to?(:to_a)
|
292
309
|
raise 'Active can\'t be nil' unless active
|
293
310
|
raise 'Active must respond to .append()' unless active.respond_to?(:append)
|
294
|
-
raise '
|
295
|
-
raise '
|
311
|
+
raise 'Delay must be an Integer' unless delay.is_a?(Integer)
|
312
|
+
raise 'Delay must be a positive Integer' unless delay.positive?
|
296
313
|
raise 'Subscription ID must be an Integer' unless subscription_id.is_a?(Integer)
|
297
314
|
raise 'Subscription ID must be a positive Integer' unless subscription_id.positive?
|
298
315
|
EventMachine.run do
|
@@ -332,7 +349,7 @@ class ERC20::Wallet
|
|
332
349
|
txn: event['transactionHash'].downcase
|
333
350
|
}
|
334
351
|
log.debug(
|
335
|
-
"Payment of #{event[:amount]} tokens arrived" \
|
352
|
+
"Payment of #{event[:amount]} tokens arrived " \
|
336
353
|
"from #{event[:from]} to #{event[:to]} in #{event[:txn]}"
|
337
354
|
)
|
338
355
|
end
|
@@ -13,8 +13,8 @@ require 'random-port'
|
|
13
13
|
require 'shellwords'
|
14
14
|
require 'threads'
|
15
15
|
require 'typhoeus'
|
16
|
-
require_relative '../../lib/erc20/fake_wallet'
|
17
16
|
require_relative '../test__helper'
|
17
|
+
require_relative '../../lib/erc20/fake_wallet'
|
18
18
|
|
19
19
|
# Test.
|
20
20
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
data/test/erc20/test_wallet.rb
CHANGED
@@ -13,15 +13,15 @@ require 'random-port'
|
|
13
13
|
require 'shellwords'
|
14
14
|
require 'threads'
|
15
15
|
require 'typhoeus'
|
16
|
-
require_relative '../../lib/erc20/wallet'
|
17
16
|
require_relative '../test__helper'
|
17
|
+
require_relative '../../lib/erc20/wallet'
|
18
18
|
|
19
19
|
# Test.
|
20
20
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
21
21
|
# Copyright:: Copyright (c) 2025 Yegor Bugayenko
|
22
22
|
# License:: MIT
|
23
23
|
class TestWallet < Minitest::Test
|
24
|
-
# At this address, in
|
24
|
+
# At this address, in Ethereum mainnet, there are $8 USDT and 0.0042 ETH. I won't
|
25
25
|
# move them anyway, that's why tests can use this address forever.
|
26
26
|
STABLE = '0x7232148927F8a580053792f44D4d59d40Fd00ABD'
|
27
27
|
|
@@ -76,7 +76,8 @@ class TestWallet < Minitest::Test
|
|
76
76
|
def test_checks_balance_on_polygon
|
77
77
|
w = ERC20::Wallet.new(
|
78
78
|
contract: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',
|
79
|
-
host: 'polygon-mainnet.infura.io',
|
79
|
+
host: 'polygon-mainnet.infura.io',
|
80
|
+
http_path: "/v3/#{env('INFURA_KEY')}",
|
80
81
|
log: loog
|
81
82
|
)
|
82
83
|
b = w.balance(STABLE)
|
@@ -290,20 +291,19 @@ class TestWallet < Minitest::Test
|
|
290
291
|
|
291
292
|
def test_checks_balance_via_proxy_on_mainnet
|
292
293
|
via_proxy do |proxy|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
end
|
294
|
+
w = ERC20::Wallet.new(
|
295
|
+
host: 'mainnet.infura.io',
|
296
|
+
http_path: "/v3/#{env('INFURA_KEY')}",
|
297
|
+
proxy:, log: loog
|
298
|
+
)
|
299
|
+
assert_equal(8_000_000, w.balance(STABLE))
|
300
300
|
end
|
301
301
|
end
|
302
302
|
|
303
303
|
def test_pays_on_mainnet
|
304
304
|
skip('This is live, must be run manually')
|
305
305
|
w = mainnet
|
306
|
-
print 'Enter
|
306
|
+
print 'Enter Ethereum ERC20 private key (64 chars): '
|
307
307
|
priv = gets.chomp
|
308
308
|
to = '0xEB2fE8872A6f1eDb70a2632EA1f869AB131532f6'
|
309
309
|
txn = w.pay(priv, to, 1_990_000)
|
@@ -315,6 +315,7 @@ class TestWallet < Minitest::Test
|
|
315
315
|
def env(var)
|
316
316
|
key = ENV.fetch(var, nil)
|
317
317
|
skip("The #{var} environment variable is not set") if key.nil?
|
318
|
+
skip("The #{var} environment variable is empty") if key.empty?
|
318
319
|
key
|
319
320
|
end
|
320
321
|
|
data/test/test__helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: erc20
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date: 2025-
|
10
|
+
date: 2025-04-05 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: eth
|
@@ -96,7 +95,7 @@ dependencies:
|
|
96
95
|
version: '4'
|
97
96
|
description: 'A simple library for making ERC20 manipulations as easy as they can
|
98
97
|
be for cryptocurrency newbies: checking balance, sending payments, and monitoring
|
99
|
-
addresses for incoming payments. The library expects
|
98
|
+
addresses for incoming payments. The library expects Ethereum node to provide JSON
|
100
99
|
RPC and Websockets API.'
|
101
100
|
email: yegor256@gmail.com
|
102
101
|
executables:
|
@@ -157,7 +156,6 @@ licenses:
|
|
157
156
|
- MIT
|
158
157
|
metadata:
|
159
158
|
rubygems_mfa_required: 'true'
|
160
|
-
post_install_message:
|
161
159
|
rdoc_options:
|
162
160
|
- "--charset=UTF-8"
|
163
161
|
require_paths:
|
@@ -173,8 +171,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
173
171
|
- !ruby/object:Gem::Version
|
174
172
|
version: '0'
|
175
173
|
requirements: []
|
176
|
-
rubygems_version: 3.
|
177
|
-
signing_key:
|
174
|
+
rubygems_version: 3.6.2
|
178
175
|
specification_version: 4
|
179
|
-
summary: Sending and receiving ERC20 tokens in
|
176
|
+
summary: Sending and receiving ERC20 tokens in Ethereum network
|
180
177
|
test_files: []
|