sibit 0.25.0 → 0.26.0

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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +18 -28
  3. data/Gemfile.lock +187 -0
  4. data/LICENSE.txt +1 -1
  5. data/LICENSES/MIT.txt +21 -0
  6. data/README.md +82 -60
  7. data/REUSE.toml +35 -0
  8. data/Rakefile +3 -29
  9. data/bin/sibit +7 -23
  10. data/cucumber.yml +3 -0
  11. data/features/cli.feature +2 -0
  12. data/features/gem_package.feature +4 -1
  13. data/features/step_definitions/steps.rb +2 -19
  14. data/features/support/env.rb +2 -19
  15. data/lib/sibit/bestof.rb +5 -22
  16. data/lib/sibit/bitcoin/base58.rb +50 -0
  17. data/lib/sibit/bitcoin/key.rb +87 -0
  18. data/lib/sibit/bitcoin/script.rb +58 -0
  19. data/lib/sibit/bitcoin/tx.rb +212 -0
  20. data/lib/sibit/bitcoin/txbuilder.rb +120 -0
  21. data/lib/sibit/bitcoinchain.rb +5 -22
  22. data/lib/sibit/blockchain.rb +5 -22
  23. data/lib/sibit/blockchair.rb +5 -22
  24. data/lib/sibit/btc.rb +6 -23
  25. data/lib/sibit/cex.rb +5 -22
  26. data/lib/sibit/cryptoapis.rb +5 -22
  27. data/lib/sibit/earn.rb +5 -21
  28. data/lib/sibit/error.rb +3 -20
  29. data/lib/sibit/fake.rb +3 -20
  30. data/lib/sibit/firstof.rb +5 -22
  31. data/lib/sibit/http.rb +3 -20
  32. data/lib/sibit/json.rb +6 -23
  33. data/lib/sibit/version.rb +4 -21
  34. data/lib/sibit.rb +31 -40
  35. data/logo.svg +1 -1
  36. data/sibit.gemspec +16 -33
  37. metadata +27 -49
  38. data/.0pdd.yml +0 -9
  39. data/.gitattributes +0 -7
  40. data/.github/workflows/codecov.yml +0 -21
  41. data/.github/workflows/pdd.yml +0 -15
  42. data/.github/workflows/rake.yml +0 -24
  43. data/.github/workflows/xcop.yml +0 -17
  44. data/.gitignore +0 -8
  45. data/.pdd +0 -7
  46. data/.rubocop.yml +0 -38
  47. data/.rultor.yml +0 -21
  48. data/.simplecov +0 -40
  49. data/lib/sibit/log.rb +0 -49
  50. data/renovate.json +0 -6
  51. data/test/test__helper.rb +0 -29
  52. data/test/test_bestof.rb +0 -62
  53. data/test/test_bitcoinchain.rb +0 -73
  54. data/test/test_blockchain.rb +0 -58
  55. data/test/test_blockchair.rb +0 -43
  56. data/test/test_btc.rb +0 -117
  57. data/test/test_cex.rb +0 -43
  58. data/test/test_cryptoapis.rb +0 -51
  59. data/test/test_fake.rb +0 -55
  60. data/test/test_firstof.rb +0 -62
  61. data/test/test_json.rb +0 -40
  62. data/test/test_live.rb +0 -138
  63. data/test/test_sibit.rb +0 -209
