erc20 0.0.21 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b64594a5ded4f8f34912d468efbf8fd2a47b716098853df38857a3a0b973cd1e
4
- data.tar.gz: bb0285b23d6624f633b92c45ab29bb0975e377a4ea971d0a9772c660c622b4ea
3
+ metadata.gz: fbce7bc57948f9c8acfeec7c0af2cf67e70e2447e064040485e6868d466828dc
4
+ data.tar.gz: cc521c55db79dca85e58235c886172a7ca81cf0f59ee61f5c134cc888eb3db4c
5
5
  SHA512:
6
- metadata.gz: de7f6cb6ff26a078860cc9530146f49b7d5df6f462a51120fd48bd3ab9dde07bfe781c03952eb5625350c2e69dad10f2222b9edb05a0902ed4fb4fc564a055ea
7
- data.tar.gz: 9ecd61346360053c15d3cdfdd838c3cfdb1d5eff1d789260a04e42662fa16d9183646d14a7fba19d1862d4f6a294ab7cfa19763c48ca4cf5586a4edf1c4e8ecd
6
+ metadata.gz: c712231ba46caabca78b45e9be366c120e2f5275bc734c874f69c7306d1f961c7b7c3a5b8ae58341cb4d48776a91c5a8bc8ec2360dfcbc294d46ae329d9bf8a4
7
+ data.tar.gz: 7a074720cfec0773a6e4e0cc70fe07fde201ae9897cb395a2b91a84429683354b822bef0be10650290b554ffe59b150034a1ea320eed34a396d574267954c130
@@ -1,5 +1,3 @@
1
- # (The MIT License)
2
- #
3
1
  # SPDX-FileCopyrightText: Copyright (c) 2025 Yegor Bugayenko
4
2
  # SPDX-License-Identifier: MIT
5
3
  ---
data/.gitignore CHANGED
@@ -1,9 +1,10 @@
1
- coverage/
2
- .idea/
3
1
  *.gem
4
- .bundle/
5
2
  .DS_Store
6
- rdoc/
7
- doc/
3
+ .bundle/
4
+ .idea/
8
5
  .yardoc/
6
+ coverage/
7
+ doc/
9
8
  node_modules/
9
+ rdoc/
10
+ vendor/
data/.rultor.yml CHANGED
@@ -3,7 +3,7 @@
3
3
  ---
4
4
  # yamllint disable rule:line-length
5
5
  docker:
6
- image: yegor256/rultor-ruby
6
+ image: yegor256/ruby
7
7
  assets:
8
8
  rubygems.yml: yegor256/home#assets/rubygems.yml
9
9
  install: |
data/Gemfile CHANGED
@@ -7,23 +7,23 @@ source 'https://rubygems.org'
7
7
  gemspec
8
8
 
9
9
  gem 'backtrace', '>0', require: false
10
+ gem 'cucumber', '~>9.2', require: false
10
11
  gem 'donce', '>0', require: false
11
12
  gem 'faraday', '>0', require: false
12
13
  gem 'loog', '>0', require: false
13
- gem 'minitest', '5.25.4', require: false
14
- gem 'minitest-reporters', '1.7.1', require: false
15
- gem 'minitest-retry', '0.2.5', require: false
14
+ gem 'minitest', '~>5.25', require: false
15
+ gem 'minitest-reporters', '~>1.7', require: false
16
+ gem 'minitest-retry', '~>0.2', require: false
16
17
  gem 'qbash', '>0', require: false
17
- gem 'rake', '13.2.1', require: false
18
+ gem 'rake', '~>13.2', require: false
18
19
  gem 'random-port', '>0', require: false
19
- gem 'rspec-rails', '7.1.1', require: false
20
- gem 'rubocop', '1.72.2', require: false
20
+ gem 'rubocop', '~>1.75', require: false
21
21
  gem 'rubocop-minitest', '>0', require: false
22
22
  gem 'rubocop-performance', '>0', require: false
23
23
  gem 'rubocop-rake', '>0', require: false
24
24
  gem 'rubocop-rspec', '>0', require: false
25
- gem 'simplecov', '0.22.0', require: false
26
- gem 'simplecov-cobertura', '2.1.0', require: false
27
- gem 'threads', '0.4.1', require: false
25
+ gem 'simplecov', '~>0.22', require: false
26
+ gem 'simplecov-cobertura', '~>2.1', require: false
27
+ gem 'threads', '~>0.4', require: false
28
28
  gem 'typhoeus', '>0', require: false
29
- gem 'yard', '0.9.37', require: false
29
+ gem 'yard', '~>0.9', require: false
data/Gemfile.lock CHANGED
@@ -7,61 +7,52 @@ PATH
7
7
  json (>= 2.10.1)
8
8
  jsonrpc-client (>= 0.1.4)
9
9
  loog (> 0)
10
+ slop (> 4)
10
11
 
11
12
  GEM
12
13
  remote: https://rubygems.org/
13
14
  specs:
