sibit 0.33.0 → 0.34.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.
data/lib/sibit/bin.rb CHANGED
@@ -22,16 +22,13 @@ class Sibit
22
22
  class Bin < Thor
23
23
  stop_on_unknown_option!
24
24
 
25
- class_option :proxy, type: :string,
26
- desc: 'HTTPS proxy for all requests, e.g. "localhost:3128"'
25
+ class_option :proxy, type: :string, desc: 'HTTPS proxy for all requests, e.g. "localhost:3128"'
27
26
  class_option :attempts, type: :numeric, default: 1,
28
27
  desc: 'How many times should we try before failing'
29
28
  class_option :dry, type: :boolean, default: false,
30
29
  desc: "Don't send a real payment, run in a read-only mode"
31
- class_option :verbose, type: :boolean, default: false,
32
- desc: 'Print all possible debug messages'
33
- class_option :quiet, type: :boolean, default: false,
34
- desc: 'Print only informative messages'
30
+ class_option :verbose, type: :boolean, default: false, desc: 'Print all possible debug messages'
31
+ class_option :quiet, type: :boolean, default: false, desc: 'Print only informative messages'
35
32
  class_option :api, type: :array, default: %w[blockchain btc bitcoinchain blockchair cex],
36
33
  desc: 'Ordered List of APIs to use, e.g. "blockchain,btc,bitcoinchain"'
37
34
  class_option :base58, type: :boolean, default: false,
@@ -45,10 +42,10 @@ class Sibit
45
42
  return new.help(command.name) if args.include?('--help') || args.include?('-h')
46
43
  unknown = args.find { |a| a.start_with?('-') }
47
44
  if unknown
48
- warn "Unknown option: #{unknown}"
49
- exit 1
45
+ warn("Unknown option: #{unknown}")
46
+ exit(1)
50
47
  end
51
- raise error
48
+ raise(error)
52
49
  end
53
50
 
54
51
  desc 'price', 'Get current price of BTC in USD'
@@ -60,12 +57,12 @@ class Sibit
60
57
  def fees
61
58
  sibit = client
62
59
  fees = sibit.fees
63
- text = %i[S M L XL].map do |m|
64
- sat = fees[m] * 250
65
- usd = sat * sibit.price / 100_000_000
66
- "#{m}: #{sat}sat / $#{format('%<usd>.02f', usd: usd)}"
67
- end.join("\n")
68
- log.info(text)
60
+ log.info(
61
+ %i[S M L XL].map do |m|
62
+ sat = fees[m] * 250
63
+ "#{m}: #{sat}sat / $#{format('%<usd>.02f', usd: (sat * sibit.price / 100_000_000))}"
64
+ end.join("\n")
65
+ )
69
66
  end
70
67
 
71
68
  desc 'latest', 'Get hash of the latest block'
@@ -86,8 +83,10 @@ class Sibit
86
83
  end
87
84
 
88
85
  desc 'balance ADDRESS', 'Check the balance of the Bitcoin address'
86
+ option :trust, type: :numeric, default: 0,
87
+ desc: 'Minimum number of confirmations required for a UTXO to count toward the balance'
89
88
  def balance(address)
90
- log.info(client.balance(address))
89
+ log.info(client.balance(address, trust: options[:trust]))
91
90
  end
92
91
 
93
92
  desc \
@@ -97,26 +96,32 @@ class Sibit
97
96
  desc: 'List of UTXO that must be skipped while paying'
98
97
  option :yes, type: :boolean, default: false,
99
98
  desc: 'Skip confirmation prompt and send the payment immediately'
100
- option :price, type: :numeric,
101
- desc: 'BTC price in USD (skips API price fetch if provided)'
99
+ option :price, type: :numeric, desc: 'BTC price in USD (skips API price fetch if provided)'
100
+ option :trust, type: :numeric, default: 0,
101
+ desc: 'Minimum number of confirmations required on a UTXO before it can be spent'
102
102
  def pay(amount, fee, sources, target, change)
103
103
  keys = sources.split(',')
104
104
  if amount.upcase == 'MAX'
105
- addrs = keys.map do |k|
106
- kk = Sibit::Key.new(k)
107
- options[:base58] ? kk.base58 : kk.bech32
108
- end
109
- amount = addrs.sum { |a| client.balance(a) }
105
+ addrs =
106
+ keys.map do |k|
107
+ kk = Sibit::Key.new(k)
108
+ options[:base58] ? kk.base58 : kk.bech32
109
+ end
110
+ amount = addrs.sum { |a| client.balance(a, trust: options[:trust]) }
110
111
  end
