erc20 0.2.8 → 0.3.0

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: 34ffb8c4c36d85d7afb74f0a573cc97cb58502ddcb5b39cdd032f771b9547592
4
- data.tar.gz: 5bb3efad4575d96a7d5fc0a3abc58b79835ec1954177dd774858793431595ce8
3
+ metadata.gz: 9719ca99febb05bab13326b5a1de126b73aa5d923ad7f091ef3c4493a6d4030f
4
+ data.tar.gz: b75de1bc31c3e1e1ac2b3167d92ac9d924841048035e190ec961dfebde81d9c5
5
5
  SHA512:
6
- metadata.gz: 4db054bf7264d2df18927384fdbbf6d72152aab5103456e319143681cc97653b7d2236941dbb26961f7de3b9752d7e057382f3695d63e7b3ba4ae92f78e8f00b
7
- data.tar.gz: 5eb68447c8736c39125d19daf27c5856ca7122b3b26784f024efc2fadcf1d5f55b6bb3ff088e335ef29cf55facfa8b734e42d9bb42a28aff78826c6e99dd2d28
6
+ metadata.gz: 6c306141b126499fe21d589809a596567439b7ec70ada449a0b7b4feee656fddb08d94f21943b10c6ea8c73526327a337cc056adc861a720fdee0bdce5e3a2f4
7
+ data.tar.gz: adc65e660ef7394c02f0d37979a7568c91b032a07620d25a40d3874e866468b3531e617e353d8bcd48b9e453d10891aa4977f67e21cbd41912123ce470ea3d79
data/Gemfile CHANGED
@@ -20,6 +20,7 @@ gem 'rake', '~>13.2', require: false
20
20
  gem 'random-port', '~>0.7', require: false
21
21
  gem 'rdoc', '~>7.0', require: false
22
22
  gem 'rubocop', '~>1.75', require: false
23
+ gem 'rubocop-elegant', '~>0.5', require: false
23
24
  gem 'rubocop-minitest', '~>0.38', require: false
24
25
  gem 'rubocop-performance', '~>1.25', require: false
25
26
  gem 'rubocop-rake', '~>0.7', require: false
data/Gemfile.lock CHANGED
@@ -8,18 +8,18 @@ PATH
8
8
  json (~> 2.10)
9
9
  jsonrpc-client (~> 0.1)
10
10
  loog (~> 0.4)
11
- slop (~> 4.0)
11
+ thor (~> 1.3)
12
12
 
13
13
  GEM
14
14
  remote: https://rubygems.org/
15
15
  specs:
16
- addressable (2.8.8)
16
+ addressable (2.9.0)
17
17
  public_suffix (>= 2.0.2, < 8.0)
18
- ansi (1.5.0)
18
+ ansi (1.6.0)
19
19
  ast (2.4.3)
20
20
  backtrace (0.4.1)
21
21
  base64 (0.3.0)
22
- bigdecimal (4.0.1)
22
+ bigdecimal (4.1.2)
23
23
  builder (3.3.0)
24
24
  concurrent-ruby (1.3.6)
25
25
  crack (1.0.1)
@@ -38,30 +38,31 @@ GEM
38
38
  multi_test (~> 1.1)
39
39
  sys-uname (~> 1.3)
40
40
  cucumber-ci-environment (11.0.0)
41
- cucumber-core (16.1.1)
41
+ cucumber-core (16.2.0)
42
42
  cucumber-gherkin (> 36, < 40)
43
43
  cucumber-messages (> 31, < 33)
44
44
  cucumber-tag-expressions (> 6, < 9)
45
- cucumber-cucumber-expressions (19.0.0)
45
+ cucumber-cucumber-expressions (19.0.1)
46
46
  bigdecimal
47
- cucumber-gherkin (38.0.0)
47
+ cucumber-gherkin (39.1.0)
48
48
  cucumber-messages (>= 31, < 33)
49
49
  cucumber-html-formatter (22.3.0)
50
50
  cucumber-messages (> 23, < 33)
51
- cucumber-messages (32.0.1)
51
+ cucumber-messages (32.3.1)
52
52
  cucumber-tag-expressions (8.1.0)
