sibit 0.18.8 → 0.19.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/.rultor.yml +2 -2
- data/README.md +8 -1
- data/bin/sibit +2 -1
- data/lib/sibit.rb +11 -41
- data/lib/sibit/bestof.rb +119 -0
- data/lib/sibit/btc.rb +10 -1
- data/lib/sibit/firstof.rb +122 -0
- data/lib/sibit/version.rb +1 -1
- data/test/test_bestof.rb +62 -0
- data/test/test_btc.rb +22 -0
- data/test/test_firstof.rb +62 -0
- data/test/test_sibit.rb +4 -2
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca53f721586f3a69839c0862f37fbb1d17cd06b880a6bfbe62d2df04b0f29e2e
|
4
|
+
data.tar.gz: 33734496a83daed1b161675b095cf478f0b9af5e3c96fa9755055fc867d6e606
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee8ecc223c8f29ba5b3ca0c1666ec16ba50e3823dbb8b30ebb3a77f058311c2a81a3f84ce78af8101fa2061cf7a51690f41e1bf980fa994ec0ec415d1cb68ed8
|
7
|
+
data.tar.gz: d2415fef9dcbf66038a3df1abd2ef70628049c3bb566d8229fd474a1d9f8ab12bc056f147020f0364400f6170db987740b8925c508fcc0a6314d753585c55830
|
data/.rubocop.yml
CHANGED
data/.rultor.yml
CHANGED
@@ -5,7 +5,7 @@ install: |
|
|
5
5
|
sudo bundle install --no-color "--gemfile=$(pwd)/Gemfile"
|
6
6
|
release:
|
7
7
|
script: |-
|
8
|
-
bundle exec rake
|
8
|
+
bundle exec rake clean test rubocop copyright
|
9
9
|
sed -i "s/1\.0\.snapshot/${tag}/g" lib/sibit/version.rb
|
10
10
|
git add lib/sibit/version.rb
|
11
11
|
git commit -m "version set to ${tag}"
|
@@ -14,7 +14,7 @@ release:
|
|
14
14
|
gem push *.gem --config-file ../rubygems.yml
|
15
15
|
merge:
|
16
16
|
script: |-
|
17
|
-
bundle exec rake
|
17
|
+
bundle exec rake clean test rubocop copyright
|
18
18
|
deploy:
|
19
19
|
script: |-
|
20
20
|
echo "There is nothing to deploy"
|
data/README.md
CHANGED
@@ -145,7 +145,14 @@ will be used one by one, until a successful response is obtained:
|
|
145
145
|
require 'sibit'
|
146
146
|
require 'sibit/btc'
|
147
147
|
require 'sibit/cryptoapis'
|
148
|
-
sibit = Sibit.new(
|
148
|
+
sibit = Sibit.new(
|
149
|
+
api: Sibit::FirstOf.new(
|
150
|
+
[
|
151
|
+
Sibit::Btc.new,
|
152
|
+
Sibit::Cryptoapis.new('key')
|
153
|
+
]
|
154
|
+
)
|
155
|
+
)
|
149
156
|
```
|
150
157
|
|
151
158
|
If you think we may need to use some other API, you can submit a ticket,
|
data/bin/sibit
CHANGED
@@ -32,6 +32,7 @@ require_relative '../lib/sibit/blockchain'
|
|
32
32
|
require_relative '../lib/sibit/btc'
|
33
33
|
require_relative '../lib/sibit/bitcoinchain'
|
34
34
|
require_relative '../lib/sibit/earn'
|
35
|
+
require_relative '../lib/sibit/firstof'
|
35
36
|
|
36
37
|
begin
|
37
38
|
begin
|
@@ -86,7 +87,7 @@ Options are:"
|
|
86
87
|
api = RetriableProxy.for_object(api, on: Sibit::Error) if opts[:attempts] > 1
|
87
88
|
api
|
88
89
|
end
|
89
|
-
sibit = Sibit.new(log: log, api: apis)
|
90
|
+
sibit = Sibit.new(log: log, api: Sibit::FirstOf.new(apis, log: log))
|
90
91
|
case opts.arguments[0]
|
91
92
|
when 'price'
|
92
93
|
puts sibit.price
|
data/lib/sibit.rb
CHANGED
@@ -55,9 +55,7 @@ class Sibit
|
|
55
55
|
|
56
56
|
# Current price of 1 BTC in USD (or another currency), float returned.
|
57
57
|
def price(currency = 'USD')
|
58
|
-
|
59
|
-
api.price(currency)
|
60
|
-
end
|
58
|
+
@api.price(currency)
|
61
59
|
end
|
62
60
|
|
63
61
|
# Generates new Bitcon private key and returns in Hash160 format.
|
@@ -76,29 +74,23 @@ class Sibit
|
|
76
74
|
|
77
75
|
# Gets the balance of the address, in satoshi.
|
78
76
|
def balance(address)
|
79
|
-
|
80
|
-
api.balance(address)
|
81
|
-
end
|
77
|
+
@api.balance(address)
|
82
78
|
end
|
83
79
|
|
84
80
|
# Get the height of the block.
|
85
81
|
def height(hash)
|
86
|
-
|
87
|
-
api.height(hash)
|
88
|
-
end
|
82
|
+
@api.height(hash)
|
89
83
|
end
|
90
84
|
|
91
85
|
# Get the hash of the next block.
|
92
86
|
def next_of(hash)
|
93
|
-
|
94
|
-
api.next_of(hash)
|
95
|
-
end
|
87
|
+
@api.next_of(hash)
|
96
88
|
end
|
97
89
|
|
98
90
|
# Get recommended fees, in satoshi per byte. The method returns
|
99
91
|
# a hash: { S: 12, M: 45, L: 100, XL: 200 }
|
100
92
|
def fees
|
101
|
-
|
93
|
+
@api.fees
|
102
94
|
end
|
103
95
|
|
104
96
|
# Sends a payment and returns the transaction hash.
|
@@ -124,7 +116,7 @@ class Sibit
|
|
124
116
|
builder = Bitcoin::Builder::TxBuilder.new
|
125
117
|
unspent = 0
|
126
118
|
size = 100
|
127
|
-
utxos =
|
119
|
+
utxos = @api.utxos(sources.keys)
|
128
120
|
@log.info("#{utxos.count} UTXOs found, these will be used \
|
129
121
|
(value/confirmations at tx_hash):")
|
130
122
|
utxos.each do |utxo|
|
@@ -170,15 +162,13 @@ class Sibit
|
|
170
162
|
Amount: #{num(satoshi, p)}
|
171
163
|
Target address: #{target}
|
172
164
|
Change address is #{change}")
|
173
|
-
|
174
|
-
api.push(tx.to_payload.bth)
|
175
|
-
end
|
165
|
+
@api.push(tx.to_payload.bth)
|
176
166
|
tx.hash
|
177
167
|
end
|
178
168
|
|
179
169
|
# Gets the hash of the latest block.
|
180
170
|
def latest
|
181
|
-
|
171
|
+
@api.latest
|
182
172
|
end
|
183
173
|
|
184
174
|
# You call this method and provide a callback. You provide the hash
|
@@ -197,7 +187,7 @@ class Sibit
|
|
197
187
|
wrong = []
|
198
188
|
json = {}
|
199
189
|
loop do
|
200
|
-
json =
|
190
|
+
json = @api.block(block)
|
201
191
|
if json[:orphan]
|
202
192
|
steps = 4
|
203
193
|
@log.info("Orphan block found at #{block}, moving #{steps} steps back...")
|
@@ -206,7 +196,7 @@ class Sibit
|
|
206
196
|
block = json[:previous]
|
207
197
|
wrong << block
|
208
198
|
@log.info("Moved back to #{block}")
|
209
|
-
json =
|
199
|
+
json = @api.block(block)
|
210
200
|
end
|
211
201
|
next
|
212
202
|
end
|
@@ -224,13 +214,13 @@ class Sibit
|
|
224
214
|
end
|
225
215
|
checked += 1
|
226
216
|
end
|
217
|
+
count += 1
|
227
218
|
@log.info("We checked #{checked} txns and #{checked_outputs} outputs in block #{block}")
|
228
219
|
block = json[:next]
|
229
220
|
if block.nil?
|
230
221
|
@log.info("The next_block is empty in block #{json[:hash]}, this is the end of Blockchain")
|
231
222
|
break
|
232
223
|
end
|
233
|
-
count += 1
|
234
224
|
if count > max
|
235
225
|
@log.info("Too many blocks (#{count}) in one go, let's get back to it next time")
|
236
226
|
break
|
@@ -242,26 +232,6 @@ class Sibit
|
|
242
232
|
|
243
233
|
private
|
244
234
|
|
245
|
-
def first_one
|
246
|
-
return yield @api unless @api.is_a?(Array)
|
247
|
-
done = false
|
248
|
-
result = nil
|
249
|
-
@api.each do |api|
|
250
|
-
begin
|
251
|
-
result = yield api
|
252
|
-
done = true
|
253
|
-
break
|
254
|
-
rescue Sibit::Error => e
|
255
|
-
@log.info("The API #{api.class.name} failed: #{e.message}")
|
256
|
-
end
|
257
|
-
end
|
258
|
-
unless done
|
259
|
-
raise Sibit::Error, "No APIs out of #{@api.length} managed to succeed: \
|
260
|
-
#{@api.map { |a| a.class.name }.join(', ')}"
|
261
|
-
end
|
262
|
-
result
|
263
|
-
end
|
264
|
-
|
265
235
|
def num(satoshi, usd)
|
266
236
|
format(
|
267
237
|
'%<satoshi>ss/$%<dollars>0.2f',
|
data/lib/sibit/bestof.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2019-2020 Yegor Bugayenko
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
13
|
+
# copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
# SOFTWARE.
|
22
|
+
|
23
|
+
require_relative 'error'
|
24
|
+
require_relative 'log'
|
25
|
+
|
26
|
+
# API best of.
|
27
|
+
#
|
28
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
29
|
+
# Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
|
30
|
+
# License:: MIT
|
31
|
+
class Sibit
|
32
|
+
# Best of API.
|
33
|
+
class BestOf
|
34
|
+
# Constructor.
|
35
|
+
def initialize(list, log: Sibit::Log.new)
|
36
|
+
@list = list
|
37
|
+
@log = log
|
38
|
+
end
|
39
|
+
|
40
|
+
# Current price of BTC in USD (float returned).
|
41
|
+
def price(currency = 'USD')
|
42
|
+
best_of('price') do |api|
|
43
|
+
api.price(currency)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Gets the balance of the address, in satoshi.
|
48
|
+
def balance(address)
|
49
|
+
best_of('balance') do |api|
|
50
|
+
api.balance(address)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Get the height of the block.
|
55
|
+
def height(hash)
|
56
|
+
best_of('height') do |api|
|
57
|
+
api.height(hash)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Get the hash of the next block.
|
62
|
+
def next_of(hash)
|
63
|
+
best_of('next_of') do |api|
|
64
|
+
api.next_of(hash)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Get recommended fees, in satoshi per byte. The method returns
|
69
|
+
# a hash: { S: 12, M: 45, L: 100, XL: 200 }
|
70
|
+
def fees
|
71
|
+
best_of('fees', &:fees)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Fetch all unspent outputs per address.
|
75
|
+
def utxos(keys)
|
76
|
+
best_of('utxos') do |api|
|
77
|
+
api.utxos(keys)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Latest block hash.
|
82
|
+
def latest
|
83
|
+
best_of('latest', &:latest)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Push this transaction (in hex format) to the network.
|
87
|
+
def push(hex)
|
88
|
+
best_of('push') do |api|
|
89
|
+
api.push(hex)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# This method should fetch a block and return as a hash.
|
94
|
+
def block(hash)
|
95
|
+
best_of('block') do |api|
|
96
|
+
api.block(hash)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def best_of(method)
|
103
|
+
return yield @list unless @list.is_a?(Array)
|
104
|
+
results = []
|
105
|
+
@list.each do |api|
|
106
|
+
begin
|
107
|
+
results << yield(api)
|
108
|
+
rescue Sibit::Error => e
|
109
|
+
@log.info("The API #{api.class.name} failed at #{method}(): #{e.message}")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
if results.empty?
|
113
|
+
raise Sibit::Error, "No APIs out of #{@list.length} managed to succeed at #{method}(): \
|
114
|
+
#{@list.map { |a| a.class.name }.join(', ')}"
|
115
|
+
end
|
116
|
+
results.group_by(&:to_s).values.max_by(&:size)[0]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/lib/sibit/btc.rb
CHANGED
@@ -58,7 +58,16 @@ class Sibit
|
|
58
58
|
@log.info("The balance of #{address} is zero (not found)")
|
59
59
|
return 0
|
60
60
|
end
|
61
|
-
|
61
|
+
data = json['data']
|
62
|
+
if data.nil?
|
63
|
+
@log.info("The balance of #{address} is probably zero (not found)")
|
64
|
+
return 0
|
65
|
+
end
|
66
|
+
txns = data['list']
|
67
|
+
if txns.nil?
|
68
|
+
@log.info("The balance of #{address} is probably zero (not found)")
|
69
|
+
return 0
|
70
|
+
end
|
62
71
|
balance = txns.map { |tx| tx['value'] }.inject(&:+) || 0
|
63
72
|
@log.info("The balance of #{address} is #{balance}, total txns: #{txns.count}")
|
64
73
|
balance
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2019-2020 Yegor Bugayenko
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
13
|
+
# copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
# SOFTWARE.
|
22
|
+
|
23
|
+
require_relative 'error'
|
24
|
+
require_relative 'log'
|
25
|
+
|
26
|
+
# API first of.
|
27
|
+
#
|
28
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
29
|
+
# Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
|
30
|
+
# License:: MIT
|
31
|
+
class Sibit
|
32
|
+
# First of API.
|
33
|
+
class FirstOf
|
34
|
+
# Constructor.
|
35
|
+
def initialize(list, log: Sibit::Log.new)
|
36
|
+
@list = list
|
37
|
+
@log = log
|
38
|
+
end
|
39
|
+
|
40
|
+
# Current price of BTC in USD (float returned).
|
41
|
+
def price(currency = 'USD')
|
42
|
+
first_of('price') do |api|
|
43
|
+
api.price(currency)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Gets the balance of the address, in satoshi.
|
48
|
+
def balance(address)
|
49
|
+
first_of('balance') do |api|
|
50
|
+
api.balance(address)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Get the height of the block.
|
55
|
+
def height(hash)
|
56
|
+
first_of('height') do |api|
|
57
|
+
api.height(hash)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Get the hash of the next block.
|
62
|
+
def next_of(hash)
|
63
|
+
first_of('next_of') do |api|
|
64
|
+
api.next_of(hash)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Get recommended fees, in satoshi per byte. The method returns
|
69
|
+
# a hash: { S: 12, M: 45, L: 100, XL: 200 }
|
70
|
+
def fees
|
71
|
+
first_of('fees', &:fees)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Fetch all unspent outputs per address.
|
75
|
+
def utxos(keys)
|
76
|
+
first_of('utxos') do |api|
|
77
|
+
api.utxos(keys)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Latest block hash.
|
82
|
+
def latest
|
83
|
+
first_of('latest', &:latest)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Push this transaction (in hex format) to the network.
|
87
|
+
def push(hex)
|
88
|
+
first_of('push') do |api|
|
89
|
+
api.push(hex)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# This method should fetch a block and return as a hash.
|
94
|
+
def block(hash)
|
95
|
+
first_of('block') do |api|
|
96
|
+
api.block(hash)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def first_of(method)
|
103
|
+
return yield @list unless @list.is_a?(Array)
|
104
|
+
done = false
|
105
|
+
result = nil
|
106
|
+
@list.each do |api|
|
107
|
+
begin
|
108
|
+
result = yield api
|
109
|
+
done = true
|
110
|
+
break
|
111
|
+
rescue Sibit::Error => e
|
112
|
+
@log.info("The API #{api.class.name} failed at #{method}(): #{e.message}")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
unless done
|
116
|
+
raise Sibit::Error, "No APIs out of #{@list.length} managed to succeed at #{method}(): \
|
117
|
+
#{@list.map { |a| a.class.name }.join(', ')}"
|
118
|
+
end
|
119
|
+
result
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
data/lib/sibit/version.rb
CHANGED
data/test/test_bestof.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2019-2020 Yegor Bugayenko
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
13
|
+
# copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
# SOFTWARE.
|
22
|
+
|
23
|
+
require 'minitest/autorun'
|
24
|
+
require_relative '../lib/sibit'
|
25
|
+
require_relative '../lib/sibit/fake'
|
26
|
+
require_relative '../lib/sibit/bestof'
|
27
|
+
|
28
|
+
# Sibit::BestOf test.
|
29
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
30
|
+
# Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
|
31
|
+
# License:: MIT
|
32
|
+
class TestBestOf < Minitest::Test
|
33
|
+
def test_not_array
|
34
|
+
sibit = Sibit::BestOf.new(Sibit::Fake.new)
|
35
|
+
assert_equal(64, sibit.latest.length)
|
36
|
+
assert_equal(12, sibit.fees[:S])
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_one_apis
|
40
|
+
sibit = Sibit::BestOf.new([Sibit::Fake.new])
|
41
|
+
assert_equal(64, sibit.latest.length)
|
42
|
+
assert_equal(12, sibit.fees[:S])
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_two_apis
|
46
|
+
sibit = Sibit::BestOf.new([Sibit::Fake.new, Sibit::Fake.new])
|
47
|
+
assert_equal(64, sibit.latest.length)
|
48
|
+
assert_equal(12, sibit.fees[:S])
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_all_fail
|
52
|
+
api = Class.new do
|
53
|
+
def latest
|
54
|
+
raise Sibit::Error, 'intentionally'
|
55
|
+
end
|
56
|
+
end.new
|
57
|
+
sibit = Sibit::BestOf.new([api, api])
|
58
|
+
assert_raises Sibit::Error do
|
59
|
+
sibit.latest
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/test/test_btc.rb
CHANGED
@@ -42,6 +42,28 @@ class TestBtc < Minitest::Test
|
|
42
42
|
assert_equal(0, balance)
|
43
43
|
end
|
44
44
|
|
45
|
+
def test_get_zero_balance_no_txns
|
46
|
+
stub_request(
|
47
|
+
:get,
|
48
|
+
'https://chain.api.btc.com/v3/address/1MZT1fa6y8H9UmbZV6HqKF4UY41o9MGT5f/unspent'
|
49
|
+
).to_return(body: '{"data":{}}')
|
50
|
+
sibit = Sibit::Btc.new
|
51
|
+
balance = sibit.balance('1MZT1fa6y8H9UmbZV6HqKF4UY41o9MGT5f')
|
52
|
+
assert(balance.is_a?(Integer))
|
53
|
+
assert_equal(0, balance)
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_get_broken_balance
|
57
|
+
stub_request(
|
58
|
+
:get,
|
59
|
+
'https://chain.api.btc.com/v3/address/1MZT1fa6y8H9UmbZV6HqKF4UY41o9MGT5f/unspent'
|
60
|
+
).to_return(body: '{}')
|
61
|
+
sibit = Sibit::Btc.new
|
62
|
+
balance = sibit.balance('1MZT1fa6y8H9UmbZV6HqKF4UY41o9MGT5f')
|
63
|
+
assert(balance.is_a?(Integer))
|
64
|
+
assert_equal(0, balance)
|
65
|
+
end
|
66
|
+
|
45
67
|
def test_get_empty_balance
|
46
68
|
stub_request(
|
47
69
|
:get,
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2019-2020 Yegor Bugayenko
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
13
|
+
# copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
# SOFTWARE.
|
22
|
+
|
23
|
+
require 'minitest/autorun'
|
24
|
+
require_relative '../lib/sibit'
|
25
|
+
require_relative '../lib/sibit/fake'
|
26
|
+
require_relative '../lib/sibit/firstof'
|
27
|
+
|
28
|
+
# Sibit::FirstOf test.
|
29
|
+
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
30
|
+
# Copyright:: Copyright (c) 2019-2020 Yegor Bugayenko
|
31
|
+
# License:: MIT
|
32
|
+
class TestFirstOf < Minitest::Test
|
33
|
+
def test_not_array
|
34
|
+
sibit = Sibit::FirstOf.new(Sibit::Fake.new)
|
35
|
+
assert_equal(64, sibit.latest.length)
|
36
|
+
assert_equal(12, sibit.fees[:S])
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_one_apis
|
40
|
+
sibit = Sibit::FirstOf.new([Sibit::Fake.new])
|
41
|
+
assert_equal(64, sibit.latest.length)
|
42
|
+
assert_equal(12, sibit.fees[:S])
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_two_apis
|
46
|
+
sibit = Sibit::FirstOf.new([Sibit::Fake.new, Sibit::Fake.new])
|
47
|
+
assert_equal(64, sibit.latest.length)
|
48
|
+
assert_equal(12, sibit.fees[:S])
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_all_fail
|
52
|
+
api = Class.new do
|
53
|
+
def latest
|
54
|
+
raise Sibit::Error, 'intentionally'
|
55
|
+
end
|
56
|
+
end.new
|
57
|
+
sibit = Sibit::FirstOf.new([api, api])
|
58
|
+
assert_raises Sibit::Error do
|
59
|
+
sibit.latest
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/test/test_sibit.rb
CHANGED
@@ -27,6 +27,8 @@ require_relative '../lib/sibit'
|
|
27
27
|
require_relative '../lib/sibit/earn'
|
28
28
|
require_relative '../lib/sibit/fake'
|
29
29
|
require_relative '../lib/sibit/blockchain'
|
30
|
+
require_relative '../lib/sibit/firstof'
|
31
|
+
require_relative '../lib/sibit/bestof'
|
30
32
|
|
31
33
|
# Sibit.
|
32
34
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
@@ -127,7 +129,7 @@ class TestSibit < Minitest::Test
|
|
127
129
|
'https://blockchain.info/unspent?active=1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi&limit=1000'
|
128
130
|
).to_return(body: JSON.pretty_generate(json))
|
129
131
|
stub_request(:post, 'https://blockchain.info/pushtx').to_return(status: 200)
|
130
|
-
sibit = Sibit.new(api: [Sibit::Earn.new, Sibit::Blockchain.new])
|
132
|
+
sibit = Sibit.new(api: Sibit::FirstOf.new([Sibit::Earn.new, Sibit::Blockchain.new]))
|
131
133
|
target = sibit.create(sibit.generate)
|
132
134
|
change = sibit.create(sibit.generate)
|
133
135
|
tx = sibit.pay(
|
@@ -156,7 +158,7 @@ class TestSibit < Minitest::Test
|
|
156
158
|
:get,
|
157
159
|
'https://blockchain.info/unspent?active=1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi&limit=1000'
|
158
160
|
).to_return(body: JSON.pretty_generate(json))
|
159
|
-
sibit = Sibit.new
|
161
|
+
sibit = Sibit.new(api: Sibit::BestOf.new([Sibit::Fake.new, Sibit::Fake.new]))
|
160
162
|
target = sibit.create(sibit.generate)
|
161
163
|
change = sibit.create(sibit.generate)
|
162
164
|
assert_raises Sibit::Error do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sibit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.19.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-07-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: backtrace
|
@@ -281,6 +281,7 @@ files:
|
|
281
281
|
- features/step_definitions/steps.rb
|
282
282
|
- features/support/env.rb
|
283
283
|
- lib/sibit.rb
|
284
|
+
- lib/sibit/bestof.rb
|
284
285
|
- lib/sibit/bitcoinchain.rb
|
285
286
|
- lib/sibit/blockchain.rb
|
286
287
|
- lib/sibit/blockchair.rb
|
@@ -290,6 +291,7 @@ files:
|
|
290
291
|
- lib/sibit/earn.rb
|
291
292
|
- lib/sibit/error.rb
|
292
293
|
- lib/sibit/fake.rb
|
294
|
+
- lib/sibit/firstof.rb
|
293
295
|
- lib/sibit/http.rb
|
294
296
|
- lib/sibit/json.rb
|
295
297
|
- lib/sibit/log.rb
|
@@ -297,6 +299,7 @@ files:
|
|
297
299
|
- logo.svg
|
298
300
|
- sibit.gemspec
|
299
301
|
- test/test__helper.rb
|
302
|
+
- test/test_bestof.rb
|
300
303
|
- test/test_bitcoinchain.rb
|
301
304
|
- test/test_blockchain.rb
|
302
305
|
- test/test_blockchair.rb
|
@@ -304,6 +307,7 @@ files:
|
|
304
307
|
- test/test_cex.rb
|
305
308
|
- test/test_cryptoapis.rb
|
306
309
|
- test/test_fake.rb
|
310
|
+
- test/test_firstof.rb
|
307
311
|
- test/test_json.rb
|
308
312
|
- test/test_live.rb
|
309
313
|
- test/test_sibit.rb
|
@@ -337,6 +341,7 @@ test_files:
|
|
337
341
|
- features/step_definitions/steps.rb
|
338
342
|
- features/support/env.rb
|
339
343
|
- test/test__helper.rb
|
344
|
+
- test/test_bestof.rb
|
340
345
|
- test/test_bitcoinchain.rb
|
341
346
|
- test/test_blockchain.rb
|
342
347
|
- test/test_blockchair.rb
|
@@ -344,6 +349,7 @@ test_files:
|
|
344
349
|
- test/test_cex.rb
|
345
350
|
- test/test_cryptoapis.rb
|
346
351
|
- test/test_fake.rb
|
352
|
+
- test/test_firstof.rb
|
347
353
|
- test/test_json.rb
|
348
354
|
- test/test_live.rb
|
349
355
|
- test/test_sibit.rb
|