sibit 0.10.0 → 0.11.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: abe4c1faeac9709e415789d44665ea4085bbb8b32a17c24513f4253dc348ff06
4
- data.tar.gz: eb36a0305ec3ec0a2a402ff2b82daa14e4a4033b9b9634b3e3f187da762316ee
3
+ metadata.gz: 6a410aaa9dcc78c30bde9cf5f0b38f5869a6b6b1bbb1a364b2a1ef603aceba72
4
+ data.tar.gz: cc2b8197a9b230607b376205029300aa68ff55ac409b4c7a1334f46417ea5069
5
5
  SHA512:
6
- metadata.gz: ac511a6fc0ab21f688cd15785d0c6d802ad207d6a30c7229297d8da2e6bfae9304d8c50c69dee4e16589b52d870d50d2584ce08a912aa0c74b9e97e938d27429
7
- data.tar.gz: e9a5dea41cd26bb9af6afa4d764e23ac61793b5c465827e687d467255237792295b3a6a59e5b4d8cdacd1d3382f457df8629b5f9ea9cd99ecc620eedd5090e26
6
+ metadata.gz: 3f28d118de6d6611298ebc0088c1583bf6a1d8ff99e0c46d9d37e19dfb896ae544a783933347ceb73a6335c8c88212ea73fee5cc81a136db854b903d79c68552
7
+ data.tar.gz: d3f3a9ee63757febd44c8b309a6edc605f360e116fdb45d6c07f769883ba05a496dd624f424fb44fb2deb13fe71593ed3d9d334ab5dcee17ba798b1b4750556c
data/.rultor.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  assets:
2
- rubygems.yml: zerocracy/home#assets/rubygems.yml
3
- s3cfg: zerocracy/home#assets/s3cfg
2
+ rubygems.yml: yegor256/home#assets/rubygems.yml
3
+ s3cfg: yegor256/home#assets/s3cfg
4
4
  install: |
5
5
  export GEM_HOME=~/.ruby
6
6
  export GEM_PATH=$GEM_HOME:$GEM_PATH
