sibit 0.30.4 → 0.30.6
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 +1 -0
- data/Gemfile.lock +8 -3
- data/README.md +9 -6
- data/lib/sibit/key.rb +19 -5
- data/lib/sibit/script.rb +5 -4
- data/lib/sibit/version.rb +1 -1
- data/lib/sibit.rb +11 -5
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aa32d663437f956373254dfd5ee62d072a984a7848ef455d26d22727293199ef
|
|
4
|
+
data.tar.gz: 6a0464cb926cce844ec89e380352c9d0e94c97ffbd26a9609ecbcefd82ee9413
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3711ea50589117bc03497b111c11f7509b7be90dd8656aa7938ae3a72e730a8f13b74a1706589ca224b883dfa2223875f9e5aa204865e58d7856dcfd28a6fd17
|
|
7
|
+
data.tar.gz: 8ed48713e2795903a90501fed8da5a48dda43d62c9e8a152e4200003cf4ca51903fc53d745068de5502faadedf69d76d99b3024742b7d0a164924df62d3796f4
|
data/Gemfile
CHANGED
|
@@ -10,6 +10,7 @@ gemspec
|
|
|
10
10
|
|
|
11
11
|
gem 'aruba', '~>2.2', require: false
|
|
12
12
|
gem 'cucumber', '~>10.0', require: false
|
|
13
|
+
gem 'donce', '~>0.2', require: false
|
|
13
14
|
gem 'logger', '~>1.7', require: false
|
|
14
15
|
gem 'minitest', '~>6.0', require: false
|
|
15
16
|
gem 'minitest-reporters', '~>1.7', require: false
|
data/Gemfile.lock
CHANGED
|
@@ -62,6 +62,10 @@ GEM
|
|
|
62
62
|
decoor (0.1.0)
|
|
63
63
|
diff-lcs (1.6.2)
|
|
64
64
|
docile (1.4.1)
|
|
65
|
+
donce (0.2.4)
|
|
66
|
+
backtrace (~> 0.3)
|
|
67
|
+
os (~> 1.1)
|
|
68
|
+
qbash (~> 0.3)
|
|
65
69
|
elapsed (0.2.1)
|
|
66
70
|
loog (~> 0.6)
|
|
67
71
|
tago (~> 0.1)
|
|
@@ -78,6 +82,7 @@ GEM
|
|
|
78
82
|
logger (~> 1.0)
|
|
79
83
|
memoist3 (1.0.0)
|
|
80
84
|
mini_mime (1.1.5)
|
|
85
|
+
mini_portile2 (2.8.9)
|
|
81
86
|
minitest (6.0.1)
|
|
82
87
|
prism (~> 1.5)
|
|
83
88
|
minitest-reporters (1.7.1)
|
|
@@ -86,9 +91,8 @@ GEM
|
|
|
86
91
|
minitest (>= 5.0)
|
|
87
92
|
ruby-progressbar
|
|
88
93
|
multi_test (1.1.0)
|
|
89
|
-
nokogiri (1.18.10
|
|
90
|
-
|
|
91
|
-
nokogiri (1.18.10-x86_64-linux-gnu)
|
|
94
|
+
nokogiri (1.18.10)
|
|
95
|
+
mini_portile2 (~> 2.8.2)
|
|
92
96
|
racc (~> 1.4)
|
|
93
97
|
openssl (3.3.2)
|
|
94
98
|
os (1.1.4)
|
|
@@ -182,6 +186,7 @@ PLATFORMS
|
|
|
182
186
|
DEPENDENCIES
|
|
183
187
|
aruba (~> 2.2)
|
|
184
188
|
cucumber (~> 10.0)
|
|
189
|
+
donce (~> 0.2)
|
|
185
190
|
logger (~> 1.7)
|
|
186
191
|
minitest (~> 6.0)
|
|
187
192
|
minitest-reporters (~> 1.7)
|
data/README.md
CHANGED
|
@@ -63,15 +63,18 @@ $ sibit pay AMOUNT FEE P1,P2,... TARGET CHANGE
|
|
|
63
63
|
e87f138c9ebf5986151667719825c28458a28cc66f69fed4f1032a93b399fdf8
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
Here
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
Here:
|
|
67
|
+
|
|
68
|
+
* `AMOUNT` is the amount of [satoshi] you are sending (integer),
|
|
69
|
+
or `0.42BTC` if in bitcoins (with a suffix),
|
|
70
|
+
* `FEE` is the [miner fee] you are ready to spend to get
|
|
69
71
|
this transaction delivered (you can say `S`, `M`, `L`, or `XL` if you want it
|
|
70
72
|
to be calculated automatically),
|
|
71
|
-
|
|
73
|
+
* `P1,P2,...` is a comma-separated list
|
|
72
74
|
of private keys `P` you are sending your coins from,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
+
* `TARGET` is the address you are sending to,
|
|
76
|
+
* `CHANGE` is the address where the change goes.
|
|
77
|
+
|
|
75
78
|
The transaction hash is returned.
|
|
76
79
|
Not all [UTXOs] may be used, but only the necessary amount of them.
|
|
77
80
|
|
data/lib/sibit/key.rb
CHANGED
|
@@ -21,6 +21,8 @@ class Sibit
|
|
|
21
21
|
MIN_PRIV = 0x01
|
|
22
22
|
MAX_PRIV = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140
|
|
23
23
|
|
|
24
|
+
attr_reader :network
|
|
25
|
+
|
|
24
26
|
def self.generate
|
|
25
27
|
key = OpenSSL::PKey::EC.generate('secp256k1')
|
|
26
28
|
pvt = key.private_key.to_s(16).rjust(64, '0').downcase
|
|
@@ -28,9 +30,10 @@ class Sibit
|
|
|
28
30
|
end
|
|
29
31
|
|
|
30
32
|
def initialize(privkey)
|
|
31
|
-
@
|
|
33
|
+
@network = :mainnet
|
|
32
34
|
@compressed = true
|
|
33
|
-
@
|
|
35
|
+
@privkey = decode(privkey)
|
|
36
|
+
@key = build(@privkey)
|
|
34
37
|
end
|
|
35
38
|
|
|
36
39
|
def priv
|
|
@@ -44,17 +47,18 @@ class Sibit
|
|
|
44
47
|
|
|
45
48
|
def addr
|
|
46
49
|
hash = hash160(pub)
|
|
47
|
-
|
|
50
|
+
prefix = @network == :mainnet ? '00' : '6f'
|
|
51
|
+
versioned = "#{prefix}#{hash}"
|
|
48
52
|
checksum = Base58.new(versioned).check
|
|
49
53
|
Base58.new(versioned + checksum).encode
|
|
50
54
|
end
|
|
51
55
|
|
|
52
56
|
def sign(data)
|
|
53
|
-
@key.
|
|
57
|
+
@key.dsa_sign_asn1(data)
|
|
54
58
|
end
|
|
55
59
|
|
|
56
60
|
def verify(data, sig)
|
|
57
|
-
@key.
|
|
61
|
+
@key.dsa_verify_asn1(data, sig)
|
|
58
62
|
rescue OpenSSL::PKey::PKeyError
|
|
59
63
|
false
|
|
60
64
|
end
|
|
@@ -82,5 +86,15 @@ class Sibit
|
|
|
82
86
|
bytes = [hex].pack('H*')
|
|
83
87
|
Digest::RMD160.hexdigest(Digest::SHA256.digest(bytes))
|
|
84
88
|
end
|
|
89
|
+
|
|
90
|
+
def decode(key)
|
|
91
|
+
return key if key.length == 64 && key.match?(/\A[0-9a-f]+\z/i)
|
|
92
|
+
raw = Base58.new(key).decode
|
|
93
|
+
version = raw[0, 2]
|
|
94
|
+
@network = version == '80' ? :mainnet : :testnet
|
|
95
|
+
body = raw[2..-9]
|
|
96
|
+
@compressed = body.length == 66 && body.end_with?('01')
|
|
97
|
+
@compressed ? body[0, 64] : body
|
|
98
|
+
end
|
|
85
99
|
end
|
|
86
100
|
end
|
data/lib/sibit/script.rb
CHANGED
|
@@ -25,8 +25,8 @@ class Sibit
|
|
|
25
25
|
@bytes = [hex].pack('H*').bytes
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
def address
|
|
29
|
-
return p2pkh_address if p2pkh?
|
|
28
|
+
def address(network = :mainnet)
|
|
29
|
+
return p2pkh_address(network) if p2pkh?
|
|
30
30
|
nil
|
|
31
31
|
end
|
|
32
32
|
|
|
@@ -46,10 +46,11 @@ class Sibit
|
|
|
46
46
|
|
|
47
47
|
private
|
|
48
48
|
|
|
49
|
-
def p2pkh_address
|
|
49
|
+
def p2pkh_address(network)
|
|
50
50
|
h = hash160
|
|
51
51
|
return nil unless h
|
|
52
|
-
|
|
52
|
+
prefix = network == :mainnet ? '00' : '6f'
|
|
53
|
+
versioned = "#{prefix}#{h}"
|
|
53
54
|
checksum = Base58.new(versioned).check
|
|
54
55
|
Base58.new(versioned + checksum).encode
|
|
55
56
|
end
|
data/lib/sibit/version.rb
CHANGED
data/lib/sibit.rb
CHANGED
|
@@ -18,7 +18,7 @@ require_relative 'sibit/version'
|
|
|
18
18
|
# Copyright:: Copyright (c) 2019-2025 Yegor Bugayenko
|
|
19
19
|
# License:: MIT
|
|
20
20
|
class Sibit
|
|
21
|
-
#
|
|
21
|
+
# Minimum fee we must pay for transaction processing:
|
|
22
22
|
MIN_SATOSHI_PER_BYTE = 0.1
|
|
23
23
|
|
|
24
24
|
# Constructor.
|
|
@@ -103,7 +103,9 @@ class Sibit
|
|
|
103
103
|
# +change+: the address where the change has to be sent to
|
|
104
104
|
def pay(amount, fee, sources, target, change, skip_utxo: [])
|
|
105
105
|
p = price('USD')
|
|
106
|
-
|
|
106
|
+
keys = sources.map { |k| Key.new(k) }
|
|
107
|
+
network = keys.first&.network || :mainnet
|
|
108
|
+
sources = keys.to_h { |k| [k.addr, k.priv] }
|
|
107
109
|
satoshi = satoshi(amount)
|
|
108
110
|
builder = TxBuilder.new
|
|
109
111
|
unspent = 0
|
|
@@ -116,12 +118,16 @@ class Sibit
|
|
|
116
118
|
@log.debug("UTXO skipped: #{utxo[:hash]}")
|
|
117
119
|
next
|
|
118
120
|
end
|
|
121
|
+
unless utxo[:confirmations]&.positive?
|
|
122
|
+
@log.debug("UTXO with no confirmations: #{utxo[:hash]}")
|
|
123
|
+
next
|
|
124
|
+
end
|
|
119
125
|
unspent += utxo[:value]
|
|
120
126
|
builder.input do |i|
|
|
121
127
|
i.prev_out(utxo[:hash])
|
|
122
128
|
i.prev_out_index(utxo[:index])
|
|
123
129
|
i.prev_out_script = script_hex(utxo[:script])
|
|
124
|
-
address = Script.new(script_hex(utxo[:script])).address
|
|
130
|
+
address = Script.new(script_hex(utxo[:script])).address(network)
|
|
125
131
|
k = sources[address]
|
|
126
132
|
raise Error, "UTXO arrived to #{address} is incorrect" unless k
|
|
127
133
|
i.signature_key(key(k))
|
|
@@ -155,7 +161,7 @@ class Sibit
|
|
|
155
161
|
#{tx.inputs.map { |i| " in: #{i.prev_out.unpack1('H*')}:#{i.prev_out_index}" }.join("\n ")}
|
|
156
162
|
#{tx.out.count} output#{'s' if tx.out.count > 1}:
|
|
157
163
|
#{tx.outputs.map { |o| "out: #{o.script_hex} / #{num(o.value, p)}" }.join("\n ")}
|
|
158
|
-
Min fee: #{num(MIN_SATOSHI_PER_BYTE, p)}
|
|
164
|
+
Min fee: #{num(MIN_SATOSHI_PER_BYTE, p)} /byte
|
|
159
165
|
Fee requested: #{num(f, p)} as \"#{fee}\"
|
|
160
166
|
Fee actually paid: #{num(left, p)}
|
|
161
167
|
Tx size: #{size} bytes
|
|
@@ -276,7 +282,7 @@ in block #{block} (by #{json[:provider]})")
|
|
|
276
282
|
sat = fees[fee.to_sym]
|
|
277
283
|
raise Error, "Can't understand the fee: #{fee.inspect}" if sat.nil?
|
|
278
284
|
f = mul * sat * size
|
|
279
|
-
@log.debug("Fee calculated as #{mul} * #{sat} * #{size} = #{f}")
|
|
285
|
+
@log.debug("Fee calculated as #{mul} * #{sat}s * #{size} = #{f}s")
|
|
280
286
|
f
|
|
281
287
|
end
|
|
282
288
|
|