53
53
  date (3.5.1)
54
54
  diff-lcs (1.6.2)
55
55
  docile (1.4.1)
56
- donce (0.4.0)
56
+ donce (0.7.0)
57
57
  backtrace (~> 0.3)
58
58
  os (~> 1.1)
59
59
  qbash (~> 0.3)
60
- elapsed (0.2.2)
60
+ drb (2.2.3)
61
+ elapsed (0.3.1)
61
62
  loog (~> 0.6)
62
63
  tago (~> 0.1)
63
64
  ellipsized (0.3.0)
64
- erb (6.0.1)
65
+ erb (6.0.4)
65
66
  eth (0.5.13)
66
67
  forwardable (~> 1.3)
67
68
  keccak (~> 1.3)
@@ -69,102 +70,107 @@ GEM
69
70
  openssl (>= 2.2, < 4.0)
70
71
  rbsecp256k1 (~> 6.0)
71
72
  scrypt (~> 3.0)
72
- ethon (0.15.0)
73
+ ethon (0.18.0)
73
74
  ffi (>= 1.15.0)
75
+ logger
74
76
  eventmachine (1.2.7)
75
- faraday (2.14.0)
77
+ faraday (2.14.2)
76
78
  faraday-net_http (>= 2.0, < 3.5)
77
79
  json
78
80
  logger
79
- faraday-net_http (3.4.2)
81
+ faraday-net_http (3.4.3)
80
82
  net-http (~> 0.5)
81
83
  faye-websocket (0.12.0)
82
84
  eventmachine (>= 0.12.0)
83
85
  websocket-driver (>= 0.8.0)
84
- ffi (1.17.3-arm64-darwin)
85
- ffi (1.17.3-x64-mingw-ucrt)
86
- ffi (1.17.3-x86_64-darwin)
87
- ffi (1.17.3-x86_64-linux-gnu)
88
- ffi-compiler (1.3.2)
86
+ ffi (1.17.4-arm64-darwin)
87
+ ffi (1.17.4-x64-mingw-ucrt)
88
+ ffi (1.17.4-x86_64-darwin)
89
+ ffi (1.17.4-x86_64-linux-gnu)
90
+ ffi-compiler (1.4.2)
89
91
  ffi (>= 1.15.5)
90
92
  rake
91
93
  forwardable (1.4.0)
92
94
  hashdiff (1.2.1)
93
- json (2.18.0)
95
+ json (2.19.5)
94
96
  jsonrpc-client (0.1.4)
95
97
  faraday
96
98
  multi_json (>= 1.1.0)
97
- keccak (1.3.2)
99
+ keccak (1.3.3)
98
100
  konstructor (1.0.2)
99
101
  language_server-protocol (3.17.0.5)
100
102
  lint_roller (1.1.0)
101
103
  logger (1.7.0)
102
- loog (0.7.2)
104
+ loog (0.8.0)
103
105
  ellipsized
104
106
  logger (~> 1.0)
105
107
  memoist3 (1.0.0)
106
108
  mini_mime (1.1.5)
107
109
  mini_portile2 (2.8.9)
108
- minitest (6.0.1)
110
+ minitest (6.0.6)
111
+ drb (~> 2.0)
109
112
  prism (~> 1.5)
110
- minitest-reporters (1.7.1)
113
+ minitest-reporters (1.8.0)
111
114
  ansi
112
115
  builder
113
- minitest (>= 5.0)
116
+ minitest (>= 5.0, < 7)
114
117
  ruby-progressbar
115
118
  minitest-retry (0.3.1)
116
119
  minitest (>= 5.0)
117
- multi_json (1.19.1)
120
+ multi_json (1.21.1)
118
121
  multi_test (1.1.0)
119
122
  net-http (0.9.1)
120
123
  uri (>= 0.11.1)
121
- openssl (3.3.2)
124
+ openssl (3.3.3)
122
125
  os (1.1.4)
123
- parallel (1.27.0)
124
- parser (3.3.10.1)
126
+ parallel (2.1.0)
127
+ parser (3.3.11.1)
125
128
  ast (~> 2.4.1)
126
129
  racc
