sibit 0.8.0 → 0.9.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: fd8d72ab658b0424c135882a0787001395a69db720bc8283cf6b2155729c5a96
4
- data.tar.gz: 37c2fab8a0bd840620e57c2a38ac831dcab13232f6274299c11477675e41734a
3
+ metadata.gz: 420c1f144c205270b6147f9f7841dc623f406da2229515491a6e62394b666a7a
4
+ data.tar.gz: 4038585222353146bcfb9095edea86cec8f16b4ec8bf2561c134e5e09df8c3a1
5
5
  SHA512:
6
- metadata.gz: 9e70e784fdf68578e1919ce2989cdfb53c8fc50289e41b57d5df0429fdb28d6679eaf0e558f34112517019f372b16f0c2212b45b7c5104ad3bafd704cf3516b8
7
- data.tar.gz: 11123bef8e29dde1689907f4536325f807510e9dd3dd10002afea284925176b37543060083ea17a8934e72d43a88cb2fc51c86697938d565bcfceb0d1487b937
6
+ metadata.gz: 2327d071a6deecf933409c9a56869889adcbece633fba1072e269130e247ea24a841e8f4b6698eaa91b0b2c6c11c54a654c10fb1049e52245270bc3449890b35
7
+ data.tar.gz: 590ff2cd99e4f060043a5d067b38013d5bf0fd0dfb09c6def61559a993d4b8c175b94122f4680b1db99e313ea33d34df6c7e8d54e7be7ad2fed57e3ea6f8c1a9
data/.rubocop.yml CHANGED
@@ -18,7 +18,7 @@ Layout/MultilineMethodCallIndentation:
18
18
  Metrics/ParameterLists:
19
19
  Max: 6
20
20
  Metrics/ClassLength:
21
- Max: 150
21
+ Max: 200
22
22
  Metrics/AbcSize:
23
23
  Enabled: false
24
24
  Metrics/BlockLength:
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- <img src="https://en.bitcoin.it/w/images/en/2/29/BC_Logo_.png" width="64px"/>
1
+ <img src="/logo.png" width="64px"/>
2
2
 