14
- actionpack (8.0.1)
15
- actionview (= 8.0.1)
16
- activesupport (= 8.0.1)
17
- nokogiri (>= 1.8.5)
18
- rack (>= 2.2.4)
19
- rack-session (>= 1.0.1)
20
- rack-test (>= 0.6.3)
21
- rails-dom-testing (~> 2.2)
22
- rails-html-sanitizer (~> 1.6)
23
- useragent (~> 0.16)
24
- actionview (8.0.1)
25
- activesupport (= 8.0.1)
26
- builder (~> 3.1)
27
- erubi (~> 1.11)
28
- rails-dom-testing (~> 2.2)
29
- rails-html-sanitizer (~> 1.6)
30
- activesupport (8.0.1)
31
- base64
32
- benchmark (>= 0.3)
33
- bigdecimal
34
- concurrent-ruby (~> 1.0, >= 1.3.1)
35
- connection_pool (>= 2.2.5)
36
- drb
37
- i18n (>= 1.6, < 2)
38
- logger (>= 1.4.2)
39
- minitest (>= 5.1)
40
- securerandom (>= 0.3)
41
- tzinfo (~> 2.0, >= 2.0.5)
42
- uri (>= 0.13.1)
43
15
  ansi (1.5.0)
44
- ast (2.4.2)
16
+ ast (2.4.3)
45
17
  backtrace (0.4.0)
46
18
  base64 (0.2.0)
47
- benchmark (0.4.0)
48
19
  bigdecimal (3.1.9)
49
20
  builder (3.3.0)
50
21
  concurrent-ruby (1.3.5)
51
- connection_pool (2.5.0)
52
- crass (1.0.6)
53
- date (3.4.1)
54
- diff-lcs (1.6.0)
22
+ cucumber (9.2.1)
23
+ builder (~> 3.2)
24
+ cucumber-ci-environment (> 9, < 11)
25
+ cucumber-core (> 13, < 14)
26
+ cucumber-cucumber-expressions (~> 17.0)
27
+ cucumber-gherkin (> 24, < 28)
28
+ cucumber-html-formatter (> 20.3, < 22)
29
+ cucumber-messages (> 19, < 25)
30
+ diff-lcs (~> 1.5)
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)
37
+ cucumber-messages (>= 20, < 23)
38
+ cucumber-tag-expressions (> 5, < 7)
39
+ cucumber-cucumber-expressions (17.1.0)
40
+ bigdecimal
41
+ cucumber-gherkin (27.0.0)
42
+ cucumber-messages (>= 19.1.4, < 23)
43
+ cucumber-html-formatter (21.9.0)
44
+ cucumber-messages (> 19, < 28)
45
+ cucumber-messages (22.0.0)
46
+ cucumber-tag-expressions (6.1.2)
47
+ diff-lcs (1.6.1)
55
48
  docile (1.4.1)
56
49
  donce (0.1.0)
57
50
  backtrace (> 0)
58
51
  os (> 0)
59
52
  qbash (> 0)
60
- drb (2.2.1)
61
53
  elapsed (0.0.1)
62
54
  loog (> 0)
63
55
  tago (> 0)
64
- erubi (1.13.1)
65
56
  eth (0.5.13)
66
57
  forwardable (~> 1.3)
67
58
  keccak (~> 1.3)
@@ -89,14 +80,7 @@ GEM
89
80
  ffi (>= 1.15.5)
90
81
  rake
91
82
  forwardable (1.3.3)
92
- i18n (1.14.7)
93
- concurrent-ruby (~> 1.0)
94
- io-console (0.8.0)
95
- irb (1.15.1)
96
- pp (>= 0.6.0)
97
- rdoc (>= 4.0.0)
98
- reline (>= 0.4.2)
99
- json (2.10.1)
83
+ json (2.10.2)
100
84
  jsonrpc-client (0.1.4)
101
85
  faraday
102
86
  multi_json (>= 1.1.0)
@@ -104,13 +88,11 @@ GEM
104
88
  konstructor (1.0.2)
105
89
  language_server-protocol (3.17.0.4)
106
90
  lint_roller (1.1.0)
107
- logger (1.6.6)
108
- loofah (2.24.0)
109
- crass (~> 1.0.2)
110
- nokogiri (>= 1.12.0)
91
+ logger (1.7.0)
111
92
  loog (0.6.0)
93
+ mini_mime (1.1.5)
112
94
  mini_portile2 (2.8.8)
113
- minitest (5.25.4)
95
+ minitest (5.25.5)
114
96
  minitest-reporters (1.7.1)
115
97
  ansi
116
98
  builder
@@ -119,58 +101,23 @@ GEM
119
101
  minitest-retry (0.2.5)
120
102
  minitest (>= 5.0)
121
103
  multi_json (1.15.0)
104
+ multi_test (1.1.0)
122
105
  net-http (0.6.0)
123
106
  uri
124
- nokogiri (1.18.3-arm64-darwin)
125
- racc (~> 1.4)
126
- nokogiri (1.18.3-x64-mingw-ucrt)
127
- racc (~> 1.4)
128
- nokogiri (1.18.3-x86_64-darwin)
129
- racc (~> 1.4)
130
- nokogiri (1.18.3-x86_64-linux-gnu)
131
- racc (~> 1.4)
132
107
  openssl (3.3.0)