111
- amount = amount.to_i if amount.is_a?(String) && /^[0-9]+$/.match?(amount)
112
- fee = fee.to_i if /^[0-9]+$/.match?(fee)
112
+ amount = Integer(amount, 10) if amount.is_a?(String) && /^[0-9]+$/.match?(amount)
113
+ fee = Integer(fee, 10) if /^[0-9]+$/.match?(fee)
113
114
  args = [amount, fee, keys, target, change]
114
- kwargs = { skip_utxo: options[:skip_utxo], base58: options[:base58], price: options[:price] }
115
+ kwargs = {
116
+ skip_utxo: options[:skip_utxo], base58: options[:base58],
117
+ price: options[:price], trust: options[:trust]
118
+ }
115
119
  unless options[:yes] || options[:dry]
116
120
  client(dry: true).pay(*args, **kwargs)
117
- print 'Do you confirm this payment? (yes/no): '
118
- answer = $stdin.gets&.strip&.downcase
119
- raise Sibit::Error, 'Payment cancelled by user' unless answer == 'yes'
121
+ print('Do you confirm this payment? (yes/no): ')
122
+ unless $stdin.gets&.strip&.downcase == 'yes'
123
+ raise(Sibit::Error, 'Payment cancelled by user')
124
+ end
120
125
  end
121
126
  log.info(client.pay(*args, **kwargs))
122
127
  end
@@ -129,36 +134,43 @@ class Sibit
129
134
  private
130
135
 
131
136
  def log
132
- @log ||= begin
133
- verbose = !options[:quiet] &&
134
- (options[:verbose] || ENV.fetch('SIBIT_VERBOSE', nil))
135
- verbose ? Loog::VERBOSE : Loog::REGULAR
136
- end
137
+ return @log if @log
138
+ @log =
139
+ if !options[:quiet] && (options[:verbose] || ENV.fetch('SIBIT_VERBOSE', nil))
140
+ Loog::VERBOSE
141
+ else
142
+ Loog::REGULAR
143
+ end
137
144
  end
138
145
 
139
146
  def client(dry: false)
140
147
  proxy = options[:proxy] || ENV.fetch('SIBIT_PROXY', nil)
141
148
  http = proxy ? Sibit::HttpProxy.new(proxy) : Sibit::Http.new
142
149
  log.debug("Using proxy at #{http.host}") if proxy
143
- apis = options[:api].flat_map { |a| a.split(',') }.map(&:downcase).map do |a|
144
- case a
145
- when 'blockchain'
146
- Sibit::Blockchain.new(http: http, log: log)
147
- when 'btc'
148
- Sibit::Btc.new(http: http, log: log)
149
- when 'bitcoinchain'
150
- Sibit::Bitcoinchain.new(http: http, log: log)
151
- when 'blockchair'
152
- Sibit::Blockchair.new(http: http, log: log)
153
- when 'cex'
154
- Sibit::Cex.new(http: http, log: log)
155
- when 'fake'
156
- Sibit::Fake.new
157
- else
158
- raise Sibit::Error, "Unknown API \"#{a}\""
159
- end
160
- end
161
- api = Sibit::FirstOf.new(apis, log: log, verbose: true)
150
+ api = Sibit::FirstOf.new(
151
+ options[:api].flat_map { |a| a.split(',') }.map(&:downcase).map do |a|
152
+ case a
153
+ when 'blockchain'
154
+ Sibit::Blockchain.new(http: http, log: log)
155
+ when 'btc'
156
+ Sibit::Btc.new(http: http, log: log)
157
+ when 'bitcoinchain'
158
+ Sibit::Bitcoinchain.new(http: http, log: log)
159
+ when 'blockchair'
160
+ Sibit::Blockchair.new(http: http, log: log)
161
+ when 'cex'
162
+ Sibit::Cex.new(http: http, log: log)
163
+ when 'cryptoapis'
164
+ Sibit::Cryptoapis.new(ENV.fetch('SIBIT_CRYPTOAPIS_KEY', nil), http: http, log: log)
165
+ when 'sochain'
166
+ Sibit::Sochain.new(http: http, log: log)
167
+ when 'fake'
168
+ Sibit::Fake.new
169
+ else
170
+ raise(Sibit::Error, "Unknown API \"#{a}\"")
171
+ end
172
+ end, log: log, verbose: true
173
+ )
162
174
  api = Sibit::Dry.new(api, log: log) if options[:dry] || dry
