erc20 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/Gemfile.lock +13 -12
- data/README.md +29 -6
- data/Rakefile +2 -0
- data/erc20.gemspec +8 -6
- data/lib/erc20/wallet.rb +63 -43
- data/lib/erc20.rb +1 -1
- data/test/erc20/test_wallet.rb +145 -24
- data/test/test__helper.rb +4 -2
- metadata +27 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 14d84ab9ee2ac821f5f404dcea22437f622fe82bf5565a04c695f718974ba129
|
4
|
+
data.tar.gz: d2ec55f58ef13c62abfb0b870d541d3cc5bd8a32f5c685eda64fb484558af332
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ef86114757f0b841b022a8cef64330610d68425d13e900487e4d99589065ed19640f393986f3ea62003fe2d24ae93513406611d4725d58dcc3165e7e70a5ffa
|
7
|
+
data.tar.gz: 92855745194e5cf9b6ff1902f0f7e4f44606aa4e306313668e7fb01849ab91e10fccf99e6f7ac6dfa0a6e176abc6d7aaa30f279b88e7c0f94b1133380f61d643
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -2,11 +2,11 @@ PATH
|
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
4
|
erc20 (0.0.0)
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
eth (>= 0.5.13)
|
6
|
+
faye-websocket (>= 0.11.3)
|
7
|
+
json (>= 2.10.1)
|
8
|
+
jsonrpc-client (>= 0.1.4)
|
8
9
|
loog (> 0)
|
9
|
-
websocket-client-simple (> 0)
|
10
10
|
|
11
11
|
GEM
|
12
12
|
remote: https://rubygems.org/
|
@@ -71,13 +71,16 @@ GEM
|
|
71
71
|
scrypt (~> 3.0)
|
72
72
|
ethon (0.16.0)
|
73
73
|
ffi (>= 1.15.0)
|
74
|
-
|
74
|
+
eventmachine (1.2.7)
|
75
75
|
faraday (2.12.2)
|
76
76
|
faraday-net_http (>= 2.0, < 3.5)
|
77
77
|
json
|
78
78
|
logger
|
79
79
|
faraday-net_http (3.4.0)
|
80
80
|
net-http (>= 0.5.0)
|
81
|
+
faye-websocket (0.11.3)
|
82
|
+
eventmachine (>= 0.12.0)
|
83
|
+
websocket-driver (>= 0.5.1)
|
81
84
|
ffi (1.17.1-arm64-darwin)
|
82
85
|
ffi (1.17.1-x64-mingw-ucrt)
|
83
86
|
ffi (1.17.1-x86_64-darwin)
|
@@ -93,7 +96,7 @@ GEM
|
|
93
96
|
pp (>= 0.6.0)
|
94
97
|
rdoc (>= 4.0.0)
|
95
98
|
reline (>= 0.4.2)
|
96
|
-
json (2.10.
|
99
|
+
json (2.10.1)
|
97
100
|
jsonrpc-client (0.1.4)
|
98
101
|
faraday
|
99
102
|
multi_json (>= 1.1.0)
|
@@ -115,7 +118,6 @@ GEM
|
|
115
118
|
minitest-retry (0.2.5)
|
116
119
|
minitest (>= 5.0)
|
117
120
|
multi_json (1.15.0)
|
118
|
-
mutex_m (0.3.0)
|
119
121
|
net-http (0.6.0)
|
120
122
|
uri
|
121
123
|
nokogiri (1.18.2-arm64-darwin)
|
@@ -251,12 +253,10 @@ GEM
|
|
251
253
|
unicode-emoji (4.0.4)
|
252
254
|
uri (1.0.2)
|
253
255
|
useragent (0.16.11)
|
254
|
-
websocket (
|
255
|
-
websocket-client-simple (0.9.0)
|
256
|
+
websocket-driver (0.7.7)
|
256
257
|
base64
|
257
|
-
|
258
|
-
|
259
|
-
websocket
|
258
|
+
websocket-extensions (>= 0.1.0)
|
259
|
+
websocket-extensions (0.1.5)
|
260
260
|
yard (0.9.37)
|
261
261
|
zeitwerk (2.7.1)
|
262
262
|
|
@@ -273,6 +273,7 @@ DEPENDENCIES
|
|
273
273
|
backtrace (> 0)
|
274
274
|
donce (> 0)
|
275
275
|
erc20!
|
276
|
+
faraday (> 0)
|
276
277
|
loog (> 0)
|
277
278
|
minitest (= 5.25.4)
|
278
279
|
minitest-reporters (= 1.7.1)
|
data/README.md
CHANGED
@@ -23,18 +23,19 @@ require 'erc20'
|
|
23
23
|
w = ERC20::Wallet.new(
|
24
24
|
contract: ERC20::Wallet.USDT, # hex of it
|
25
25
|
host: 'mainnet.infura.io',
|
26
|
-
|
26
|
+
http_path: '/v3/<your-infura-key>',
|
27
|
+
ws_path: '/ws/v3/<your-infura-key>',
|
27
28
|
log: $stdout
|
28
29
|
)
|
29
30
|
|
30
|
-
# Check
|
31
|
+
# Check how many ERC20 tokens are on the given address:
|
31
32
|
usdt = w.balance(address)
|
32
33
|
|
33
|
-
# Send a few tokens to someone and get transaction hash:
|
34
|
-
|
34
|
+
# Send a few ERC20 tokens to someone and get transaction hash:
|
35
|
+
hex = w.pay(private_key, to_address, amount)
|
35
36
|
|
36
|
-
# Stay waiting, and trigger the block when
|
37
|
-
addresses = ['0x...', '0x...']
|
37
|
+
# Stay waiting, and trigger the block when new ERC20 payments show up:
|
38
|
+
addresses = ['0x...', '0x...'] # only wait for payments to these addresses
|
38
39
|
w.accept(addresses) do |event|
|
39
40
|
puts event[:amount] # how much
|
40
41
|
puts event[:from] # who sent the payment
|
@@ -55,6 +56,22 @@ To get address from private one:
|
|
55
56
|
public_hex = Eth::Key.new(priv: key).address
|
56
57
|
```
|
57
58
|
|
59
|
+
To connect to the server via [HTTP proxy] with [basic authentication]:
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
w = ERC20::Wallet.new(
|
63
|
+
host: 'go.getblock.io',
|
64
|
+
http_path: '/<your-rpc-getblock-key>',
|
65
|
+
ws_path: '/<your-ws-getblock-key>',
|
66
|
+
proxy: 'http://jeffrey:swordfish@example.com:3128' # here!
|
67
|
+
)
|
68
|
+
```
|
69
|
+
|
70
|
+
You can use [squid-proxy] [Docker] image to set up your own [HTTP proxy] server.
|
71
|
+
|
72
|
+
Of course, this library works with [Polygon], [Optimism],
|
73
|
+
and other forks of [Etherium].
|
74
|
+
|
58
75
|
## How to contribute
|
59
76
|
|
60
77
|
Read
|
@@ -78,3 +95,9 @@ If it's clean and you don't see any error messages, submit your pull request.
|
|
78
95
|
[Infura]: https://infura.io/
|
79
96
|
[Alchemy]: https://alchemy.com/
|
80
97
|
[GetBlock]: https://getblock.io/
|
98
|
+
[basic authentication]: https://en.wikipedia.org/wiki/Basic_access_authentication
|
99
|
+
[HTTP proxy]: https://en.wikipedia.org/wiki/Proxy_server
|
100
|
+
[squid-proxy]: https://github.com/yegor256/squid-proxy
|
101
|
+
[Docker]: https://www.docker.com/
|
102
|
+
[Polygon]: https://polygon.technology/
|
103
|
+
[Optimism]: https://www.optimism.io/
|
data/Rakefile
CHANGED
data/erc20.gemspec
CHANGED
@@ -31,18 +31,20 @@ Gem::Specification.new do |s|
|
|
31
31
|
s.license = 'MIT'
|
32
32
|
s.summary = 'Sending and receiving ERC20 tokens in Etherium network'
|
33
33
|
s.description =
|
34
|
-
'A simple library for making ERC20 manipulations as easy as they' \
|
35
|
-
'can be for cryptocurrency newbies'
|
34
|
+
'A simple library for making ERC20 manipulations as easy as they ' \
|
35
|
+
'can be for cryptocurrency newbies: checking balance, sending payments, ' \
|
36
|
+
'and monitoring addresses for incoming payments. The library expects ' \
|
37
|
+
'Etherium node to provide JSON RPC and Websockets API.'
|
36
38
|
s.authors = ['Yegor Bugayenko']
|
37
39
|
s.email = 'yegor256@gmail.com'
|
38
40
|
s.homepage = 'http://github.com/yegor256/erc20.rb'
|
39
41
|
s.files = `git ls-files`.split($RS)
|
40
42
|
s.rdoc_options = ['--charset=UTF-8']
|
41
43
|
s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
|
42
|
-
s.add_dependency '
|
43
|
-
s.add_dependency '
|
44
|
-
s.add_dependency '
|
44
|
+
s.add_dependency 'eth', '>=0.5.13'
|
45
|
+
s.add_dependency 'faye-websocket', '>=0.11.3'
|
46
|
+
s.add_dependency 'json', '>=2.10.1'
|
47
|
+
s.add_dependency 'jsonrpc-client', '>=0.1.4'
|
45
48
|
s.add_dependency 'loog', '>0'
|
46
|
-
s.add_dependency 'websocket-client-simple', '>0'
|
47
49
|
s.metadata['rubygems_mfa_required'] = 'true'
|
48
50
|
end
|
data/lib/erc20/wallet.rb
CHANGED
@@ -21,9 +21,12 @@
|
|
21
21
|
# SOFTWARE.
|
22
22
|
|
23
23
|
require 'eth'
|
24
|
+
require 'eventmachine'
|
25
|
+
require 'faye/websocket'
|
26
|
+
require 'json'
|
24
27
|
require 'jsonrpc/client'
|
25
28
|
require 'loog'
|
26
|
-
require '
|
29
|
+
require 'uri'
|
27
30
|
require_relative '../erc20'
|
28
31
|
|
29
32
|
# A wallet.
|
@@ -37,34 +40,31 @@ class ERC20::Wallet
|
|
37
40
|
# Address of USDT contract.
|
38
41
|
USDT = '0xdac17f958d2ee523a2206206994597c13d831ec7'
|
39
42
|
|
43
|
+
# These properties are read-only:
|
44
|
+
attr_reader :host, :port, :ssl, :chain, :contract, :ws_path, :http_path
|
45
|
+
|
40
46
|
# Constructor.
|
41
47
|
# @param [String] contract Hex of the contract in Etherium
|
42
|
-
# @param [String] rpc The URL of Etherium JSON-RPC provider
|
43
48
|
# @param [Integer] chain The ID of the chain (1 for mainnet)
|
44
49
|
# @param [String] host The host to connect to
|
45
50
|
# @param [Integer] port TCP port to use
|
46
|
-
# @param [String]
|
51
|
+
# @param [String] http_path The path in the connection URL, for HTTP RPC
|
52
|
+
# @param [String] ws_path The path in the connection URL, for Websockets
|
47
53
|
# @param [Boolean] ssl Should we use SSL (for https and wss)
|
54
|
+
# @param [String] proxy The URL of the proxy to use
|
48
55
|
# @param [Object] log The destination for logs
|
49
|
-
def initialize(contract: USDT,
|
50
|
-
host: nil, port: 443,
|
56
|
+
def initialize(contract: USDT, chain: 1, log: $stdout,
|
57
|
+
host: nil, port: 443, http_path: '/', ws_path: '/',
|
58
|
+
ssl: true, proxy: nil)
|
51
59
|
@contract = contract
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
raise 'Either rpc or host+port+path are required' unless host && port && path
|
58
|
-
@rpc = "http#{ssl ? 's' : ''}://#{host}:#{port}#{path}"
|
59
|
-
end
|
60
|
-
if wss
|
61
|
-
@wss = wss
|
62
|
-
else
|
63
|
-
raise 'Either wss or host+port+path are required' unless host && port && path
|
64
|
-
@wss = "http#{ssl ? 's' : ''}://#{host}:#{port}#{path}"
|
65
|
-
end
|
60
|
+
@host = host
|
61
|
+
@port = port
|
62
|
+
@ssl = ssl
|
63
|
+
@http_path = http_path
|
64
|
+
@ws_path = ws_path
|
66
65
|
@log = log
|
67
66
|
@chain = chain
|
67
|
+
@proxy = proxy
|
68
68
|
end
|
69
69
|
|
70
70
|
# Get balance of a public address.
|
@@ -119,35 +119,39 @@ class ERC20::Wallet
|
|
119
119
|
|
120
120
|
# Wait for incoming transactions and let the block know when they
|
121
121
|
# arrive. It's a blocking call, it's better to run it in a separate
|
122
|
-
# thread.
|
122
|
+
# thread. It will never finish. In order to stop it, you should do
|
123
|
+
# +Thread.kill+.
|
123
124
|
#
|
124
125
|
# @param [Array<String>] addresses Addresses to monitor
|
125
126
|
# @param [Array] ready When connected, TRUE will be added to this array
|
126
127
|
# @param [Boolean] raw TRUE if you need to get JSON events as they arrive from Websockets
|
127
128
|
def accept(addresses, connected: [], raw: false)
|
128
|
-
|
129
|
+
EM.run do
|
130
|
+
u = url(http: false)
|
131
|
+
@log.debug("Connecting to #{u}...")
|
132
|
+
ws = Faye::WebSocket::Client.new(u, [], proxy: @proxy ? { origin: @proxy } : {})
|
129
133
|
log = @log
|
130
134
|
contract = @contract
|
131
|
-
wss = @wss
|
132
135
|
ws.on(:open) do
|
133
|
-
log.debug("Connected to #{
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
136
|
+
log.debug("Connected to #{@host}")
|
137
|
+
ws.send(
|
138
|
+
{
|
139
|
+
jsonrpc: '2.0',
|
140
|
+
id: 1,
|
141
|
+
method: 'eth_subscribe',
|
142
|
+
params: [
|
143
|
+
'logs',
|
144
|
+
{
|
145
|
+
address: contract,
|
146
|
+
topics: [
|
147
|
+
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
|
148
|
+
nil,
|
149
|
+
addresses.map { |a| "0x000000000000000000000000#{a[2..]}" }
|
150
|
+
]
|
151
|
+
}
|
152
|
+
]
|
153
|
+
}.to_json
|
154
|
+
)
|
151
155
|
connected.append(1)
|
152
156
|
log.debug("Subscribed to #{addresses.count} addresses")
|
153
157
|
end
|
@@ -172,19 +176,35 @@ class ERC20::Wallet
|
|
172
176
|
end
|
173
177
|
end
|
174
178
|
ws.on(:close) do |_e|
|
175
|
-
log.debug("Disconnected from #{
|
179
|
+
log.debug("Disconnected from #{@host}")
|
176
180
|
end
|
177
181
|
ws.on(:error) do |e|
|
178
|
-
log.debug("Error at #{
|
182
|
+
log.debug("Error at #{@host}: #{e.message}")
|
179
183
|
end
|
180
184
|
end
|
181
185
|
end
|
182
186
|
|
183
187
|
private
|
184
188
|
|
189
|
+
def url(http: true)
|
190
|
+
"#{http ? 'http' : 'ws'}#{@ssl ? 's' : ''}://#{@host}:#{@port}#{http ? @http_path : @ws_path}"
|
191
|
+
end
|
192
|
+
|
185
193
|
def jsonrpc
|
186
194
|
JSONRPC.logger = Loog::NULL
|
187
|
-
|
195
|
+
connection =
|
196
|
+
if @proxy
|
197
|
+
uri = URI.parse(@proxy)
|
198
|
+
Faraday.new do |f|
|
199
|
+
f.adapter(Faraday.default_adapter)
|
200
|
+
f.proxy = {
|
201
|
+
uri: "#{uri.scheme}://#{uri.hostname}:#{uri.port}",
|
202
|
+
user: uri.user,
|
203
|
+
password: uri.password
|
204
|
+
}
|
205
|
+
end
|
206
|
+
end
|
207
|
+
JSONRPC::Client.new(url, connection:)
|
188
208
|
end
|
189
209
|
|
190
210
|
def gas_estimate(from, data)
|
data/lib/erc20.rb
CHANGED
data/test/erc20/test_wallet.rb
CHANGED
@@ -23,22 +23,24 @@
|
|
23
23
|
require 'backtrace'
|
24
24
|
require 'donce'
|
25
25
|
require 'eth'
|
26
|
+
require 'faraday'
|
26
27
|
require 'loog'
|
28
|
+
require 'minitest/autorun'
|
27
29
|
require 'random-port'
|
28
30
|
require 'shellwords'
|
29
31
|
require 'typhoeus'
|
30
|
-
require 'minitest/autorun'
|
31
32
|
require_relative '../../lib/erc20'
|
32
33
|
require_relative '../../lib/erc20/wallet'
|
34
|
+
require_relative '../test__helper'
|
33
35
|
|
34
36
|
# Test.
|
35
37
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
36
38
|
# Copyright:: Copyright (c) 2025 Yegor Bugayenko
|
37
39
|
# License:: MIT
|
38
40
|
class TestWallet < Minitest::Test
|
39
|
-
# At this address, in
|
41
|
+
# At this address, in Etherium mainnet, there are a few USDT tokens. I won't
|
40
42
|
# move them anyway, that's why tests can use this address forever.
|
41
|
-
|
43
|
+
STABLE = '0xEB2fE8872A6f1eDb70a2632EA1f869AB131532f6'
|
42
44
|
|
43
45
|
# One guy private hex.
|
44
46
|
JEFF = '81a9b2114d53731ecc84b261ef6c0387dde34d5907fe7b441240cc21d61bf80a'
|
@@ -47,7 +49,7 @@ class TestWallet < Minitest::Test
|
|
47
49
|
WALTER = '91f9111b1744d55361e632771a4e53839e9442a9fef45febc0a5c838c686a15b'
|
48
50
|
|
49
51
|
def test_checks_balance_on_mainnet
|
50
|
-
b = mainnet.balance(
|
52
|
+
b = mainnet.balance(STABLE)
|
51
53
|
refute_nil(b)
|
52
54
|
assert_equal(27_258_889, b)
|
53
55
|
end
|
@@ -61,18 +63,28 @@ class TestWallet < Minitest::Test
|
|
61
63
|
|
62
64
|
def test_fails_with_invalid_infura_key
|
63
65
|
w = ERC20::Wallet.new(
|
64
|
-
|
65
|
-
|
66
|
-
log:
|
66
|
+
host: 'mainnet.infura.io',
|
67
|
+
http_path: '/v3/invalid-key-here',
|
68
|
+
log: loog
|
67
69
|
)
|
68
|
-
assert_raises(StandardError) { w.balance(
|
70
|
+
assert_raises(StandardError) { w.balance(STABLE) }
|
69
71
|
end
|
70
72
|
|
71
73
|
def test_checks_balance_on_testnet
|
72
|
-
|
73
|
-
b
|
74
|
+
b = testnet.balance(STABLE)
|
75
|
+
refute_nil(b)
|
76
|
+
assert_predicate(b, :zero?)
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_checks_balance_on_polygon
|
80
|
+
w = ERC20::Wallet.new(
|
81
|
+
contract: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',
|
82
|
+
host: 'polygon-mainnet.infura.io', http_path: "/v3/#{env('INFURA_KEY')}",
|
83
|
+
log: loog
|
84
|
+
)
|
85
|
+
b = w.balance(STABLE)
|
74
86
|
refute_nil(b)
|
75
|
-
assert_predicate(b, :
|
87
|
+
assert_predicate(b, :zero?)
|
76
88
|
end
|
77
89
|
|
78
90
|
def test_checks_balance_on_hardhat
|
@@ -106,7 +118,7 @@ class TestWallet < Minitest::Test
|
|
106
118
|
event = e
|
107
119
|
end
|
108
120
|
rescue StandardError => e
|
109
|
-
|
121
|
+
loog.error(Backtrace.new(e))
|
110
122
|
end
|
111
123
|
wait_for { !connected.empty? }
|
112
124
|
sum = 77_000
|
@@ -120,8 +132,80 @@ class TestWallet < Minitest::Test
|
|
120
132
|
end
|
121
133
|
end
|
122
134
|
|
135
|
+
def test_accepts_payments_on_hardhat_via_proxy
|
136
|
+
via_proxy do |proxy|
|
137
|
+
walter = Eth::Key.new(priv: WALTER).address.to_s.downcase
|
138
|
+
jeff = Eth::Key.new(priv: JEFF).address.to_s.downcase
|
139
|
+
on_hardhat do |w|
|
140
|
+
wallet = through_proxy(w, proxy)
|
141
|
+
connected = []
|
142
|
+
event = nil
|
143
|
+
daemon =
|
144
|
+
Thread.new do
|
145
|
+
wallet.accept([walter, jeff], connected:) do |e|
|
146
|
+
event = e
|
147
|
+
end
|
148
|
+
rescue StandardError => e
|
149
|
+
loog.error(Backtrace.new(e))
|
150
|
+
end
|
151
|
+
wait_for { !connected.empty? }
|
152
|
+
sum = 55_000
|
153
|
+
wallet.pay(JEFF, walter, sum)
|
154
|
+
wait_for { !event.nil? }
|
155
|
+
daemon.kill
|
156
|
+
daemon.join(30)
|
157
|
+
assert_equal(sum, event[:amount])
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_accepts_payments_on_mainnet
|
163
|
+
connected = []
|
164
|
+
failed = false
|
165
|
+
net = mainnet
|
166
|
+
daemon =
|
167
|
+
Thread.new do
|
168
|
+
net.accept([STABLE], connected:) do |_|
|
169
|
+
# ignore it
|
170
|
+
end
|
171
|
+
rescue StandardError => e
|
172
|
+
failed = true
|
173
|
+
loog.error(Backtrace.new(e))
|
174
|
+
end
|
175
|
+
wait_for { !connected.empty? }
|
176
|
+
daemon.kill
|
177
|
+
daemon.join(30)
|
178
|
+
refute(failed)
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_checks_balance_via_proxy
|
182
|
+
via_proxy do |proxy|
|
183
|
+
on_hardhat do |w|
|
184
|
+
wallet = through_proxy(w, proxy)
|
185
|
+
b = wallet.balance(Eth::Key.new(priv: JEFF).address.to_s)
|
186
|
+
assert_equal(123_000_100_000, b)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def test_checks_balance_via_proxy_on_mainnet
|
192
|
+
via_proxy do |proxy|
|
193
|
+
on_hardhat do
|
194
|
+
w = ERC20::Wallet.new(
|
195
|
+
host: 'mainnet.infura.io', http_path: "/v3/#{env('INFURA_KEY')}",
|
196
|
+
proxy:, log: loog
|
197
|
+
)
|
198
|
+
assert_equal(27_258_889, w.balance(STABLE))
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
123
203
|
private
|
124
204
|
|
205
|
+
def loog
|
206
|
+
ENV['RAKE'] ? Loog::NULL : Loog::VERBOSE
|
207
|
+
end
|
208
|
+
|
125
209
|
def wait_for
|
126
210
|
start = Time.now
|
127
211
|
loop do
|
@@ -145,29 +229,66 @@ class TestWallet < Minitest::Test
|
|
145
229
|
|
146
230
|
def mainnet
|
147
231
|
[
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
232
|
+
{
|
233
|
+
host: 'mainnet.infura.io',
|
234
|
+
http_path: "/v3/#{env('INFURA_KEY')}",
|
235
|
+
ws_path: "/ws/v3/#{env('INFURA_KEY')}"
|
236
|
+
},
|
237
|
+
{
|
238
|
+
host: 'go.getblock.io',
|
239
|
+
http_path: "/#{env('GETBLOCK_KEY')}",
|
240
|
+
ws_path: "/#{env('GETBLOCK_WS_KEY')}"
|
241
|
+
}
|
242
|
+
].map do |server|
|
243
|
+
ERC20::Wallet.new(host: server[:host], http_path: server[:http_path], ws_path: server[:ws_path], log: loog)
|
152
244
|
end.sample
|
153
245
|
end
|
154
246
|
|
155
247
|
def testnet
|
156
248
|
[
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
249
|
+
{
|
250
|
+
host: 'sepolia.infura.io',
|
251
|
+
http_path: "/v3/#{env('INFURA_KEY')}",
|
252
|
+
ws_path: "/ws/v3/#{env('INFURA_KEY')}"
|
253
|
+
},
|
254
|
+
{
|
255
|
+
host: 'go.getblock.io',
|
256
|
+
http_path: "/#{env('GETBLOCK_SEPOILA_KEY')}",
|
257
|
+
ws_path: "/#{env('GETBLOCK_SEPOILA_KEY')}"
|
258
|
+
}
|
259
|
+
].map do |server|
|
260
|
+
ERC20::Wallet.new(host: server[:host], http_path: server[:http_path], ws_path: server[:ws_path], log: loog)
|
161
261
|
end.sample
|
162
262
|
end
|
163
263
|
|
264
|
+
def through_proxy(wallet, proxy)
|
265
|
+
ERC20::Wallet.new(
|
266
|
+
contract: wallet.contract, chain: wallet.chain,
|
267
|
+
host: donce_host, port: wallet.port, http_path: wallet.http_path, ws_path: wallet.ws_path,
|
268
|
+
ssl: wallet.ssl, proxy:, log: loog
|
269
|
+
)
|
270
|
+
end
|
271
|
+
|
272
|
+
def via_proxy
|
273
|
+
RandomPort::Pool::SINGLETON.acquire do |port|
|
274
|
+
donce(
|
275
|
+
image: 'yegor256/squid-proxy:latest',
|
276
|
+
ports: { port => 3128 },
|
277
|
+
env: { 'USERNAME' => 'jeffrey', 'PASSWORD' => 'swordfish' },
|
278
|
+
root: true, log: loog
|
279
|
+
) do
|
280
|
+
yield "http://jeffrey:swordfish@localhost:#{port}"
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
164
285
|
def on_hardhat
|
165
286
|
RandomPort::Pool::SINGLETON.acquire do |port|
|
166
287
|
donce(
|
167
288
|
home: File.join(__dir__, '../../hardhat'),
|
168
289
|
ports: { port => 8545 },
|
169
290
|
command: 'npx hardhat node',
|
170
|
-
log:
|
291
|
+
log: loog
|
171
292
|
) do
|
172
293
|
wait_for_port(port)
|
173
294
|
cmd = [
|
@@ -180,13 +301,13 @@ class TestWallet < Minitest::Test
|
|
180
301
|
home: File.join(__dir__, '../../hardhat'),
|
181
302
|
command: "/bin/bash -c #{Shellwords.escape(cmd)}",
|
182
303
|
build_args: { 'HOST' => donce_host, 'PORT' => port },
|
183
|
-
log:
|
304
|
+
log: loog,
|
184
305
|
root: true
|
185
306
|
).split("\n").last
|
186
307
|
wallet = ERC20::Wallet.new(
|
187
308
|
contract:, chain: 4242,
|
188
|
-
host: 'localhost', port:,
|
189
|
-
log:
|
309
|
+
host: 'localhost', port:, http_path: '/', ws_path: '/', ssl: false,
|
310
|
+
log: loog
|
190
311
|
)
|
191
312
|
yield wallet
|
192
313
|
end
|
data/test/test__helper.rb
CHANGED
@@ -35,5 +35,7 @@ require 'minitest/reporters'
|
|
35
35
|
Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new]
|
36
36
|
|
37
37
|
# To make tests retry on failure:
|
38
|
-
|
39
|
-
|
38
|
+
if ENV['RAKE']
|
39
|
+
require 'minitest/retry'
|
40
|
+
Minitest::Retry.use!(methods_to_skip: [])
|
41
|
+
end
|
metadata
CHANGED
@@ -1,73 +1,73 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: erc20
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-02-
|
11
|
+
date: 2025-02-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: eth
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 0.5.13
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 0.5.13
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: faye-websocket
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 0.11.3
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 0.11.3
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: json
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 2.10.1
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: 2.10.1
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: jsonrpc-client
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: 0.1.4
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
68
|
+
version: 0.1.4
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: loog
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">"
|
@@ -80,8 +80,10 @@ dependencies:
|
|
80
80
|
- - ">"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
-
description: A simple library for making ERC20 manipulations as easy as
|
84
|
-
for cryptocurrency newbies
|
83
|
+
description: 'A simple library for making ERC20 manipulations as easy as they can
|
84
|
+
be for cryptocurrency newbies: checking balance, sending payments, and monitoring
|
85
|
+
addresses for incoming payments. The library expects Etherium node to provide JSON
|
86
|
+
RPC and Websockets API.'
|
85
87
|
email: yegor256@gmail.com
|
86
88
|
executables: []
|
87
89
|
extensions: []
|