3
3
  [![EO principles respected here](http://www.elegantobjects.org/badge.svg)](http://www.elegantobjects.org)
4
4
  [![Managed by Zerocracy](https://www.0crat.com/badge/C3RFVLU72.svg)](https://www.0crat.com/p/C3RFVLU72)
@@ -26,6 +26,9 @@ something more complex, I would recommend using
26
26
  [bitcoin-ruby](https://github.com/lian/bitcoin-ruby) for Ruby and
27
27
  [Electrum](https://electrum.org/) as a GUI client.
28
28
 
29
+ You may want to discuss this tool at [Bitcointalk](https://bitcointalk.org/index.php?topic=5130324)
30
+ and give the thread a few merits.
31
+
29
32
  This is a Ruby gem, install it first (if doesn't work, there are
30
33
  some hints at the bottom of this page):
31
34
 
data/Rakefile CHANGED
@@ -36,7 +36,6 @@ end
36
36
  task default: %i[clean test features rubocop copyright]
37
37
 
38
38
  require 'rake/testtask'
39
- desc 'Run all unit tests'
40
39
  Rake::TestTask.new(:test) do |test|
41
40
  Rake::Cleaner.cleanup_files(['coverage'])
42
41
  test.libs << 'lib' << 'test'
@@ -45,7 +44,6 @@ Rake::TestTask.new(:test) do |test|
45
44
  end
46
45
 
47
46
  require 'rdoc/task'
48
- desc 'Build RDoc documentation'
49
47
  Rake::RDocTask.new do |rdoc|
50
48
  rdoc.rdoc_dir = 'rdoc'
51
49
  rdoc.title = "#{name} #{version}"
@@ -54,7 +52,6 @@ Rake::RDocTask.new do |rdoc|
54
52
  end
55
53
 
56
54
  require 'rubocop/rake_task'
57
- desc 'Run RuboCop on all directories'
58
55
  RuboCop::RakeTask.new(:rubocop) do |task|
59
56
  task.fail_on_error = true
60
57
  task.requires << 'rubocop-rspec'
data/appveyor.yml CHANGED
@@ -15,7 +15,7 @@ build_script:
15
15
  - bundle update
16
16
  - bundle install
17
17
  test_script:
18
- - rake
18
+ - bundle exec rake
19
19
  cache:
20
20
  - C:\Ruby200\bin -> sibit.gemspec
21
21
  - C:\Ruby200\lib\ruby\gems\2.0.0 -> sibit.gemspec
data/bin/sibit CHANGED
@@ -39,6 +39,7 @@ Commands are:
39
39
  pay: Send a new Bitcoin transaction
40
40
  Options are:"
41
41
  o.string '--proxy', 'HTTPS proxy for all requests, e.g. "localhost:3128"'
42
+ o.bool '--dry', 'Don\'t send a real payment, run in a read-only mode'
42
43
  o.bool '--help', 'Read this: https://github.com/yegor256/sibit' do
43
44
  puts o
44
45
  exit
@@ -51,7 +52,8 @@ Options are:"
51
52
  raise 'Try --help' if opts.arguments.empty?
52
53
  sibit = Sibit.new(
53
54
  log: opts[:verbose] ? STDOUT : nil,
54
- http: opts[:proxy] ? Sibit.proxy_http(opts[:proxy]) : Sibit.default_http
55
+ http: opts[:proxy] ? Sibit.proxy_http(opts[:proxy]) : Sibit.default_http,
56
+ dry: opts[:dry]
55
57
  )
56
58
  case opts.arguments[0]
57
59
  when 'price'
data/features/cli.feature CHANGED
@@ -25,3 +25,7 @@ Feature: Command Line Processing
25
25
  Scenario: Bitcoin balance can be checked
26
26
  When I run bin/sibit with "balance 1MZT1fa6y8H9UmbZV6HqKF4UY41o9MGT5f --verbose"
27
27
  Then Exit code is zero
28
+
29
+ Scenario: Bitcoin transaction can be sent
30
+ When I run bin/sibit with "--verbose --dry pay 100000 S 1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi:fd2333686f49d8647e1ce8d5ef39c304520b08f3c756b67068b30a3db217dcb2 1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi 1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi"
31
+ 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.8.0'
29
+ VERSION = '0.9.0'
30
30
  end
data/lib/sibit.rb CHANGED
@@ -25,6 +25,7 @@ require 'uri'
25
25
  require 'bitcoin'
26
26
  require 'json'
27
27
  require 'cgi'
28
+ require_relative 'sibit/version'
28
29
 
29
30
  # Sibit main class.
30
31
  #
@@ -90,9 +91,10 @@ class Sibit
90
91
  # provide anything, the console will be used. The object you provide
91
92
  # has to respond to the method +info+ or +puts+ in order to receive logging
92
93
  # messages.
93
- def initialize(log: STDOUT, http: Sibit.default_http)
94
+ def initialize(log: STDOUT, http: Sibit.default_http, dry: false)
94
95
  @log = log
95
96
  @http = http
97
+ @dry = dry
96
98
  end
97
99
 
98
100
  # Current price of 1 BTC.
@@ -138,6 +140,7 @@ class Sibit
138
140
  # +target+: the target address to send to
139
141
  # +change+: the address where the change has to be sent to
140
142
  def pay(amount, fee, sources, target, change)
143
+ p = price
141
144
  satoshi = satoshi(amount)
142
145
  builder = Bitcoin::Builder::TxBuilder.new
143
146
  unspent = 0
@@ -157,11 +160,11 @@ class Sibit
157
160
  i.signature_key(key(sources[address]))
158
161
  end
159
162
  size += 180
160
- info(" #{num(utxo['value'])}/#{utxo['confirmations']} at #{utxo['tx_hash_big_endian']}")
163
+ info(" #{num(utxo['value'], p)}/#{utxo['confirmations']} at #{utxo['tx_hash_big_endian']}")
161
164
  break if unspent > satoshi
162
165
  end
163
166
  if unspent < satoshi
164
- raise Error, "Not enough funds to send #{num(amount)}, only #{num(unspent)} left"
167
+ raise Error, "Not enough funds to send #{num(satoshi, p)}, only #{num(unspent, p)} left"
165
168
  end
166
169
  builder.output(satoshi, target)
167
170
  f = mfee(fee, size)
@@ -171,20 +174,21 @@ class Sibit
171
174
  extra_fee: f - Bitcoin.network[:min_tx_fee],
172
175
  change_address: change
173
176
  )
177
+ left = unspent - tx.outputs.map(&:value).inject(&:+)
174
178
  info("A new Bitcoin transaction #{tx.hash} prepared:
175
179
  #{tx.in.count} input#{tx.in.count > 1 ? 's' : ''}:
176
180
  #{tx.inputs.map { |i| " in: #{i.prev_out.bth}:#{i.prev_out_index}" }.join("\n ")}
177
181
  #{tx.out.count} output#{tx.out.count > 1 ? 's' : ''}:
178
- #{tx.outputs.map { |o| "out: #{o.script.bth} / #{num(o.value)}" }.join("\n ")}
179
- Fee required: #{num(f)} satoshi
180
- Min tx fee: #{num(Bitcoin.network[:min_tx_fee])} satoshi
181
- Fee left: #{num(unspent - tx.outputs.map(&:value).inject(&:+))} satoshi
182
- Tx size: #{num(size)} bytes
183
- Unspent: #{num(unspent)} satoshi
184
- Amount: #{num(satoshi)} satoshi
182
+ #{tx.outputs.map { |o| "out: #{o.script.bth} / #{num(o.value, p)}" }.join("\n ")}
183
+ Fee required: #{num(f, p)}
184
+ Min tx fee: #{num(Bitcoin.network[:min_tx_fee], p)}
185
+ Fee left: #{num(left, p)}
186
+ Tx size: #{size} bytes
187
+ Unspent: #{num(unspent, p)}
188
+ Amount: #{num(satoshi, p)}
185
189
  Target address: #{target}
186
190
  Change address is #{change}")
187
- post_tx(tx.to_payload.bth)
191
+ post_tx(tx.to_payload.bth) unless @dry
188
192
  tx.hash
189
193
  end
190
194
 
@@ -211,8 +215,12 @@ class Sibit
211
215
 
212
216
  private
213
217
 
214
- def num(int)
215
- int.to_s.gsub(/\d(?=(...)+$)/, '\0,')
218
+ def num(satoshi, usd)
219
+ format(
220
+ '%<satoshi>ss/$%<dollars>0.2f',
221
+ satoshi: satoshi.to_s.gsub(/\d(?=(...)+$)/, '\0,'),
222
+ dollars: satoshi * usd / 100_000_000
223
+ )
216
224
  end
217
225
 
218
226
  # Convert text to amount.
data/logo.png ADDED
Binary file
data/test/test_sibit.rb CHANGED
@@ -80,6 +80,9 @@ class TestSibit < Minitest::Test
80
80
  end
81
81
 
82
82
  def test_send_payment
83
+ stub_request(
84
+ :get, 'https://blockchain.info/ticker'
85
+ ).to_return(status: 200, body: '{"USD" : {"15m" : 5160.04}}')
83
86
  json = {
84
87
  unspent_outputs: [
85
88
  {
@@ -110,4 +113,44 @@ class TestSibit < Minitest::Test
110
113
  assert(!tx.nil?)
111
114
  assert(tx.length > 30, tx)
112
115
  end
116
+
117
+ def test_fail_if_not_enough_funds
118
+ stub_request(
119
+ :get, 'https://blockchain.info/ticker'
120
+ ).to_return(status: 200, body: '{"USD" : {"15m" : 5160.04}}')
121
+ json = {
122
+ unspent_outputs: []
123
+ }
124
+ stub_request(
125
+ :get,
126
+ 'https://blockchain.info/unspent?active=1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi&limit=1000'
127
+ ).to_return(status: 200, body: JSON.pretty_generate(json))
128
+ sibit = Sibit.new
129
+ target = sibit.create(sibit.generate)
130
+ change = sibit.create(sibit.generate)
131
+ assert_raises Sibit::Error do
132
+ sibit.pay(
133
+ '0.0001BTC', 'XL',
134
+ {
135
+ '1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi' =>
136
+ 'fd2333686f49d8647e1ce8d5ef39c304520b08f3c756b67068b30a3db217dcb2'
137
+ },
138
+ target, change
139
+ )
140
+ end
141
+ end
142
+
143
+ def test_fake_object_works
144
+ sibit = Sibit::Fake.new
145
+ assert_equal(4_000, sibit.price)
146
+ assert_equal('fd2333686f49d8647e1ce8d5ef39c304520b08f3c756b67068b30a3db217dcb2', sibit.generate)
147
+ assert_equal('1JvCsJtLmCxEk7ddZFnVkGXpr9uhxZPmJi', sibit.create(''))
148
+ assert_equal(100_000_000, sibit.balance(''))
149
+ assert_equal(
150
+ '9dfe55a30b5ee732005158c589179a398117117a68d21531fb6c78b85b544c54',
151
+ sibit.pay(0, 'M', {}, '', '')
152
+ )
153
+ assert_equal('00000000000000000008df8a6e1b61d1136803ac9791b8725235c9f780b4ed71', sibit.latest)
154
+ assert_equal({}, sibit.get_json('/'))
155
+ end
113
156
  end
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.8.0
4
+ version: 0.9.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-03 00:00:00.000000000 Z
11
+ date: 2019-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backtrace
@@ -240,6 +240,7 @@ files:
240
240
  - features/support/env.rb
241
241
  - lib/sibit.rb
242
242
  - lib/sibit/version.rb
243
+ - logo.png
243
244
  - sibit.gemspec
244
245
  - test/test__helper.rb
245
246
  - test/test_sibit.rb