erc20 0.1.1 → 0.1.2

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: fbce7bc57948f9c8acfeec7c0af2cf67e70e2447e064040485e6868d466828dc
4
- data.tar.gz: cc521c55db79dca85e58235c886172a7ca81cf0f59ee61f5c134cc888eb3db4c
3
+ metadata.gz: 96f0b876fa43c7c6ca87ebd998987fce27fa8a3c1923d906e71d674265083e7a
4
+ data.tar.gz: 9b43b005266bb003a086b4457a0d31f1dcd7eba08b82d6301ae5a93f9bfd32d3
5
5
  SHA512:
6
- metadata.gz: c712231ba46caabca78b45e9be366c120e2f5275bc734c874f69c7306d1f961c7b7c3a5b8ae58341cb4d48776a91c5a8bc8ec2360dfcbc294d46ae329d9bf8a4
7
- data.tar.gz: 7a074720cfec0773a6e4e0cc70fe07fde201ae9897cb395a2b91a84429683354b822bef0be10650290b554ffe59b150034a1ea320eed34a396d574267954c130
6
+ metadata.gz: 1d3e51d047763a3139c77286b41af1fdfeb40c2d10ed0c86dbfe1f1443d328957a1b37fc27a147ffcfcbb2c40f1071144a781292cf71e58dd5858045740cefd4
7
+ data.tar.gz: d4baf3bd795940d5daad717ec0b8b182bc849fc000fd402ae3906d93ad31d371c1ed5aaf82e02af2ccc4ff051bd24b83104c73316c34eeb917c094e747f1f9f0
data/Gemfile CHANGED
@@ -7,6 +7,7 @@ source 'https://rubygems.org'
7
7
  gemspec
8
8
 
9
9
  gem 'backtrace', '>0', require: false
10
+ gem 'concurrent-ruby', '~>1.2', require: false
10
11
  gem 'cucumber', '~>9.2', require: false
11
12
  gem 'donce', '>0', require: false
12
13
  gem 'faraday', '>0', require: false
data/Gemfile.lock CHANGED
@@ -46,14 +46,15 @@ GEM
46
46
  cucumber-tag-expressions (6.1.2)
47
47
  diff-lcs (1.6.1)
48
48
  docile (1.4.1)
49
- donce (0.1.0)
50
- backtrace (> 0)
51
- os (> 0)
52
- qbash (> 0)
49
+ donce (0.2.0)
50
+ backtrace (~> 0.3)
51
+ os (~> 1.1)
52
+ qbash (~> 0.3)
53
53
  elapsed (0.0.1)
54
54
  loog (> 0)
55
55
  tago (> 0)
56
- eth (0.5.13)
56
+ eth (0.5.14)
57
+ bigdecimal (~> 3.1)
57
58
  forwardable (~> 1.3)
58
59
  keccak (~> 1.3)
59
60
  konstructor (~> 1.0)
@@ -63,7 +64,7 @@ GEM
63
64
  ethon (0.16.0)
64
65
  ffi (>= 1.15.0)
65
66
  eventmachine (1.2.7)
66
- faraday (2.12.2)
67
+ faraday (2.13.0)
67
68
  faraday-net_http (>= 2.0, < 3.5)
68
69
  json
69
70
  logger
@@ -72,10 +73,10 @@ GEM
72
73
  faye-websocket (0.11.3)
73
74
  eventmachine (>= 0.12.0)
74
75
  websocket-driver (>= 0.5.1)
75
- ffi (1.17.1-arm64-darwin)
76
- ffi (1.17.1-x64-mingw-ucrt)
77
- ffi (1.17.1-x86_64-darwin)
78
- ffi (1.17.1-x86_64-linux-gnu)
76
+ ffi (1.17.2-arm64-darwin)
77
+ ffi (1.17.2-x64-mingw-ucrt)
78
+ ffi (1.17.2-x86_64-darwin)
79
+ ffi (1.17.2-x86_64-linux-gnu)
79
80
  ffi-compiler (1.3.2)
80
81
  ffi (>= 1.15.5)
81
82
  rake
@@ -106,11 +107,11 @@ GEM
106
107
  uri
107
108
  openssl (3.3.0)
108
109
  os (1.1.4)
109
- parallel (1.26.3)
110
- parser (3.3.7.4)
110
+ parallel (1.27.0)
111
+ parser (3.3.8.0)
111
112
  ast (~> 2.4.1)
112
113
  racc
113
- pkg-config (1.6.0)
114
+ pkg-config (1.6.1)
114
115
  prism (1.4.0)
