erc20 0.2.0 → 0.2.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/Gemfile +12 -12
- data/Gemfile.lock +81 -71
- data/Rakefile +1 -0
- data/bin/erc20 +6 -3
- data/erc20.gemspec +2 -2
- data/hardhat/package.json +1 -1
- data/lib/erc20/erc20.rb +1 -1
- data/lib/erc20/fake_wallet.rb +1 -1
- data/lib/erc20/wallet.rb +3 -3
- metadata +3 -28
- data/.0pdd.yml +0 -5
- data/.gitattributes +0 -7
- data/.github/workflows/actionlint.yml +0 -25
- data/.github/workflows/codecov.yml +0 -27
- data/.github/workflows/copyrights.yml +0 -19
- data/.github/workflows/hadolint.yml +0 -16
- data/.github/workflows/markdown-lint.yml +0 -23
- data/.github/workflows/pdd.yml +0 -19
- data/.github/workflows/rake.yml +0 -38
- data/.github/workflows/reuse.yml +0 -19
- data/.github/workflows/shellcheck.yml +0 -19
- data/.github/workflows/typos.yml +0 -19
- data/.github/workflows/xcop.yml +0 -19
- data/.github/workflows/yamllint.yml +0 -21
- data/.gitignore +0 -10
- data/.gitleaksignore +0 -2
- data/.pdd +0 -7
- data/.rubocop.yml +0 -49
- data/.rultor.yml +0 -26
- data/.yamllint.yml +0 -12
- data/renovate.json +0 -6
- data/test/erc20/test_fake_wallet.rb +0 -118
- data/test/erc20/test_wallet.rb +0 -343
- data/test/erc20/test_wallet_live.rb +0 -126
- data/test/test__helper.rb +0 -206
data/test/erc20/test_wallet.rb
DELETED
|
@@ -1,343 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2025 Yegor Bugayenko
|
|
4
|
-
# SPDX-License-Identifier: MIT
|
|
5
|
-
|
|
6
|
-
require 'backtrace'
|
|
7
|
-
require 'donce'
|
|
8
|
-
require 'eth'
|
|
9
|
-
require 'faraday'
|
|
10
|
-
require 'fileutils'
|
|
11
|
-
require 'json'
|
|
12
|
-
require 'os'
|
|
13
|
-
require 'random-port'
|
|
14
|
-
require 'shellwords'
|
|
15
|
-
require 'threads'
|
|
16
|
-
require 'typhoeus'
|
|
17
|
-
require_relative '../test__helper'
|
|
18
|
-
require_relative '../../lib/erc20/wallet'
|
|
19
|
-
|
|
20
|
-
# Test.
|
|
21
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
22
|
-
# Copyright:: Copyright (c) 2025 Yegor Bugayenko
|
|
23
|
-
# License:: MIT
|
|
24
|
-
class TestWallet < ERC20::Test
|
|
25
|
-
# One guy private hex.
|
|
26
|
-
JEFF = '81a9b2114d53731ecc84b261ef6c0387dde34d5907fe7b441240cc21d61bf80a'
|
|
27
|
-
|
|
28
|
-
# Another guy private hex.
|
|
29
|
-
WALTER = '91f9111b1744d55361e632771a4e53839e9442a9fef45febc0a5c838c686a15b'
|
|
30
|
-
|
|
31
|
-
def test_logs_to_stdout
|
|
32
|
-
WebMock.disable_net_connect!
|
|
33
|
-
stub_request(:post, 'https://example.org/').to_return(
|
|
34
|
-
body: { jsonrpc: '2.0', id: 42, result: '0x1F1F1F' }.to_json,
|
|
35
|
-
headers: { 'Content-Type' => 'application/json' }
|
|
36
|
-
)
|
|
37
|
-
w = ERC20::Wallet.new(
|
|
38
|
-
host: 'example.org',
|
|
39
|
-
http_path: '/',
|
|
40
|
-
log: $stdout
|
|
41
|
-
)
|
|
42
|
-
w.balance(Eth::Key.new(priv: JEFF).address.to_s)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def test_checks_balance_on_testnet
|
|
46
|
-
WebMock.enable_net_connect!
|
|
47
|
-
b = testnet.balance(Eth::Key.new(priv: JEFF).address.to_s)
|
|
48
|
-
refute_nil(b)
|
|
49
|
-
assert_predicate(b, :zero?)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def test_checks_gas_estimate_on_hardhat
|
|
53
|
-
WebMock.enable_net_connect!
|
|
54
|
-
sum = 100_000
|
|
55
|
-
on_hardhat do |wallet|
|
|
56
|
-
b1 = wallet.gas_estimate(
|
|
57
|
-
Eth::Key.new(priv: JEFF).address.to_s,
|
|
58
|
-
Eth::Key.new(priv: WALTER).address.to_s,
|
|
59
|
-
sum
|
|
60
|
-
)
|
|
61
|
-
assert_operator(b1, :>, 21_000)
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def test_checks_balance_on_hardhat
|
|
66
|
-
WebMock.enable_net_connect!
|
|
67
|
-
on_hardhat do |wallet|
|
|
68
|
-
b = wallet.balance(Eth::Key.new(priv: JEFF).address.to_s)
|
|
69
|
-
assert_equal(123_000_100_000, b)
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def test_checks_eth_balance_on_hardhat
|
|
74
|
-
WebMock.enable_net_connect!
|
|
75
|
-
on_hardhat do |wallet|
|
|
76
|
-
b = wallet.balance(Eth::Key.new(priv: WALTER).address.to_s)
|
|
77
|
-
assert_equal(456_000_000_000, b)
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def test_checks_balance_on_hardhat_in_threads
|
|
82
|
-
WebMock.enable_net_connect!
|
|
83
|
-
on_hardhat do |wallet|
|
|
84
|
-
Threads.new.assert do
|
|
85
|
-
b = wallet.balance(Eth::Key.new(priv: JEFF).address.to_s)
|
|
86
|
-
assert_equal(123_000_100_000, b)
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def test_pays_on_hardhat
|
|
92
|
-
WebMock.enable_net_connect!
|
|
93
|
-
on_hardhat do |wallet|
|
|
94
|
-
to = Eth::Key.new(priv: WALTER).address.to_s
|
|
95
|
-
before = wallet.balance(to)
|
|
96
|
-
sum = 42_000
|
|
97
|
-
from = Eth::Key.new(priv: JEFF).address.to_s
|
|
98
|
-
assert_operator(wallet.balance(from), :>, sum * 2)
|
|
99
|
-
txn = wallet.pay(JEFF, to, sum)
|
|
100
|
-
assert_equal(66, txn.length)
|
|
101
|
-
assert_match(/^0x[a-f0-9]{64}$/, txn)
|
|
102
|
-
assert_equal(before + sum, wallet.balance(to))
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def test_reads_payment_amount_on_hardhat
|
|
107
|
-
WebMock.enable_net_connect!
|
|
108
|
-
on_hardhat do |wallet|
|
|
109
|
-
sum = 33_330
|
|
110
|
-
txn = wallet.pay(JEFF, Eth::Key.new(priv: WALTER).address.to_s, sum)
|
|
111
|
-
assert_equal(sum, wallet.sum_of(txn))
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
def test_eth_pays_on_hardhat
|
|
116
|
-
WebMock.enable_net_connect!
|
|
117
|
-
on_hardhat do |wallet|
|
|
118
|
-
to = Eth::Key.new(priv: WALTER).address.to_s
|
|
119
|
-
before = wallet.eth_balance(to)
|
|
120
|
-
sum = 42_000
|
|
121
|
-
from = Eth::Key.new(priv: JEFF).address.to_s
|
|
122
|
-
assert_operator(wallet.eth_balance(from), :>, sum * 2)
|
|
123
|
-
txn = wallet.eth_pay(JEFF, to, sum)
|
|
124
|
-
assert_equal(66, txn.length)
|
|
125
|
-
assert_match(/^0x[a-f0-9]{64}$/, txn)
|
|
126
|
-
assert_equal(before + sum, wallet.eth_balance(to))
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
def test_pays_on_hardhat_in_threads
|
|
131
|
-
WebMock.enable_net_connect!
|
|
132
|
-
on_hardhat do |wallet|
|
|
133
|
-
to = Eth::Key.new(priv: WALTER).address.to_s
|
|
134
|
-
before = wallet.balance(to)
|
|
135
|
-
sum = 42_000
|
|
136
|
-
mul = 10
|
|
137
|
-
Threads.new(mul).assert do
|
|
138
|
-
wallet.pay(JEFF, to, sum)
|
|
139
|
-
end
|
|
140
|
-
assert_equal(before + (sum * mul), wallet.balance(to))
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def test_pays_eth_on_hardhat_in_threads
|
|
145
|
-
WebMock.enable_net_connect!
|
|
146
|
-
on_hardhat do |wallet|
|
|
147
|
-
to = Eth::Key.new(priv: WALTER).address.to_s
|
|
148
|
-
before = wallet.eth_balance(to)
|
|
149
|
-
sum = 42_000
|
|
150
|
-
mul = 10
|
|
151
|
-
Threads.new(mul).assert do
|
|
152
|
-
wallet.eth_pay(JEFF, to, sum)
|
|
153
|
-
end
|
|
154
|
-
assert_equal(before + (sum * mul), wallet.eth_balance(to))
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def test_accepts_payments_on_hardhat
|
|
159
|
-
WebMock.enable_net_connect!
|
|
160
|
-
walter = Eth::Key.new(priv: WALTER).address.to_s.downcase
|
|
161
|
-
jeff = Eth::Key.new(priv: JEFF).address.to_s.downcase
|
|
162
|
-
on_hardhat do |wallet|
|
|
163
|
-
active = []
|
|
164
|
-
event = nil
|
|
165
|
-
daemon =
|
|
166
|
-
Thread.new do
|
|
167
|
-
wallet.accept([walter, jeff], active) do |e|
|
|
168
|
-
event = e
|
|
169
|
-
end
|
|
170
|
-
rescue StandardError => e
|
|
171
|
-
fake_loog.error(Backtrace.new(e))
|
|
172
|
-
end
|
|
173
|
-
wait_for { !active.empty? }
|
|
174
|
-
sum = 77_000
|
|
175
|
-
wallet.pay(JEFF, walter, sum)
|
|
176
|
-
wait_for { !event.nil? }
|
|
177
|
-
daemon.kill
|
|
178
|
-
daemon.join(30)
|
|
179
|
-
assert_equal(sum, event[:amount])
|
|
180
|
-
assert_equal(jeff, event[:from])
|
|
181
|
-
assert_equal(walter, event[:to])
|
|
182
|
-
assert_equal(66, event[:txn].length)
|
|
183
|
-
end
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
def test_accepts_payments_on_hardhat_after_disconnect
|
|
187
|
-
skip('Works only on macOS') unless OS.mac?
|
|
188
|
-
WebMock.enable_net_connect!
|
|
189
|
-
walter = Eth::Key.new(priv: WALTER).address.to_s.downcase
|
|
190
|
-
Dir.mktmpdir do |home|
|
|
191
|
-
die = File.join(home, 'die.txt')
|
|
192
|
-
on_hardhat(die:) do |wallet|
|
|
193
|
-
active = []
|
|
194
|
-
events = []
|
|
195
|
-
daemon =
|
|
196
|
-
Thread.new do
|
|
197
|
-
wallet.accept([walter], active, subscription_id: 42) do |e|
|
|
198
|
-
events.append(e)
|
|
199
|
-
end
|
|
200
|
-
rescue StandardError => e
|
|
201
|
-
fake_loog.error(Backtrace.new(e))
|
|
202
|
-
end
|
|
203
|
-
wait_for { !active.empty? }
|
|
204
|
-
wallet.pay(JEFF, walter, 4_567)
|
|
205
|
-
wait_for { events.size == 1 }
|
|
206
|
-
FileUtils.touch(die)
|
|
207
|
-
on_hardhat(port: wallet.port) do
|
|
208
|
-
wallet.pay(JEFF, walter, 3_456)
|
|
209
|
-
wait_for { events.size > 1 }
|
|
210
|
-
daemon.kill
|
|
211
|
-
daemon.join(30)
|
|
212
|
-
assert_equal(3, events.size)
|
|
213
|
-
end
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
def test_accepts_many_payments_on_hardhat
|
|
219
|
-
WebMock.enable_net_connect!
|
|
220
|
-
walter = Eth::Key.new(priv: WALTER).address.to_s.downcase
|
|
221
|
-
on_hardhat do |wallet|
|
|
222
|
-
active = []
|
|
223
|
-
events = Concurrent::Set.new
|
|
224
|
-
total = 10
|
|
225
|
-
daemon =
|
|
226
|
-
Thread.new do
|
|
227
|
-
wallet.accept([walter], active) do |e|
|
|
228
|
-
events.add(e)
|
|
229
|
-
end
|
|
230
|
-
rescue StandardError => e
|
|
231
|
-
fake_loog.error(Backtrace.new(e))
|
|
232
|
-
end
|
|
233
|
-
wait_for { !active.empty? }
|
|
234
|
-
sum = 1_234
|
|
235
|
-
Threads.new(total).assert do
|
|
236
|
-
wallet.pay(JEFF, walter, sum)
|
|
237
|
-
end
|
|
238
|
-
wait_for { events.size == total }
|
|
239
|
-
daemon.kill
|
|
240
|
-
daemon.join(30)
|
|
241
|
-
assert_equal(total, events.size)
|
|
242
|
-
end
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
def test_accepts_payments_with_failures_on_hardhat
|
|
246
|
-
WebMock.enable_net_connect!
|
|
247
|
-
walter = Eth::Key.new(priv: WALTER).address.to_s.downcase
|
|
248
|
-
on_hardhat do |wallet|
|
|
249
|
-
active = []
|
|
250
|
-
events = Concurrent::Set.new
|
|
251
|
-
total = 10
|
|
252
|
-
daemon =
|
|
253
|
-
Thread.new do
|
|
254
|
-
wallet.accept([walter], active) do |e|
|
|
255
|
-
events.add(e)
|
|
256
|
-
raise 'intentional'
|
|
257
|
-
end
|
|
258
|
-
end
|
|
259
|
-
wait_for { !active.empty? }
|
|
260
|
-
sum = 1_234
|
|
261
|
-
Threads.new(total).assert do
|
|
262
|
-
wallet.pay(JEFF, walter, sum)
|
|
263
|
-
end
|
|
264
|
-
wait_for { events.size == total }
|
|
265
|
-
daemon.kill
|
|
266
|
-
daemon.join(30)
|
|
267
|
-
assert_equal(total, events.size)
|
|
268
|
-
end
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
def test_accepts_payments_on_changing_addresses_on_hardhat
|
|
272
|
-
WebMock.enable_net_connect!
|
|
273
|
-
walter = Eth::Key.new(priv: WALTER).address.to_s.downcase
|
|
274
|
-
jeff = Eth::Key.new(priv: JEFF).address.to_s.downcase
|
|
275
|
-
addresses = Primitivo.new([walter])
|
|
276
|
-
on_hardhat do |wallet|
|
|
277
|
-
active = Primitivo.new([])
|
|
278
|
-
event = nil
|
|
279
|
-
daemon =
|
|
280
|
-
Thread.new do
|
|
281
|
-
wallet.accept(addresses, active) do |e|
|
|
282
|
-
event = e
|
|
283
|
-
end
|
|
284
|
-
rescue StandardError => e
|
|
285
|
-
fake_loog.error(Backtrace.new(e))
|
|
286
|
-
end
|
|
287
|
-
wait_for { active.to_a.include?(walter) }
|
|
288
|
-
sum1 = 453_000
|
|
289
|
-
wallet.pay(JEFF, walter, sum1)
|
|
290
|
-
wait_for { !event.nil? }
|
|
291
|
-
assert_equal(sum1, event[:amount])
|
|
292
|
-
sum2 = 22_000
|
|
293
|
-
event = nil
|
|
294
|
-
addresses.append(jeff)
|
|
295
|
-
wait_for { active.to_a.include?(jeff) }
|
|
296
|
-
wallet.pay(WALTER, jeff, sum2)
|
|
297
|
-
wait_for { !event.nil? }
|
|
298
|
-
assert_equal(sum2, event[:amount])
|
|
299
|
-
daemon.kill
|
|
300
|
-
daemon.join(30)
|
|
301
|
-
end
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
def test_accepts_payments_on_hardhat_via_proxy
|
|
305
|
-
WebMock.enable_net_connect!
|
|
306
|
-
via_proxy do |proxy|
|
|
307
|
-
walter = Eth::Key.new(priv: WALTER).address.to_s.downcase
|
|
308
|
-
jeff = Eth::Key.new(priv: JEFF).address.to_s.downcase
|
|
309
|
-
on_hardhat do |w|
|
|
310
|
-
wallet = through_proxy(w, proxy)
|
|
311
|
-
active = []
|
|
312
|
-
event = nil
|
|
313
|
-
daemon =
|
|
314
|
-
Thread.new do
|
|
315
|
-
wallet.accept([walter, jeff], active) do |e|
|
|
316
|
-
event = e
|
|
317
|
-
end
|
|
318
|
-
rescue StandardError => e
|
|
319
|
-
fake_loog.error(Backtrace.new(e))
|
|
320
|
-
end
|
|
321
|
-
wait_for { !active.empty? }
|
|
322
|
-
sum = 55_000
|
|
323
|
-
wallet.pay(JEFF, walter, sum)
|
|
324
|
-
wait_for { !event.nil? }
|
|
325
|
-
daemon.kill
|
|
326
|
-
daemon.join(30)
|
|
327
|
-
assert_equal(sum, event[:amount])
|
|
328
|
-
end
|
|
329
|
-
end
|
|
330
|
-
end
|
|
331
|
-
|
|
332
|
-
def test_checks_balance_via_proxy
|
|
333
|
-
WebMock.enable_net_connect!
|
|
334
|
-
b = nil
|
|
335
|
-
via_proxy do |proxy|
|
|
336
|
-
on_hardhat do |w|
|
|
337
|
-
wallet = through_proxy(w, proxy)
|
|
338
|
-
b = wallet.balance(Eth::Key.new(priv: JEFF).address.to_s)
|
|
339
|
-
end
|
|
340
|
-
end
|
|
341
|
-
assert_equal(123_000_100_000, b)
|
|
342
|
-
end
|
|
343
|
-
end
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2025 Yegor Bugayenko
|
|
4
|
-
# SPDX-License-Identifier: MIT
|
|
5
|
-
|
|
6
|
-
require 'backtrace'
|
|
7
|
-
require 'donce'
|
|
8
|
-
require 'eth'
|
|
9
|
-
require 'faraday'
|
|
10
|
-
require 'fileutils'
|
|
11
|
-
require 'json'
|
|
12
|
-
require 'os'
|
|
13
|
-
require 'random-port'
|
|
14
|
-
require 'shellwords'
|
|
15
|
-
require 'threads'
|
|
16
|
-
require 'typhoeus'
|
|
17
|
-
require_relative '../test__helper'
|
|
18
|
-
require_relative '../../lib/erc20/wallet'
|
|
19
|
-
|
|
20
|
-
# Test.
|
|
21
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
22
|
-
# Copyright:: Copyright (c) 2025 Yegor Bugayenko
|
|
23
|
-
# License:: MIT
|
|
24
|
-
class TestWalletLive < ERC20::Test
|
|
25
|
-
# At this address, in Ethereum mainnet, there are $8 USDT and 0.0042 ETH. I won't
|
|
26
|
-
# move them anyway, that's why tests can use this address forever.
|
|
27
|
-
STABLE = '0x7232148927F8a580053792f44D4d59d40Fd00ABD'
|
|
28
|
-
|
|
29
|
-
def test_checks_balance_on_mainnet
|
|
30
|
-
WebMock.enable_net_connect!
|
|
31
|
-
b = mainnet.balance(STABLE)
|
|
32
|
-
refute_nil(b)
|
|
33
|
-
assert_equal(8_000_000, b) # this is $8 USDT
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def test_checks_eth_balance_on_mainnet
|
|
37
|
-
WebMock.enable_net_connect!
|
|
38
|
-
b = mainnet.eth_balance(STABLE)
|
|
39
|
-
refute_nil(b)
|
|
40
|
-
assert_equal(4_200_000_000_000_000, b) # this is 0.0042 ETH
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def test_checks_balance_of_absent_address
|
|
44
|
-
WebMock.enable_net_connect!
|
|
45
|
-
a = '0xEB2fE8872A6f1eDb70a2632Effffffffffffffff'
|
|
46
|
-
b = mainnet.balance(a)
|
|
47
|
-
refute_nil(b)
|
|
48
|
-
assert_equal(0, b)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def test_checks_gas_estimate_on_mainnet
|
|
52
|
-
WebMock.enable_net_connect!
|
|
53
|
-
b = mainnet.gas_estimate(STABLE, '0x7232148927F8a580053792f44D4d5FFFFFFFFFFF', 44_000)
|
|
54
|
-
refute_nil(b)
|
|
55
|
-
assert_predicate(b, :positive?)
|
|
56
|
-
assert_operator(b, :>, 1000)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def test_fails_with_invalid_infura_key
|
|
60
|
-
WebMock.enable_net_connect!
|
|
61
|
-
skip('Apparently, even with invalid key, Infura returns balance')
|
|
62
|
-
w = ERC20::Wallet.new(
|
|
63
|
-
contract: ERC20::Wallet.USDT,
|
|
64
|
-
host: 'mainnet.infura.io',
|
|
65
|
-
http_path: '/v3/invalid-key-here',
|
|
66
|
-
log: fake_loog
|
|
67
|
-
)
|
|
68
|
-
assert_raises(StandardError) { w.balance(STABLE) }
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def test_checks_balance_on_polygon
|
|
72
|
-
WebMock.enable_net_connect!
|
|
73
|
-
w = ERC20::Wallet.new(
|
|
74
|
-
contract: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',
|
|
75
|
-
host: 'polygon-mainnet.infura.io',
|
|
76
|
-
http_path: "/v3/#{env('INFURA_KEY')}",
|
|
77
|
-
log: fake_loog
|
|
78
|
-
)
|
|
79
|
-
b = w.balance(STABLE)
|
|
80
|
-
refute_nil(b)
|
|
81
|
-
assert_predicate(b, :zero?)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def test_accepts_payments_on_mainnet
|
|
85
|
-
WebMock.enable_net_connect!
|
|
86
|
-
active = []
|
|
87
|
-
failed = false
|
|
88
|
-
net = mainnet
|
|
89
|
-
daemon =
|
|
90
|
-
Thread.new do
|
|
91
|
-
net.accept([STABLE], active) do |_|
|
|
92
|
-
# ignore it
|
|
93
|
-
end
|
|
94
|
-
rescue StandardError => e
|
|
95
|
-
failed = true
|
|
96
|
-
fake_loog.error(Backtrace.new(e))
|
|
97
|
-
end
|
|
98
|
-
wait_for { !active.empty? }
|
|
99
|
-
daemon.kill
|
|
100
|
-
daemon.join(30)
|
|
101
|
-
refute(failed)
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def test_checks_balance_via_proxy_on_mainnet
|
|
105
|
-
WebMock.enable_net_connect!
|
|
106
|
-
via_proxy do |proxy|
|
|
107
|
-
w = ERC20::Wallet.new(
|
|
108
|
-
host: 'mainnet.infura.io',
|
|
109
|
-
http_path: "/v3/#{env('INFURA_KEY')}",
|
|
110
|
-
proxy:, log: fake_loog
|
|
111
|
-
)
|
|
112
|
-
assert_equal(8_000_000, w.balance(STABLE))
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def test_pays_on_mainnet
|
|
117
|
-
WebMock.enable_net_connect!
|
|
118
|
-
skip('This is live, must be run manually')
|
|
119
|
-
w = mainnet
|
|
120
|
-
print 'Enter Ethereum ERC20 private key (64 chars): '
|
|
121
|
-
priv = gets.chomp
|
|
122
|
-
to = '0xEB2fE8872A6f1eDb70a2632EA1f869AB131532f6'
|
|
123
|
-
txn = w.pay(priv, to, 1_990_000)
|
|
124
|
-
assert_equal(66, txn.length)
|
|
125
|
-
end
|
|
126
|
-
end
|
data/test/test__helper.rb
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2025 Yegor Bugayenko
|
|
4
|
-
# SPDX-License-Identifier: MIT
|
|
5
|
-
|
|
6
|
-
$stdout.sync = true
|
|
7
|
-
|
|
8
|
-
require 'simplecov'
|
|
9
|
-
require 'simplecov-cobertura'
|
|
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
|
|
28
|
-
|
|
29
|
-
require 'minitest/autorun'
|
|
30
|
-
require 'minitest/reporters'
|
|
31
|
-
Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new]
|
|
32
|
-
|
|
33
|
-
# To make tests retry on failure:
|
|
34
|
-
if ENV['RAKE']
|
|
35
|
-
require 'minitest/retry'
|
|
36
|
-
Minitest::Retry.use!
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
# Primitive array.
|
|
40
|
-
class Primitivo
|
|
41
|
-
def initialize(array)
|
|
42
|
-
@array = array
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def clear
|
|
46
|
-
@array.clear
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def to_a
|
|
50
|
-
@array.to_a
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def append(item)
|
|
54
|
-
@array.append(item)
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
require 'webmock/minitest'
|
|
59
|
-
|
|
60
|
-
# Test.
|
|
61
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
62
|
-
# Copyright:: Copyright (c) 2025 Yegor Bugayenko
|
|
63
|
-
# License:: MIT
|
|
64
|
-
class ERC20::Test < Minitest::Test
|
|
65
|
-
def fake_loog
|
|
66
|
-
ENV['RAKE'] ? Loog::ERRORS : Loog::VERBOSE
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def wait_for(seconds = 30)
|
|
70
|
-
start = Time.now
|
|
71
|
-
loop do
|
|
72
|
-
sleep(0.1)
|
|
73
|
-
break if yield
|
|
74
|
-
passed = Time.now - start
|
|
75
|
-
raise "Giving up after #{passed} seconds of waiting" if passed > seconds
|
|
76
|
-
rescue Errno::ECONNREFUSED
|
|
77
|
-
retry
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def wait_for_port(port)
|
|
82
|
-
wait_for { Typhoeus::Request.get("http://localhost:#{port}").code == 200 }
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def env(var)
|
|
86
|
-
key = ENV.fetch(var, nil)
|
|
87
|
-
skip("The #{var} environment variable is not set") if key.nil?
|
|
88
|
-
skip("The #{var} environment variable is empty") if key.empty?
|
|
89
|
-
key
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def mainnet
|
|
93
|
-
[
|
|
94
|
-
{
|
|
95
|
-
host: 'mainnet.infura.io',
|
|
96
|
-
http_path: "/v3/#{env('INFURA_KEY')}",
|
|
97
|
-
ws_path: "/ws/v3/#{env('INFURA_KEY')}"
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
host: 'go.getblock.io',
|
|
101
|
-
http_path: "/#{env('GETBLOCK_KEY')}",
|
|
102
|
-
ws_path: "/#{env('GETBLOCK_WS_KEY')}"
|
|
103
|
-
}
|
|
104
|
-
].map do |server|
|
|
105
|
-
ERC20::Wallet.new(
|
|
106
|
-
host: server[:host],
|
|
107
|
-
http_path: server[:http_path],
|
|
108
|
-
ws_path: server[:ws_path],
|
|
109
|
-
log: fake_loog
|
|
110
|
-
)
|
|
111
|
-
end.sample
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def testnet
|
|
115
|
-
[
|
|
116
|
-
{
|
|
117
|
-
host: 'sepolia.infura.io',
|
|
118
|
-
http_path: "/v3/#{env('INFURA_KEY')}",
|
|
119
|
-
ws_path: "/ws/v3/#{env('INFURA_KEY')}"
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
host: 'go.getblock.io',
|
|
123
|
-
http_path: "/#{env('GETBLOCK_SEPOILA_KEY')}",
|
|
124
|
-
ws_path: "/#{env('GETBLOCK_SEPOILA_KEY')}"
|
|
125
|
-
}
|
|
126
|
-
].map do |server|
|
|
127
|
-
ERC20::Wallet.new(
|
|
128
|
-
host: server[:host],
|
|
129
|
-
http_path: server[:http_path],
|
|
130
|
-
ws_path: server[:ws_path],
|
|
131
|
-
log: fake_loog
|
|
132
|
-
)
|
|
133
|
-
end.sample
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def through_proxy(wallet, proxy)
|
|
137
|
-
ERC20::Wallet.new(
|
|
138
|
-
contract: wallet.contract, chain: wallet.chain,
|
|
139
|
-
host: donce_host, port: wallet.port, http_path: wallet.http_path, ws_path: wallet.ws_path,
|
|
140
|
-
ssl: wallet.ssl, proxy:, log: fake_loog
|
|
141
|
-
)
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def via_proxy
|
|
145
|
-
RandomPort::Pool::SINGLETON.acquire do |port|
|
|
146
|
-
donce(
|
|
147
|
-
image: 'yegor256/squid-proxy:latest',
|
|
148
|
-
ports: { port => 3128 },
|
|
149
|
-
env: { 'USERNAME' => 'jeffrey', 'PASSWORD' => 'swordfish' },
|
|
150
|
-
root: true, log: fake_loog
|
|
151
|
-
) do
|
|
152
|
-
yield "http://jeffrey:swordfish@localhost:#{port}"
|
|
153
|
-
end
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
def on_hardhat(port: nil, die: nil)
|
|
158
|
-
RandomPort::Pool::SINGLETON.acquire do |rnd|
|
|
159
|
-
port = rnd if port.nil?
|
|
160
|
-
if die
|
|
161
|
-
killer = [
|
|
162
|
-
'&',
|
|
163
|
-
'HARDHAT_PID=$!;',
|
|
164
|
-
'export HARDHAT_PID;',
|
|
165
|
-
'while true; do',
|
|
166
|
-
" if [ -e #{Shellwords.escape(File.join('/die', File.basename(die)))} ]; then",
|
|
167
|
-
' kill -9 "${HARDHAT_PID}";',
|
|
168
|
-
' break;',
|
|
169
|
-
' else',
|
|
170
|
-
' sleep 0.1;',
|
|
171
|
-
' fi;',
|
|
172
|
-
'done'
|
|
173
|
-
].join(' ')
|
|
174
|
-
end
|
|
175
|
-
cmd = "npx hardhat node #{killer if die}"
|
|
176
|
-
donce(
|
|
177
|
-
home: File.join(__dir__, '../hardhat'),
|
|
178
|
-
ports: { port => 8545 },
|
|
179
|
-
volumes: die ? { File.dirname(die) => '/die' } : {},
|
|
180
|
-
command: "/bin/bash -c #{Shellwords.escape(cmd)}",
|
|
181
|
-
log: fake_loog
|
|
182
|
-
) do
|
|
183
|
-
wait_for_port(port)
|
|
184
|
-
cmd = [
|
|
185
|
-
'(cat hardhat.config.js)',
|
|
186
|
-
'(ls -al)',
|
|
187
|
-
'(echo y | npx hardhat ignition deploy ./ignition/modules/Foo.ts --network foo --deployment-id foo)',
|
|
188
|
-
'(npx hardhat ignition status foo | tail -1 | cut -d" " -f3)'
|
|
189
|
-
].join(' && ')
|
|
190
|
-
contract = donce(
|
|
191
|
-
home: File.join(__dir__, '../hardhat'),
|
|
192
|
-
command: "/bin/bash -c #{Shellwords.escape(cmd)}",
|
|
193
|
-
build_args: { 'HOST' => donce_host, 'PORT' => port },
|
|
194
|
-
log: fake_loog,
|
|
195
|
-
root: true
|
|
196
|
-
).split("\n").last
|
|
197
|
-
wallet = ERC20::Wallet.new(
|
|
198
|
-
contract:, chain: 4242,
|
|
199
|
-
host: 'localhost', port:, http_path: '/', ws_path: '/', ssl: false,
|
|
200
|
-
log: fake_loog
|
|
201
|
-
)
|
|
202
|
-
yield wallet
|
|
203
|
-
end
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
end
|