133
108
  os (1.1.4)
134
109
  parallel (1.26.3)
135
- parser (3.3.7.1)
110
+ parser (3.3.7.4)
136
111
  ast (~> 2.4.1)
137
112
  racc
138
- pkg-config (1.5.9)
139
- pp (0.6.2)
140
- prettyprint
141
- prettyprint (0.2.0)
142
- psych (5.2.3)
143
- date
144
- stringio
113
+ pkg-config (1.6.0)
114
+ prism (1.4.0)
145
115
  qbash (0.4.0)
146
116
  backtrace (> 0)
147
117
  elapsed (> 0)
148
118
  loog (> 0)
149
119
  tago (> 0)
150
120
  racc (1.8.1)
151
- rack (3.1.10)
152
- rack-session (2.1.0)
153
- base64 (>= 0.1.0)
154
- rack (>= 3.0.0)
155
- rack-test (2.2.0)
156
- rack (>= 1.3)
157
- rackup (2.2.1)
158
- rack (>= 3)
159
- rails-dom-testing (2.2.0)
160
- activesupport (>= 5.0.0)
161
- minitest
162
- nokogiri (>= 1.6)
163
- rails-html-sanitizer (1.6.2)
164
- loofah (~> 2.21)
165
- 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)
166
- railties (8.0.1)
167
- actionpack (= 8.0.1)
168
- activesupport (= 8.0.1)
169
- irb (~> 1.13)
170
- rackup (>= 1.0.0)
171
- rake (>= 12.2)
172
- thor (~> 1.0, >= 1.2.2)
173
- zeitwerk (~> 2.6)
174
121
  rainbow (3.1.1)
175
122
  rake (13.2.1)
176
123
  random-port (0.7.5)
@@ -179,30 +126,9 @@ GEM
179
126
  mini_portile2 (~> 2.8)
180
127
  pkg-config (~> 1.5)
181
128
  rubyzip (~> 2.3)
182
- rdoc (6.12.0)
183
- psych (>= 4.0.0)
184
129
  regexp_parser (2.10.0)
185
- reline (0.6.0)
186
- io-console (~> 0.5)
187
130
  rexml (3.4.1)
188
- rspec-core (3.13.3)
189
- rspec-support (~> 3.13.0)
190
- rspec-expectations (3.13.3)
191
- diff-lcs (>= 1.2.0, < 2.0)
192
- rspec-support (~> 3.13.0)
193
- rspec-mocks (3.13.2)
194
- diff-lcs (>= 1.2.0, < 2.0)
195
- rspec-support (~> 3.13.0)
196
- rspec-rails (7.1.1)
197
- actionpack (>= 7.0)
198
- activesupport (>= 7.0)
199
- railties (>= 7.0)
200
- rspec-core (~> 3.13)
201
- rspec-expectations (~> 3.13)
202
- rspec-mocks (~> 3.13)
203
- rspec-support (~> 3.13)
204
- rspec-support (3.13.2)
205
- rubocop (1.72.2)
131
+ rubocop (1.75.2)
206
132
  json (~> 2.3)
207
133
  language_server-protocol (~> 3.17.0.2)
208
134
  lint_roller (~> 1.1.0)
@@ -210,18 +136,19 @@ GEM
210
136
  parser (>= 3.3.0.2)
211
137
  rainbow (>= 2.2.2, < 4.0)
212
138
  regexp_parser (>= 2.9.3, < 3.0)
213
- rubocop-ast (>= 1.38.0, < 2.0)
139
+ rubocop-ast (>= 1.44.0, < 2.0)
214
140
  ruby-progressbar (~> 1.7)
215
141
  unicode-display_width (>= 2.4.0, < 4.0)
216
- rubocop-ast (1.38.0)
217
- parser (>= 3.3.1.0)
218
- rubocop-minitest (0.37.1)
142
+ rubocop-ast (1.44.0)
143
+ parser (>= 3.3.7.2)
144
+ prism (~> 1.4)
145
+ rubocop-minitest (0.38.0)
219
146
  lint_roller (~> 1.1)
220
- rubocop (>= 1.72.1, < 2.0)
147
+ rubocop (>= 1.75.0, < 2.0)
221
148
  rubocop-ast (>= 1.38.0, < 2.0)
222
- rubocop-performance (1.24.0)
149
+ rubocop-performance (1.25.0)
223
150
  lint_roller (~> 1.1)
224
- rubocop (>= 1.72.1, < 2.0)
151
+ rubocop (>= 1.75.0, < 2.0)
225
152
  rubocop-ast (>= 1.38.0, < 2.0)
226
153
  rubocop-rake (0.7.1)
227
154
  lint_roller (~> 1.1)
@@ -234,7 +161,6 @@ GEM
234
161
  scrypt (3.0.8)
235
162
  ffi-compiler (>= 1.0, < 2.0)
236
163
  rake (>= 9, < 14)
237
- securerandom (0.4.1)
238
164
  simplecov (0.22.0)
239
165
  docile (~> 1.1)
240
166
  simplecov-html (~> 0.11)
@@ -244,27 +170,24 @@ GEM
244
170
  simplecov (~> 0.19)