127
130
  pkg-config (1.6.5)
128
- prism (1.8.0)
131
+ prism (1.9.0)
129
132
  psych (5.3.1)
130
133
  date
131
134
  stringio
132
- public_suffix (7.0.2)
133
- qbash (0.6.0)
135
+ public_suffix (7.0.5)
136
+ qbash (0.8.4)
134
137
  backtrace (> 0)
135
138
  elapsed (> 0)
136
139
  loog (> 0)
137
140
  tago (> 0)
138
141
  racc (1.8.1)
139
142
  rainbow (3.1.1)
140
- rake (13.3.1)
141
- random-port (0.7.6)
143
+ rake (13.4.2)
144
+ random-port (0.8.2)
142
145
  tago (~> 0.0)
143
146
  rbsecp256k1 (6.0.0)
144
147
  mini_portile2 (~> 2.8)
145
148
  pkg-config (~> 1.5)
146
149
  rubyzip (~> 2.3)
147
- rdoc (7.1.0)
150
+ rdoc (7.2.0)
148
151
  erb
149
152
  psych (>= 4.0.0)
150
153
  tsort
151
- regexp_parser (2.11.3)
154
+ regexp_parser (2.12.0)
152
155
  rexml (3.4.4)
153
- rubocop (1.82.1)
156
+ rubocop (1.86.2)
154
157
  json (~> 2.3)
155
158
  language_server-protocol (~> 3.17.0.2)
156
159
  lint_roller (~> 1.1.0)
157
- parallel (~> 1.10)
160
+ parallel (>= 1.10)
158
161
  parser (>= 3.3.0.2)
159
162
  rainbow (>= 2.2.2, < 4.0)
160
163
  regexp_parser (>= 2.9.3, < 3.0)
161
- rubocop-ast (>= 1.48.0, < 2.0)
164
+ rubocop-ast (>= 1.49.0, < 2.0)
162
165
  ruby-progressbar (~> 1.7)
163
166
  unicode-display_width (>= 2.4.0, < 4.0)
164
- rubocop-ast (1.49.0)
167
+ rubocop-ast (1.49.1)
165
168
  parser (>= 3.3.7.2)
166
169
  prism (~> 1.7)
167
- rubocop-minitest (0.38.2)
170
+ rubocop-elegant (0.5.1)
171
+ lint_roller (~> 1.1)
172
+ rubocop (~> 1.75)
173
+ rubocop-minitest (0.39.1)
168
174
  lint_roller (~> 1.1)
169
175
  rubocop (>= 1.75.0, < 2.0)
170
176
  rubocop-ast (>= 1.38.0, < 2.0)
@@ -189,23 +195,27 @@ GEM
189
195
  simplecov (~> 0.19)
190
196
  simplecov-html (0.13.2)
191
197
  simplecov_json_formatter (0.1.4)
192
- slop (4.10.1)
193
198
  stringio (3.2.0)
194
- sys-uname (1.4.1)
199
+ sys-uname (1.5.1)
200
+ ffi (~> 1.1)
201
+ memoist3 (~> 1.0.0)
202
+ sys-uname (1.5.1-universal-mingw32)
195
203
  ffi (~> 1.1)
196
204
  memoist3 (~> 1.0.0)
197
- tago (0.6.0)
205
+ win32ole
206
+ tago (0.7.0)
207
+ thor (1.5.0)
198
208
  threads (0.5.0)
199
209
  backtrace (~> 0)
200
210
  concurrent-ruby (~> 1.0)
201
211
  tsort (0.2.0)
202
- typhoeus (1.5.0)
203
- ethon (>= 0.9.0, < 0.16.0)
212
+ typhoeus (1.6.0)
213
+ ethon (>= 0.18.0)
204
214
  unicode-display_width (3.2.0)
205
215
  unicode-emoji (~> 4.1)
206
216
  unicode-emoji (4.2.0)
207
217
  uri (1.1.1)
208
- webmock (3.26.1)
218
+ webmock (3.26.2)
209
219
  addressable (>= 2.8.0)
210
220
  crack (>= 0.3.2)
211
221
  hashdiff (>= 0.4.0, < 2.0.0)