data/README.md CHANGED
@@ -15,7 +15,9 @@
15
15
  [![Hits-of-Code](https://hitsofcode.com/github/yegor256/sibit)](https://hitsofcode.com/view/github/yegor256/sibit)
16
16
 
17
17
  To understand how Bitcoin protocol works, I recommend you watching
18
- this [short video](https://www.youtube.com/watch?v=IV9pRBq5A4g).
18
+ this [short video](https://www.youtube.com/watch?v=IV9pRBq5A4g) and
19
+ then reading this blog post of mine:
20
+ [_Sibit Demonstrates How Bitcoin Works_](https://www.yegor256.com/2019/05/07/sibit-bitcoin-command-line-client.html).
19
21
 
20
22
  This is a simple Bitcoin client, to use from the command line
21
23
  or from your Ruby app. You don't need to run any Bitcoin software,
data/bin/sibit CHANGED
@@ -32,6 +32,7 @@ begin
32
32
  o.banner = "Usage (#{Sibit::VERSION}): sibit [options] command [args]
33
33
  Commands are:
34
34
  price: Get current price of BTC in USD
35
+ fees: Get currently recommended transaction fees
35
36
  latest: Get hash of the latest block
36
37
  generate: Generate a new private key
37
38
  create: Create a public Bitcoin address from the key
@@ -61,6 +62,14 @@ Options are:"
61
62
  case opts.arguments[0]
62
63
  when 'price'
63
64
  puts sibit.price
65
+ when 'fees'
66
+ fees = sibit.fees
67
+ text = %i[S M L XL].map do |m|
68
+ sat = fees[m] * 250
69
+ usd = sat * sibit.price / 100_000_000
70
+ "#{m}: #{sat}sat / $#{format('%.02f', usd)}"
71
+ end.join("\n")
72
+ puts text
64
73
  when 'latest'
65
74
  puts sibit.latest
66
75
  when 'generate'
data/features/cli.feature CHANGED
@@ -26,6 +26,10 @@ Feature: Command Line Processing
26
26
  When I run bin/sibit with "balance 1MZT1fa6y8H9UmbZV6HqKF4UY41o9MGT5f --verbose"
27
27
  Then Exit code is zero
28
28
 
29
+ Scenario: Bitcoin fees can be printed
30
+ When I run bin/sibit with "fees --verbose"
31
+ Then Exit code is zero
32
+
29
33
  Scenario: Bitcoin transaction can be sent
30
34
  When I run bin/sibit with "--verbose --dry pay 100000 S 1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi:fd2333686f49d8647e1ce8d5ef39c304520b08f3c756b67068b30a3db217dcb2 1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi 1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi"
31
35
  Then Exit code is zero
data/lib/sibit/version.rb CHANGED
@@ -26,5 +26,5 @@
26
26
  # License:: MIT
27
27
  class Sibit
28
28
  # Current version of the library.
29
- VERSION = '0.10.0'
29
+ VERSION = '0.11.0'
30
30
  end
data/lib/sibit.rb CHANGED
@@ -123,6 +123,24 @@ class Sibit
123
123
  json['final_balance']
124
124
  end
125
125
 
126
+ # Get recommended fees, in satoshi per byte. The method returns
127
+ # a hash: { S: 12, M: 45, L: 100, XL: 200 }
128
+ def fees
129
+ json = JSON.parse(
130
+ Net::HTTP.get(
131
+ URI('https://bitcoinfees.earn.com/api/v1/fees/recommended')
132
+ )
133
+ )
134
+ info("Current recommended Bitcoin fees: \
135
+ #{json['hourFee']}/#{json['halfHourFee']}/#{json['fastestFee']} sat/byte")
136
+ {
137
+ S: json['hourFee'] / 3,
138
+ M: json['hourFee'],
139
+ L: json['halfHourFee'],
140
+ XL: json['fastestFee']
141
+ }
142
+ end
143
+
126
144
  # Sends a payment and returns the transaction hash.
127
145
  #
128
146
  # If the payment can't be signed (the key is wrong, for example) or the
@@ -181,7 +199,6 @@ class Sibit
181
199
  #{tx.inputs.map { |i| " in: #{i.prev_out.bth}:#{i.prev_out_index}" }.join("\n ")}
182
200
  #{tx.out.count} output#{tx.out.count > 1 ? 's' : ''}:
183
201
  #{tx.outputs.map { |o| "out: #{o.script.bth} / #{num(o.value, p)}" }.join("\n ")}
184
- Fee required: #{num(f, p)}
185
202
  Min tx fee: #{num(Bitcoin.network[:min_tx_fee], p)}
186
203
  Fee left: #{num(left, p)}
187
204
  Tx size: #{size} bytes
@@ -242,11 +259,9 @@ class Sibit
242
259
  def mfee(fee, size)
243
260
  return fee.to_i if fee.is_a?(Integer)
244
261
  raise Error, 'Fee should either be a String or Integer' unless fee.is_a?(String)
245
- return 10 * size if fee == 'S'
246
- return 50 * size if fee == 'M'
247
- return 100 * size if fee == 'L'
248
- return 250 * size if fee == 'XL'
249
- raise Error, "Can't understand the fee: #{fee.inspect}"
262
+ sat = fees[fee.to_sym]
263
+ raise Error, "Can't understand the fee: #{fee.inspect}" if sat.nil?
264
+ sat * size
250
265
  end
251
266
 
252
267
  # Make key from private key string in Hash160.
data/test/test_sibit.rb CHANGED
@@ -30,10 +30,22 @@ require_relative '../lib/sibit'
30
30
  # Copyright:: Copyright (c) 2019 Yegor Bugayenko
31
31
  # License:: MIT
32
32
  class TestSibit < Minitest::Test
33
+ def test_loads_fees
34
+ stub_request(
35
+ :get, 'https://bitcoinfees.earn.com/api/v1/fees/recommended'
36
+ ).to_return(body: '{"fastestFee":300,"halfHourFee":200,"hourFee":180}')
37
+ sibit = Sibit.new
38
+ fees = sibit.fees
39
+ assert_equal(60, fees[:S])
40
+ assert_equal(180, fees[:M])
41
+ assert_equal(200, fees[:L])
42
+ assert_equal(300, fees[:XL])
43
+ end
44
+
33
45
  def test_fetch_current_price
34
46
  stub_request(
35
47
  :get, 'https://blockchain.info/ticker'
36
- ).to_return(status: 200, body: '{"USD" : {"15m" : 5160.04}}')
48
+ ).to_return(body: '{"USD" : {"15m" : 5160.04}}')
37
49
  sibit = Sibit.new
38
50
  price = sibit.price
39
51
  assert(!price.nil?)
@@ -62,7 +74,7 @@ class TestSibit < Minitest::Test
62
74
  stub_request(
63
75
  :get,
64
76
  'https://blockchain.info/rawaddr/1MZT1fa6y8H9UmbZV6HqKF4UY41o9MGT5f'
65
- ).to_return(status: 200, body: '{"final_balance": 100}')
77
+ ).to_return(body: '{"final_balance": 100}')
66
78
  sibit = Sibit.new
67
79
  balance = sibit.balance('1MZT1fa6y8H9UmbZV6HqKF4UY41o9MGT5f')
68
80
  assert(balance.is_a?(Integer))
@@ -71,7 +83,6 @@ class TestSibit < Minitest::Test
71
83
 
72
84
  def test_get_latest_block
73
85
  stub_request(:get, 'https://blockchain.info/latestblock').to_return(
74
- status: 200,
75
86
  body: '{"hash": "0000000000000538200a48202ca6340e983646ca088c7618ae82d68e0c76ef5a"}'
76
87
  )
77
88
  sibit = Sibit.new
@@ -80,9 +91,12 @@ class TestSibit < Minitest::Test
80
91
  end
81
92
 
82
93
  def test_send_payment
94
+ stub_request(
95
+ :get, 'https://bitcoinfees.earn.com/api/v1/fees/recommended'
96
+ ).to_return(body: '{"fastestFee":300,"halfHourFee":200,"hourFee":180}')
83
97
  stub_request(
84
98
  :get, 'https://blockchain.info/ticker'
85
- ).to_return(status: 200, body: '{"USD" : {"15m" : 5160.04}}')
99
+ ).to_return(body: '{"USD" : {"15m" : 5160.04}}')
86
100
  json = {
87
101
  unspent_outputs: [
88
102
  {
@@ -97,7 +111,7 @@ class TestSibit < Minitest::Test
97
111
  stub_request(
98
112
  :get,
99
113
  'https://blockchain.info/unspent?active=1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi&limit=1000'
100
- ).to_return(status: 200, body: JSON.pretty_generate(json))
114
+ ).to_return(body: JSON.pretty_generate(json))
101
115
  stub_request(:post, 'https://blockchain.info/pushtx').to_return(status: 200)
102
116
  sibit = Sibit.new
103
117
  target = sibit.create(sibit.generate)
@@ -117,14 +131,14 @@ class TestSibit < Minitest::Test
117
131
  def test_fail_if_not_enough_funds
118
132
  stub_request(
119
133
  :get, 'https://blockchain.info/ticker'
120
- ).to_return(status: 200, body: '{"USD" : {"15m" : 5160.04}}')
134
+ ).to_return(body: '{"USD" : {"15m" : 5160.04}}')
121
135
  json = {
122
136
  unspent_outputs: []
123
137
  }
124
138
  stub_request(
125
139
  :get,
126
140
  'https://blockchain.info/unspent?active=1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi&limit=1000'
127
- ).to_return(status: 200, body: JSON.pretty_generate(json))
141
+ ).to_return(body: JSON.pretty_generate(json))
128
142
  sibit = Sibit.new
129
143
  target = sibit.create(sibit.generate)
130
144
  change = sibit.create(sibit.generate)
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.10.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-27 00:00:00.000000000 Z
11
+ date: 2019-05-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backtrace