245
171
  simplecov-html (0.13.1)
246
172
  simplecov_json_formatter (0.1.4)
247
- stringio (3.1.3)
248
- tago (0.0.2)
249
- thor (1.3.2)
173
+ slop (4.10.1)
174
+ sys-uname (1.3.1)
175
+ ffi (~> 1.1)
176
+ tago (0.1.0)
250
177
  threads (0.4.1)
251
178
  backtrace (~> 0)
252
179
  concurrent-ruby (~> 1.0)
253
180
  typhoeus (1.4.1)
254
181
  ethon (>= 0.9.0)
255
- tzinfo (2.0.6)
256
- concurrent-ruby (~> 1.0)
257
182
  unicode-display_width (3.1.4)
258
183
  unicode-emoji (~> 4.0, >= 4.0.4)
259
184
  unicode-emoji (4.0.4)
260
- uri (1.0.2)
261
- useragent (0.16.11)
185
+ uri (1.0.3)
262
186
  websocket-driver (0.7.7)
263
187
  base64
264
188
  websocket-extensions (>= 0.1.0)
265
189
  websocket-extensions (0.1.5)
266
190
  yard (0.9.37)
267
- zeitwerk (2.7.2)
268
191
 
269
192
  PLATFORMS
270
193
  arm64-darwin-22
@@ -277,27 +200,27 @@ PLATFORMS
277
200
 
278
201
  DEPENDENCIES
279
202
  backtrace (> 0)
203
+ cucumber (~> 9.2)
280
204
  donce (> 0)
281
205
  erc20!
282
206
  faraday (> 0)
283
207
  loog (> 0)
284
- minitest (= 5.25.4)
285
- minitest-reporters (= 1.7.1)
286
- minitest-retry (= 0.2.5)
208
+ minitest (~> 5.25)
209
+ minitest-reporters (~> 1.7)
210
+ minitest-retry (~> 0.2)
287
211
  qbash (> 0)
288
- rake (= 13.2.1)
212
+ rake (~> 13.2)
289
213
  random-port (> 0)
290
- rspec-rails (= 7.1.1)
291
- rubocop (= 1.72.2)
214
+ rubocop (~> 1.75)
292
215
  rubocop-minitest (> 0)
293
216
  rubocop-performance (> 0)
294
217
  rubocop-rake (> 0)
295
218
  rubocop-rspec (> 0)
296
- simplecov (= 0.22.0)
297
- simplecov-cobertura (= 2.1.0)
298
- threads (= 0.4.1)
219
+ simplecov (~> 0.22)
220
+ simplecov-cobertura (~> 2.1)
221
+ threads (~> 0.4)
299
222
  typhoeus (> 0)
300
- yard (= 0.9.37)
223
+ yard (~> 0.9)
301
224
 
302
225
  BUNDLED WITH
303
226
  2.5.16
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Etherium ERC20 Manipulations in Ruby
1
+ # Ethereum ERC20 Manipulations in Ruby
2
2
 