data/test/test_live.rb DELETED
@@ -1,138 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright (c) 2019-2023 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 'webmock/minitest'
25
- require 'json'
26
- require 'backtrace'
27
- require_relative '../lib/sibit'
28
-
29
- # Live tests.
30
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
31
- # Copyright:: Copyright (c) 2019-2023 Yegor Bugayenko
32
- # License:: MIT
33
- class TestLive < Minitest::Test
34
- def test_block
35
- for_each do |api|
36
- hash = '000000003031a0e73735690c5a1ff2a4be82553b2a12b776fbd3a215dc8f778d'
37
- json = api.block(hash)
38
- assert_equal(hash, json[:hash])
39
- assert(json[:txns].is_a?(Array))
40
- assert_equal(1, json[:txns].length)
41
- assert_equal(
42
- '20251a76e64e920e58291a30d4b212939aae976baca40e70818ceaa596fb9d37',
43
- json[:txns][0][:hash]
44
- )
45
- assert(json[:txns][0][:outputs].is_a?(Array))
46
- assert_equal(1, json[:txns][0][:outputs].length)
47
- out = json[:txns][0][:outputs][0]
48
- assert_equal('1GkQmKAmHtNfnD3LHhTkewJxKHVSta4m2a', out[:address])
49
- assert_equal(5_000_000_000, out[:value])
50
- assert(json[:next], 'Next block not found')
51
- assert(json[:previous], 'Previous block not found')
52
- end
53
- end
54
-
55
- def test_balance
56
- for_each do |api|
57
- hash = '1GkQmKAmHtNfnD3LHhTkewJxKHVSta4m2a'
58
- satoshi = api.balance(hash)
59
- assert(satoshi.is_a?(Integer), "Wrong type of balance: #{satoshi.class.name}")
60
- assert_equal(5_000_028_421, satoshi)
61
- end
62
- end
63
-
64
- def test_absent_balance
65
- for_each do |api|
66
- hash = '12NJ7DxjBMCkk7EFdb6nXnMsuJV1nAXGiM'
67
- satoshi = api.balance(hash)
68
- assert_equal(0, satoshi)
69
- end
70
- end
71
-
72
- def test_latest
73
- for_each do |api|
74
- hash = api.latest
75
- assert_equal(64, hash.length)
76
- end
77
- end
78
-
79
- def test_price
80
- for_each do |api|
81
- price = api.price
82
- assert(price.is_a?(Float))
83
- end
84
- end
85
-
86
- def test_next_of
87
- for_each do |api|
88
- hash = '000000003031a0e73735690c5a1ff2a4be82553b2a12b776fbd3a215dc8f778d'
89
- nxt = api.next_of(hash)
90
- assert_equal(
91
- '0000000071966c2b1d065fd446b1e485b2c9d9594acd2007ccbd5441cfc89444',
92
- nxt
93
- )
94
- end
95
- end
96
-
97
- def test_height
98
- for_each do |api|
99
- hash = '000000003031a0e73735690c5a1ff2a4be82553b2a12b776fbd3a215dc8f778d'
100
- height = api.height(hash)
101
- assert_equal(6, height)
102
- end
103
- end
104
-
105
- def test_utxos
106
- for_each do |api|
107
- json = api.utxos(['12fCwqBN4XsHq4iu2Wbfgq5e8YhqEGP3ee'])
108
- assert_equal(3, json.length)
109
- assert(json.find { |t| t[:value] == 16_200_000 }, 'UTXO not found')
110
- assert(json.find { |t| t[:script].unpack1('H*').start_with?('76a9141231e760') })
111
- end
112
- end
113
-
114
- private
115
-
116
- def for_each
117
- skip if ENV['skip_live']
118
- WebMock.allow_net_connect!
119
- apis = []
120
- require_relative '../lib/sibit/btc'
121
- apis << Sibit::Btc.new
122
- require_relative '../lib/sibit/blockchain'
123
- apis << Sibit::Blockchain.new
124
- require_relative '../lib/sibit/blockchair'
125
- apis << Sibit::Blockchair.new
126
- require_relative '../lib/sibit/cryptoapis'
127
- apis << Sibit::Cryptoapis.new('')
128
- require_relative '../lib/sibit/cex'
129
- apis << Sibit::Cex.new
130
- require_relative '../lib/sibit/bitcoinchain'
131
- apis << Sibit::Bitcoinchain.new
132
- apis.each do |api|
133
- yield api
134
- rescue Sibit::Error => e
135
- puts Backtrace.new(e)
136
- end
137
- end
138
- end
data/test/test_sibit.rb DELETED
@@ -1,209 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright (c) 2019-2023 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 'webmock/minitest'
25
- require 'json'
26
- require_relative '../lib/sibit'
27
- require_relative '../lib/sibit/earn'
28
- require_relative '../lib/sibit/fake'
29
- require_relative '../lib/sibit/blockchain'
30
- require_relative '../lib/sibit/firstof'
31
- require_relative '../lib/sibit/bestof'
32
-
33
- # Sibit.
34
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
35
- # Copyright:: Copyright (c) 2019-2023 Yegor Bugayenko
36
- # License:: MIT
37
- class TestSibit < Minitest::Test
38
- def test_loads_fees
39
- stub_request(
40
- :get, 'https://bitcoinfees.earn.com/api/v1/fees/recommended'
41
- ).to_return(body: '{"fastestFee":300,"halfHourFee":200,"hourFee":180}')
42
- sibit = Sibit.new(api: Sibit::Earn.new)
43
- fees = sibit.fees
44
- assert_equal(60, fees[:S])
45
- assert_equal(180, fees[:M])
46
- assert_equal(200, fees[:L])
47
- assert_equal(300, fees[:XL])
48
- end
49
-
50
- def test_fetch_current_price
51
- stub_request(
52
- :get, 'https://blockchain.info/ticker'
53
- ).to_return(body: '{"USD" : {"15m" : 5160.04}}')
54
- sibit = Sibit.new
55
- price = sibit.price
56
- assert(!price.nil?)
57
- assert_equal(5160.04, price, price)
58
- end
59
-
60
- def test_generate_key
61
- sibit = Sibit.new(api: Sibit::Fake.new)
62
- pkey = sibit.generate
63
- assert(!pkey.nil?)
64
- assert(/^[0-9a-f]{64}$/.match?(pkey))
65
- end
66
-
67
- def test_generate_key_and_prints
68
- require 'stringio'
69
- require 'logger'
70
- strio = StringIO.new
71
- sibit = Sibit.new(log: Logger.new(strio), api: Sibit::Fake.new)
72
- key = sibit.generate
73
- assert(strio.string.include?('private key generated'))
74
- assert(strio.string.include?(key[0..4]))
75
- assert(!strio.string.include?(key))
76
- end
77
-
78
- def test_create_address
79
- sibit = Sibit.new(api: Sibit::Fake.new)
80
- pkey = sibit.generate
81
- puts "key: #{pkey}"
82
- address = sibit.create(pkey)
83
- puts "address: #{address}"
84
- assert(!address.nil?)
85
- assert(/^1[0-9a-zA-Z]+$/.match?(address))
86
- assert_equal(address, sibit.create(pkey))
87
- end
88
-
89
- def test_get_balance
90
- stub_request(
91
- :get,
92
- 'https://blockchain.info/rawaddr/1MZT1fa6y8H9UmbZV6HqKF4UY41o9MGT5f?limit=0'
93
- ).to_return(body: '{"final_balance": 100}')
94
- sibit = Sibit.new
95
- balance = sibit.balance('1MZT1fa6y8H9UmbZV6HqKF4UY41o9MGT5f')
96
- assert(balance.is_a?(Integer))
97
- assert_equal(100, balance)
98
- end
99
-
100
- def test_get_latest_block
101
- stub_request(:get, 'https://blockchain.info/latestblock').to_return(
102
- body: '{"hash": "0000000000000538200a48202ca6340e983646ca088c7618ae82d68e0c76ef5a"}'
103
- )
104
- sibit = Sibit.new
105
- hash = sibit.latest
106
- assert_equal('0000000000000538200a48202ca6340e983646ca088c7618ae82d68e0c76ef5a', hash)
107
- end
108
-
109
- def test_send_payment
110
- stub_request(
111
- :get, 'https://bitcoinfees.earn.com/api/v1/fees/recommended'
112
- ).to_return(body: '{"fastestFee":300,"halfHourFee":200,"hourFee":180}')
113
- stub_request(
114
- :get, 'https://blockchain.info/ticker'
115
- ).to_return(body: '{"USD" : {"15m" : 5160.04}}')
116
- json = {
117
- unspent_outputs: [
118
- {
119
- tx_hash: 'fc8fb1a526aef220b54a66bbb3e0549bf34db4f25e1aebc3feb87e86d341e65d',
120
- tx_hash_big_endian: '5de641d3867eb8fec3eb1a5ef2b44df39b54e0b3bb664ab520f2ae26a5b18ffc',
121
- tx_output_n: 0,
122
- script: '76a914c48a1737b35a9f9d9e3b624a910f1e22f7e80bbc88ac',
123
- value: 100_000
124
- }
125
- ]
126
- }
127
- stub_request(
128
- :get,
129
- 'https://blockchain.info/unspent?active=1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi&limit=1000'
130
- ).to_return(body: JSON.pretty_generate(json))
131
- stub_request(:post, 'https://blockchain.info/pushtx').to_return(status: 200)
132
- sibit = Sibit.new(api: Sibit::FirstOf.new([Sibit::Earn.new, Sibit::Blockchain.new]))
133
- target = sibit.create(sibit.generate)
134
- change = sibit.create(sibit.generate)
135
- tx = sibit.pay(
136
- '0.0001BTC', 'S',
137
- {
138
- '1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi' =>
139
- 'fd2333686f49d8647e1ce8d5ef39c304520b08f3c756b67068b30a3db217dcb2'
140
- },
141
- target, change
142
- )
143
- assert(!tx.nil?)
144
- assert(tx.length > 30, tx)
145
- end
146
-
147
- def test_fail_if_not_enough_funds
148
- stub_request(
149
- :get, 'https://bitcoinfees.earn.com/api/v1/fees/recommended'
150
- ).to_return(body: '{"fastestFee":300,"halfHourFee":200,"hourFee":180}')
151
- stub_request(
152
- :get, 'https://blockchain.info/ticker'
153
- ).to_return(body: '{"USD" : {"15m" : 5160.04}}')
154
- json = {
155
- unspent_outputs: []
156
- }
157
- stub_request(
158
- :get,
159
- 'https://blockchain.info/unspent?active=1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi&limit=1000'
160
- ).to_return(body: JSON.pretty_generate(json))
161
- sibit = Sibit.new(api: Sibit::BestOf.new([Sibit::Fake.new, Sibit::Fake.new]))
162
- target = sibit.create(sibit.generate)
163
- change = sibit.create(sibit.generate)
164
- assert_raises Sibit::Error do
165
- sibit.pay(
166
- '0.0001BTC', -5000,
167
- {
168
- '1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi' =>
169
- 'fd2333686f49d8647e1ce8d5ef39c304520b08f3c756b67068b30a3db217dcb2'
170
- },
171
- target, change
172
- )
173
- end
174
- end
175
-
176
- def test_scan
177
- api = Object.new
178
- def api.block(hash)
179
- {
180
- hash: hash,
181
- orphan: false,
182
- next: 'next',
183
- previous: 'previous',
184
- txns: [
185
- {
186
- hash: 'hash',
187
- outputs: [
188
- {
189
- address: 'addr',
190
- value: 123
191
- }
192
- ]
193
- }
194
- ]
195
- }
196
- end
197
- sibit = Sibit.new(api: api)
198
- found = false
199
- start = '00000000000000000008df8a6e1b61d1136803ac9791b8725235c9f780b4ed71'
200
- tail = sibit.scan(start) do |addr, tx, satoshi|
201
- assert_equal(123, satoshi)
202
- assert_equal('addr', addr)
203
- assert_equal('hash:0', tx)
204
- found = true
205
- end
206
- assert(found)
207
- assert_equal('next', tail)
208
- end
209
- end