@@ -26,60 +26,166 @@ Server and browser compatible. Vanilla JS. 0 Dependencies.
26
26
npm install --save @dashincubator/secp256k1
27
27
npm install --save dashkeys
28
28
npm install --save dashtx
29
+ npm install --save dashkeys
29
30
```
30
31
31
- Note: You may provide your own ` sign() ` function , as shown below.
32
+ Note: You must provide your own _ Key Util _ functions , as shown below.
32
33
33
34
``` js
34
35
" use strict" ;
35
36
36
- let Tx = require (" dashtx" );
37
- let tx = Tx .create ({ sign: sign });
38
-
37
+ let DashKeys = require (" dashkeys" );
38
+ let DashTx = require (" dashtx" );
39
39
let Secp256k1 = require (" @dashincubator/secp256k1" );
40
40
41
- async function sign (privKeyBytes , hashBytes ) {
42
- let sigOpts = { canonical: true , extraEntropy: true };
43
- let sigBytes = await Secp256k1 .sign (hashBytes, privKeyBytes, sigOpts);
44
- return sigBytes;
45
- }
41
+ let yourWalletKeyDataMapGoesHere = {
42
+ /* SEE BELOW */
43
+ };
46
44
47
- // ...
45
+ let keyUtils = {
46
+ /* SEE BELOW */
47
+ };
48
+ let dashTx = DashTx .create (keyUtils);
49
+
50
+ let inputs = [{ outputIndex, publicKey, txid /* , optional addr/pkh/hdpath */ }];
51
+ let outputs = [{ satoshis, pubKeyHash /* , optional addr/hdpath/etc */ }];
52
+ let txInfo = { inputs, outputs };
53
+
54
+ // Sorted as per "Lexicographical Indexing of Transaction Inputs and Outputs"
55
+ txInfo .inputs .sort (DashTx .sortInputs );
56
+ txInfo .outputs .sort (DashTx .sortOutputs );
57
+
58
+ let txInfoSigned = await dashTx .hashAndSignAll (txInfo);
59
+
60
+ console .info (JSON .stringify (txInfo, null , 2 ));
61
+ console .info (txInfo .transaction );
48
62
```
49
63
50
64
## Browsers
51
65
52
66
``` html
53
67
<script src =" https://unpkg.com/@dashincubator/secp256k1/secp256k1.js" ></script >
68
+ <script src =" https://unpkg.com/dashkeys/dashkeys.js" ></script >
54
69
<script src =" https://unpkg.com/dashtx/dashtx.js" ></script >
55
70
```
56
71
57
- Note: You must provide your own ` sign() ` function , as shown below.
72
+ Note: You must provide your own _ Key Util _ functions , as shown below.
58
73
59
74
``` js
60
- (function () {
75
+ (async function () {
61
76
" use strict" ;
62
77
63
- let Tx = window .DashTx ;
64
- let tx = Tx .create ({ sign: sign });
65
-
78
+ let DashKeys = window .DashTx ;
79
+ let DashTx = window .DashKeys ;
66
80
let Secp256k1 = window .nobleSecp256k1 ;
67
81
68
- async function sign (privKeyBytes , hashBytes ) {
69
- let sigOpts = { canonical: true , extraEntropy: true };
70
- let sigBytes = await Secp256k1 .sign (hashBytes, privKeyBytes, sigOpts);
71
- return sigBytes;
72
- }
82
+ let yourWalletKeyDataMapGoesHere = {
83
+ /* SEE BELOW */
84
+ };
85
+
86
+ let keyUtils = {
87
+ /* SEE BELOW */
88
+ };
89
+ let dashTx = DashTx .create (keyUtils);
90
+
91
+ let inputs = [
92
+ { outputIndex, publicKey, txid /* , optional addr/pkh/hdpath */ },
93
+ ];
94
+ let outputs = [{ satoshis, pubKeyHash /* , optional addr/hdpath/etc */ }];
95
+ let txInfo = { inputs, outputs };
96
+
97
+ // Sorted as per "Lexicographical Indexing of Transaction Inputs and Outputs"
98
+ txInfo .inputs .sort (DashTx .sortInputs );
99
+ txInfo .outputs .sort (DashTx .sortOutputs );
100
+
101
+ let txInfoSigned = await dashTx .hashAndSignAll (txInfo);
102
+
103
+ console .info (JSON .stringify (txInfo, null , 2 ));
104
+ console .info (txInfo .transaction );
73
105
74
106
// ...
75
107
})();
76
108
```
77
109
78
- ## Example Usage
110
+ ## Example Wallet Key Data
79
111
80
- See also: [ example.js] ( /example.js ) .
112
+ DashTx does not depend on any specific implementation of a wallet key storage
113
+ engine, but it works great with plain-old JSON:
114
+
115
+ ``` js
116
+ let yourWalletKeyMapGoesHere = {
117
+ yTw3SFk9PbQ1kikMgJBRA7CFyLfNt2G6QD: {
118
+ hdpath: " 0bGYi3S7n2Q|m/44'/1'/0'/0/0" ,
119
+ address: " yTw3SFk9PbQ1kikMgJBRA7CFyLfNt2G6QD" ,
120
+ wif: " cUeUEgRQWfKiYPBeRZsYsrvvSZiKHbUNqiQE2AdKA4s7ymycdVxc" ,
121
+ },
122
+ yb4zn8MSW4hHsvmP6PxX2tUPDb9bvmxSrS: {
123
+ hdpath: " 0bGYi3S7n2Q|m/44'/1'/0'/0/1" ,
124
+ wif: " cN28SZpmmuVFmmBQBHCNdwa6a14kWZM8VVpZETjzk47aGNvVGXK7" ,
125
+ address: " yb4zn8MSW4hHsvmP6PxX2tUPDb9bvmxSrS" ,
126
+ },
127
+ yfrB4v4cih7os6t1tg4YuWkrTYmHyMHkZb: {
128
+ hdpath: " 0bGYi3S7n2Q|m/44'/1'/0'/0/2" ,
129
+ address: " yfrB4v4cih7os6t1tg4YuWkrTYmHyMHkZb" ,
130
+ wif: " cQBHjCxspabNZKGMK3gbuvSLgssqSxAuDsaMMDuzgXioYyR723Bg" ,
131
+ },
132
+ // ...
133
+ };
134
+ ```
135
+
136
+ You can use any indexing, query, or storage strategy you like, with values in
137
+ Base58Check, Hex, Byte, or whatever else you fancy - just as long as your
138
+ provided _ Key Util_ functions can convert them.
139
+
140
+ ## Example Key Utils
141
+
142
+ DashTx does not depend on any specific implementation of signing or key
143
+ transformation, but it works greeat ** NobleSecp256k1** and ** DashKeys** :
144
+
145
+ ``` text
146
+ getPrivateKey(txInput, i)
147
+ getPublicKey(txInput, i)
148
+ sign(privKeyBytes, txHashBytes)
149
+ toPublicKey(privKeyBytes)
150
+ ```
151
+
152
+ ``` js
153
+ let keyUtils = {
154
+ getPrivateKey : async function (txInput , i ) {
155
+ let pkhBytes = DashKeys .utils .hexToBytes (txInput .pubKeyHash );
156
+ let address = await DashKeys .pkhToAddr (txInput .pubKeyHash );
157
+
158
+ let yourKeyData = yourWalletKeyMapGoesHere[address];
159
+
160
+ let privKeyBytes = DashKeys .wifToPrivKey (yourKeyData .wif );
161
+ return privKeyBytes;
162
+ },
163
+
164
+ getPublicKey : async function (txInput , i ) {
165
+ let privKeyBytes = getPrivateKey (txInput, i);
166
+ let publicKey = await keyUtils .toPublicKey (privKeyBytes);
167
+
168
+ return publicKey;
169
+ },
170
+
171
+ sign : async function (privKeyBytes , txHashBytes ) {
172
+ let sigOpts = { canonical: true , extraEntropy: true };
173
+ let sigBytes = await Secp256k1 .sign (txHashBytes, privKeyBytes, sigOpts);
174
+
175
+ return sigBytes;
176
+ },
177
+
178
+ toPublicKey : async function (privKeyBytes ) {
179
+ let isCompressed = true ;
180
+ let pubKeyBytes = Secp256k1 .getPublicKey (privateKey, isCompressed);
181
+ return pubKeyBytes;
182
+ },
183
+ };
184
+ ```
81
185
82
- Note: You must provide your own ` sign() ` function, as shown above.
186
+ ## Example Tx Info
187
+
188
+ See also: [ example.js] ( /example.js ) .
83
189
84
190
``` js
85
191
let memo = Tx .utils .strToHex (" Hello, Dash!" );
@@ -114,7 +220,6 @@ let txInfo = {
114
220
txInfo .inputs .sort (Tx .sortInputs );
115
221
txInfo .outputs .sort (Tx .sortOutputs );
116
222
117
- let keys = txInfo .inputs .map (getPrivateKey);
118
223
let txInfoSigned = await tx .hashAndSignAll (txInfo);
119
224
120
225
console .info (JSON .stringify (txInfo, null , 2 ));
@@ -160,7 +265,6 @@ let txInfo = {
160
265
txInfo .inputs .sort (Tx .sortInputs );
161
266
txInfo .outputs .sort (Tx .sortOutputs );
162
267
163
- let keys = txInfo .inputs .map (getPrivateKey);
164
268
let txInfoSigned = await tx .hashAndSignAll (txInfo);
165
269
166
270
console .info (JSON .stringify (txInfo, null , 2 ));
@@ -278,7 +382,7 @@ Tx.OUTPUT_SIZE // 34
278
382
```
279
383
280
384
``` text
281
- Tx.create({ sign, getPrivateKey });
385
+ Tx.create({ getPrivateKey, getPublicKey, sign, toPublicKey });
282
386
tx.hashAndSignAll(txInfo);
283
387
tx.legacy.draftSingleOutput({ utxos, inputs, output });
284
388
tx.legacy.finalizePresorted(txDraft, keys);
@@ -304,18 +408,13 @@ Tx.hashPartial(txHex, Tx.SIGHASH_ALL);
304
408
305
409
// Deprecated
306
410
Tx.createLegacyTx(coins, outputs, changeOutput);
307
-
308
- // Not API-locked, May change
309
- Tx.utils.sign(privKeyBytes, txHashBytes);
310
- Tx.utils.toPublicKey(privKeyBytes);
311
- Tx.utils.addrToPubKeyHash(addr);
312
411
```
313
412
314
413
``` js
315
414
/**
316
415
* Creates a tx signer instance.
317
416
*/
318
- Tx .create ({ sign, getPrivateKey });
417
+ Tx .create ({ getPrivateKey, getPublicKey, sign, toPublicKey });
319
418
320
419
/**
321
420
* Estimates the min, mid, and max sizes of (fees for) a transaction (including memos).
@@ -469,26 +568,7 @@ Tx.utils.strToHex(str);
469
568
### You-do-It Functions
470
569
471
570
``` js
472
- Tx .create ({ sign, getPrivateKey });
473
-
474
- /**
475
- * Sign a 256-bit hash. 'canonical' form is required for
476
- * blockchains. Must return the signature as an ASN.1 DER.
477
- * These may or may not be the default options, depending
478
- * on the library used.
479
- *
480
- * We recommend @dashincubator/secp256k1 and @noble/secp256k1.
481
- *
482
- * @param {Uint8Array} privateKey - an input's corresponding key
483
- * @param {Uint8Array} txHashBytes - the (not reversed) 2x-sha256-hash
484
- * @returns {String} - hex representation of an ASN.1 signature
485
- */
486
- async function sign (privateKey , txHashBytes ) {
487
- let sigOpts = { canonical: true };
488
- let sigBytes = await Secp256k1 .sign (txHashBytes, privateKey, sigOpts);
489
-
490
- return Tx .utils .bytesToHex (sigBytes);
491
- }
571
+ Tx .create ({ getPrivateKey, getPublicKey, sign, toPublicKey });
492
572
493
573
/**
494
574
* Given information that you provided about an input
@@ -504,10 +584,47 @@ async function sign(privateKey, txHashBytes) {
504
584
* @returns {Uint8Array} - the private key bytes
505
585
*/
506
586
async function getPrivateKey (txInput , i ) {
507
- let address = await DashKeys .pubkeyToAddr (txInput .publicKey );
508
- let privateKey = privateKeys[address];
587
+ let pkhBytes = DashKeys .utils .hexToBytes (txInput .pubKeyHash );
588
+ let address = await DashKeys .pkhToAddr (txInput .pubKeyHash );
589
+ let privKeyBytes = privateKeys[address];
590
+
591
+ return privKeyBytes;
592
+ }
593
+
594
+ async function getPublicKey (txInput , i ) {
595
+ let privKeyBytes = getPrivateKey (txInput, i);
596
+ let publicKey = await toPublicKey (privKeyBytes);
597
+
598
+ return publicKey;
599
+ }
600
+
601
+ let Secp256k1 =
602
+ // @ts-ignore
603
+ window .nobleSecp256k1 || require (" @dashincubator/secp256k1" );
604
+
605
+ /**
606
+ * Sign a 256-bit hash. 'canonical' form is required for
607
+ * blockchains. Must return the signature as an ASN.1 DER.
608
+ * These may or may not be the default options, depending
609
+ * on the library used.
610
+ *
611
+ * We recommend @dashincubator/secp256k1 and @noble/secp256k1.
612
+ *
613
+ * @param {Uint8Array} privateKey - an input's corresponding key
614
+ * @param {Uint8Array} txHashBytes - the (not reversed) 2x-sha256-hash
615
+ * @returns {String} - hex representation of an ASN.1 signature
616
+ */
617
+ async function sign (privKeyBytes , txHashBytes ) {
618
+ let sigOpts = { canonical: true , extraEntropy: true };
619
+ let sigBytes = await Secp256k1 .sign (txHashBytes, privKeyBytes, sigOpts);
620
+
621
+ return sigBytes;
622
+ }
509
623
510
- return privateKey;
624
+ async function toPublicKey (privKeyBytes ) {
625
+ let isCompressed = true ;
626
+ let pubKeyBytes = Secp256k1 .getPublicKey (privateKey, isCompressed);
627
+ return pubKeyBytes;
511
628
}
512
629
```
513
630
0 commit comments