3
3
  [![DevOps By Rultor.com](http://www.rultor.com/b/yegor256/erc20)](http://www.rultor.com/p/yegor256/erc20)
4
4
  [![We recommend RubyMine](https://www.elegantobjects.org/rubymine.svg)](https://www.jetbrains.com/ruby/)
@@ -12,9 +12,9 @@
12
12
  [![License](https://img.shields.io/badge/license-MIT-green.svg)](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 [Etherium] [ERC20] tokens
16
- as simple as they can be, if you have a provider of
17
- [JSON-RPC] and [WebSockets] Etherium APIs, for example
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
- It's also possible to check ETH balance and send ETH transaction:
47
+ You can also check ETH balance and send ETH transactions:
48
48
 
49
49
  ```ruby
50
- # Check how many ETHs are there on the given address:
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,13 +91,32 @@ 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 forks of [Etherium].
94
+ and other EVM compatible blockchains.
95
+
96
+ ## How to use in command line
97
+
98
+ This gem also provides a command line tool for sending ETH and ERC20 payments
99
+ and checking balances.
100
+
101
+ First, you install it, via [gem]:
102
+
103
+ ```bash
104
+ gem install erc20
105
+ ```
106
+
107
+ Then, run it:
108
+
109
+ ```bash
110
+ erc20 --help
111
+ ```
112
+
113
+ Usage should be straightforward. If you have questions, please submit an issue.
95
114
 
96
115
  ## How to use in tests
97
116
 
98
- You can use `ERC20::FakeWallet` class that behaves exactly like
117
+ You can use the `ERC20::FakeWallet` class that behaves exactly like
99
118
  `ERC20::Wallet`, but doesn't make any network connections to the provider.
100
- Also, it remembers all requests that were sent to it:
119
+ Additionally, it records all requests sent to it:
101
120
 
102
121
  ```ruby
103
122
  require 'erc20'
@@ -110,7 +129,7 @@ assert w.history.include?({ method: :pay, priv:, address:, amount: 42_000 })
110
129
 
111
130
  Read
112
131
  [these guidelines](https://www.yegor256.com/2014/04/15/github-guidelines.html).
113
- Make sure you build is green before you contribute
132
+ Make sure your build is green before you contribute
114
133
  your pull request. You will need to have
115
134
  [Ruby](https://www.ruby-lang.org/en/) 3.2+ and
116
135
  [Bundler](https://bundler.io/) installed. Then:
@@ -122,7 +141,8 @@ bundle exec rake
122
141
 
123
142
  If it's clean and you don't see any error messages, submit your pull request.
124
143
 
125
- [Etherium]: https://en.wikipedia.org/wiki/Ethereum
144
+ [gem]: https://github.com/rubygems/rubygems
145
+ [Ethereum]: https://en.wikipedia.org/wiki/Ethereum
126
146
  [ERC20]: https://ethereum.org/en/developers/docs/standards/tokens/erc-20/
127
147
  [JSON-RPC]: https://ethereum.org/en/developers/docs/apis/json-rpc/
128
148
  [Websockets]: https://ethereum.org/en/developers/tutorials/using-websockets/
data/REUSE.toml CHANGED
@@ -4,15 +4,37 @@
4
4
  version = 1
5
5
  [[annotations]]
6
6
  path = [
7
+ "**.json",
8
+ "**.md",
9
+ "**.png",
10
+ "**.txt",
11
+ "**/*.csv",
12
+ "**/*.jpg",
13
+ "**/*.json",
14
+ "**/*.md",
15
+ "**/*.pdf",
16
+ "**/*.png",
17
+ "**/*.svg",
18
+ "**/*.txt",
19
+ "**/*.vm",
20
+ "**/.DS_Store",
21
+ "**/.gitignore",
22
+ "**/.gitleaksignore",
23
+ "**/.pdd",
24
+ "**/CNAME",
25
+ "**/Cargo.toml",
26
+ "**/Gemfile.lock",
27
+ ".DS_Store",
7
28
  ".gitattributes",
8
29
  ".gitignore",
9
30
  ".gitleaksignore",
10
31
  ".pdd",
32
+ "Cargo.toml",
11
33
  "Gemfile.lock",
12
34
  "README.md",
13
35
  "hardhat/.gitignore",
14
36
  "hardhat/package.json",
15
- "renovate.json"
37
+ "renovate.json",
16
38
  ]
17
39
  precedence = "override"
18
40
  SPDX-FileCopyrightText = "Copyright (c) 2025 Yegor Bugayenko"
data/Rakefile CHANGED
@@ -17,7 +17,7 @@ def version
17
17
  Gem::Specification.load(Dir['*.gemspec'].first).version
18
18
  end
19
19
 
20
- task default: %i[clean test rubocop yard]
20
+ task default: %i[clean test features rubocop yard]
21
21
 
22
22
  require 'rake/testtask'
23
23
  desc 'Run all unit tests'
@@ -42,6 +42,14 @@ RuboCop::RakeTask.new(:rubocop) do |task|
42
42
  task.requires << 'rubocop-rspec'
43
43
  end
44
44
 
45
+ require 'cucumber/rake/task'
46
+ Cucumber::Rake::Task.new(:features) do
47
+ Rake::Cleaner.cleanup_files(['coverage'])
48
+ end
49
+ Cucumber::Rake::Task.new(:'features:html') do |t|
50
+ t.profile = 'html_report'
51
+ end
52
+
45
53
  desc 'Run benchmark script'
46
54
  task :benchmark do
47
55
  ruby 'benchmarks/simple.rb'
data/bin/erc20 ADDED
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # SPDX-FileCopyrightText: Copyright (c) 2025 Yegor Bugayenko
5
+ # SPDX-License-Identifier: MIT
6
+
7
+ $stdout.sync = true
8
+
9
+ require 'backtrace'
10
+ require 'loog'
11
+ require 'slop'
12
+ require_relative '../lib/erc20'
13
+ require_relative '../lib/erc20/erc20'
14
+ require_relative '../lib/erc20/wallet'
15
+
16
+ begin
17
+ begin
18
+ opts = Slop.parse(ARGV, strict: true, help: true) do |o|
19
+ o.banner = "Usage (#{ERC20::VERSION}): erc20 [options] command [args]
20
+ Commands are:
21
+ key: Generate a new Ethereum private key (64 symbols)
22
+ address: Turn private key into a public address (44 symbols)
23
+ price: Get current price of one gas unit, in gwei
24
+ pay: Send ERC20 payment
25
+ eth_pay: Send ETH payment
26
+ balance: Get ERC20 balance
27
+ eth_balance: Get ETH balance
28
+ Options are:"
29
+ o.string(
30
+ '--contract',
31
+ 'Public address of ERC20 contract',
32
+ default: ERC20::Wallet::USDT
33
+ )
34
+ o.integer(
35
+ '--chain',
36
+ 'Ethereum chain ID',
37
+ default: 1
38
+ )
39
+ o.string(
40
+ '--host',
41
+ 'Host name of the provider',
42
+ default: 'eth.llamarpc.com'
43
+ )
44
+ o.string(
45
+ '--port',
46
+ 'TCP port of the provider',
47
+ default: 443
48
+ )
49
+ o.string(
50
+ '--http_path',
51
+ 'URL path for the HTTP RPC entry point of the provider',
52
+ default: '/'
53
+ )
54
+ o.string(
55
+ '--ws_path',
56
+ 'URL path for the Websockets entry point of the provider',
57
+ default: '/'
58
+ )
59
+ o.string(
60
+ '--proxy',
61
+ 'HTTP/S proxy for all requests, e.g. "localhost:3128"'
62
+ )
63
+ o.integer(
64
+ '--attempts',
65
+ 'How many times should we try before failing',
66
+ default: 1
67
+ )
68
+ o.bool(
69
+ '--dry',
70
+ 'Don\'t send a real payment, run in a read-only mode'
71
+ )
72
+ o.bool('--help', 'Read this: https://github.com/yegor256/erc20') do
73
+ puts o
74
+ exit
75
+ end
76
+ o.bool('--verbose', 'Print all possible debug messages')
77
+ end
78
+ rescue Slop::Error => e
79
+ raise e.message
80
+ end
81
+ raise 'Try --help' if opts.arguments.empty?
82
+ log = opts[:verbose] ? Loog::VERBOSE : Loog::REGULAR
83
+ wallet = ERC20::Wallet.new(
84
+ contract: opts[:contract],
85
+ host: opts[:host], port: opts[:port],
86
+ http_path: opts[:http_path], ws_path: opts[:ws_path],
87
+ log:
88
+ )
89
+ case opts.arguments[0]
90
+ when 'key'
91
+ puts Eth::Key.new.private_hex
92
+ when 'address'
93
+ puts Eth::Key.new(priv: opts.arguments[1]).address.to_s
94
+ when 'price'
95
+ puts wallet.gas_price
96
+ when 'balance'
97
+ address = opts.arguments[1]
98
+ raise 'Address is required' if address.nil?
99
+ log.debug("Checking ERC20 balance of #{address}")
100
+ tokens = wallet.balance(address)
101
+ log.debug("The balance is #{tokens} ERC20 tokens (#{tokens.to_f / 1_000_000} USDT)")
102
+ puts tokens
103
+ when 'eth_balance'
104
+ address = opts.arguments[1]
105
+ raise 'Address is required' if address.nil?
106
+ log.debug("Checking ETH balance of #{address}")
107
+ wei = wallet.eth_balance(address)
108
+ log.debug("The balance of #{address} is #{wei} wei (#{format('%0.4f', wei.to_f / 1_000_000_000_000_000_000)} ETH)")
109
+ puts wei
110
+ when 'pay'
111
+ pkey = opts.arguments[1]
112
+ raise 'Private key is required' if pkey.nil?
113
+ priv = Eth::Key.new(priv: pkey)
114
+ log.debug("Sending ERC20 tokens from #{priv.address.to_s}")
115
+ address = opts.arguments[2]
116
+ raise 'Address is required' if address.nil?
117
+ log.debug("Sending ERC20 tokens to #{address}")
118
+ amount = opts.arguments[3]
119
+ raise 'Amount argument is required' if amount.nil?
120
+ raise 'Amount is not valid' unless /^[0-9]+(usdt)?$/.match?(amount)
121
+ amount = amount.to_i if /^[0-9]+$/.match?(amount)
122
+ amount = (amount.gsub(/usdt^/, '').to_f * 1_000_000).to_i if /^[0-9]usdt+$/.match?(amount)
123
+ log.debug("Sending #{amount} ERC20 tokens")
124
+ puts wallet.pay(priv.private_hex, address, amount)
125
+ when 'eth_pay'
126
+ pkey = opts.arguments[1]
127
+ raise 'Private key is required' if pkey.nil?
128
+ priv = Eth::Key.new(priv: pkey)
129
+ log.debug("Sending ETH from #{priv.address.to_s}")
130
+ address = opts.arguments[2]
131
+ raise 'Address is required' if address.nil?
132
+ log.debug("Sending ETH to #{address}")
133
+ amount = opts.arguments[3]
134
+ raise 'Amount argument is required' if amount.nil?
135
+ raise "Amount #{amount.inspect} is not valid" unless /^[0-9]+(\.[0-9]+)?(eth|wei|gwei)?$/.match?(amount)
136
+ amount = amount.to_i if /^[0-9]+$/.match?(amount)
137
+ amount = amount.gsub(/wei^/, '').to_i if /[0-9]wei+$/.match?(amount)
138
+ amount = (amount.gsub(/gwei^/, '').to_f * 1_000_000_000).to_i if /[0-9]gwei+$/.match?(amount)
139
+ amount = (amount.gsub(/eth^/, '').to_f * 1_000_000_000_000_000_000).to_i if /[0-9]eth+$/.match?(amount)
140
+ log.debug("Sending #{amount} wei...")
141
+ puts wallet.eth_pay(priv.private_hex, address, amount)
142
+ else
143
+ raise "Command #{opts.arguments[0]} is not supported"
144
+ end
145
+ rescue StandardError => e
146
+ if opts[:verbose]
147
+ puts Backtrace.new(e)
148
+ else
149
+ puts "ERROR: #{e.message}"
150
+ end
151
+ exit(255)
152
+ end
data/erc20.gemspec CHANGED
@@ -12,22 +12,24 @@ 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 Etherium network'
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
- 'Etherium node to provide JSON RPC and Websockets API.'
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'
24
24
  s.files = `git ls-files`.split($RS)
25
25
  s.rdoc_options = ['--charset=UTF-8']
26
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
26
27
  s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
27
28
  s.add_dependency 'eth', '>=0.5.13'
28
29
  s.add_dependency 'faye-websocket', '>=0.11.3'
29
30
  s.add_dependency 'json', '>=2.10.1'
30
31
  s.add_dependency 'jsonrpc-client', '>=0.1.4'
31
32
  s.add_dependency 'loog', '>0'
33
+ s.add_dependency 'slop', '>4'
32
34
  s.metadata['rubygems_mfa_required'] = 'true'
33
35
  end
@@ -0,0 +1,30 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025 Yegor Bugayenko
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ Feature: Command Line Processing
5
+ As a simple ETH/ERC20 user I want to send payments
6
+
7
+ Scenario: Help can be printed
8
+ When I run bin/erc20 with "--help"
9
+ Then Exit code is zero
10
+ And Stdout contains "--help"
11
+
12
+ Scenario: Gas price price can be retrieved
13
+ When I run bin/erc20 with "price --attempts=4"
14
+ Then Exit code is zero
15
+
16
+ Scenario: ETH private key can be generated
17
+ When I run bin/erc20 with "key"
18
+ Then Exit code is zero
19
+
20
+ Scenario: ETH address can be created
21
+ When I run bin/erc20 with "address 46feba063e9b59a8ae0dba68abd39a3cb8f52089e776576d6eb1bb5bfec123d1"
22
+ Then Exit code is zero
23
+
24
+ Scenario: ERC20 balance can be checked
25
+ When I run bin/erc20 with "balance 0x7232148927F8a580053792f44D4d59d40Fd00ABD --verbose"
26
+ Then Exit code is zero
27
+
28
+ Scenario: ETH balance can be checked
29
+ When I run bin/erc20 with "eth_balance 0x7232148927F8a580053792f44D4d59d40Fd00ABD --verbose"
30
+ Then Exit code is zero
@@ -0,0 +1,27 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025 Yegor Bugayenko
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ Feature: Gem Package
5
+ As a source code writer I want to be able to
6
+ package the Gem into .gem file
7
+
8
+ Scenario: Gem can be packaged
9
+ Given It is Unix
10
+ Given I have a "execs.rb" file with content:
11
+ """
12
+ #!/usr/bin/env ruby
13
+ require 'rubygems'
14
+ spec = Gem::Specification::load('./spec.rb')
15
+ if spec.executables.empty?
16
+ fail 'no executables: ' + File.read('./spec.rb')
17
+ end
18
+ """
19
+ When I run bash with:
20
+ """
21
+ cd erc20
22
+ gem build erc20.gemspec
23
+ gem specification --ruby erc20-*.gem > ../spec.rb
24
+ cd ..
25
+ ruby execs.rb
26
+ """
27
+ Then Exit code is zero
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ require 'tmpdir'
7
+ require 'slop'
8
+ require 'English'
9
+ require_relative '../../lib/erc20'
10
+
11
+ Before do
12
+ @cwd = Dir.pwd
13
+ @dir = Dir.mktmpdir('test')
14
+ FileUtils.mkdir_p(@dir)
15
+ Dir.chdir(@dir)
16
+ @opts =
17
+ Slop.parse ['-v'] do |o|
18
+ o.bool '-v', '--verbose'
19
+ end
20
+ end
21
+
22
+ After do
23
+ Dir.chdir(@cwd)
24
+ FileUtils.rm_rf(@dir)
25
+ end
26
+
27
+ Given(/^I have a "([^"]*)" file with content:$/) do |file, text|
28
+ FileUtils.mkdir_p(File.dirname(file)) unless File.exist?(file)
29
+ File.write(file, text.gsub('\\xFF', 0xFF.chr))
30
+ end
31
+
32
+ When(%r{^I run bin/erc20 with "([^"]*)"$}) do |arg|
33
+ home = File.join(File.dirname(__FILE__), '../..')
34
+ @stdout = `ruby -I#{home}/lib #{home}/bin/erc20 #{arg}`
35
+ @exitstatus = $CHILD_STATUS.exitstatus
36
+ end
37
+
38
+ Then(/^Stdout contains "([^"]*)"$/) do |txt|
39
+ raise "STDOUT doesn't contain '#{txt}':\n#{@stdout}" unless @stdout.include?(txt)
40
+ end
41
+
42
+ Then(/^Stdout is empty$/) do
43
+ raise "STDOUT is not empty:\n#{@stdout}" unless @stdout == ''
44
+ end
45
+
46
+ Then(/^Exit code is zero$/) do
47
+ raise "Non-zero exit #{@exitstatus}:\n#{@stdout}" unless @exitstatus.zero?
48
+ end
49
+
50
+ Then(/^Exit code is not zero$/) do
51
+ raise 'Zero exit code' if @exitstatus.zero?
52
+ end
53
+
54
+ When(/^I run bash with "([^"]*)"$/) do |text|
55
+ FileUtils.copy_entry(@cwd, File.join(@dir, 'erc20'))
56
+ @stdout = `#{text}`
57
+ @exitstatus = $CHILD_STATUS.exitstatus
58
+ end
59
+
60
+ When(/^I run bash with:$/) do |text|
61
+ FileUtils.copy_entry(@cwd, File.join(@dir, 'erc20'))
62
+ @stdout = `#{text}`
63
+ @exitstatus = $CHILD_STATUS.exitstatus
64
+ end
65
+
66
+ Given(/^It is Unix$/) do
67
+ pending if Gem.win_platform?
68
+ end
69
+
70
+ Given(/^It is Windows$/) do
71
+ pending unless Gem.win_platform?
72
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ require 'simplecov'
7
+ require 'cucumber'
8
+ require_relative '../../lib/erc20'
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 Etherium ERC20 tokens
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 Etherium APIs, for example
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.0.21'
28
+ VERSION = '0.1.1'
29
29
  end
@@ -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] _priv Private key, in hex
95
- # @param [String] _address Public key, in hex
96
- # @param [Integer] _amount The amount of ERC20 tokens to send
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 Etherium.
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 Etherium
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 Etherium may have many balances. One of them is the main
111
- # balance in ETH crypto. Another balance is the one kept by ERC20 contract
112
- # in its own ledge in root storage. This balance is checked by this method.
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 Etherium may have many balances. One of them is the main
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 much gas units is required in order to send ERC20 transaction.
145
+ # How many gas units are required to send an ERC20 transaction.
146
146
  #
147
- # @param [String] from The departing address, in hex
148
- # @param [String] to Arriving address, in hex
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] How many gas units required
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
- gwei = jsonrpc.eth_getBlockByNumber('latest', false)['baseFeePerGas'].to_i(16)
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 ERC20 tokens to send
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 +eht_subscribe+ to the addresses
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 'Amount must be an Integer' unless delay.is_a?(Integer)
295
- raise 'Amount must be a positive Integer' unless delay.positive?
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)
@@ -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 Etherium mainnet, there are $8 USDT and 0.0042 ETH. I won't
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', http_path: "/v3/#{env('INFURA_KEY')}",
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
- on_hardhat do
294
- w = ERC20::Wallet.new(
295
- host: 'mainnet.infura.io', http_path: "/v3/#{env('INFURA_KEY')}",
296
- proxy:, log: loog
297
- )
298
- assert_equal(8_000_000, w.balance(STABLE))
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 Etherium ERC20 private key (64 chars): '
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
@@ -20,7 +20,7 @@ Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new]
20
20
  # To make tests retry on failure:
21
21
  if ENV['RAKE']
22
22
  require 'minitest/retry'
23
- Minitest::Retry.use!(methods_to_skip: [])
23
+ Minitest::Retry.use!
24
24
  end
25
25
 
26
26
  # Primitive array.
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.0.21
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-02-19 00:00:00.000000000 Z
10
+ date: 2025-04-05 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: eth
@@ -80,12 +79,27 @@ dependencies:
80
79
  - - ">"
81
80
  - !ruby/object:Gem::Version
82
81
  version: '0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: slop
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">"
87
+ - !ruby/object:Gem::Version
88
+ version: '4'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">"
94
+ - !ruby/object:Gem::Version
95
+ version: '4'
83
96
  description: 'A simple library for making ERC20 manipulations as easy as they can
84
97
  be for cryptocurrency newbies: checking balance, sending payments, and monitoring
85
- addresses for incoming payments. The library expects Etherium node to provide JSON
98
+ addresses for incoming payments. The library expects Ethereum node to provide JSON
86
99
  RPC and Websockets API.'
87
100
  email: yegor256@gmail.com
88
- executables: []
101
+ executables:
102
+ - erc20
89
103
  extensions: []
90
104
  extra_rdoc_files:
91
105
  - README.md
@@ -117,7 +131,12 @@ files:
117
131
  - README.md
118
132
  - REUSE.toml
119
133
  - Rakefile
134
+ - bin/erc20
120
135
  - erc20.gemspec
136
+ - features/cli.feature
137
+ - features/gem_package.feature
138
+ - features/step_definitions/steps.rb
139
+ - features/support/env.rb
121
140
  - hardhat/.gitignore
122
141
  - hardhat/Dockerfile
123
142
  - hardhat/contracts/Foo.sol
@@ -137,7 +156,6 @@ licenses:
137
156
  - MIT
138
157
  metadata:
139
158
  rubygems_mfa_required: 'true'
140
- post_install_message:
141
159
  rdoc_options:
142
160
  - "--charset=UTF-8"
143
161
  require_paths:
@@ -153,8 +171,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
153
171
  - !ruby/object:Gem::Version
154
172
  version: '0'
155
173
  requirements: []
156
- rubygems_version: 3.4.10
157
- signing_key:
174
+ rubygems_version: 3.6.2
158
175
  specification_version: 4
159
- summary: Sending and receiving ERC20 tokens in Etherium network
176
+ summary: Sending and receiving ERC20 tokens in Ethereum network
160
177
  test_files: []