@@ -213,7 +223,8 @@ GEM
213
223
  base64
214
224
  websocket-extensions (>= 0.1.0)
215
225
  websocket-extensions (0.1.5)
216
- yard (0.9.38)
226
+ win32ole (1.9.3)
227
+ yard (0.9.44)
217
228
 
218
229
  PLATFORMS
219
230
  arm64-darwin-22
@@ -240,6 +251,7 @@ DEPENDENCIES
240
251
  random-port (~> 0.7)
241
252
  rdoc (~> 7.0)
242
253
  rubocop (~> 1.75)
254
+ rubocop-elegant (~> 0.5)
243
255
  rubocop-minitest (~> 0.38)
244
256
  rubocop-performance (~> 1.25)
245
257
  rubocop-rake (~> 0.7)
data/README.md CHANGED
@@ -29,7 +29,7 @@ Or simply add this to your Gemfile:
29
29
  gem 'erc20'
30
30
  ```
31
31
 
32
- Then, make an instance of the main class and use to read
32
+ Then, make an instance of the main class and use it to read
33
33
  balances, send and receive payments:
34
34
 
35
35
  ```ruby
@@ -40,6 +40,8 @@ w = ERC20::Wallet.new(
40
40
  host: 'mainnet.infura.io',
41
41
  http_path: '/v3/<your-infura-key>',
42
42
  ws_path: '/ws/v3/<your-infura-key>',
43
+ attempts: 3, # retry failed HTTP RPC calls up to 3 times, with backoff
44
+ fallbacks: ['https://eth.drpc.org'], # alternative RPC endpoints to try
43
45
  log: $stdout
44
46
  )
45
47
 
@@ -75,8 +77,8 @@ To check the price of a gas unit and the expected cost of a payment:
75
77
  # How many gas units required to send this payment:
76
78
  units = w.gas_estimate(from, to, amount)
77
79
 
78
- # What is the price of a gas unit, in gwei:
79
- gwei = w.gas_price
80
+ # What is the price of a gas unit, in wei:
81
+ price = w.gas_price
80
82
  ```
81
83
 
82
84
  To generate a new private key, use [eth](https://rubygems.org/gems/eth):
@@ -106,7 +108,7 @@ w = ERC20::Wallet.new(
106
108
  You can use [squid-proxy] [Docker] image to set up your own [HTTP proxy] server.
107
109
 
108
110
  Of course, this library works with [Polygon], [Optimism],
109
- and other EVM compatible blockchains.
111
+ and other [EVM] compatible blockchains.
110
112
 
111
113
  ## How to use in command line
112
114
 
@@ -122,7 +124,7 @@ gem install erc20
122
124
  Then, run it:
123
125
 
124
126
  ```bash