163
175
  api = RetriableProxy.for_object(api, on: Sibit::Error) if options[:attempts] > 1
164
176
  Sibit.new(log: log, api: api)
@@ -26,12 +26,12 @@ class Sibit::Bitcoinchain
26
26
 
27
27
  # Current price of BTC in USD (float returned).
28
28
  def price(_currency = 'USD')
29
- raise Sibit::NotSupportedError, 'Bitcoinchain API doesn\'t provide BTC price'
29
+ raise(Sibit::NotSupportedError, 'Bitcoinchain API doesn\'t provide BTC price')
30
30
  end
31
31
 
32
32
  # The height of the block.
33
33
  def height(_hash)
34
- raise Sibit::NotSupportedError, 'Bitcoinchain API doesn\'t provide height()'
34
+ raise(Sibit::NotSupportedError, 'Bitcoinchain API doesn\'t provide height()')
35
35
  end
36
36
 
37
37
  # Get hash of the block after this one.
@@ -39,7 +39,7 @@ class Sibit::Bitcoinchain
39
39
  block = Sibit::Json.new(http: @http, log: @log).get(
40
40
  Iri.new('https://api-r.bitcoinchain.com/v1/block').append(hash)
41
41
  )[0]
42
- raise Sibit::Error, "Block #{hash} not found" if block.nil?
42
+ raise(Sibit::Error, "Block #{hash} not found") if block.nil?
43
43
  nxt = block['next_block']
44
44
  nxt = nil if nxt == '0000000000000000000000000000000000000000000000000000000000000000'
45
45
  @log.debug("The block #{hash} is the latest, there is no next block") if nxt.nil?
@@ -59,14 +59,14 @@ class Sibit::Bitcoinchain
59
59
  return 0
60
60
  end
61
61
  b *= 100_000_000
62
- b = b.to_i
62
+ b = Integer(b)
63
63
  @log.debug("The balance of #{address} is #{b} satoshi (#{json['transactions']} txns)")
64
64
  b
65
65
  end
66
66
 
67
67
  # Get recommended fees, in satoshi per byte.
68
68
  def fees
69
- raise Sibit::NotSupportedError, 'Not implemented yet'
69
+ raise(Sibit::NotSupportedError, 'Not implemented yet')
70
70
  end
71
71
 
72
72
  # Gets the hash of the latest block.
@@ -80,12 +80,12 @@ class Sibit::Bitcoinchain
80
80
 
81
81
  # Fetch all unspent outputs per address.
82
82
  def utxos(_sources)
83
- raise Sibit::NotSupportedError, 'Not implemented yet'
83
+ raise(Sibit::NotSupportedError, 'Not implemented yet')
84
84
  end
85
85
 
86
86
  # Push this transaction (in hex format) to the network.
87
87
  def push(_hex)
88
- raise Sibit::NotSupportedError, 'Not implemented yet'
88
+ raise(Sibit::NotSupportedError, 'Not implemented yet')
89
89
  end
90
90
 
91
91
  # This method should fetch a Blockchain block and return as a hash. Raises
@@ -94,7 +94,7 @@ class Sibit::Bitcoinchain
94
94
  head = Sibit::Json.new(http: @http, log: @log).get(
95
95
  Iri.new('https://api-r.bitcoinchain.com/v1/block').append(hash)
96
96
  )[0]
97
- raise Sibit::Error, "The block #{hash} is not found" if head.nil?
97
+ raise(Sibit::Error, "The block #{hash} is not found") if head.nil?
98
98
  txs = Sibit::Json.new(http: @http, log: @log).get(
99
99
  Iri.new('https://api-r.bitcoinchain.com/v1/block/txs').append(hash)
100
100
  )
@@ -32,7 +32,7 @@ class Sibit::Blockchain
32
32
  h = Sibit::Json.new(http: @http, log: @log).get(
33
33
  Iri.new('https://blockchain.info/ticker')
34
34
  )[currency]
35
- raise Error, "Unrecognized currency #{currency}" if h.nil?
35
+ raise(Error, "Unrecognized currency #{currency}") if h.nil?
36
36
  price = h['15m']