115
116
  qbash (0.4.0)
116
117
  backtrace (> 0)
@@ -139,7 +140,7 @@ GEM
139
140
  rubocop-ast (>= 1.44.0, < 2.0)
140
141
  ruby-progressbar (~> 1.7)
141
142
  unicode-display_width (>= 2.4.0, < 4.0)
142
- rubocop-ast (1.44.0)
143
+ rubocop-ast (1.44.1)
143
144
  parser (>= 3.3.7.2)
144
145
  prism (~> 1.4)
145
146
  rubocop-minitest (0.38.0)
@@ -153,7 +154,7 @@ GEM
153
154
  rubocop-rake (0.7.1)
154
155
  lint_roller (~> 1.1)
155
156
  rubocop (>= 1.72.1)
156
- rubocop-rspec (3.5.0)
157
+ rubocop-rspec (3.6.0)
157
158
  lint_roller (~> 1.1)
158
159
  rubocop (~> 1.72, >= 1.72.1)
159
160
  ruby-progressbar (1.13.0)
@@ -200,6 +201,7 @@ PLATFORMS
200
201
 
201
202
  DEPENDENCIES
202
203
  backtrace (> 0)
204
+ concurrent-ruby (~> 1.2)
203
205
  cucumber (~> 9.2)
204
206
  donce (> 0)
205
207
  erc20!
data/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # Ethereum ERC20 Manipulations in Ruby
2
2
 
