sibit 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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