37
37
  @log.debug("The price of BTC is #{price} USD")
38
38
  price
@@ -40,25 +40,14 @@ class Sibit::Blockchain
40
40
 
41
41
  # Get hash of the block after this one.
42
42
  def next_of(_hash)
43
- raise Sibit::NotSupportedError, 'next_of() in Blockchain API is broken, always returns NULL'
44
- # json = Sibit::Json.new(http: @http, log: @log).get(
45
- # Iri.new('https://blockchain.info/rawblock').append(hash)
46
- # )
47
- # nxt = json['next_block'][0]
48
- # if nxt.nil?
49
- # @log.debug("There is no block after #{hash}")
50
- # else
51
- # @log.debug("The next block of #{hash} is #{nxt}")
52
- # end
53
- # nxt
43
+ raise(Sibit::NotSupportedError, 'next_of() in Blockchain API is broken, always returns NULL')
54
44
  end
55
45
 
56
46
  # The height of the block.
57
47
  def height(hash)
58
- json = Sibit::Json.new(http: @http, log: @log).get(
48
+ h = Sibit::Json.new(http: @http, log: @log).get(
59
49
  Iri.new('https://blockchain.info/rawblock').append(hash)
60
- )
61
- h = json['height']
50
+ )['height']
62
51
  @log.debug("The height of #{hash} is #{h}")
63
52
  h
64
53
  end
@@ -111,10 +100,7 @@ class Sibit::Blockchain
111
100
 
112
101
  # Push this transaction (in hex format) to the network.
113
102
  def push(hex)
114
- Sibit::Json.new(http: @http, log: @log).post(
115
- Iri.new('https://blockchain.info/pushtx'),
116
- hex
117
- )
103
+ Sibit::Json.new(http: @http, log: @log).post(Iri.new('https://blockchain.info/pushtx'), hex)
118
104
  end
119
105
 
120
106
  # Gets the hash of the latest block.
@@ -3,7 +3,6 @@
3
3
  # SPDX-FileCopyrightText: Copyright (c) 2019-2026 Yegor Bugayenko
4
4
  # SPDX-License-Identifier: MIT
5
5
 
6
- require 'cgi'
7
6
  require 'iri'
8
7
  require 'json'
9
8
  require 'loog'
@@ -28,67 +27,58 @@ class Sibit::Blockchair
28
27
 
29
28
  # Current price of BTC in USD (float returned).
30
29
  def price(_currency = 'USD')
31
- raise Sibit::NotSupportedError, 'Blockchair doesn\'t provide BTC price'
30
+ raise(Sibit::NotSupportedError, 'Blockchair doesn\'t provide BTC price')
32
31
  end
33
32
 
34
33
  # The height of the block.
35
34
  def height(_hash)
36
- raise Sibit::NotSupportedError, 'Blockchair API doesn\'t provide height()'
35
+ raise(Sibit::NotSupportedError, 'Blockchair API doesn\'t provide height()')
37
36
  end
38
37
 
39
38
  # Get hash of the block after this one.
40
39
  def next_of(_hash)
41
- # They don't provide next block hash
42
- raise Sibit::NotSupportedError, 'Blockchair API doesn\'t provide next_of()'
40
+ raise(Sibit::NotSupportedError, 'Blockchair API doesn\'t provide next_of()')
43
41
  end
44
42
 
45
43
  # Gets the balance of the address, in satoshi.
46
44
  def balance(address)
47
- json = Sibit::Json.new(http: @http, log: @log).get(
48
- Iri.new('https://api.blockchair.com/bitcoin/dashboards/address').append(address).fragment(the_key)
49
- )['data'][address]
45
+ uri = Iri.new('https://api.blockchair.com/bitcoin/dashboards/address').append(address)
46
+ uri = uri.add(key: @key) unless @key.nil?
47
+ json = Sibit::Json.new(http: @http, log: @log).get(uri)['data'][address]
50
48
  if json.nil?
51
49
  @log.debug("Address #{address} not found")
52
50
  return 0
53
51
  end
54
- a = json['address']
55
- b = a['balance']
52
+ b = json['address']['balance']
56
53
  @log.debug("The balance of #{address} is #{b} satoshi")
57
54
  b
58
55
  end
59
56
 
60
57
  # Get recommended fees, in satoshi per byte.
61
58
  def fees