125
- erc20 --help
127
+ erc20 help
126
128
  ```
127
129
 
128
130
  Usage should be straightforward. If you have questions, please submit an issue.
@@ -170,3 +172,4 @@ If it's clean and you don't see any error messages, submit your pull request.
170
172
  [Docker]: https://www.docker.com/
171
173
  [Polygon]: https://polygon.technology/
172
174
  [Optimism]: https://www.optimism.io/
175
+ [EVM]: https://ethereum.org/developers/docs/evm/
data/Rakefile CHANGED
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'rake'
4
+ require 'rake/clean'
3
5
  # SPDX-FileCopyrightText: Copyright (c) 2025 Yegor Bugayenko
4
6
  # SPDX-License-Identifier: MIT
5
7
 
6
8
  require 'rubygems'
7
- require 'rake'
8
- require 'rake/clean'
9
9
 
10
10
  ENV['RAKE'] = 'true'
11
11
 
data/bin/erc20 CHANGED
@@ -8,126 +8,145 @@ $stdout.sync = true
8
8
 
9
9
  require 'backtrace'
10
10
  require 'loog'
11
- require 'slop'
11
+ require 'thor'
12
12
  require_relative '../lib/erc20'
13
13
  require_relative '../lib/erc20/erc20'
14
14
  require_relative '../lib/erc20/wallet'
15
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.bool(
40
- '--ssl',
41
- 'Use SSL for HTTP connections',
42
- default: true
43
- )
44
- o.string(
45
- '--host',
46
- 'Host name of the provider',
47
- default: 'eth.llamarpc.com'
48
- )
49
- o.string(
50
- '--port',
51
- 'TCP port of the provider',
52
- default: 443
53
- )
54
- o.string(
55
- '--http_path',
56
- 'URL path for the HTTP RPC entry point of the provider',
57
- default: '/'
58
- )
59
- o.string(
60
- '--ws_path',
61
- 'URL path for the Websockets entry point of the provider',
62
- default: '/'
63
- )
64
- o.string(
65
- '--proxy',
66
- 'HTTP/S proxy for all requests, e.g. "localhost:3128"'
67
- )
68
- o.integer(
69
- '--attempts',
70
- 'How many times should we try before failing',
71
- default: 1
72
- )
73
- o.bool(
74
- '--dry',
75
- 'Don\'t send a real payment, run in a read-only mode'
76
- )
77
- o.bool('--help', 'Read this: https://github.com/yegor256/erc20') do
78
- puts o
79
- exit
80
- end
81
- o.bool('--verbose', 'Print all possible debug messages')
82
- end
83
- rescue Slop::Error => e
84
- raise e.message
16
+ # Command line interface for ERC20 operations.
17
+ #
18
+ # This CLI provides commands for managing ERC20 tokens and ETH on Ethereum:
19
+ # generating keys, checking balances, and sending payments.
20
+ #
21
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
22
+ # Copyright:: Copyright (c) 2025 Yegor Bugayenko
23
+ # License:: MIT
24
+ class Bin < Thor
25
+ def self.exit_on_failure?
26
+ true
85
27
  end
86
- raise 'Try --help' if opts.arguments.empty?
87
- log = opts[:verbose] ? Loog::VERBOSE : Loog::REGULAR
88
- wallet =
89
- if opts[:dry]
90
- ERC20::FakeWallet.new
91
- else
92
- ERC20::Wallet.new(
93
- contract: opts[:contract],
94
- host: opts[:host], port: opts[:port].to_i,
95
- http_path: opts[:http_path], ws_path: opts[:ws_path],
96
- ssl: opts[:ssl],
97
- log:
98
- )
99
- end
100
- case opts.arguments[0]
101
- when 'key'
102
- puts Eth::Key.new.private_hex.downcase
103
- when 'address'
104
- puts Eth::Key.new(priv: opts.arguments[1]).address.to_s.downcase
105
- when 'price'
106
- puts wallet.gas_price
107
- when 'balance'
108
- address = opts.arguments[1]
109
- raise 'Address is required' if address.nil?
28
+
29
+ class_option :contract, type: :string, default: ERC20::Wallet::USDT,
30
+ desc: 'Public address of ERC20 contract'
31
+ class_option :chain, type: :numeric, default: 1,
32
+ desc: 'Ethereum chain ID'
33
+ class_option :ssl, type: :boolean, default: true,
34
+ desc: 'Use SSL for HTTP connections'
35
+ class_option :host, type: :string, default: 'eth.llamarpc.com',
36
+ desc: 'Host name of the provider'
37
+ class_option :port, type: :numeric, default: 443,
38
+ desc: 'TCP port of the provider'
39
+ class_option :http_path, type: :string, default: '/',
40
+ desc: 'URL path for the HTTP RPC entry point of the provider'
41
+ class_option :ws_path, type: :string, default: '/',
42
+ desc: 'URL path for the Websockets entry point of the provider'
43
+ class_option :proxy, type: :string,
44
+ desc: 'HTTP/S proxy for all requests, e.g. "localhost:3128"'
45
+ class_option :attempts, type: :numeric, default: 1,
46
+ desc: 'How many times should we try before failing'
47
+ class_option :fallbacks, type: :array,
48
+ default: ['https://ethereum.publicnode.com', 'https://eth.drpc.org', 'https://rpc.ankr.com/eth'],
49
+ desc: 'Fallback HTTP RPC endpoint URLs to try when the primary host fails'
50
+ class_option :dry, type: :boolean, default: false,
51
+ desc: "Don't send a real payment, run in a read-only mode"
52
+ class_option :verbose, type: :boolean, default: false,
53
+ desc: 'Print all possible debug messages'
54
+
55
+ desc 'version', 'Print version of the tool'
56
+ def version
57
+ log.info(ERC20::VERSION)
58
+ end
59
+
60
+ desc 'key', 'Generate a new Ethereum private key (64 hex symbols)'
61
+ def key
62
+ log.info(Eth::Key.new.private_hex.downcase)
63
+ end
64
+
65
+ desc 'address KEY', 'Turn private key into a public address (44 hex symbols)'
66
+ def address(pvt)
67
+ log.info(Eth::Key.new(priv: pvt).address.to_s.downcase)
68
+ end
69
+
70
+ desc 'price', 'Get current price of one gas unit, in gwei'
71
+ def price
72
+ log.info(wallet.gas_price)
73
+ end
74
+
75
+ desc 'balance ADDRESS', 'Get ERC20 balance'
76
+ def balance(address)
110
77
  log.debug("Checking ERC20 balance of #{address}")
111
78
  tokens = wallet.balance(address)
112
79
  log.debug("The balance is #{tokens} ERC20 tokens (#{tokens.to_f / 1_000_000} USDT)")
113
- puts tokens
114
- when 'eth_balance'
115
- address = opts.arguments[1]
116
- raise 'Address is required' if address.nil?
80
+ log.info(tokens)
81
+ end
82
+
83
+ desc 'eth_balance ADDRESS', 'Get ETH balance'
84
+ def eth_balance(address)
117
85
  log.debug("Checking ETH balance of #{address}")
118
86
  wei = wallet.eth_balance(address)
119
87
  log.debug("The balance of #{address} is #{wei} wei (#{format('%0.4f', wei.to_f / 1_000_000_000_000_000_000)} ETH)")
120
- puts wei
121
- when 'pay'
122
- pkey = opts.arguments[1]
123
- raise 'Private key is required' if pkey.nil?
88
+ log.info(wei)
89
+ end
90
+
91
+ desc 'pay KEY ADDRESS AMOUNT', 'Send ERC20 payment'
92
+ def pay(pkey, address, amount)
124
93
  priv = Eth::Key.new(priv: pkey)
125
- log.debug("Sending ERC20 tokens from #{priv.address.to_s}")
126
- address = opts.arguments[2]
127
- raise 'Address is required' if address.nil?
94
+ log.debug("Sending ERC20 tokens from #{priv.address}")
128
95
  log.debug("Sending ERC20 tokens to #{address}")
129
- amount = opts.arguments[3]
130
- raise 'Amount argument is required (for example, "19.9usdt" or "$19.9")' if amount.nil?
96
+ amount = tokens(amount)
97
+ log.debug("Sending #{amount} ERC20 tokens")
98
+ if wallet.eth_balance(priv.address.to_s).zero?
99
+ log.debug("ETH balance of #{priv.address} is zero, the txn most definitely will be rejected by the server!")
100
+ end
101
+ log.info(wallet.pay(priv.private_hex, address, amount))
102
+ end
103
+
104
+ desc 'eth_pay KEY ADDRESS AMOUNT', 'Send ETH payment'
105
+ def eth_pay(pkey, address, amount)
106
+ priv = Eth::Key.new(priv: pkey)
107
+ log.debug("Sending ETH from #{priv.address}")
108
+ log.debug("Sending ETH to #{address}")
109
+ raise "Amount #{amount.inspect} is not valid" unless /^[0-9]+(\.[0-9]+)?(eth|wei|gwei)?$/.match?(amount)
110
+ amount = wei(amount)
111
+ log.debug("Sending #{amount} wei...")
112
+ log.info(wallet.eth_pay(priv.private_hex, address, amount))
113
+ end
114
+
115
+ def self.banner(task, namespace = false, subcommand = false)
116
+ "#{basename} #{task.usage}"
117
+ end
118
+
119
+ def self.help(shell, subcommand = false)
120
+ shell.say "Usage (#{ERC20::VERSION}): erc20 [options] command [args]"
121
+ shell.say 'Commands are:'
122
+ super
123
+ shell.say "\nRead this: https://github.com/yegor256/erc20"
124
+ end
125
+
126
+ private
127
+
128
+ def log
129
+ @log ||= options[:verbose] ? Loog::VERBOSE : Loog::REGULAR
130
+ end
131
+
132
+ def wallet
133
+ @wallet ||=
134
+ if options[:dry]
135
+ ERC20::FakeWallet.new
136
+ else
137
+ ERC20::Wallet.new(
138
+ contract: options[:contract],
139
+ host: options[:host], port: options[:port].to_i,
140
+ http_path: options[:http_path], ws_path: options[:ws_path],
141
+ ssl: options[:ssl],
142
+ attempts: options[:attempts].to_i,
143
+ fallbacks: options[:fallbacks],
144
+ log: log
145
+ )
146
+ end
147
+ end
148
+
149
+ def tokens(amount)
131
150
  if /^[0-9]+$/.match?(amount)
132
151
  amount = amount.to_i
133
152
  log.debug("The token amount equals to #{amount} ERC20 tokens (as provided)")
@@ -140,43 +159,29 @@ Options are:"
140
159
  else
141
160
  raise "Can't understand amount: #{amount.inspect}"
142
161
  end
143
- log.debug("Sending #{amount} ERC20 tokens")
144
- if wallet.eth_balance(priv.address.to_s).zero?
145
- log.debug("ETH balance of #{priv.address} is zero, the txn most definitely will be rejected by the server!")
146
- end
147
- puts wallet.pay(priv.private_hex, address, amount)
148
- when 'eth_pay'
149
- pkey = opts.arguments[1]
150
- raise 'Private key is required' if pkey.nil?
151
- priv = Eth::Key.new(priv: pkey)
152
- log.debug("Sending ETH from #{priv.address.to_s}")
153
- address = opts.arguments[2]
154
- raise 'Address is required' if address.nil?
155
- log.debug("Sending ETH to #{address}")
156
- amount = opts.arguments[3]
157
- raise 'Amount argument is required' if amount.nil?
158
- raise "Amount #{amount.inspect} is not valid" unless /^[0-9]+(\.[0-9]+)?(eth|wei|gwei)?$/.match?(amount)
162
+ amount
163
+ end
164
+
165
+ def wei(amount)
159
166
  if /^[0-9]+$/.match?(amount)
160
- amount = amount.to_i
161
- elsif /[0-9]wei+$/.match?(amount)
162
- amount = amount.gsub(/wei^/, '').to_i
163
- elsif /[0-9]gwei+$/.match?(amount)
164
- amount = (amount.gsub(/gwei^/, '').to_f * 1_000_000_000).to_i
165
- elsif /[0-9]eth+$/.match?(amount)
166
- amount = (amount.gsub(/eth^/, '').to_f * 1_000_000_000_000_000_000).to_i
167
+ amount.to_i
168
+ elsif /[0-9]wei$/.match?(amount)
169
+ amount.gsub(/wei$/, '').to_i
170
+ elsif /[0-9]gwei$/.match?(amount)
171
+ (amount.gsub(/gwei$/, '').to_f * 1_000_000_000).to_i
172
+ elsif /[0-9]eth$/.match?(amount)
173
+ (amount.gsub(/eth$/, '').to_f * 1_000_000_000_000_000_000).to_i
167
174
  else
168
175
  raise "Can't understand amount: #{amount.inspect}"
169
176
  end
170
- log.debug("Sending #{amount} wei...")
171
- puts wallet.eth_pay(priv.private_hex, address, amount)
172
- else
173
- raise "Command #{opts.arguments[0]} is not supported"
174
177
  end
178
+ end
179
+
180
+ begin
181
+ Bin.start(ARGV)
175
182
  rescue StandardError => e
176
- if opts[:verbose]
177
- puts Backtrace.new(e)
178
- else
179
- puts "ERROR: #{e.message}"
180
- end
183
+ log = ARGV.include?('--verbose') ? Loog::VERBOSE : Loog::REGULAR
184
+ log.debug(Backtrace.new(e))
185
+ log.error(e.message)
181
186
  exit(255)
182
187
  end