@bitcoinerlab/descriptors 2.1.0 → 2.2.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.
package/README.md CHANGED
@@ -84,10 +84,10 @@ To call `updatePsbtAsInput()`, use the following syntax:
84
84
  ```javascript
85
85
  import { Psbt } from 'bitcoinjs-lib';
86
86
  const psbt = new Psbt();
87
- const inputFinalizer = output.updatePsbtAsInput({ psbt, txHex, vout });
87
+ const inputFinalizer = output.updatePsbtAsInput({ psbt, txHex, vout, rbf });
88
88
  ```
89
89
 
90
- Here, `psbt` refers to an instance of the [bitcoinjs-lib Psbt class](https://github.com/bitcoinjs/bitcoinjs-lib). The parameter `txHex` denotes a hex string that serializes the previous transaction containing this output. Meanwhile, `vout` is an integer that marks the position of the output within that transaction.
90
+ Here, `psbt` refers to an instance of the [bitcoinjs-lib Psbt class](https://github.com/bitcoinjs/bitcoinjs-lib). The parameter `txHex` denotes a hex string that serializes the previous transaction containing this output. Meanwhile, `vout` is an integer that marks the position of the output within that transaction. Finally, `rbf` is an optional parameter (defaulting to `true`) used to indicate whether the transaction uses Replace-By-Fee (RBF). When RBF is enabled, transactions can be replaced while they are in the mempool with others that have higher fees. Note that RBF is enabled for the entire transaction if at least one input signals it. Also, note that transactions using relative time locks inherently opt into RBF due to the `nSequence` range used.
91
91
 
92
92
  The method returns the `inputFinalizer()` function. This finalizer function completes a PSBT input by adding the unlocking script (`scriptWitness` or `scriptSig`) that satisfies the previous output's spending conditions. Bear in mind that both `scriptSig` and `scriptWitness` incorporate signatures. As such, you should complete all necessary signing operations before calling `inputFinalizer()`. Detailed [explanations on the `inputFinalizer` method](#signers-and-finalizers-finalize-psbt-input) can be found in the Signers and Finalizers section.
93
93
 
@@ -158,6 +158,7 @@ export declare function DescriptorsFactory(ecc: TinySecp256k1Interface): {
158
158
  txId?: string;
159
159
  value?: number;
160
160
  vout: number;
161
+ rbf?: boolean;
161
162
  }): number;
162
163
  /**
163
164
  * Sets this output as an input of the provided `psbt` and updates the
@@ -176,6 +177,14 @@ export declare function DescriptorsFactory(ecc: TinySecp256k1Interface): {
176
177
  *
177
178
  * When unsure, always use `txHex`, and skip `txId` and `value` for safety.
178
179
  *
180
+ * Use `rbf` to mark whether this tx can be replaced with another with
181
+ * higher fee while being in the mempool. Note that a tx will automatically
182
+ * be marked as replacable if a single input requests it.
183
+ * Note that any transaction using a relative timelock (nSequence < 0x80000000)
184
+ * also falls within the RBF range (nSequence < 0xFFFFFFFE), making it
185
+ * inherently replaceable. So don't set `rbf` to false if this is tx uses
186
+ * relative time locks.
187
+ *
179
188
  * @returns A finalizer function to be used after signing the `psbt`.
180
189
  * This function ensures that this input is properly finalized.
181
190
  * The finalizer has this signature:
@@ -183,12 +192,13 @@ export declare function DescriptorsFactory(ecc: TinySecp256k1Interface): {
183
192
  * `( { psbt, validate = true } : { psbt: Psbt; validate: boolean | undefined } ) => void`
184
193
  *
185
194
  */
186
- updatePsbtAsInput({ psbt, txHex, txId, value, vout }: {
195
+ updatePsbtAsInput({ psbt, txHex, txId, value, vout, rbf }: {
187
196
  psbt: Psbt;
188
197
  txHex?: string;
189
198
  txId?: string;
190
199
  value?: number;
191
200
  vout: number;
201
+ rbf?: boolean;
192
202
  }): ({ psbt, validate }: {
193
203
  psbt: Psbt;
194
204
  /** Runs further test on the validity of the signatures.
@@ -440,6 +450,7 @@ export declare function DescriptorsFactory(ecc: TinySecp256k1Interface): {
440
450
  txId?: string;
441
451
  value?: number;
442
452
  vout: number;
453
+ rbf?: boolean;
443
454
  }): number;
444
455
  /**
445
456
  * Sets this output as an input of the provided `psbt` and updates the
@@ -458,6 +469,14 @@ export declare function DescriptorsFactory(ecc: TinySecp256k1Interface): {
458
469
  *
459
470
  * When unsure, always use `txHex`, and skip `txId` and `value` for safety.
460
471
  *
472
+ * Use `rbf` to mark whether this tx can be replaced with another with
473
+ * higher fee while being in the mempool. Note that a tx will automatically
474
+ * be marked as replacable if a single input requests it.
475
+ * Note that any transaction using a relative timelock (nSequence < 0x80000000)
476
+ * also falls within the RBF range (nSequence < 0xFFFFFFFE), making it
477
+ * inherently replaceable. So don't set `rbf` to false if this is tx uses
478
+ * relative time locks.
479
+ *
461
480
  * @returns A finalizer function to be used after signing the `psbt`.
462
481
  * This function ensures that this input is properly finalized.
463
482
  * The finalizer has this signature:
@@ -465,12 +484,13 @@ export declare function DescriptorsFactory(ecc: TinySecp256k1Interface): {
465
484
  * `( { psbt, validate = true } : { psbt: Psbt; validate: boolean | undefined } ) => void`
466
485
  *
467
486
  */
468
- updatePsbtAsInput({ psbt, txHex, txId, value, vout }: {
487
+ updatePsbtAsInput({ psbt, txHex, txId, value, vout, rbf }: {
469
488
  psbt: Psbt;
470
489
  txHex?: string;
471
490
  txId?: string;
472
491
  value?: number;
473
492
  vout: number;
493
+ rbf?: boolean;
474
494
  }): ({ psbt, validate }: {
475
495
  psbt: Psbt;
476
496
  /** Runs further test on the validity of the signatures.
@@ -905,6 +905,14 @@ function DescriptorsFactory(ecc) {
905
905
  *
906
906
  * When unsure, always use `txHex`, and skip `txId` and `value` for safety.
907
907
  *
908
+ * Use `rbf` to mark whether this tx can be replaced with another with
909
+ * higher fee while being in the mempool. Note that a tx will automatically
910
+ * be marked as replacable if a single input requests it.
911
+ * Note that any transaction using a relative timelock (nSequence < 0x80000000)
912
+ * also falls within the RBF range (nSequence < 0xFFFFFFFE), making it
913
+ * inherently replaceable. So don't set `rbf` to false if this is tx uses
914
+ * relative time locks.
915
+ *
908
916
  * @returns A finalizer function to be used after signing the `psbt`.
909
917
  * This function ensures that this input is properly finalized.
910
918
  * The finalizer has this signature:
@@ -912,8 +920,8 @@ function DescriptorsFactory(ecc) {
912
920
  * `( { psbt, validate = true } : { psbt: Psbt; validate: boolean | undefined } ) => void`
913
921
  *
914
922
  */
915
- updatePsbtAsInput({ psbt, txHex, txId, value, vout //vector output index
916
- }) {
923
+ updatePsbtAsInput({ psbt, txHex, txId, value, vout, //vector output index
924
+ rbf = true }) {
917
925
  if (txHex === undefined) {
918
926
  console.warn(`Warning: missing txHex may allow fee attacks`);
919
927
  }
@@ -934,7 +942,8 @@ function DescriptorsFactory(ecc) {
934
942
  scriptPubKey: this.getScriptPubKey(),
935
943
  isSegwit,
936
944
  witnessScript: this.getWitnessScript(),
937
- redeemScript: this.getRedeemScript()
945
+ redeemScript: this.getRedeemScript(),
946
+ rbf
938
947
  });
939
948
  const finalizer = ({ psbt, validate = true }) => this.finalizePsbtInput({ index, psbt, validate });
940
949
  return finalizer;
@@ -1072,16 +1081,20 @@ function DescriptorsFactory(ecc) {
1072
1081
  scriptPubKey = out.script;
1073
1082
  }
1074
1083
  const locktime = this.getLockTime() || 0;
1075
- let sequence = this.getSequence();
1076
- if (sequence === undefined && locktime !== 0)
1077
- sequence = 0xfffffffe;
1078
- if (sequence === undefined && locktime === 0)
1079
- sequence = 0xffffffff;
1084
+ const sequence = this.getSequence();
1085
+ //We don't know whether the user opted for RBF or not. So check that
1086
+ //at least one of the 2 sequences matches.
1087
+ const sequenceNoRBF = sequence !== undefined
1088
+ ? sequence
1089
+ : locktime === 0
1090
+ ? 0xffffffff
1091
+ : 0xfffffffe;
1092
+ const sequenceRBF = sequence !== undefined ? sequence : 0xfffffffd;
1080
1093
  const eqBuffers = (buf1, buf2) => buf1 instanceof Buffer && buf2 instanceof Buffer
1081
1094
  ? Buffer.compare(buf1, buf2) === 0
1082
1095
  : buf1 === buf2;
1083
1096
  if (Buffer.compare(scriptPubKey, this.getScriptPubKey()) !== 0 ||
1084
- sequence !== inputSequence ||
1097
+ (sequenceRBF !== inputSequence && sequenceNoRBF !== inputSequence) ||
1085
1098
  locktime !== psbt.locktime ||
1086
1099
  !eqBuffers(this.getWitnessScript(), input.witnessScript) ||
1087
1100
  !eqBuffers(this.getRedeemScript(), input.redeemScript)) {
package/dist/psbt.d.ts CHANGED
@@ -21,7 +21,7 @@ export declare function finalScriptsFuncFactory(scriptSatisfaction: Buffer, netw
21
21
  /**
22
22
  * Important: Read comments on descriptor.updatePsbt regarding not passing txHex
23
23
  */
24
- export declare function updatePsbt({ psbt, vout, txHex, txId, value, sequence, locktime, keysInfo, scriptPubKey, isSegwit, witnessScript, redeemScript }: {
24
+ export declare function updatePsbt({ psbt, vout, txHex, txId, value, sequence, locktime, keysInfo, scriptPubKey, isSegwit, witnessScript, redeemScript, rbf }: {
25
25
  psbt: Psbt;
26
26
  vout: number;
27
27
  txHex?: string;
@@ -34,5 +34,6 @@ export declare function updatePsbt({ psbt, vout, txHex, txId, value, sequence, l
34
34
  isSegwit: boolean;
35
35
  witnessScript: Buffer | undefined;
36
36
  redeemScript: Buffer | undefined;
37
+ rbf: boolean;
37
38
  }): number;
38
39
  export {};
package/dist/psbt.js CHANGED
@@ -86,8 +86,10 @@ exports.finalScriptsFuncFactory = finalScriptsFuncFactory;
86
86
  /**
87
87
  * Important: Read comments on descriptor.updatePsbt regarding not passing txHex
88
88
  */
89
- function updatePsbt({ psbt, vout, txHex, txId, value, sequence, locktime, keysInfo, scriptPubKey, isSegwit, witnessScript, redeemScript }) {
89
+ function updatePsbt({ psbt, vout, txHex, txId, value, sequence, locktime, keysInfo, scriptPubKey, isSegwit, witnessScript, redeemScript, rbf }) {
90
90
  //Some data-sanity checks:
91
+ if (sequence !== undefined && rbf && sequence > 0xfffffffd)
92
+ throw new Error(`Error: incompatible sequence and rbf settings`);
91
93
  if (!isSegwit && txHex === undefined)
92
94
  throw new Error(`Error: txHex is mandatory for Non-Segwit inputs`);
93
95
  if (isSegwit &&
@@ -129,13 +131,23 @@ function updatePsbt({ psbt, vout, txHex, txId, value, sequence, locktime, keysIn
129
131
  // this input's sequence < 0xffffffff
130
132
  if (sequence === undefined) {
131
133
  //NOTE: if sequence is undefined, bitcoinjs-lib uses 0xffffffff as default
132
- sequence = 0xfffffffe;
134
+ sequence = rbf ? 0xfffffffd : 0xfffffffe;
133
135
  }
134
136
  else if (sequence > 0xfffffffe) {
135
137
  throw new Error(`Error: incompatible sequence: ${sequence} and locktime: ${locktime}`);
136
138
  }
139
+ if (sequence === undefined && rbf)
140
+ sequence = 0xfffffffd;
137
141
  psbt.setLocktime(locktime);
138
142
  }
143
+ else {
144
+ if (sequence === undefined) {
145
+ if (rbf)
146
+ sequence = 0xfffffffd;
147
+ else
148
+ sequence = 0xffffffff;
149
+ }
150
+ }
139
151
  const input = {
140
152
  hash: reverseBuffer(Buffer.from(txId, 'hex')),
141
153
  index: vout
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@bitcoinerlab/descriptors",
3
3
  "description": "This library parses and creates Bitcoin Miniscript Descriptors and generates Partially Signed Bitcoin Transactions (PSBTs). It provides PSBT finalizers and signers for single-signature, BIP32 and Hardware Wallets.",
4
4
  "homepage": "https://github.com/bitcoinerlab/descriptors",
5
- "version": "2.1.0",
5
+ "version": "2.2.0",
6
6
  "author": "Jose-Luis Landabaso",
7
7
  "license": "MIT",
8
8
  "repository": {
@@ -67,8 +67,8 @@
67
67
  "yargs": "^17.7.2"
68
68
  },
69
69
  "dependencies": {
70
- "@bitcoinerlab/miniscript": "^1.2.1",
71
- "@bitcoinerlab/secp256k1": "^1.0.5",
70
+ "@bitcoinerlab/miniscript": "^1.4.0",
71
+ "@bitcoinerlab/secp256k1": "^1.1.1",
72
72
  "bip32": "^4.0.0",
73
73
  "bitcoinjs-lib": "^6.1.3",
74
74
  "ecpair": "^2.1.0",