62
- raise Sibit::NotSupportedError, 'Blockchair doesn\'t implement fees()'
59
+ raise(Sibit::NotSupportedError, 'Blockchair doesn\'t implement fees()')
63
60
  end
64
61
 
65
62
  # Gets the hash of the latest block.
66
63
  def latest
67
- raise Sibit::NotSupportedError, 'Blockchair doesn\'t implement latest()'
64
+ raise(Sibit::NotSupportedError, 'Blockchair doesn\'t implement latest()')
68
65
  end
69
66
 
70
67
  # Fetch all unspent outputs per address.
71
68
  def utxos(_sources)
72
- raise Sibit::NotSupportedError, 'Blockchair doesn\'t implement utxos()'
69
+ raise(Sibit::NotSupportedError, 'Blockchair doesn\'t implement utxos()')
73
70
  end
74
71
 
75
72
  # Push this transaction (in hex format) to the network.
76
73
  def push(hex)
77
- Sibit::Json.new(http: @http, log: @log).post(
78
- Iri.new('https://api.blockchair.com/bitcoin/push/transaction').fragment(the_key),
79
- "data=#{hex}"
80
- )
74
+ uri = Iri.new('https://api.blockchair.com/bitcoin/push/transaction')
75
+ uri = uri.add(key: @key) unless @key.nil?
76
+ Sibit::Json.new(http: @http, log: @log).post(uri, "data=#{hex}")
81
77
  @log.debug("Transaction (#{hex.length} in hex) has been pushed to Blockchair")
82
78
  end
83
79
 
84
80
  # This method should fetch a Blockchain block and return as a hash.
85
81
  def block(_hash)
86
- raise Sibit::NotSupportedError, 'Blockchair doesn\'t implement block()'
87
- end
88
-
89
- private
90
-
91
- def the_key
92
- @key.nil? ? '' : "key=#{CGI.escape(@key)}"
82
+ raise(Sibit::NotSupportedError, 'Blockchair doesn\'t implement block()')
93
83
  end
94
84
  end
data/lib/sibit/btc.rb CHANGED
@@ -28,13 +28,12 @@ class Sibit::Btc
28
28
 
29
29
  # Current price of BTC in USD (float returned).
30
30
  def price(_currency = 'USD')
31
- raise Sibit::NotSupportedError, 'Btc.com API doesn\'t provide prices'
31
+ raise(Sibit::NotSupportedError, 'Btc.com API doesn\'t provide prices')
32
32
  end
33
33
 
34
34
  # Gets the balance of the address, in satoshi.
35
35
  def balance(address)
36
- uri = Iri.new('https://chain.api.btc.com/v3/address').append(address).append('unspent')
37
- json = Sibit::Json.new(http: @http, log: @log).get(uri)
36
+ json = Sibit::Json.new(http: @http, log: @log).get(Iri.new('https://chain.api.btc.com/v3/address').append(address).append('unspent'))
38
37
  if json['err_no'] == 1
39
38
  @log.debug("The balance of #{address} is zero (not found)")
40
39
  return 0
@@ -56,11 +55,10 @@ class Sibit::Btc
56
55
 
57
56
  # Get hash of the block after this one, or NIL if it's the last one in Blockchain.
58
57
  def next_of(hash)
59
- head = Sibit::Json.new(http: @http, log: @log).get(
58
+ data = Sibit::Json.new(http: @http, log: @log).get(
60
59
  Iri.new('https://chain.api.btc.com/v3/block').append(hash)
61
- )
62
- data = head['data']
63
- raise Sibit::Error, "The block #{hash} not found" if data.nil?
60
+ )['data']
61
+ raise(Sibit::Error, "The block #{hash} not found") if data.nil?
64
62
  nxt = data['next_block_hash']
65
63
  nxt = nil if nxt == '0000000000000000000000000000000000000000000000000000000000000000'
66
64
  @log.debug("In BTC.com the block #{hash} is the latest, there is no next block") if nxt.nil?
@@ -70,28 +68,25 @@ class Sibit::Btc
70
68
 
71
69
  # The height of the block.
72
70
  def height(hash)
73
- json = Sibit::Json.new(http: @http, log: @log).get(
71
+ data = Sibit::Json.new(http: @http, log: @log).get(
74
72
  Iri.new('https://chain.api.btc.com/v3/block').append(hash)
75
- )
76
- data = json['data']
77
- raise Sibit::Error, "The block #{hash} not found" if data.nil?
73
+ )['data']
74
+ raise(Sibit::Error, "The block #{hash} not found") if data.nil?
78
75
  h = data['height']