3
- [![DevOps By Rultor.com](http://www.rultor.com/b/yegor256/erc20)](http://www.rultor.com/p/yegor256/erc20)
3
+ [![DevOps By Rultor.com](https://www.rultor.com/b/yegor256/erc20)](https://www.rultor.com/p/yegor256/erc20)
4
4
  [![We recommend RubyMine](https://www.elegantobjects.org/rubymine.svg)](https://www.jetbrains.com/ruby/)
5
5
 
6
6
  [![rake](https://github.com/yegor256/erc20/actions/workflows/rake.yml/badge.svg)](https://github.com/yegor256/erc20/actions/workflows/rake.yml)
7
- [![PDD status](http://www.0pdd.com/svg?name=yegor256/erc20)](http://www.0pdd.com/p?name=yegor256/erc20)
8
- [![Gem Version](https://badge.fury.io/rb/erc20.svg)](http://badge.fury.io/rb/erc20)
7
+ [![PDD status](https://www.0pdd.com/svg?name=yegor256/erc20)](https://www.0pdd.com/p?name=yegor256/erc20)
8
+ [![Gem Version](https://badge.fury.io/rb/erc20.svg)](https://badge.fury.io/rb/erc20)
9
9
  [![Test Coverage](https://img.shields.io/codecov/c/github/yegor256/erc20.svg)](https://codecov.io/github/yegor256/erc20?branch=master)
10
- [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/github/yegor256/erc20/master/frames)
10
+ [![Yard Docs](https://img.shields.io/badge/yard-docs-blue.svg)](https://rubydoc.info/github/yegor256/erc20/master/frames)
11
11
  [![Hits-of-Code](https://hitsofcode.com/github/yegor256/erc20)](https://hitsofcode.com/view/github/yegor256/erc20)
12
12
  [![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/yegor256/erc20/blob/master/LICENSE.txt)
13
13
 
@@ -15,7 +15,22 @@ This small Ruby [gem](https://rubygems.org/gems/erc20)
15
15
  makes manipulations with [Ethereum] [ERC20] tokens
16
16
  as simple as possible, when you have a provider of
17
17
  [JSON-RPC] and [WebSockets] Ethereum APIs, such as
18
- [Infura], [GetBlock], or [Alchemy]:
18
+ [Infura], [GetBlock], or [Alchemy].
19
+
20
+ Install it like this:
21
+
22
+ ```bash
23
+ gem install erc20
24
+ ```
25
+
26
+ Or simply add this to your Gemfile:
27
+
28
+ ```ruby
29
+ gem 'erc20'
30
+ ```
31
+
32
+ Then, make an instance of the main class and use to read
33
+ balances, send and receive payments:
19
34
 
20
35
  ```ruby
21
36
  # Create a wallet:
data/lib/erc20/erc20.rb CHANGED
@@ -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.1'
28
+ VERSION = '0.1.2'
29
29
  end
data/lib/erc20/wallet.rb CHANGED
@@ -121,7 +121,7 @@ class ERC20::Wallet
121
121
  data = "0x#{func}000000000000000000000000#{address[2..].downcase}"
122
122
  r = jsonrpc.eth_call({ to: @contract, data: data }, 'latest')
123
123
  b = r[2..].to_i(16)
124
- @log.debug("Balance of #{address} is #{b} ERC20 tokens")
124
+ @log.debug("The balance of #{address} is #{b} ERC20 tokens")
125
125
  b
126
126
  end
127
127
 
@@ -138,7 +138,7 @@ class ERC20::Wallet
138
138
  raise 'Invalid format of the address' unless /^0x[0-9a-fA-F]{40}$/.match?(address)
139
139
  r = jsonrpc.eth_getBalance(address, 'latest')
140
140
  b = r[2..].to_i(16)
141
- @log.debug("Balance of #{address} is #{b} ETHs")
141
+ @log.debug("The balance of #{address} is #{b} ETHs")
142
142
  b
143
143
  end
144
144
 
@@ -294,9 +294,14 @@ class ERC20::Wallet
294
294
  # Once we actually start listening, the +active+ array will be updated
295
295
  # with the list of addresses.
296
296
  #
297
- # The +addresses+ must have +to_a()+ implemented.
298
- # The +active+ must have +append()+ implemented.
299
- # Only these methods will be called.
297
+ # The +addresses+ must have +to_a()+ implemented. This method will be
298
+ # called every +delay+ seconds. It is expected that it returns the list
299
+ # of Ethereum public addresses that must be monitored.
300
+ #
301
+ # The +active+ must have +append()+ and +to_a()+ implemented. This array
302
+ # maintains the list of addresses that were mentioned in incoming transactions.
303
+ # This array is used mostly for testing. It is suggested to always provide
304
+ # an empty array.
300
305
  #
301
306
  # @param [Array<String>] addresses Addresses to monitor
302
307
  # @param [Array] active List of addresses that we are actually listening to
@@ -353,7 +358,11 @@ class ERC20::Wallet
353
358
  "from #{event[:from]} to #{event[:to]} in #{event[:txn]}"
354
359
  )
355
360
  end
356
- yield event
361
+ begin
362
+ yield event
363
+ rescue StandardError => e
364
+ @log.error(Backtrace.new(e).to_s)
365
+ end
357
366
  end
358
367
  end
359
368
  end
@@ -8,7 +8,6 @@ require 'donce'
8
8
  require 'eth'
9
9
  require 'faraday'
10
10
  require 'loog'
11
- require 'minitest/autorun'
12
11
  require 'random-port'
13
12
  require 'shellwords'
14
13
  require 'threads'
@@ -20,7 +19,7 @@ require_relative '../../lib/erc20/fake_wallet'
20
19
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
21
20
  # Copyright:: Copyright (c) 2025 Yegor Bugayenko
22
21
  # License:: MIT
23
- class TestFakeWallet < Minitest::Test
22
+ class TestFakeWallet < ERC20::Test
24
23
  def test_checks_gas_estimate
25
24
  b = ERC20::FakeWallet.new.gas_estimate(
26
25
  '0xEB2fE8872A6f1eDb70a2632Effffffffffffffff',
@@ -8,7 +8,6 @@ require 'donce'
8
8
  require 'eth'
9
9
  require 'faraday'
10
10
  require 'loog'
11
- require 'minitest/autorun'
12
11
  require 'random-port'
13
12
  require 'shellwords'
14
13
  require 'threads'
@@ -20,7 +19,7 @@ require_relative '../../lib/erc20/wallet'
20
19
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
21
20
  # Copyright:: Copyright (c) 2025 Yegor Bugayenko
22
21
  # License:: MIT
23
- class TestWallet < Minitest::Test
22
+ class TestWallet < ERC20::Test
24
23
  # At this address, in Ethereum mainnet, there are $8 USDT and 0.0042 ETH. I won't
25
24
  # move them anyway, that's why tests can use this address forever.
26
25
  STABLE = '0x7232148927F8a580053792f44D4d59d40Fd00ABD'
@@ -60,6 +59,7 @@ class TestWallet < Minitest::Test
60
59
  def test_fails_with_invalid_infura_key
61
60
  skip('Apparently, even with invalid key, Infura returns balance')
62
61
  w = ERC20::Wallet.new(
62
+ contract: ERC20::Wallet.USDT,
63
63
  host: 'mainnet.infura.io',
64
64
  http_path: '/v3/invalid-key-here',
65
65
  log: loog
@@ -201,6 +201,57 @@ class TestWallet < Minitest::Test
201
201
  end
202
202
  end
203
203
 
204
+ def test_accepts_many_payments_on_hardhat
205
+ walter = Eth::Key.new(priv: WALTER).address.to_s.downcase
206
+ on_hardhat do |wallet|
207
+ active = []
208
+ events = Concurrent::Set.new
209
+ total = 10
210
+ daemon =
211
+ Thread.new do
212
+ wallet.accept([walter], active) do |e|
213
+ events.add(e)
214
+ end
215
+ rescue StandardError => e
216
+ loog.error(Backtrace.new(e))
217
+ end
218
+ wait_for { !active.empty? }
219
+ sum = 1_234
220
+ Threads.new(total).assert do
221
+ wallet.pay(JEFF, walter, sum)
222
+ end
223
+ wait_for { events.size == total }
224
+ daemon.kill
225
+ daemon.join(30)
226
+ assert_equal(total, events.size)
227
+ end
228
+ end
229
+
230
+ def test_accepts_payments_with_failures_on_hardhat
231
+ walter = Eth::Key.new(priv: WALTER).address.to_s.downcase
232
+ on_hardhat do |wallet|
233
+ active = []
234
+ events = Concurrent::Set.new
235
+ total = 10
236
+ daemon =
237
+ Thread.new do
238
+ wallet.accept([walter], active) do |e|
239
+ events.add(e)
240
+ raise 'intentional'
241
+ end
242
+ end
243
+ wait_for { !active.empty? }
244
+ sum = 1_234
245
+ Threads.new(total).assert do
246
+ wallet.pay(JEFF, walter, sum)
247
+ end
248
+ wait_for { events.size == total }
249
+ daemon.kill
250
+ daemon.join(30)
251
+ assert_equal(total, events.size)
252
+ end
253
+ end
254
+
204
255
  def test_accepts_payments_on_changing_addresses_on_hardhat
205
256
  walter = Eth::Key.new(priv: WALTER).address.to_s.downcase
206
257
  jeff = Eth::Key.new(priv: JEFF).address.to_s.downcase
data/test/test__helper.rb CHANGED
@@ -6,14 +6,27 @@
6
6
  $stdout.sync = true
7
7
 
8
8
  require 'simplecov'
9
- SimpleCov.external_at_exit = true
10
- SimpleCov.start
11
-
12
9
  require 'simplecov-cobertura'
13
- SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter
10
+ unless SimpleCov.running
11
+ SimpleCov.command_name('test')
12
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
13
+ [
14
+ SimpleCov::Formatter::HTMLFormatter,
15
+ SimpleCov::Formatter::CoberturaFormatter
16
+ ]
17
+ )
18
+ SimpleCov.minimum_coverage 90
19
+ SimpleCov.minimum_coverage_by_file 90
20
+ SimpleCov.start do
21
+ add_filter 'test/'
22
+ add_filter 'vendor/'
23
+ add_filter 'target/'
24
+ track_files 'lib/**/*.rb'
25
+ track_files '*.rb'
26
+ end
27
+ end
14
28
 
15
29
  require 'minitest/autorun'
16
-
17
30
  require 'minitest/reporters'
18
31
  Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new]
19
32
 
@@ -42,7 +55,7 @@ end
42
55
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
43
56
  # Copyright:: Copyright (c) 2025 Yegor Bugayenko
44
57
  # License:: MIT
45
- class Minitest::Test
58
+ class ERC20::Test < Minitest::Test
46
59
  def loog
47
60
  ENV['RAKE'] ? Loog::ERRORS : Loog::VERBOSE
48
61
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: erc20
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-04-05 00:00:00.000000000 Z
10
+ date: 2025-04-20 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: eth
@@ -122,7 +122,6 @@ files:
122
122
  - ".pdd"
123
123
  - ".rubocop.yml"
124
124
  - ".rultor.yml"
125
- - ".simplecov"
126
125
  - ".yamllint.yml"
127
126
  - Gemfile
128
127
  - Gemfile.lock
data/.simplecov DELETED
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #
4
- # SPDX-FileCopyrightText: Copyright (c) 2025 Yegor Bugayenko
5
- # SPDX-License-Identifier: MIT
6
-
7
- if Gem.win_platform?
8
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
9
- SimpleCov::Formatter::HTMLFormatter
10
- ]
11
- SimpleCov.start do
12
- add_filter '/test/'
13
- end
14
- else
15
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
16
- [SimpleCov::Formatter::HTMLFormatter]
17
- )
18
- SimpleCov.start do
19
- add_filter '/test/'
20
- minimum_coverage 20
21
- end
22
- end