erc20 0.0.3 → 0.0.5
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/.rubocop.yml +2 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +13 -12
- data/README.md +30 -7
- data/Rakefile +2 -0
- data/erc20.gemspec +8 -6
- data/lib/erc20/wallet.rb +66 -29
- 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/.rubocop.yml
CHANGED
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
@@ -22,19 +22,20 @@ as simple as they can be, if you have a provider of
|
|
22
22
|
require 'erc20'
|
23
23
|
w = ERC20::Wallet.new(
|
24
24
|
contract: ERC20::Wallet.USDT, # hex of it
|
25
|
-
|
26
|
-
|
25
|
+
host: 'mainnet.infura.io',
|
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,17 +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)
|
49
|
+
# @param [String] host The host to connect to
|
50
|
+
# @param [Integer] port TCP port to use
|
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
|
53
|
+
# @param [Boolean] ssl Should we use SSL (for https and wss)
|
54
|
+
# @param [String] proxy The URL of the proxy to use
|
44
55
|
# @param [Object] log The destination for logs
|
45
|
-
def initialize(contract: USDT,
|
56
|
+
def initialize(contract: USDT, chain: 1, log: $stdout,
|
57
|
+
host: nil, port: 443, http_path: '/', ws_path: '/',
|
58
|
+
ssl: true, proxy: nil)
|
46
59
|
@contract = contract
|
47
|
-
@
|
48
|
-
@
|
60
|
+
@host = host
|
61
|
+
@port = port
|
62
|
+
@ssl = ssl
|
63
|
+
@http_path = http_path
|
64
|
+
@ws_path = ws_path
|
49
65
|
@log = log
|
50
66
|
@chain = chain
|
67
|
+
@proxy = proxy
|
51
68
|
end
|
52
69
|
|
53
70
|
# Get balance of a public address.
|
@@ -102,35 +119,39 @@ class ERC20::Wallet
|
|
102
119
|
|
103
120
|
# Wait for incoming transactions and let the block know when they
|
104
121
|
# arrive. It's a blocking call, it's better to run it in a separate
|
105
|
-
# thread.
|
122
|
+
# thread. It will never finish. In order to stop it, you should do
|
123
|
+
# +Thread.kill+.
|
106
124
|
#
|
107
125
|
# @param [Array<String>] addresses Addresses to monitor
|
108
126
|
# @param [Array] ready When connected, TRUE will be added to this array
|
109
127
|
# @param [Boolean] raw TRUE if you need to get JSON events as they arrive from Websockets
|
110
128
|
def accept(addresses, connected: [], raw: false)
|
111
|
-
|
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 } : {})
|
112
133
|
log = @log
|
113
134
|
contract = @contract
|
114
|
-
wss = @wss
|
115
135
|
ws.on(:open) do
|
116
|
-
log.debug("Connected to #{
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
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
|
+
)
|
134
155
|
connected.append(1)
|
135
156
|
log.debug("Subscribed to #{addresses.count} addresses")
|
136
157
|
end
|
@@ -155,19 +176,35 @@ class ERC20::Wallet
|
|
155
176
|
end
|
156
177
|
end
|
157
178
|
ws.on(:close) do |_e|
|
158
|
-
log.debug("Disconnected from #{
|
179
|
+
log.debug("Disconnected from #{@host}")
|
159
180
|
end
|
160
181
|
ws.on(:error) do |e|
|
161
|
-
log.debug("Error at #{
|
182
|
+
log.debug("Error at #{@host}: #{e.message}")
|
162
183
|
end
|
163
184
|
end
|
164
185
|
end
|
165
186
|
|
166
187
|
private
|
167
188
|
|
189
|
+
def url(http: true)
|
190
|
+
"#{http ? 'http' : 'ws'}#{@ssl ? 's' : ''}://#{@host}:#{@port}#{http ? @http_path : @ws_path}"
|
191
|
+
end
|
192
|
+
|
168
193
|
def jsonrpc
|
169
194
|
JSONRPC.logger = Loog::NULL
|
170
|
-
|
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:)
|
171
208
|
end
|
172
209
|
|
173
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,17 +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
|
+
host: 'mainnet.infura.io',
|
67
|
+
http_path: '/v3/invalid-key-here',
|
68
|
+
log: loog
|
66
69
|
)
|
67
|
-
assert_raises(StandardError) { w.balance(
|
70
|
+
assert_raises(StandardError) { w.balance(STABLE) }
|
68
71
|
end
|
69
72
|
|
70
73
|
def test_checks_balance_on_testnet
|
71
|
-
|
72
|
-
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)
|
73
86
|
refute_nil(b)
|
74
|
-
assert_predicate(b, :
|
87
|
+
assert_predicate(b, :zero?)
|
75
88
|
end
|
76
89
|
|
77
90
|
def test_checks_balance_on_hardhat
|
@@ -105,7 +118,7 @@ class TestWallet < Minitest::Test
|
|
105
118
|
event = e
|
106
119
|
end
|
107
120
|
rescue StandardError => e
|
108
|
-
|
121
|
+
loog.error(Backtrace.new(e))
|
109
122
|
end
|
110
123
|
wait_for { !connected.empty? }
|
111
124
|
sum = 77_000
|
@@ -119,8 +132,80 @@ class TestWallet < Minitest::Test
|
|
119
132
|
end
|
120
133
|
end
|
121
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
|
+
|
122
203
|
private
|
123
204
|
|
205
|
+
def loog
|
206
|
+
ENV['RAKE'] ? Loog::NULL : Loog::VERBOSE
|
207
|
+
end
|
208
|
+
|
124
209
|
def wait_for
|
125
210
|
start = Time.now
|
126
211
|
loop do
|
@@ -144,29 +229,66 @@ class TestWallet < Minitest::Test
|
|
144
229
|
|
145
230
|
def mainnet
|
146
231
|
[
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
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)
|
151
244
|
end.sample
|
152
245
|
end
|
153
246
|
|
154
247
|
def testnet
|
155
248
|
[
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
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)
|
160
261
|
end.sample
|
161
262
|
end
|
162
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
|
+
|
163
285
|
def on_hardhat
|
164
286
|
RandomPort::Pool::SINGLETON.acquire do |port|
|
165
287
|
donce(
|
166
288
|
home: File.join(__dir__, '../../hardhat'),
|
167
289
|
ports: { port => 8545 },
|
168
290
|
command: 'npx hardhat node',
|
169
|
-
log:
|
291
|
+
log: loog
|
170
292
|
) do
|
171
293
|
wait_for_port(port)
|
172
294
|
cmd = [
|
@@ -179,14 +301,13 @@ class TestWallet < Minitest::Test
|
|
179
301
|
home: File.join(__dir__, '../../hardhat'),
|
180
302
|
command: "/bin/bash -c #{Shellwords.escape(cmd)}",
|
181
303
|
build_args: { 'HOST' => donce_host, 'PORT' => port },
|
182
|
-
log:
|
304
|
+
log: loog,
|
183
305
|
root: true
|
184
306
|
).split("\n").last
|
185
307
|
wallet = ERC20::Wallet.new(
|
186
308
|
contract:, chain: 4242,
|
187
|
-
|
188
|
-
|
189
|
-
log: Loog::NULL
|
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: []
|