79
- raise Sibit::Error, "The block #{hash} found but the height is absent" if h.nil?
76
+ raise(Sibit::Error, "The block #{hash} found but the height is absent") if h.nil?
80
77
  @log.debug("The height of #{hash} is #{h}")
81
78
  h
82
79
  end
83
80
 
84
81
  # Get recommended fees, in satoshi per byte.
85
82
  def fees
86
- raise Sibit::NotSupportedError, 'Btc.com doesn\'t provide recommended fees'
83
+ raise(Sibit::NotSupportedError, 'Btc.com doesn\'t provide recommended fees')
87
84
  end
88
85
 
89
86
  # Gets the hash of the latest block.
90
87
  def latest
91
- uri = Iri.new('https://chain.api.btc.com/v3/block/latest')
92
- json = Sibit::Json.new(http: @http, log: @log).get(uri)
93
- data = json['data']
94
- raise Sibit::Error, 'The latest block not found' if data.nil?
88
+ data = Sibit::Json.new(http: @http, log: @log).get(Iri.new('https://chain.api.btc.com/v3/block/latest'))['data']
89
+ raise(Sibit::Error, 'The latest block not found') if data.nil?
95
90
  hash = data['hash']
96
91
  @log.debug("The hash of the latest block is #{hash}")
97
92
  hash
@@ -99,22 +94,21 @@ class Sibit::Btc
99
94
 
100
95
  # Fetch all unspent outputs per address.
101
96
  def utxos(sources)
102
- txns = []
97
+ results = []
103
98
  sources.each do |hash|
104
- json = Sibit::Json.new(http: @http, log: @log).get(
99
+ data = Sibit::Json.new(http: @http, log: @log).get(
105
100
  Iri.new('https://chain.api.btc.com/v3/address').append(hash).append('unspent')
106
- )
107
- data = json['data']
108
- raise Sibit::Error, "The address #{hash} not found" if data.nil?
109
- txns = data['list']
110
- next if txns.nil?
111
- txns.each do |u|
101
+ )['data']
102
+ raise(Sibit::Error, "The address #{hash} not found") if data.nil?
103
+ list = data['list']
104
+ next if list.nil?
105
+ list.each do |u|
112
106
  outs = Sibit::Json.new(http: @http, log: @log).get(
113
107
  Iri.new('https://chain.api.btc.com/v3/tx').append(u['tx_hash']).add(verbose: 3)
114
108
  )['data']['outputs']
115
109
  outs.each_with_index do |o, i|
116
110
  next unless o['addresses'].include?(hash)
