@scure/btc-signer 1.6.0 → 1.8.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 +194 -25
- package/esm/_type_test.js +1 -1
- package/esm/index.d.ts +12 -12
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +10 -10
- package/esm/index.js.map +1 -1
- package/esm/musig2.d.ts +148 -0
- package/esm/musig2.d.ts.map +1 -0
- package/esm/musig2.js +405 -0
- package/esm/musig2.js.map +1 -0
- package/esm/p2p.d.ts +38 -0
- package/esm/p2p.d.ts.map +1 -0
- package/esm/p2p.js +156 -0
- package/esm/p2p.js.map +1 -0
- package/esm/payment.d.ts +77 -21
- package/esm/payment.d.ts.map +1 -1
- package/esm/payment.js +63 -60
- package/esm/payment.js.map +1 -1
- package/esm/psbt.d.ts +463 -463
- package/esm/psbt.d.ts.map +1 -1
- package/esm/psbt.js +10 -39
- package/esm/psbt.js.map +1 -1
- package/esm/script.d.ts +16 -16
- package/esm/script.d.ts.map +1 -1
- package/esm/script.js +1 -1
- package/esm/transaction.d.ts +59 -6
- package/esm/transaction.d.ts.map +1 -1
- package/esm/transaction.js +154 -11
- package/esm/transaction.js.map +1 -1
- package/esm/utils.d.ts.map +1 -1
- package/esm/utxo.d.ts +73 -125
- package/esm/utxo.d.ts.map +1 -1
- package/esm/utxo.js +17 -122
- package/esm/utxo.js.map +1 -1
- package/index.d.ts +12 -12
- package/index.d.ts.map +1 -1
- package/index.js +58 -58
- package/index.js.map +1 -1
- package/musig2.d.ts +148 -0
- package/musig2.d.ts.map +1 -0
- package/musig2.js +417 -0
- package/musig2.js.map +1 -0
- package/p2p.d.ts +38 -0
- package/p2p.d.ts.map +1 -0
- package/p2p.js +158 -0
- package/p2p.js.map +1 -0
- package/package.json +15 -11
- package/payment.d.ts +77 -21
- package/payment.d.ts.map +1 -1
- package/payment.js +81 -78
- package/payment.js.map +1 -1
- package/psbt.d.ts +463 -463
- package/psbt.d.ts.map +1 -1
- package/psbt.js +30 -59
- package/psbt.js.map +1 -1
- package/script.d.ts +16 -16
- package/script.d.ts.map +1 -1
- package/script.js +3 -3
- package/src/_type_test.ts +1 -1
- package/src/index.ts +12 -12
- package/src/musig2.ts +517 -0
- package/src/p2p.ts +158 -0
- package/src/payment.ts +160 -75
- package/src/psbt.ts +11 -39
- package/src/script.ts +1 -1
- package/src/transaction.ts +170 -17
- package/src/utxo.ts +29 -122
- package/transaction.d.ts +59 -6
- package/transaction.d.ts.map +1 -1
- package/transaction.js +224 -77
- package/transaction.js.map +1 -1
- package/utils.d.ts.map +1 -1
- package/utxo.d.ts +73 -125
- package/utxo.d.ts.map +1 -1
- package/utxo.js +54 -163
- package/utxo.js.map +1 -1
package/src/transaction.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { hex } from '@scure/base';
|
|
2
2
|
import * as P from 'micro-packed';
|
|
3
|
-
import { Address, type CustomScript, OutScript, checkScript, tapLeafHash } from './payment.
|
|
4
|
-
import * as psbt from './psbt.
|
|
3
|
+
import { Address, type CustomScript, OutScript, checkScript, tapLeafHash } from './payment.ts';
|
|
4
|
+
import * as psbt from './psbt.ts';
|
|
5
5
|
import {
|
|
6
6
|
CompactSizeLen,
|
|
7
7
|
RawOldTx,
|
|
@@ -10,16 +10,16 @@ import {
|
|
|
10
10
|
RawWitness,
|
|
11
11
|
Script,
|
|
12
12
|
VarBytes,
|
|
13
|
-
} from './script.
|
|
14
|
-
import * as u from './utils.
|
|
15
|
-
import { type Bytes, NETWORK, concatBytes, equalBytes, isBytes } from './utils.
|
|
16
|
-
import { getInputType, getPrevOut, normalizeInput, toVsize } from './utxo.js'; // circular
|
|
13
|
+
} from './script.ts';
|
|
14
|
+
import * as u from './utils.ts';
|
|
15
|
+
import { type Bytes, NETWORK, concatBytes, equalBytes, isBytes } from './utils.ts';
|
|
17
16
|
|
|
18
17
|
const EMPTY32 = new Uint8Array(32);
|
|
19
18
|
const EMPTY_OUTPUT: P.UnwrapCoder<typeof RawOutput> = {
|
|
20
19
|
amount: 0xffffffffffffffffn,
|
|
21
20
|
script: P.EMPTY,
|
|
22
21
|
};
|
|
22
|
+
export const toVsize = (weight: number): number => Math.ceil(weight / 4);
|
|
23
23
|
|
|
24
24
|
// @scure/bip32 interface
|
|
25
25
|
interface HDKey {
|
|
@@ -61,7 +61,7 @@ export function cloneDeep<T>(obj: T): T {
|
|
|
61
61
|
|
|
62
62
|
// Mostly security features, hardened defaults;
|
|
63
63
|
// but you still can parse other people tx with unspendable outputs and stuff if you want
|
|
64
|
-
export
|
|
64
|
+
export interface TxOpts {
|
|
65
65
|
version?: number;
|
|
66
66
|
lockTime?: number;
|
|
67
67
|
PSBTVersion?: number;
|
|
@@ -84,7 +84,9 @@ export type TxOpts = {
|
|
|
84
84
|
allowLegacyWitnessUtxo?: boolean;
|
|
85
85
|
lowR?: boolean; // Use lowR signatures
|
|
86
86
|
customScripts?: CustomScript[]; // UNSAFE: Custom payment scripts
|
|
87
|
-
|
|
87
|
+
// Allow to add additional unknown keys/values to the "unknown" array member
|
|
88
|
+
allowUnknown?: boolean;
|
|
89
|
+
}
|
|
88
90
|
|
|
89
91
|
/**
|
|
90
92
|
* Internal, exported only for backwards-compat. Use `SigHash` instead.
|
|
@@ -228,6 +230,146 @@ function validateOpts(opts: TxOpts): Readonly<TxOpts> {
|
|
|
228
230
|
return Object.freeze(_opts);
|
|
229
231
|
}
|
|
230
232
|
|
|
233
|
+
// NOTE: we cannot do this inside PSBTInput coder, because there is no index/txid at this point!
|
|
234
|
+
function validateInput(i: psbt.TransactionInput): psbt.TransactionInput {
|
|
235
|
+
if (i.nonWitnessUtxo && i.index !== undefined) {
|
|
236
|
+
const last = i.nonWitnessUtxo.outputs.length - 1;
|
|
237
|
+
if (i.index > last) throw new Error(`validateInput: index(${i.index}) not in nonWitnessUtxo`);
|
|
238
|
+
const prevOut = i.nonWitnessUtxo.outputs[i.index];
|
|
239
|
+
if (
|
|
240
|
+
i.witnessUtxo &&
|
|
241
|
+
(!equalBytes(i.witnessUtxo.script, prevOut.script) || i.witnessUtxo.amount !== prevOut.amount)
|
|
242
|
+
)
|
|
243
|
+
throw new Error('validateInput: witnessUtxo different from nonWitnessUtxo');
|
|
244
|
+
if (i.txid) {
|
|
245
|
+
const outputs = i.nonWitnessUtxo.outputs;
|
|
246
|
+
if (outputs.length - 1 < i.index) throw new Error('nonWitnessUtxo: incorect output index');
|
|
247
|
+
// At this point, we are using previous tx output to create new input.
|
|
248
|
+
// Script safety checks are unnecessary:
|
|
249
|
+
// - User has no control over previous tx. If somebody send money in same tx
|
|
250
|
+
// as unspendable output, we still want user able to spend money
|
|
251
|
+
// - We still want some checks to notify user about possible errors early
|
|
252
|
+
// in case user wants to use wrong input by mistake
|
|
253
|
+
// - Worst case: tx will be rejected by nodes. Still better than disallowing user
|
|
254
|
+
// to spend real input, no matter how broken it looks
|
|
255
|
+
const tx = Transaction.fromRaw(RawTx.encode(i.nonWitnessUtxo), {
|
|
256
|
+
allowUnknownOutputs: true,
|
|
257
|
+
disableScriptCheck: true,
|
|
258
|
+
allowUnknownInputs: true,
|
|
259
|
+
});
|
|
260
|
+
const txid = hex.encode(i.txid);
|
|
261
|
+
// PSBTv2 vectors have non-final tx in inputs
|
|
262
|
+
if (tx.isFinal && tx.id !== txid)
|
|
263
|
+
throw new Error(`nonWitnessUtxo: wrong txid, exp=${txid} got=${tx.id}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return i;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export type PSBTInputs = psbt.PSBTKeyMapKeys<typeof psbt.PSBTInput>;
|
|
270
|
+
|
|
271
|
+
// Normalizes input
|
|
272
|
+
export function getPrevOut(input: psbt.TransactionInput): P.UnwrapCoder<typeof RawOutput> {
|
|
273
|
+
if (input.nonWitnessUtxo) {
|
|
274
|
+
if (input.index === undefined) throw new Error('Unknown input index');
|
|
275
|
+
return input.nonWitnessUtxo.outputs[input.index];
|
|
276
|
+
} else if (input.witnessUtxo) return input.witnessUtxo;
|
|
277
|
+
else throw new Error('Cannot find previous output info');
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export function normalizeInput(
|
|
281
|
+
i: psbt.TransactionInputUpdate,
|
|
282
|
+
cur?: psbt.TransactionInput,
|
|
283
|
+
allowedFields?: (keyof psbt.TransactionInput)[],
|
|
284
|
+
disableScriptCheck = false,
|
|
285
|
+
allowUnknown = false
|
|
286
|
+
): psbt.TransactionInput {
|
|
287
|
+
let { nonWitnessUtxo, txid } = i;
|
|
288
|
+
// String support for common fields. We usually prefer Uint8Array to avoid errors
|
|
289
|
+
// like hex looking string accidentally passed, however, in case of nonWitnessUtxo
|
|
290
|
+
// it is better to expect string, since constructing this complex object will be
|
|
291
|
+
// difficult for user
|
|
292
|
+
if (typeof nonWitnessUtxo === 'string') nonWitnessUtxo = hex.decode(nonWitnessUtxo);
|
|
293
|
+
if (isBytes(nonWitnessUtxo)) nonWitnessUtxo = RawTx.decode(nonWitnessUtxo);
|
|
294
|
+
if (!('nonWitnessUtxo' in i) && nonWitnessUtxo === undefined)
|
|
295
|
+
nonWitnessUtxo = cur?.nonWitnessUtxo;
|
|
296
|
+
if (typeof txid === 'string') txid = hex.decode(txid);
|
|
297
|
+
// TODO: if we have nonWitnessUtxo, we can extract txId from here
|
|
298
|
+
if (txid === undefined) txid = cur?.txid;
|
|
299
|
+
let res: PSBTInputs = { ...cur, ...i, nonWitnessUtxo, txid };
|
|
300
|
+
if (!('nonWitnessUtxo' in i) && res.nonWitnessUtxo === undefined) delete res.nonWitnessUtxo;
|
|
301
|
+
if (res.sequence === undefined) res.sequence = DEFAULT_SEQUENCE;
|
|
302
|
+
if (res.tapMerkleRoot === null) delete res.tapMerkleRoot;
|
|
303
|
+
res = psbt.mergeKeyMap(psbt.PSBTInput, res, cur, allowedFields, allowUnknown);
|
|
304
|
+
psbt.PSBTInputCoder.encode(res); // Validates that everything is correct at this point
|
|
305
|
+
|
|
306
|
+
let prevOut;
|
|
307
|
+
if (res.nonWitnessUtxo && res.index !== undefined)
|
|
308
|
+
prevOut = res.nonWitnessUtxo.outputs[res.index];
|
|
309
|
+
else if (res.witnessUtxo) prevOut = res.witnessUtxo;
|
|
310
|
+
if (prevOut && !disableScriptCheck)
|
|
311
|
+
checkScript(prevOut && prevOut.script, res.redeemScript, res.witnessScript);
|
|
312
|
+
return res;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export function getInputType(input: psbt.TransactionInput, allowLegacyWitnessUtxo = false) {
|
|
316
|
+
let txType = 'legacy';
|
|
317
|
+
let defaultSighash = SignatureHash.ALL;
|
|
318
|
+
const prevOut = getPrevOut(input);
|
|
319
|
+
const first = OutScript.decode(prevOut.script);
|
|
320
|
+
let type = first.type;
|
|
321
|
+
let cur = first;
|
|
322
|
+
const stack = [first];
|
|
323
|
+
if (first.type === 'tr') {
|
|
324
|
+
defaultSighash = SignatureHash.DEFAULT;
|
|
325
|
+
return {
|
|
326
|
+
txType: 'taproot',
|
|
327
|
+
type: 'tr',
|
|
328
|
+
last: first,
|
|
329
|
+
lastScript: prevOut.script,
|
|
330
|
+
defaultSighash,
|
|
331
|
+
sighash: input.sighashType || defaultSighash,
|
|
332
|
+
};
|
|
333
|
+
} else {
|
|
334
|
+
if (first.type === 'wpkh' || first.type === 'wsh') txType = 'segwit';
|
|
335
|
+
if (first.type === 'sh') {
|
|
336
|
+
if (!input.redeemScript) throw new Error('inputType: sh without redeemScript');
|
|
337
|
+
let child = OutScript.decode(input.redeemScript);
|
|
338
|
+
if (child.type === 'wpkh' || child.type === 'wsh') txType = 'segwit';
|
|
339
|
+
stack.push(child);
|
|
340
|
+
cur = child;
|
|
341
|
+
type += `-${child.type}`;
|
|
342
|
+
}
|
|
343
|
+
// wsh can be inside sh
|
|
344
|
+
if (cur.type === 'wsh') {
|
|
345
|
+
if (!input.witnessScript) throw new Error('inputType: wsh without witnessScript');
|
|
346
|
+
let child = OutScript.decode(input.witnessScript);
|
|
347
|
+
if (child.type === 'wsh') txType = 'segwit';
|
|
348
|
+
stack.push(child);
|
|
349
|
+
cur = child;
|
|
350
|
+
type += `-${child.type}`;
|
|
351
|
+
}
|
|
352
|
+
const last = stack[stack.length - 1];
|
|
353
|
+
if (last.type === 'sh' || last.type === 'wsh')
|
|
354
|
+
throw new Error('inputType: sh/wsh cannot be terminal type');
|
|
355
|
+
const lastScript = OutScript.encode(last);
|
|
356
|
+
const res = {
|
|
357
|
+
type,
|
|
358
|
+
txType,
|
|
359
|
+
last,
|
|
360
|
+
lastScript,
|
|
361
|
+
defaultSighash,
|
|
362
|
+
sighash: input.sighashType || defaultSighash,
|
|
363
|
+
};
|
|
364
|
+
if (txType === 'legacy' && !allowLegacyWitnessUtxo && !input.nonWitnessUtxo) {
|
|
365
|
+
throw new Error(
|
|
366
|
+
`Transaction/sign: legacy input without nonWitnessUtxo, can result in attack that forces paying higher fees. Pass allowLegacyWitnessUtxo=true, if you sure`
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
return res;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
231
373
|
export class Transaction {
|
|
232
374
|
private global: psbt.PSBTKeyMapKeys<typeof psbt.PSBTGlobal> = {};
|
|
233
375
|
private inputs: psbt.TransactionInput[] = []; // use getInput()
|
|
@@ -275,11 +417,13 @@ export class Transaction {
|
|
|
275
417
|
const tx = new Transaction({ ...opts, version, lockTime, PSBTVersion });
|
|
276
418
|
// We need slice here, because otherwise
|
|
277
419
|
const inputCount = PSBTVersion === 0 ? unsigned?.inputs.length : parsed.global.inputCount;
|
|
278
|
-
tx.inputs = parsed.inputs.slice(0, inputCount).map((i, j) =>
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
420
|
+
tx.inputs = parsed.inputs.slice(0, inputCount).map((i, j) =>
|
|
421
|
+
validateInput({
|
|
422
|
+
finalScriptSig: P.EMPTY,
|
|
423
|
+
...parsed.global.unsignedTx?.inputs[j],
|
|
424
|
+
...i,
|
|
425
|
+
})
|
|
426
|
+
);
|
|
283
427
|
const outputCount = PSBTVersion === 0 ? unsigned?.outputs.length : parsed.global.outputCount;
|
|
284
428
|
tx.outputs = parsed.outputs.slice(0, outputCount).map((i, j) => ({
|
|
285
429
|
...i,
|
|
@@ -297,7 +441,9 @@ export class Transaction {
|
|
|
297
441
|
// 'PSBT version=0 export for transaction without inputs disabled, please use version=2. Please check `toPSBT` method for explanation.'
|
|
298
442
|
// );
|
|
299
443
|
// }
|
|
300
|
-
const inputs = this.inputs.map((i) =>
|
|
444
|
+
const inputs = this.inputs.map((i) =>
|
|
445
|
+
validateInput(psbt.cleanPSBTFields(PSBTVersion, psbt.PSBTInput, i))
|
|
446
|
+
);
|
|
301
447
|
for (const inp of inputs) {
|
|
302
448
|
// Don't serialize empty fields
|
|
303
449
|
if (inp.partialSig && !inp.partialSig.length) delete inp.partialSig;
|
|
@@ -520,7 +666,8 @@ export class Transaction {
|
|
|
520
666
|
input,
|
|
521
667
|
this.inputs[idx],
|
|
522
668
|
allowedFields,
|
|
523
|
-
this.opts.disableScriptCheck
|
|
669
|
+
this.opts.disableScriptCheck,
|
|
670
|
+
this.opts.allowUnknown
|
|
524
671
|
);
|
|
525
672
|
}
|
|
526
673
|
// Output stuff
|
|
@@ -556,7 +703,7 @@ export class Transaction {
|
|
|
556
703
|
if (script === undefined) script = cur?.script;
|
|
557
704
|
let res: psbt.PSBTKeyMapKeys<typeof psbt.PSBTOutput> = { ...cur, ...o, amount, script };
|
|
558
705
|
if (res.amount === undefined) delete res.amount;
|
|
559
|
-
res = psbt.mergeKeyMap(psbt.PSBTOutput, res, cur, allowedFields);
|
|
706
|
+
res = psbt.mergeKeyMap(psbt.PSBTOutput, res, cur, allowedFields, this.opts.allowUnknown);
|
|
560
707
|
psbt.PSBTOutputCoder.encode(res);
|
|
561
708
|
if (
|
|
562
709
|
res.script &&
|
|
@@ -1070,7 +1217,13 @@ export class Transaction {
|
|
|
1070
1217
|
: P.EMPTY;
|
|
1071
1218
|
if (!equalBytes(thisUnsigned, otherUnsigned))
|
|
1072
1219
|
throw new Error(`Transaction/combine: different unsigned tx`);
|
|
1073
|
-
this.global = psbt.mergeKeyMap(
|
|
1220
|
+
this.global = psbt.mergeKeyMap(
|
|
1221
|
+
psbt.PSBTGlobal,
|
|
1222
|
+
this.global,
|
|
1223
|
+
other.global,
|
|
1224
|
+
undefined,
|
|
1225
|
+
this.opts.allowUnknown
|
|
1226
|
+
);
|
|
1074
1227
|
for (let i = 0; i < this.inputs.length; i++) this.updateInput(i, other.inputs[i], true);
|
|
1075
1228
|
for (let i = 0; i < this.outputs.length; i++) this.updateOutput(i, other.outputs[i], true);
|
|
1076
1229
|
return this;
|
package/src/utxo.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { hex } from '@scure/base';
|
|
2
2
|
import * as P from 'micro-packed';
|
|
3
|
-
import { Address, type CustomScript, OutScript, checkScript, tapLeafHash } from './payment.
|
|
4
|
-
import * as psbt from './psbt.
|
|
5
|
-
import { CompactSizeLen,
|
|
3
|
+
import { Address, type CustomScript, OutScript, checkScript, tapLeafHash } from './payment.ts';
|
|
4
|
+
import * as psbt from './psbt.ts';
|
|
5
|
+
import { CompactSizeLen, RawWitness, Script, VarBytes } from './script.ts';
|
|
6
6
|
import {
|
|
7
|
-
DEFAULT_SEQUENCE,
|
|
8
7
|
SignatureHash,
|
|
9
8
|
Transaction,
|
|
10
9
|
type TxOpts,
|
|
10
|
+
getInputType,
|
|
11
|
+
getPrevOut,
|
|
11
12
|
inputBeforeSign,
|
|
12
|
-
|
|
13
|
+
normalizeInput,
|
|
14
|
+
toVsize,
|
|
15
|
+
} from './transaction.ts';
|
|
13
16
|
import {
|
|
14
17
|
type Bytes,
|
|
15
18
|
NETWORK,
|
|
@@ -20,112 +23,8 @@ import {
|
|
|
20
23
|
isBytes,
|
|
21
24
|
sha256,
|
|
22
25
|
validatePubkey,
|
|
23
|
-
} from './utils.
|
|
26
|
+
} from './utils.ts';
|
|
24
27
|
|
|
25
|
-
export type PSBTInputs = psbt.PSBTKeyMapKeys<typeof psbt.PSBTInput>;
|
|
26
|
-
|
|
27
|
-
// Normalizes input
|
|
28
|
-
export function getPrevOut(input: psbt.TransactionInput): P.UnwrapCoder<typeof RawOutput> {
|
|
29
|
-
if (input.nonWitnessUtxo) {
|
|
30
|
-
if (input.index === undefined) throw new Error('Unknown input index');
|
|
31
|
-
return input.nonWitnessUtxo.outputs[input.index];
|
|
32
|
-
} else if (input.witnessUtxo) return input.witnessUtxo;
|
|
33
|
-
else throw new Error('Cannot find previous output info');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function normalizeInput(
|
|
37
|
-
i: psbt.TransactionInputUpdate,
|
|
38
|
-
cur?: psbt.TransactionInput,
|
|
39
|
-
allowedFields?: (keyof psbt.TransactionInput)[],
|
|
40
|
-
disableScriptCheck = false
|
|
41
|
-
): psbt.TransactionInput {
|
|
42
|
-
let { nonWitnessUtxo, txid } = i;
|
|
43
|
-
// String support for common fields. We usually prefer Uint8Array to avoid errors
|
|
44
|
-
// like hex looking string accidentally passed, however, in case of nonWitnessUtxo
|
|
45
|
-
// it is better to expect string, since constructing this complex object will be
|
|
46
|
-
// difficult for user
|
|
47
|
-
if (typeof nonWitnessUtxo === 'string') nonWitnessUtxo = hex.decode(nonWitnessUtxo);
|
|
48
|
-
if (isBytes(nonWitnessUtxo)) nonWitnessUtxo = RawTx.decode(nonWitnessUtxo);
|
|
49
|
-
if (!('nonWitnessUtxo' in i) && nonWitnessUtxo === undefined)
|
|
50
|
-
nonWitnessUtxo = cur?.nonWitnessUtxo;
|
|
51
|
-
if (typeof txid === 'string') txid = hex.decode(txid);
|
|
52
|
-
// TODO: if we have nonWitnessUtxo, we can extract txId from here
|
|
53
|
-
if (txid === undefined) txid = cur?.txid;
|
|
54
|
-
let res: PSBTInputs = { ...cur, ...i, nonWitnessUtxo, txid };
|
|
55
|
-
if (!('nonWitnessUtxo' in i) && res.nonWitnessUtxo === undefined) delete res.nonWitnessUtxo;
|
|
56
|
-
if (res.sequence === undefined) res.sequence = DEFAULT_SEQUENCE;
|
|
57
|
-
if (res.tapMerkleRoot === null) delete res.tapMerkleRoot;
|
|
58
|
-
res = psbt.mergeKeyMap(psbt.PSBTInput, res, cur, allowedFields);
|
|
59
|
-
psbt.PSBTInputCoder.encode(res); // Validates that everything is correct at this point
|
|
60
|
-
|
|
61
|
-
let prevOut;
|
|
62
|
-
if (res.nonWitnessUtxo && res.index !== undefined)
|
|
63
|
-
prevOut = res.nonWitnessUtxo.outputs[res.index];
|
|
64
|
-
else if (res.witnessUtxo) prevOut = res.witnessUtxo;
|
|
65
|
-
if (prevOut && !disableScriptCheck)
|
|
66
|
-
checkScript(prevOut && prevOut.script, res.redeemScript, res.witnessScript);
|
|
67
|
-
return res;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export function getInputType(input: psbt.TransactionInput, allowLegacyWitnessUtxo = false) {
|
|
71
|
-
let txType = 'legacy';
|
|
72
|
-
let defaultSighash = SignatureHash.ALL;
|
|
73
|
-
const prevOut = getPrevOut(input);
|
|
74
|
-
const first = OutScript.decode(prevOut.script);
|
|
75
|
-
let type = first.type;
|
|
76
|
-
let cur = first;
|
|
77
|
-
const stack = [first];
|
|
78
|
-
if (first.type === 'tr') {
|
|
79
|
-
defaultSighash = SignatureHash.DEFAULT;
|
|
80
|
-
return {
|
|
81
|
-
txType: 'taproot',
|
|
82
|
-
type: 'tr',
|
|
83
|
-
last: first,
|
|
84
|
-
lastScript: prevOut.script,
|
|
85
|
-
defaultSighash,
|
|
86
|
-
sighash: input.sighashType || defaultSighash,
|
|
87
|
-
};
|
|
88
|
-
} else {
|
|
89
|
-
if (first.type === 'wpkh' || first.type === 'wsh') txType = 'segwit';
|
|
90
|
-
if (first.type === 'sh') {
|
|
91
|
-
if (!input.redeemScript) throw new Error('inputType: sh without redeemScript');
|
|
92
|
-
let child = OutScript.decode(input.redeemScript);
|
|
93
|
-
if (child.type === 'wpkh' || child.type === 'wsh') txType = 'segwit';
|
|
94
|
-
stack.push(child);
|
|
95
|
-
cur = child;
|
|
96
|
-
type += `-${child.type}`;
|
|
97
|
-
}
|
|
98
|
-
// wsh can be inside sh
|
|
99
|
-
if (cur.type === 'wsh') {
|
|
100
|
-
if (!input.witnessScript) throw new Error('inputType: wsh without witnessScript');
|
|
101
|
-
let child = OutScript.decode(input.witnessScript);
|
|
102
|
-
if (child.type === 'wsh') txType = 'segwit';
|
|
103
|
-
stack.push(child);
|
|
104
|
-
cur = child;
|
|
105
|
-
type += `-${child.type}`;
|
|
106
|
-
}
|
|
107
|
-
const last = stack[stack.length - 1];
|
|
108
|
-
if (last.type === 'sh' || last.type === 'wsh')
|
|
109
|
-
throw new Error('inputType: sh/wsh cannot be terminal type');
|
|
110
|
-
const lastScript = OutScript.encode(last);
|
|
111
|
-
const res = {
|
|
112
|
-
type,
|
|
113
|
-
txType,
|
|
114
|
-
last,
|
|
115
|
-
lastScript,
|
|
116
|
-
defaultSighash,
|
|
117
|
-
sighash: input.sighashType || defaultSighash,
|
|
118
|
-
};
|
|
119
|
-
if (txType === 'legacy' && !allowLegacyWitnessUtxo && !input.nonWitnessUtxo) {
|
|
120
|
-
throw new Error(
|
|
121
|
-
`Transaction/sign: legacy input without nonWitnessUtxo, can result in attack that forces paying higher fees. Pass allowLegacyWitnessUtxo=true, if you sure`
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
return res;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export const toVsize = (weight: number): number => Math.ceil(weight / 4);
|
|
129
28
|
// UTXO Select
|
|
130
29
|
export type Output = { address: string; amount: bigint } | { script: Uint8Array; amount: bigint };
|
|
131
30
|
export type Accumulated =
|
|
@@ -341,11 +240,11 @@ export class _Estimator {
|
|
|
341
240
|
// - change address: can be smaller for segwit
|
|
342
241
|
// - accumExact: ???
|
|
343
242
|
private dust: bigint; // total dust limit (3||opts.dustRelayFeeRate * 182||opts.dust). Default: 546
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
243
|
+
private outputs: Output[];
|
|
244
|
+
private opts: EstimatorOpts;
|
|
245
|
+
constructor(inputs: psbt.TransactionInputUpdate[], outputs: Output[], opts: EstimatorOpts) {
|
|
246
|
+
this.outputs = outputs;
|
|
247
|
+
this.opts = opts;
|
|
349
248
|
if (typeof opts.feePerByte !== 'bigint')
|
|
350
249
|
throw new Error(
|
|
351
250
|
`Estimator: wrong feePerByte=${
|
|
@@ -410,7 +309,13 @@ export class _Estimator {
|
|
|
410
309
|
}
|
|
411
310
|
const inputKeys = new Set();
|
|
412
311
|
this.normalizedInputs = allInputs.map((i) => {
|
|
413
|
-
const normalized = normalizeInput(
|
|
312
|
+
const normalized = normalizeInput(
|
|
313
|
+
i,
|
|
314
|
+
undefined,
|
|
315
|
+
undefined,
|
|
316
|
+
opts.disableScriptCheck,
|
|
317
|
+
opts.allowUnknown
|
|
318
|
+
);
|
|
414
319
|
inputBeforeSign(normalized); // check fields
|
|
415
320
|
const key = `${hex.encode(normalized.txid!)}:${normalized.index}`;
|
|
416
321
|
if (!opts.allowSameUtxo && inputKeys.has(key))
|
|
@@ -487,10 +392,11 @@ export class _Estimator {
|
|
|
487
392
|
let num = 0;
|
|
488
393
|
let inputsAmount = 0n;
|
|
489
394
|
const targetAmount = this.amount;
|
|
490
|
-
const res =
|
|
395
|
+
const res: Set<number> = new Set();
|
|
491
396
|
let fee;
|
|
492
397
|
for (const idx of this.requiredIndices) {
|
|
493
398
|
this.checkInputIdx(idx);
|
|
399
|
+
if (res.has(idx)) throw new Error('required input encountered multiple times'); // should not happen
|
|
494
400
|
const { estimate, amount } = this.normalizedInputs[idx];
|
|
495
401
|
let newWeight = weight + estimate.weight;
|
|
496
402
|
if (!hasWitnesses && estimate.hasWitnesses) newWeight += 2; // enable witness if needed
|
|
@@ -500,13 +406,14 @@ export class _Estimator {
|
|
|
500
406
|
if (estimate.hasWitnesses) hasWitnesses = true;
|
|
501
407
|
num++;
|
|
502
408
|
inputsAmount += amount;
|
|
503
|
-
res.
|
|
409
|
+
res.add(idx);
|
|
504
410
|
// inputsAmount is enough to cover cost of tx
|
|
505
411
|
if (!all && targetAmount + fee <= inputsAmount)
|
|
506
|
-
return { indices: res, fee, weight: totalWeight, total: inputsAmount };
|
|
412
|
+
return { indices: Array.from(res), fee, weight: totalWeight, total: inputsAmount };
|
|
507
413
|
}
|
|
508
414
|
for (const idx of indices) {
|
|
509
415
|
this.checkInputIdx(idx);
|
|
416
|
+
if (res.has(idx)) continue; // skip required inputs
|
|
510
417
|
const { estimate, amount, value } = this.normalizedInputs[idx];
|
|
511
418
|
let newWeight = weight + estimate.weight;
|
|
512
419
|
if (!hasWitnesses && estimate.hasWitnesses) newWeight += 2; // enable witness if needed
|
|
@@ -522,14 +429,14 @@ export class _Estimator {
|
|
|
522
429
|
if (estimate.hasWitnesses) hasWitnesses = true;
|
|
523
430
|
num++;
|
|
524
431
|
inputsAmount += amount;
|
|
525
|
-
res.
|
|
432
|
+
res.add(idx);
|
|
526
433
|
// inputsAmount is enough to cover cost of tx
|
|
527
434
|
if (!all && targetAmount + fee <= inputsAmount)
|
|
528
|
-
return { indices: res, fee, weight: totalWeight, total: inputsAmount };
|
|
435
|
+
return { indices: Array.from(res), fee, weight: totalWeight, total: inputsAmount };
|
|
529
436
|
}
|
|
530
437
|
if (all) {
|
|
531
438
|
const newWeight = weight + 4 * CompactSizeLen.encode(num).length;
|
|
532
|
-
return { indices: res, fee, weight: newWeight, total: inputsAmount };
|
|
439
|
+
return { indices: Array.from(res), fee, weight: newWeight, total: inputsAmount };
|
|
533
440
|
}
|
|
534
441
|
return undefined;
|
|
535
442
|
}
|
package/transaction.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import * as P from 'micro-packed';
|
|
2
|
-
import { type CustomScript } from './payment.
|
|
3
|
-
import * as psbt from './psbt.
|
|
4
|
-
import
|
|
5
|
-
import
|
|
2
|
+
import { type CustomScript } from './payment.ts';
|
|
3
|
+
import * as psbt from './psbt.ts';
|
|
4
|
+
import { RawOutput } from './script.ts';
|
|
5
|
+
import * as u from './utils.ts';
|
|
6
|
+
import { type Bytes } from './utils.ts';
|
|
7
|
+
export declare const toVsize: (weight: number) => number;
|
|
6
8
|
interface HDKey {
|
|
7
9
|
publicKey: Bytes;
|
|
8
10
|
privateKey: Bytes;
|
|
@@ -19,7 +21,7 @@ export declare const DEFAULT_SEQUENCE = 4294967295;
|
|
|
19
21
|
export declare const Decimal: P.Coder<bigint, string>;
|
|
20
22
|
export declare const def: <T>(value: T | undefined, def: T) => T;
|
|
21
23
|
export declare function cloneDeep<T>(obj: T): T;
|
|
22
|
-
export
|
|
24
|
+
export interface TxOpts {
|
|
23
25
|
version?: number;
|
|
24
26
|
lockTime?: number;
|
|
25
27
|
PSBTVersion?: number;
|
|
@@ -34,7 +36,8 @@ export type TxOpts = {
|
|
|
34
36
|
allowLegacyWitnessUtxo?: boolean;
|
|
35
37
|
lowR?: boolean;
|
|
36
38
|
customScripts?: CustomScript[];
|
|
37
|
-
|
|
39
|
+
allowUnknown?: boolean;
|
|
40
|
+
}
|
|
38
41
|
/**
|
|
39
42
|
* Internal, exported only for backwards-compat. Use `SigHash` instead.
|
|
40
43
|
* @deprecated
|
|
@@ -64,6 +67,56 @@ export type TransactionInputRequired = {
|
|
|
64
67
|
};
|
|
65
68
|
export declare function inputBeforeSign(i: psbt.TransactionInput): TransactionInputRequired;
|
|
66
69
|
declare function validateOpts(opts: TxOpts): Readonly<TxOpts>;
|
|
70
|
+
export type PSBTInputs = psbt.PSBTKeyMapKeys<typeof psbt.PSBTInput>;
|
|
71
|
+
export declare function getPrevOut(input: psbt.TransactionInput): P.UnwrapCoder<typeof RawOutput>;
|
|
72
|
+
export declare function normalizeInput(i: psbt.TransactionInputUpdate, cur?: psbt.TransactionInput, allowedFields?: (keyof psbt.TransactionInput)[], disableScriptCheck?: boolean, allowUnknown?: boolean): psbt.TransactionInput;
|
|
73
|
+
export declare function getInputType(input: psbt.TransactionInput, allowLegacyWitnessUtxo?: boolean): {
|
|
74
|
+
type: string;
|
|
75
|
+
txType: string;
|
|
76
|
+
last: {
|
|
77
|
+
type: "p2a";
|
|
78
|
+
script: Bytes;
|
|
79
|
+
} | {
|
|
80
|
+
type: "pk";
|
|
81
|
+
pubkey: Bytes;
|
|
82
|
+
} | {
|
|
83
|
+
type: "pkh";
|
|
84
|
+
hash: Bytes;
|
|
85
|
+
} | {
|
|
86
|
+
type: "wpkh";
|
|
87
|
+
hash: Bytes;
|
|
88
|
+
} | {
|
|
89
|
+
type: "ms";
|
|
90
|
+
pubkeys: Bytes[];
|
|
91
|
+
m: number;
|
|
92
|
+
} | {
|
|
93
|
+
type: "tr";
|
|
94
|
+
pubkey: Bytes;
|
|
95
|
+
} | {
|
|
96
|
+
type: "tr_ns";
|
|
97
|
+
pubkeys: Bytes[];
|
|
98
|
+
} | {
|
|
99
|
+
type: "tr_ms";
|
|
100
|
+
pubkeys: Bytes[];
|
|
101
|
+
m: number;
|
|
102
|
+
} | {
|
|
103
|
+
type: "unknown";
|
|
104
|
+
script: Bytes;
|
|
105
|
+
};
|
|
106
|
+
lastScript: P.Bytes;
|
|
107
|
+
defaultSighash: SignatureHash.ALL;
|
|
108
|
+
sighash: number;
|
|
109
|
+
} | {
|
|
110
|
+
txType: string;
|
|
111
|
+
type: string;
|
|
112
|
+
last: {
|
|
113
|
+
type: "tr";
|
|
114
|
+
pubkey: Bytes;
|
|
115
|
+
};
|
|
116
|
+
lastScript: Uint8Array<ArrayBufferLike>;
|
|
117
|
+
defaultSighash: SignatureHash.DEFAULT;
|
|
118
|
+
sighash: number;
|
|
119
|
+
};
|
|
67
120
|
export declare class Transaction {
|
|
68
121
|
private global;
|
|
69
122
|
private inputs;
|
package/transaction.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["src/transaction.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAClC,OAAO,EAAW,KAAK,YAAY,EAAuC,MAAM,cAAc,CAAC;AAC/F,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["src/transaction.ts"],"names":[],"mappings":"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"}
|