sibit 0.30.7 → 0.31.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 +4 -4
- data/Gemfile.lock +6 -7
- data/Rakefile +1 -1
- data/bin/sibit +107 -105
- data/features/cli.feature +6 -1
- data/features/step_definitions/steps.rb +0 -5
- data/lib/sibit/version.rb +1 -1
- data/sibit.gemspec +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d7d8d002bcff6bcb41fc9dcd1a4a4ebd2d622460a23777e36da39406e4de8684
|
|
4
|
+
data.tar.gz: 91d217414aec0258cd458dbbae530738e2efc211f3d259888413a0532554d203
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '099247f1d77cdb32d500e5798f7480b03ce48279d198c059e410f35ca9bb1fc345ee5b6f8342aa8b4ac9982079c9ec0848a26ae8201bb35af04f9bed67f9d2bc'
|
|
7
|
+
data.tar.gz: 16c9a7c880dc2bb401383bb5e0593fdfcafcdc7ebd77cfe19a7bc0509be14f8e7946b0a663bcd3e71826e60d93296533104a1d094bd25fb0955a1bdc181f6442
|
data/Gemfile.lock
CHANGED
|
@@ -11,7 +11,7 @@ PATH
|
|
|
11
11
|
loog (~> 0.6)
|
|
12
12
|
openssl (~> 3.0)
|
|
13
13
|
retriable_proxy (~> 1.0)
|
|
14
|
-
|
|
14
|
+
thor (~> 1.3)
|
|
15
15
|
|
|
16
16
|
GEM
|
|
17
17
|
remote: https://rubygems.org/
|
|
@@ -63,7 +63,7 @@ GEM
|
|
|
63
63
|
decoor (0.1.0)
|
|
64
64
|
diff-lcs (1.6.2)
|
|
65
65
|
docile (1.4.1)
|
|
66
|
-
donce (0.
|
|
66
|
+
donce (0.4.0)
|
|
67
67
|
backtrace (~> 0.3)
|
|
68
68
|
os (~> 1.1)
|
|
69
69
|
qbash (~> 0.3)
|
|
@@ -75,7 +75,7 @@ GEM
|
|
|
75
75
|
ffi (1.17.3-arm64-darwin)
|
|
76
76
|
ffi (1.17.3-x86_64-linux-gnu)
|
|
77
77
|
hashdiff (1.2.1)
|
|
78
|
-
iri (0.11.
|
|
78
|
+
iri (0.11.6)
|
|
79
79
|
json (2.18.0)
|
|
80
80
|
language_server-protocol (3.17.0.5)
|
|
81
81
|
lint_roller (1.1.0)
|
|
@@ -106,8 +106,8 @@ GEM
|
|
|
106
106
|
psych (5.3.1)
|
|
107
107
|
date
|
|
108
108
|
stringio
|
|
109
|
-
public_suffix (7.0.
|
|
110
|
-
qbash (0.
|
|
109
|
+
public_suffix (7.0.2)
|
|
110
|
+
qbash (0.5.0)
|
|
111
111
|
backtrace (> 0)
|
|
112
112
|
elapsed (> 0)
|
|
113
113
|
loog (> 0)
|
|
@@ -163,13 +163,12 @@ GEM
|
|
|
163
163
|
simplecov (~> 0.19)
|
|
164
164
|
simplecov-html (0.13.2)
|
|
165
165
|
simplecov_json_formatter (0.1.4)
|
|
166
|
-
slop (4.10.1)
|
|
167
166
|
stringio (3.2.0)
|
|
168
167
|
sys-uname (1.4.1)
|
|
169
168
|
ffi (~> 1.1)
|
|
170
169
|
memoist3 (~> 1.0.0)
|
|
171
170
|
tago (0.6.0)
|
|
172
|
-
thor (1.
|
|
171
|
+
thor (1.5.0)
|
|
173
172
|
tsort (0.2.0)
|
|
174
173
|
unicode-display_width (3.2.0)
|
|
175
174
|
unicode-emoji (~> 4.1)
|
data/Rakefile
CHANGED
|
@@ -33,7 +33,7 @@ end
|
|
|
33
33
|
desc 'Run them via Ruby, one by one'
|
|
34
34
|
task :picks do
|
|
35
35
|
next if OS.windows?
|
|
36
|
-
%w[
|
|
36
|
+
%w[lib].each do |d|
|
|
37
37
|
Dir["#{d}/**/*.rb"].each do |f|
|
|
38
38
|
qbash("bundle exec ruby #{Shellwords.escape(f)}", log: $stdout, env: { 'PICKS' => 'yes' })
|
|
39
39
|
end
|
data/bin/sibit
CHANGED
|
@@ -10,7 +10,7 @@ require 'backtrace'
|
|
|
10
10
|
require 'ellipsized'
|
|
11
11
|
require 'loog'
|
|
12
12
|
require 'retriable_proxy'
|
|
13
|
-
require '
|
|
13
|
+
require 'thor'
|
|
14
14
|
require_relative '../lib/sibit'
|
|
15
15
|
require_relative '../lib/sibit/http'
|
|
16
16
|
require_relative '../lib/sibit/httpproxy'
|
|
@@ -24,79 +24,35 @@ require_relative '../lib/sibit/fake'
|
|
|
24
24
|
require_relative '../lib/sibit/firstof'
|
|
25
25
|
require_relative '../lib/sibit/version'
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
Options are:"
|
|
42
|
-
o.string '--proxy', 'HTTPS proxy for all requests, e.g. "localhost:3128"'
|
|
43
|
-
o.integer(
|
|
44
|
-
'--attempts',
|
|
45
|
-
'How many times should we try before failing',
|
|
46
|
-
default: 1
|
|
47
|
-
)
|
|
48
|
-
o.bool '--dry', 'Don\'t send a real payment, run in a read-only mode'
|
|
49
|
-
o.bool '--help', 'Read this: https://github.com/yegor256/sibit' do
|
|
50
|
-
log.info(o)
|
|
51
|
-
exit
|
|
52
|
-
end
|
|
53
|
-
o.bool '--verbose', 'Print all possible debug messages'
|
|
54
|
-
o.array(
|
|
55
|
-
'--api',
|
|
56
|
-
'Ordered List of APIs to use, e.g. "eblockchain,btc,bitcoinchain"',
|
|
57
|
-
default: %w[blockchain btc bitcoinchain blockchair cex]
|
|
58
|
-
)
|
|
59
|
-
o.array(
|
|
60
|
-
'--skip-utxo',
|
|
61
|
-
'List of UTXTO that must be skipped while paying',
|
|
62
|
-
default: []
|
|
63
|
-
)
|
|
64
|
-
end
|
|
65
|
-
rescue Slop::Error => e
|
|
66
|
-
raise e.message
|
|
27
|
+
# Command-line interface for Sibit.
|
|
28
|
+
# Provides commands to interact with the Bitcoin network.
|
|
29
|
+
class Bin < Thor
|
|
30
|
+
class_option :proxy, type: :string, desc: 'HTTPS proxy for all requests, e.g. "localhost:3128"'
|
|
31
|
+
class_option :attempts, type: :numeric, default: 1,
|
|
32
|
+
desc: 'How many times should we try before failing'
|
|
33
|
+
class_option :dry, type: :boolean, default: false,
|
|
34
|
+
desc: "Don't send a real payment, run in a read-only mode"
|
|
35
|
+
class_option :verbose, type: :boolean, default: false, desc: 'Print all possible debug messages'
|
|
36
|
+
class_option :api, type: :array, default: %w[blockchain btc bitcoinchain blockchair cex],
|
|
37
|
+
desc: 'Ordered List of APIs to use, e.g. "blockchain,btc,bitcoinchain"'
|
|
38
|
+
|
|
39
|
+
def self.exit_on_failure?
|
|
40
|
+
true
|
|
67
41
|
end
|
|
68
42
|
|
|
69
|
-
|
|
43
|
+
def self.handle_argument_error(command, error, args, _arity)
|
|
44
|
+
raise error unless args.include?('--help') || args.include?('-h')
|
|
45
|
+
new.help(command.name)
|
|
46
|
+
end
|
|
70
47
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
apis = opts[:api].map(&:downcase).map do |a|
|
|
75
|
-
case a
|
|
76
|
-
when 'blockchain'
|
|
77
|
-
Sibit::Blockchain.new(http: http, log: log)
|
|
78
|
-
when 'btc'
|
|
79
|
-
Sibit::Btc.new(http: http, log: log)
|
|
80
|
-
when 'bitcoinchain'
|
|
81
|
-
Sibit::Bitcoinchain.new(http: http, log: log)
|
|
82
|
-
when 'blockchair'
|
|
83
|
-
Sibit::Blockchair.new(http: http, log: log)
|
|
84
|
-
when 'cex'
|
|
85
|
-
Sibit::Cex.new(http: http, log: log)
|
|
86
|
-
when 'fake'
|
|
87
|
-
Sibit::Fake.new
|
|
88
|
-
else
|
|
89
|
-
raise Sibit::Error, "Unknown API \"#{a}\""
|
|
90
|
-
end
|
|
48
|
+
desc 'price', 'Get current price of BTC in USD'
|
|
49
|
+
def price
|
|
50
|
+
log.info(client.price)
|
|
91
51
|
end
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
case opts.arguments[0]
|
|
97
|
-
when 'price'
|
|
98
|
-
log.info(sibit.price)
|
|
99
|
-
when 'fees'
|
|
52
|
+
|
|
53
|
+
desc 'fees', 'Get currently recommended transaction fees'
|
|
54
|
+
def fees
|
|
55
|
+
sibit = client
|
|
100
56
|
fees = sibit.fees
|
|
101
57
|
text = %i[S M L XL].map do |m|
|
|
102
58
|
sat = fees[m] * 250
|
|
@@ -104,45 +60,91 @@ begin
|
|
|
104
60
|
"#{m}: #{sat}sat / $#{format('%<usd>.02f', usd: usd)}"
|
|
105
61
|
end.join("\n")
|
|
106
62
|
log.info(text)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
desc 'latest', 'Get hash of the latest block'
|
|
66
|
+
def latest
|
|
67
|
+
log.info(client.latest)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
desc 'generate', 'Generate a new private key'
|
|
71
|
+
def generate
|
|
72
|
+
log.info(client.generate)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
desc 'create KEY', 'Create a public Bitcoin address from the private key'
|
|
76
|
+
def create(key)
|
|
77
|
+
log.debug("Private key provided: #{key.ellipsized(8).inspect}")
|
|
78
|
+
log.info(client.create(key))
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
desc 'balance ADDRESS', 'Check the balance of the Bitcoin address'
|
|
82
|
+
def balance(address)
|
|
83
|
+
log.info(client.balance(address))
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
desc 'pay AMOUNT FEE SOURCES TARGET CHANGE', 'Send a new Bitcoin transaction'
|
|
87
|
+
option :skip_utxo, type: :array, default: [],
|
|
88
|
+
desc: 'List of UTXO that must be skipped while paying'
|
|
89
|
+
option :yes, type: :boolean, default: false,
|
|
90
|
+
desc: 'Skip confirmation prompt and send the payment immediately'
|
|
91
|
+
def pay(amount, fee, sources, target, change)
|
|
123
92
|
amount = amount.to_i if /^[0-9]+$/.match?(amount)
|
|
124
|
-
fee = opts.arguments[2]
|
|
125
|
-
raise 'Miners fee argument is required' if fee.nil?
|
|
126
93
|
fee = fee.to_i if /^[0-9]+$/.match?(fee)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
)
|
|
141
|
-
|
|
142
|
-
|
|
94
|
+
args = [amount, fee, sources.split(','), target, change]
|
|
95
|
+
kwargs = { skip_utxo: options[:skip_utxo] }
|
|
96
|
+
unless options[:yes] || options[:dry]
|
|
97
|
+
client(dry: true).pay(*args, **kwargs)
|
|
98
|
+
print 'Do you confirm this payment? (yes/no): '
|
|
99
|
+
answer = $stdin.gets&.strip&.downcase
|
|
100
|
+
raise Sibit::Error, 'Payment cancelled by user' unless answer == 'yes'
|
|
101
|
+
end
|
|
102
|
+
log.info(client.pay(*args, **kwargs))
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
desc 'version', 'Print program version'
|
|
106
|
+
def version
|
|
107
|
+
log.info(Sibit::VERSION)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
private
|
|
111
|
+
|
|
112
|
+
def log
|
|
113
|
+
@log ||= options[:verbose] ? Loog::VERBOSE : Loog::REGULAR
|
|
143
114
|
end
|
|
115
|
+
|
|
116
|
+
def client(dry: false)
|
|
117
|
+
http = options[:proxy] ? Sibit::HttpProxy.new(options[:proxy]) : Sibit::Http.new
|
|
118
|
+
apis = options[:api].flat_map { |a| a.split(',') }.map(&:downcase).map do |a|
|
|
119
|
+
case a
|
|
120
|
+
when 'blockchain'
|
|
121
|
+
Sibit::Blockchain.new(http: http, log: log)
|
|
122
|
+
when 'btc'
|
|
123
|
+
Sibit::Btc.new(http: http, log: log)
|
|
124
|
+
when 'bitcoinchain'
|
|
125
|
+
Sibit::Bitcoinchain.new(http: http, log: log)
|
|
126
|
+
when 'blockchair'
|
|
127
|
+
Sibit::Blockchair.new(http: http, log: log)
|
|
128
|
+
when 'cex'
|
|
129
|
+
Sibit::Cex.new(http: http, log: log)
|
|
130
|
+
when 'fake'
|
|
131
|
+
Sibit::Fake.new
|
|
132
|
+
else
|
|
133
|
+
raise Sibit::Error, "Unknown API \"#{a}\""
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
api = Sibit::FirstOf.new(apis, log: log, verbose: true)
|
|
137
|
+
api = Sibit::Dry.new(api, log: log) if options[:dry] || dry
|
|
138
|
+
api = RetriableProxy.for_object(api, on: Sibit::Error) if options[:attempts] > 1
|
|
139
|
+
Sibit.new(log: log, api: api)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
begin
|
|
144
|
+
Bin.start(ARGV)
|
|
144
145
|
rescue StandardError => e
|
|
145
|
-
|
|
146
|
+
log = ARGV.include?('--verbose') ? Loog::VERBOSE : Loog::REGULAR
|
|
147
|
+
if ARGV.include?('--verbose')
|
|
146
148
|
log.error(Backtrace.new(e))
|
|
147
149
|
else
|
|
148
150
|
log.error(e.message)
|
data/features/cli.feature
CHANGED
|
@@ -6,7 +6,7 @@ Feature: Command Line Processing
|
|
|
6
6
|
Scenario: Help can be printed
|
|
7
7
|
When I run bin/sibit with "--help"
|
|
8
8
|
Then Exit code is zero
|
|
9
|
-
And Stdout contains "
|
|
9
|
+
And Stdout contains "Commands:"
|
|
10
10
|
|
|
11
11
|
Scenario: Bitcoin price can be retrieved
|
|
12
12
|
When I run bin/sibit with "price --attempts=4"
|
|
@@ -31,3 +31,8 @@ Feature: Command Line Processing
|
|
|
31
31
|
Scenario: Bitcoin fees can be printed
|
|
32
32
|
When I run bin/sibit with "fees --verbose --api=fake"
|
|
33
33
|
Then Exit code is zero
|
|
34
|
+
|
|
35
|
+
Scenario: Pay help shows all options
|
|
36
|
+
When I run bin/sibit with "pay --help"
|
|
37
|
+
Then Exit code is zero
|
|
38
|
+
And Stdout contains "--skip-utxo"
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
require 'nokogiri'
|
|
7
7
|
require 'tmpdir'
|
|
8
|
-
require 'slop'
|
|
9
8
|
require 'English'
|
|
10
9
|
require_relative '../../lib/sibit'
|
|
11
10
|
|
|
@@ -14,10 +13,6 @@ Before do
|
|
|
14
13
|
@dir = Dir.mktmpdir('test')
|
|
15
14
|
FileUtils.mkdir_p(@dir)
|
|
16
15
|
Dir.chdir(@dir)
|
|
17
|
-
@opts = Slop.parse ['-v', '-s', @dir] do |o|
|
|
18
|
-
o.bool '-v', '--verbose'
|
|
19
|
-
o.string '-s', '--source'
|
|
20
|
-
end
|
|
21
16
|
end
|
|
22
17
|
|
|
23
18
|
After do
|
data/lib/sibit/version.rb
CHANGED
data/sibit.gemspec
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sibit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.31.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yegor Bugayenko
|
|
@@ -136,19 +136,19 @@ dependencies:
|
|
|
136
136
|
- !ruby/object:Gem::Version
|
|
137
137
|
version: '1.0'
|
|
138
138
|
- !ruby/object:Gem::Dependency
|
|
139
|
-
name:
|
|
139
|
+
name: thor
|
|
140
140
|
requirement: !ruby/object:Gem::Requirement
|
|
141
141
|
requirements:
|
|
142
142
|
- - "~>"
|
|
143
143
|
- !ruby/object:Gem::Version
|
|
144
|
-
version: '
|
|
144
|
+
version: '1.3'
|
|
145
145
|
type: :runtime
|
|
146
146
|
prerelease: false
|
|
147
147
|
version_requirements: !ruby/object:Gem::Requirement
|
|
148
148
|
requirements:
|
|
149
149
|
- - "~>"
|
|
150
150
|
- !ruby/object:Gem::Version
|
|
151
|
-
version: '
|
|
151
|
+
version: '1.3'
|
|
152
152
|
description: This is a simple Bitcoin client, to use from command line or from your
|
|
153
153
|
Ruby app. You don't need to run any Bitcoin software, no need to install anything,
|
|
154
154
|
etc. All you need is just a command line and Ruby 2.5+.
|