117
- txns << {
111
+ results << {
118
112
  value: o['value'],
119
113
  hash: u['tx_hash'],
120
114
  index: i,
@@ -124,21 +118,20 @@ class Sibit::Btc
124
118
  end
125
119
  end
126
120
  end
127
- txns
121
+ results
128
122
  end
129
123
 
130
124
  # Push this transaction (in hex format) to the network.
131
125
  def push(_hex)
132
- raise Sibit::NotSupportedError, 'Btc.com doesn\'t provide payment gateway'
126
+ raise(Sibit::NotSupportedError, 'Btc.com doesn\'t provide payment gateway')
133
127
  end
134
128
 
135
129
  # This method should fetch a Blockchain block and return as a hash.
136
130
  def block(hash)
137
- head = Sibit::Json.new(http: @http, log: @log).get(
131
+ data = Sibit::Json.new(http: @http, log: @log).get(
138
132
  Iri.new('https://chain.api.btc.com/v3/block').append(hash)
139
- )
140
- data = head['data']
141
- raise Sibit::Error, "The block #{hash} not found" if data.nil?
133
+ )['data']
134
+ raise(Sibit::Error, "The block #{hash} not found") if data.nil?
142
135
  nxt = data['next_block_hash']
143
136
  nxt = nil if nxt == '0000000000000000000000000000000000000000000000000000000000000000'
144
137
  {
@@ -162,20 +155,21 @@ class Sibit::Btc
162
155
  Iri.new('https://chain.api.btc.com/v3/block')
163
156
  .append(hash).append('tx').add(page: page, pagesize: psize)
164
157
  )['data']
165
- raise Sibit::Error, "The block #{hash} has no data at page #{page}" if data.nil?
158
+ raise(Sibit::Error, "The block #{hash} has no data at page #{page}") if data.nil?
166
159
  list = data['list']
167
- raise Sibit::Error, "The list is empty for block #{hash} at page #{page}" if list.nil?
168
- txns = list.map do |t|
169
- {
170
- hash: t['hash'],
171
- outputs: t['outputs'].reject { |o| o['spent_by_tx'] }.map do |o|
172
- {
173
- address: o['addresses'][0],
174
- value: o['value']
175
- }
176
- end
177
- }
178
- end
160
+ raise(Sibit::Error, "The list is empty for block #{hash} at page #{page}") if list.nil?
161
+ txns =
162
+ list.map do |t|
163
+ {
164
+ hash: t['hash'],
165
+ outputs: t['outputs'].reject { |o| o['spent_by_tx'] }.map do |o|
166
+ {
167
+ address: o['addresses'][0],
168
+ value: o['value']
169
+ }
170
+ end
171
+ }
172
+ end
179
173
  all += txns
180
174
  page += 1
181
175
  break if txns.length < psize
data/lib/sibit/cex.rb CHANGED
@@ -25,51 +25,52 @@ class Sibit::Cex
25
25
 
26
26
  # Current price of BTC in USD (float returned).
27
27
  def price(currency = 'USD')
28
- json = Sibit::Json.new(http: @http, log: @log).get(
29
- Iri.new('https://cex.io/api/last_price/BTC').append(currency)
28
+ p = Float(
29
+ Sibit::Json.new(http: @http, log: @log).get(
30
+ Iri.new('https://cex.io/api/last_price/BTC').append(currency)
31
+ )['lprice']
30
32
  )
31
- p = json['lprice'].to_f
32
33
  @log.debug("The price of BTC is #{p} #{currency}")
33
34
  p
34
35
  end
35
36
 
36
37
  # Get hash of the block after this one.
37
38
  def next_of(_hash)
38
- raise Sibit::NotSupportedError, 'Cex.io API doesn\'t provide next_of()'
39
+ raise(Sibit::NotSupportedError, 'Cex.io API doesn\'t provide next_of()')
39
40
  end
40
41
 
41
42
  # Gets the balance of the address, in satoshi.
42
43
  def balance(_address)
43
- raise Sibit::NotSupportedError, 'Cex.io doesn\'t implement balance()'
44
+ raise(Sibit::NotSupportedError, 'Cex.io doesn\'t implement balance()')
44
45
  end
45
46
 
46
47
  # The height of the block.
47
48
  def height(_hash)
48
- raise Sibit::NotSupportedError, 'Cex.io doesn\'t implement height()'
49
+ raise(Sibit::NotSupportedError, 'Cex.io doesn\'t implement height()')
49
50
  end
50
51
 
51
52
  # Get recommended fees, in satoshi per byte.
52
53
  def fees
53
- raise Sibit::NotSupportedError, 'Cex.io doesn\'t implement fees()'
54
+ raise(Sibit::NotSupportedError, 'Cex.io doesn\'t implement fees()')
54
55
  end
55
56
 
56
57
  # Gets the hash of the latest block.
57
58
  def latest
58
- raise Sibit::NotSupportedError, 'Cex.io doesn\'t implement latest()'
59
+ raise(Sibit::NotSupportedError, 'Cex.io doesn\'t implement latest()')
59
60
  end
60
61
 
61
62
  # Fetch all unspent outputs per address.
62
63
  def utxos(_sources)
63
- raise Sibit::NotSupportedError, 'Cex.io doesn\'t implement utxos()'
64
+ raise(Sibit::NotSupportedError, 'Cex.io doesn\'t implement utxos()')
64
65
  end
65
66
 
66
67
  # Push this transaction (in hex format) to the network.
67
68
  def push(_hex)
68
- raise Sibit::NotSupportedError, 'Cex.io doesn\'t implement push()'
69
+ raise(Sibit::NotSupportedError, 'Cex.io doesn\'t implement push()')
69
70
  end
70
71
 
71
72
  # This method should fetch a Blockchain block and return as a hash.
72
73
  def block(_hash)
73
- raise Sibit::NotSupportedError, 'Cex.io doesn\'t implement block()'
74
+ raise(Sibit::NotSupportedError, 'Cex.io doesn\'t implement block()')
74
75
  end
75
76
  end