pochette 0.2.0 → 0.2.2
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/README.md +70 -3
- data/lib/pochette.rb +2 -1
- data/lib/pochette/transaction_builder.rb +0 -1
- data/lib/pochette/trezor_transaction_builder.rb +48 -6
- data/lib/pochette/version.rb +1 -1
- data/pochette.gemspec +1 -0
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 232aedff3f83a84ce22d5c17d27cfb9663b8d2a5
|
4
|
+
data.tar.gz: f53d4c8ddef9552dc4be39640dbb6d2ae0c429f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bc2996d2eece872696c85d2bb2ef1a72f7b703ead2c945ae114e6c201eeb8b40a5f16c51ed8d960e793227d673afee28ca1ccfa9a04ea7c1b718fc6dc0600ffb
|
7
|
+
data.tar.gz: 88c8709b576c2e68d7a1b2689fc193c7c94679100df7d0913d342173853952eb4b3c99187027277381b254590ddb0c83df2e71dcccec555c2bb7b5e24433d6e6
|
data/README.md
CHANGED
@@ -20,7 +20,8 @@ and broadcasted.
|
|
20
20
|
|
21
21
|
The Pochette::TrezorTransactionBuilder class extends Pochette::TransactionBuilder
|
22
22
|
including transactions, inputs and outputs that are formatted in a way they can
|
23
|
-
be passed directly to a Trezor device for signing.
|
23
|
+
be passed directly to a Trezor device for signing. You can even build transactions
|
24
|
+
for multisig addresses to be signed by several trezors.
|
24
25
|
|
25
26
|
## Table of contents
|
26
27
|
- [Installation and Setup](#installation-and-setup)
|
@@ -187,15 +188,34 @@ If you're using [Trezor Connect](https://github.com/trezor/connect) for signing
|
|
187
188
|
then you won't need to pass in the transactions.
|
188
189
|
|
189
190
|
#### Receives
|
190
|
-
The
|
191
|
+
The TrezorTransactionBuilder's initializer receives a single options hash with:
|
191
192
|
|
192
193
|
<dl>
|
193
|
-
<dt>
|
194
|
+
<dt>bip32_addresses:</dt>
|
194
195
|
<dd>
|
195
196
|
List of addresses in wallet. We will be spending their unspent outputs.
|
196
197
|
Each address is represented as a pair, with the public address string
|
197
198
|
and the BIP32 path as a list of integers, for example:
|
199
|
+
|
200
|
+
<pre>
|
198
201
|
['public-address-as-string', [44, 1, 3, 11]]
|
202
|
+
</pre>
|
203
|
+
|
204
|
+
If you're spending from a multisig address then you should provide
|
205
|
+
all the root xpubs ( session.getPublicKey([]) ) from your different trezor devices, the path as a list of
|
206
|
+
integers and the M number (as in M out of N).
|
207
|
+
The actual bitcoin address will be derived from these.
|
208
|
+
The following example is for a multi-sig address where 2 out of 3 trezors can sign.
|
209
|
+
The address is generated from the public key at path [42, 1, 1] in each trezor.
|
210
|
+
|
211
|
+
<pre>
|
212
|
+
[['xpub661MyMwAqRbcGCmcnz4JtnieVyuvgQFGqZqw3KS1g9khndpF3segkAYbYCKKaQ9Di2ZuWLaZU4Axt7TrKq41aVYx8XTbDbQFzhhDMntKLU5',
|
213
|
+
'xpub661MyMwAqRbcFwc3Nmz8WmMU9okGmeVSmuprwNHCVsfhy6vMyg6g79octqwNftK4g62TMWmb7UtVpnAWnANzqwtKrCDFe2UaDCv1HoErssE'
|
214
|
+
'xpub661MyMwAqRbcGkqPSKVkwTMtFZzEpbWXjM4t1Dv1XQbfMxtyLRGupWkp3fcSCDtp6nd1AUrRtq8tnFGTYgkY1pB9muwzaBDnJSMo2rVENhz'],
|
215
|
+
[42,1,1],
|
216
|
+
2]
|
217
|
+
<pre>
|
218
|
+
|
199
219
|
</dd>
|
200
220
|
<dt>outputs:</dt>
|
201
221
|
<dd>
|
@@ -250,6 +270,53 @@ A hash with
|
|
250
270
|
{ address_n: [42,1,1],
|
251
271
|
prev_hash: "956b30c3c4335f019dbee60c60d76994319473acac356f774c7858cd5c968e40",
|
252
272
|
prev_index: 1}
|
273
|
+
|
274
|
+
When spending from a multisig address, the inputs will also include the multisig structure,
|
275
|
+
with nodes and everything your trezor needs to sign.
|
276
|
+
Notice there's a 'signatures' key inside 'multisig', you should sign the transaction as is,
|
277
|
+
then populate the corresponding value in 'signatures' and keep signing until you have
|
278
|
+
all the required signatures.
|
279
|
+
|
280
|
+
{ address_n: [42,1,1],
|
281
|
+
prev_hash: "eeeb30c3c4335f019dbee60c60d76994319473acac356f774c7858cd5c968eee",
|
282
|
+
prev_index: 0,
|
283
|
+
script_type: 'SPENDMULTISIG',
|
284
|
+
multisig: {
|
285
|
+
signatures: ['','',''],
|
286
|
+
m: 2,
|
287
|
+
pubkeys: [
|
288
|
+
{ address_n: [42,1,1],
|
289
|
+
node: {
|
290
|
+
chain_code: 'a6d47170817f78094180f1a7a3a9df7634df75fa9604d71b87e92a5a6bf9d30a',
|
291
|
+
depth: 0,
|
292
|
+
child_num: 0,
|
293
|
+
fingerprint: 0,
|
294
|
+
path: [],
|
295
|
+
public_key: '03142b0a6fa6943e7276ddc42582c6b169243d289ff17e7c8101797047eed90c9b',
|
296
|
+
}
|
297
|
+
},
|
298
|
+
{ address_n: [42,1,1],
|
299
|
+
node: {
|
300
|
+
chain_code: '8c9151740446b9e0063ca934df66c5e14121a0b4d8a360748f1b19bfef675460',
|
301
|
+
depth: 0,
|
302
|
+
child_num: 0,
|
303
|
+
fingerprint: 0,
|
304
|
+
path: [],
|
305
|
+
public_key: '027565ceb190647ec5c566805ebc5cb6166ae2ee1d4995495f61b9eff371ec0e61',
|
306
|
+
}
|
307
|
+
},
|
308
|
+
{ address_n: [42,1,1],
|
309
|
+
node: {
|
310
|
+
chain_code: 'de5bc5918414df3777ff52ae733bdbc87431485cfd39aea65da6133e183ef68a',
|
311
|
+
depth: 0,
|
312
|
+
child_num: 0,
|
313
|
+
fingerprint: 0,
|
314
|
+
path: [],
|
315
|
+
public_key: '028776ff18f0f3808d6d42749a6e2baee5c75c3f7ae07445403a3a5690d580a0af',
|
316
|
+
}
|
317
|
+
}
|
318
|
+
]
|
319
|
+
}
|
253
320
|
</dd>
|
254
321
|
<dt>trezor_outputs:</dt>
|
255
322
|
<dd>
|
data/lib/pochette.rb
CHANGED
@@ -3,6 +3,7 @@ require "bitcoin_rpc"
|
|
3
3
|
require "active_support"
|
4
4
|
require "active_support/core_ext"
|
5
5
|
require "bitcoin"
|
6
|
+
require "money-tree"
|
6
7
|
require "contracts"
|
7
8
|
C = Contracts
|
8
9
|
|
@@ -13,7 +14,7 @@ module Pochette
|
|
13
14
|
|
14
15
|
Contract C::Bool => C::Bool
|
15
16
|
def self.testnet=(v)
|
16
|
-
Bitcoin.network = v ? :
|
17
|
+
Bitcoin.network = v ? :testnet3 : :bitcoin
|
17
18
|
@testnet = v
|
18
19
|
end
|
19
20
|
|
@@ -1,10 +1,12 @@
|
|
1
1
|
# Same as TransactionBuilder but outputs a transaction hash with all the
|
2
2
|
# required data to create and sign a transaction using a BitcoinTrezor.
|
3
|
-
|
4
3
|
class Pochette::TrezorTransactionBuilder < Pochette::TransactionBuilder
|
5
4
|
|
6
5
|
Contract ({
|
7
|
-
:bip32_addresses => C::ArrayOf[
|
6
|
+
:bip32_addresses => C::ArrayOf[C::Or[
|
7
|
+
[C::Or[String, C::ArrayOf[String]], C::ArrayOf[Integer]],
|
8
|
+
[C::Or[String, C::ArrayOf[String]], C::ArrayOf[Integer], C::Maybe[Integer]]
|
9
|
+
]],
|
8
10
|
:outputs => C::Maybe[C::ArrayOf[[String, C::Num]]],
|
9
11
|
:utxo_blacklist => C::Maybe[C::ArrayOf[[String, Integer]]],
|
10
12
|
:change_address => C::Maybe[String],
|
@@ -32,7 +34,9 @@ class Pochette::TrezorTransactionBuilder < Pochette::TransactionBuilder
|
|
32
34
|
:trezor_inputs => C::ArrayOf[{
|
33
35
|
address_n: C::ArrayOf[Integer],
|
34
36
|
prev_hash: String,
|
35
|
-
prev_index: Integer
|
37
|
+
prev_index: Integer,
|
38
|
+
script_type: C::Maybe[C::Any],
|
39
|
+
multisig: C::Maybe[C::Any],
|
36
40
|
}],
|
37
41
|
:trezor_outputs => C::ArrayOf[{
|
38
42
|
script_type: String,
|
@@ -59,17 +63,55 @@ protected
|
|
59
63
|
self.errors = [:no_bip32_addresses_given]
|
60
64
|
return
|
61
65
|
end
|
62
|
-
options[:addresses] = options[:bip32_addresses].collect(
|
66
|
+
options[:addresses] = options[:bip32_addresses].collect{|a| address_from_bip32(a) }
|
63
67
|
self.bip32_address_lookup = options[:bip32_addresses].reduce({}) do |accum, addr|
|
64
|
-
accum[addr
|
68
|
+
accum[address_from_bip32(addr)] = addr
|
65
69
|
accum
|
66
70
|
end
|
67
71
|
end
|
68
72
|
|
73
|
+
# Bip32 addresses may look like an address with a bip32 path, or
|
74
|
+
# an array of xpubs, bip32 path and M (as in M of N) for multisig p2sh addresses.
|
75
|
+
def address_from_bip32(array)
|
76
|
+
if array.first.is_a?(String)
|
77
|
+
array.first
|
78
|
+
else
|
79
|
+
public_keys = array.first.collect do |x|
|
80
|
+
MoneyTree::Node.from_bip32(x).node_for_path(array[1].join('/')).public_key.key
|
81
|
+
end
|
82
|
+
address, _ = Bitcoin.pubkeys_to_p2sh_multisig_address(array.last, *public_keys)
|
83
|
+
address
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
69
87
|
def build_trezor_inputs
|
70
88
|
self.trezor_inputs = inputs.collect do |input|
|
71
|
-
|
89
|
+
address = bip32_address_lookup[input[0]]
|
90
|
+
hash = { address_n: address[1],
|
72
91
|
prev_hash: input[1], prev_index: input[2] }
|
92
|
+
if address.size == 3
|
93
|
+
xpubs = address.first
|
94
|
+
m = address.last
|
95
|
+
hash[:script_type] = 'SPENDMULTISIG'
|
96
|
+
hash[:multisig] = {
|
97
|
+
signatures: [''] * xpubs.size,
|
98
|
+
m: m,
|
99
|
+
pubkeys: xpubs.collect do |xpub|
|
100
|
+
node = MoneyTree::Node.from_bip32(xpub)
|
101
|
+
{ address_n: address[1],
|
102
|
+
node: {
|
103
|
+
chain_code: node.chain_code.to_s(16),
|
104
|
+
depth: 0,
|
105
|
+
child_num: 0,
|
106
|
+
fingerprint: 0,
|
107
|
+
path: [],
|
108
|
+
public_key: node.public_key.key,
|
109
|
+
}
|
110
|
+
}
|
111
|
+
end
|
112
|
+
}
|
113
|
+
end
|
114
|
+
hash
|
73
115
|
end
|
74
116
|
end
|
75
117
|
|
data/lib/pochette/version.rb
CHANGED
data/pochette.gemspec
CHANGED
@@ -23,6 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_dependency "activesupport", "~> 4.2"
|
24
24
|
spec.add_dependency "bitcoin_rpc", "~> 0.1.1"
|
25
25
|
spec.add_dependency "bitcoin-ruby", "~> 0.0.7"
|
26
|
+
spec.add_dependency "money-tree", "~> 0.9.0"
|
26
27
|
spec.add_dependency "contracts", "~> 0.12.0"
|
27
28
|
|
28
29
|
spec.add_development_dependency "bundler", "~> 1.9"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pochette
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nubis
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-12-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -53,6 +53,20 @@ dependencies:
|
|
53
53
|
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: 0.0.7
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: money-tree
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 0.9.0
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 0.9.0
|
56
70
|
- !ruby/object:Gem::Dependency
|
57
71
|
name: contracts
|
58
72
|
requirement: !ruby/object:Gem::Requirement
|