@scure/btc-signer 1.3.1 → 1.4.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 +7 -10
- package/_type_test.d.ts.map +1 -0
- package/_type_test.js.map +1 -0
- package/esm/_type_test.d.ts +2 -0
- package/esm/_type_test.js.map +1 -0
- package/{lib → esm}/index.d.ts +5 -4
- package/esm/index.d.ts.map +1 -0
- package/{lib/esm → esm}/index.js +10 -3
- package/esm/index.js.map +1 -0
- package/{lib → esm}/payment.d.ts.map +1 -1
- package/{lib/esm → esm}/payment.js +6 -6
- package/esm/payment.js.map +1 -0
- package/{lib → esm}/psbt.d.ts +2 -16
- package/esm/psbt.d.ts.map +1 -0
- package/{lib/esm → esm}/psbt.js +7 -9
- package/esm/psbt.js.map +1 -0
- package/{lib → esm}/script.d.ts +15 -1
- package/{lib → esm}/script.d.ts.map +1 -1
- package/{lib/esm → esm}/script.js +14 -5
- package/esm/script.js.map +1 -0
- package/{lib → esm}/transaction.d.ts +16 -10
- package/esm/transaction.d.ts.map +1 -0
- package/{lib/esm → esm}/transaction.js +45 -19
- package/esm/transaction.js.map +1 -0
- package/{lib → esm}/utils.d.ts +4 -4
- package/esm/utils.d.ts.map +1 -0
- package/{lib/esm → esm}/utils.js +3 -2
- package/esm/utils.js.map +1 -0
- package/{lib → esm}/utxo.d.ts +18 -21
- package/esm/utxo.d.ts.map +1 -0
- package/{lib/esm → esm}/utxo.js +68 -30
- package/esm/utxo.js.map +1 -0
- package/index.d.ts +20 -0
- package/index.d.ts.map +1 -0
- package/{lib/index.js → index.js} +10 -2
- package/index.js.map +1 -0
- package/package.json +41 -44
- package/payment.d.ts +177 -0
- package/payment.d.ts.map +1 -0
- package/{lib/payment.js → payment.js} +17 -17
- package/payment.js.map +1 -0
- package/psbt.d.ts +820 -0
- package/psbt.d.ts.map +1 -0
- package/{lib/psbt.js → psbt.js} +12 -14
- package/psbt.js.map +1 -0
- package/script.d.ts +168 -0
- package/script.d.ts.map +1 -0
- package/{lib/script.js → script.js} +17 -8
- package/script.js.map +1 -0
- package/src/index.ts +17 -3
- package/src/payment.ts +8 -8
- package/src/psbt.ts +7 -9
- package/src/script.ts +14 -5
- package/src/transaction.ts +50 -20
- package/src/utils.ts +3 -2
- package/src/utxo.ts +91 -26
- package/transaction.d.ts +229 -0
- package/transaction.d.ts.map +1 -0
- package/{lib/transaction.js → transaction.js} +56 -30
- package/transaction.js.map +1 -0
- package/utils.d.ts +30 -0
- package/utils.d.ts.map +1 -0
- package/{lib/utils.js → utils.js} +13 -11
- package/utils.js.map +1 -0
- package/utxo.d.ts +248 -0
- package/utxo.d.ts.map +1 -0
- package/{lib/utxo.js → utxo.js} +72 -34
- package/utxo.js.map +1 -0
- package/lib/_type_test.js.map +0 -1
- package/lib/esm/_type_test.js.map +0 -1
- package/lib/esm/index.js.map +0 -1
- package/lib/esm/payment.js.map +0 -1
- package/lib/esm/psbt.js.map +0 -1
- package/lib/esm/script.js.map +0 -1
- package/lib/esm/transaction.js.map +0 -1
- package/lib/esm/utils.js.map +0 -1
- package/lib/esm/utxo.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/payment.js.map +0 -1
- package/lib/psbt.d.ts.map +0 -1
- package/lib/psbt.js.map +0 -1
- package/lib/script.js.map +0 -1
- package/lib/transaction.d.ts.map +0 -1
- package/lib/transaction.js.map +0 -1
- package/lib/utils.d.ts.map +0 -1
- package/lib/utils.js.map +0 -1
- package/lib/utxo.d.ts.map +0 -1
- package/lib/utxo.js.map +0 -1
- /package/{lib/_type_test.d.ts → _type_test.d.ts} +0 -0
- /package/{lib/_type_test.js → _type_test.js} +0 -0
- /package/{lib → esm}/_type_test.d.ts.map +0 -0
- /package/{lib/esm → esm}/_type_test.js +0 -0
- /package/{lib/esm → esm}/package.json +0 -0
- /package/{lib → esm}/payment.d.ts +0 -0
package/src/transaction.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as P from 'micro-packed';
|
|
2
2
|
import { hex } from '@scure/base';
|
|
3
|
-
|
|
4
3
|
import { Address, CustomScript, OutScript, checkScript, tapLeafHash } from './payment.js';
|
|
5
4
|
import * as psbt from './psbt.js'; // circular
|
|
6
|
-
import { CompactSizeLen,
|
|
7
|
-
import {
|
|
5
|
+
import { CompactSizeLen, Script, VarBytes } from './script.js';
|
|
6
|
+
import { RawOutput, RawTx, RawOldTx, RawWitness } from './script.js';
|
|
7
|
+
import { NETWORK, Bytes, concatBytes, isBytes, equalBytes } from './utils.js';
|
|
8
8
|
import * as u from './utils.js';
|
|
9
9
|
import { getInputType, toVsize, normalizeInput, getPrevOut } from './utxo.js'; // circular
|
|
10
10
|
|
|
@@ -108,7 +108,7 @@ function getTaprootKeys(
|
|
|
108
108
|
internalKey: Bytes,
|
|
109
109
|
merkleRoot: Bytes = P.EMPTY
|
|
110
110
|
) {
|
|
111
|
-
if (
|
|
111
|
+
if (equalBytes(internalKey, pubKey)) {
|
|
112
112
|
privKey = u.taprootTweakPrivKey(privKey, merkleRoot);
|
|
113
113
|
pubKey = u.pubSchnorr(privKey);
|
|
114
114
|
}
|
|
@@ -284,6 +284,11 @@ export class Transaction {
|
|
|
284
284
|
toPSBT(PSBTVersion = this.opts.PSBTVersion) {
|
|
285
285
|
if (PSBTVersion !== 0 && PSBTVersion !== 2)
|
|
286
286
|
throw new Error(`Wrong PSBT version=${PSBTVersion}`);
|
|
287
|
+
// if (PSBTVersion === 0 && this.inputs.length === 0) {
|
|
288
|
+
// throw new Error(
|
|
289
|
+
// 'PSBT version=0 export for transaction without inputs disabled, please use version=2. Please check `toPSBT` method for explanation.'
|
|
290
|
+
// );
|
|
291
|
+
// }
|
|
287
292
|
const inputs = this.inputs.map((i) => psbt.cleanPSBTFields(PSBTVersion, psbt.PSBTInput, i));
|
|
288
293
|
for (const inp of inputs) {
|
|
289
294
|
// Don't serialize empty fields
|
|
@@ -294,7 +299,23 @@ export class Transaction {
|
|
|
294
299
|
const outputs = this.outputs.map((i) => psbt.cleanPSBTFields(PSBTVersion, psbt.PSBTOutput, i));
|
|
295
300
|
const global = { ...this.global };
|
|
296
301
|
if (PSBTVersion === 0) {
|
|
297
|
-
|
|
302
|
+
/*
|
|
303
|
+
- Bitcoin raw transaction expects to have at least 1 input because it uses case with zero inputs as marker for SegWit
|
|
304
|
+
- this means we cannot serialize raw tx with zero inputs since it will be parsed as SegWit tx
|
|
305
|
+
- Parsing of PSBTv0 depends on unsignedTx (it looks for input count here)
|
|
306
|
+
- BIP-174 requires old serialization format (without witnesses) inside global, which solves this
|
|
307
|
+
*/
|
|
308
|
+
global.unsignedTx = RawOldTx.decode(
|
|
309
|
+
RawOldTx.encode({
|
|
310
|
+
version: this.version,
|
|
311
|
+
lockTime: this.lockTime,
|
|
312
|
+
inputs: this.inputs.map(inputBeforeSign).map((i) => ({
|
|
313
|
+
...i,
|
|
314
|
+
finalScriptSig: P.EMPTY,
|
|
315
|
+
})),
|
|
316
|
+
outputs: this.outputs.map(outputBeforeSign),
|
|
317
|
+
})
|
|
318
|
+
);
|
|
298
319
|
delete global.fallbackLocktime;
|
|
299
320
|
delete global.txVersion;
|
|
300
321
|
} else {
|
|
@@ -502,6 +523,12 @@ export class Transaction {
|
|
|
502
523
|
this.checkOutputIdx(idx);
|
|
503
524
|
return cloneDeep(this.outputs[idx]);
|
|
504
525
|
}
|
|
526
|
+
getOutputAddress(idx: number, network = NETWORK): string | undefined {
|
|
527
|
+
const out = this.getOutput(idx);
|
|
528
|
+
if (!out.script) return;
|
|
529
|
+
return Address(network).encode(OutScript.decode(out.script));
|
|
530
|
+
}
|
|
531
|
+
|
|
505
532
|
get outputsLength() {
|
|
506
533
|
return this.outputs.length;
|
|
507
534
|
}
|
|
@@ -512,7 +539,10 @@ export class Transaction {
|
|
|
512
539
|
): psbt.TransactionOutput {
|
|
513
540
|
let { amount, script } = o;
|
|
514
541
|
if (amount === undefined) amount = cur?.amount;
|
|
515
|
-
if (typeof amount !== 'bigint')
|
|
542
|
+
if (typeof amount !== 'bigint')
|
|
543
|
+
throw new Error(
|
|
544
|
+
`Wrong amount type, should be of type bigint in sats, but got ${amount} of type ${typeof amount}`
|
|
545
|
+
);
|
|
516
546
|
if (typeof script === 'string') script = hex.decode(script);
|
|
517
547
|
if (script === undefined) script = cur?.script;
|
|
518
548
|
let res: psbt.PSBTKeyMapKeys<typeof psbt.PSBTOutput> = { ...cur, ...o, amount, script };
|
|
@@ -700,7 +730,7 @@ export class Transaction {
|
|
|
700
730
|
.map(([pubKey, { path }]) => {
|
|
701
731
|
let s = privateKey as HDKey;
|
|
702
732
|
for (const i of path) s = s.deriveChild(i);
|
|
703
|
-
if (!
|
|
733
|
+
if (!equalBytes(s.publicKey, pubKey)) throw new Error('bip32Derivation: wrong pubKey');
|
|
704
734
|
if (!s.privateKey) throw new Error('bip32Derivation: no privateKey');
|
|
705
735
|
return s;
|
|
706
736
|
});
|
|
@@ -735,7 +765,6 @@ export class Transaction {
|
|
|
735
765
|
// Taproot
|
|
736
766
|
const prevOut = getPrevOut(input);
|
|
737
767
|
if (inputType.txType === 'taproot') {
|
|
738
|
-
if (input.tapBip32Derivation) throw new Error('tapBip32Derivation unsupported');
|
|
739
768
|
const prevOuts = this.inputs.map(getPrevOut);
|
|
740
769
|
const prevOutScript = prevOuts.map((i) => i.script);
|
|
741
770
|
const amount = prevOuts.map((i) => i.amount);
|
|
@@ -754,7 +783,7 @@ export class Transaction {
|
|
|
754
783
|
merkleRoot
|
|
755
784
|
);
|
|
756
785
|
const [taprootPubKey, _] = u.taprootTweakPubkey(input.tapInternalKey, merkleRoot);
|
|
757
|
-
if (
|
|
786
|
+
if (equalBytes(taprootPubKey, pubKey)) {
|
|
758
787
|
const hash = this.preimageWitnessV1(idx, prevOutScript, sighash, amount);
|
|
759
788
|
const sig = concatBytes(
|
|
760
789
|
u.signSchnorr(hash, privKey, _auxRand),
|
|
@@ -772,7 +801,7 @@ export class Transaction {
|
|
|
772
801
|
const ver = _script[_script.length - 1];
|
|
773
802
|
const hash = tapLeafHash(script, ver);
|
|
774
803
|
// NOTE: no need to tweak internal key here, since we don't support nested p2tr
|
|
775
|
-
const pos = scriptDecoded.findIndex((i) => isBytes(i) &&
|
|
804
|
+
const pos = scriptDecoded.findIndex((i) => isBytes(i) && equalBytes(i, schnorrPub));
|
|
776
805
|
// Skip if there is no public key in tapLeafScript
|
|
777
806
|
if (pos === -1) continue;
|
|
778
807
|
const msg = this.preimageWitnessV1(
|
|
@@ -806,8 +835,7 @@ export class Transaction {
|
|
|
806
835
|
let hasPubkey = false;
|
|
807
836
|
const pubKeyHash = u.hash160(pubKey);
|
|
808
837
|
for (const i of Script.decode(inputType.lastScript)) {
|
|
809
|
-
if (isBytes(i) && (
|
|
810
|
-
hasPubkey = true;
|
|
838
|
+
if (isBytes(i) && (equalBytes(i, pubKey) || equalBytes(i, pubKeyHash))) hasPubkey = true;
|
|
811
839
|
}
|
|
812
840
|
if (!hasPubkey) throw new Error(`Input script doesn't have pubKey: ${inputType.lastScript}`);
|
|
813
841
|
let hash;
|
|
@@ -870,14 +898,14 @@ export class Transaction {
|
|
|
870
898
|
const ver = _script[_script.length - 1];
|
|
871
899
|
const outScript = OutScript.decode(script);
|
|
872
900
|
const hash = tapLeafHash(script, ver);
|
|
873
|
-
const scriptSig = input.tapScriptSig.filter((i) =>
|
|
901
|
+
const scriptSig = input.tapScriptSig.filter((i) => equalBytes(i[0].leafHash, hash));
|
|
874
902
|
let signatures: Bytes[] = [];
|
|
875
903
|
if (outScript.type === 'tr_ms') {
|
|
876
904
|
const m = outScript.m;
|
|
877
905
|
const pubkeys = outScript.pubkeys;
|
|
878
906
|
let added = 0;
|
|
879
907
|
for (const pub of pubkeys) {
|
|
880
|
-
const sigIdx = scriptSig.findIndex((i) =>
|
|
908
|
+
const sigIdx = scriptSig.findIndex((i) => equalBytes(i[0].pubKey, pub));
|
|
881
909
|
// Should have exact amount of signatures (more -- will fail)
|
|
882
910
|
if (added === m || sigIdx === -1) {
|
|
883
911
|
signatures.push(P.EMPTY);
|
|
@@ -890,7 +918,7 @@ export class Transaction {
|
|
|
890
918
|
if (added !== m) continue;
|
|
891
919
|
} else if (outScript.type === 'tr_ns') {
|
|
892
920
|
for (const pub of outScript.pubkeys) {
|
|
893
|
-
const sigIdx = scriptSig.findIndex((i) =>
|
|
921
|
+
const sigIdx = scriptSig.findIndex((i) => equalBytes(i[0].pubKey, pub));
|
|
894
922
|
if (sigIdx === -1) continue;
|
|
895
923
|
signatures.push(scriptSig[sigIdx][1]);
|
|
896
924
|
}
|
|
@@ -900,7 +928,7 @@ export class Transaction {
|
|
|
900
928
|
const scriptDecoded = Script.decode(script);
|
|
901
929
|
signatures = scriptSig
|
|
902
930
|
.map(([{ pubKey }, signature]) => {
|
|
903
|
-
const pos = scriptDecoded.findIndex((i) => isBytes(i) &&
|
|
931
|
+
const pos = scriptDecoded.findIndex((i) => isBytes(i) && equalBytes(i, pubKey));
|
|
904
932
|
if (pos === -1)
|
|
905
933
|
throw new Error('finalize/taproot: cannot find position of pubkey in script');
|
|
906
934
|
return { signature, pos };
|
|
@@ -951,7 +979,7 @@ export class Transaction {
|
|
|
951
979
|
let signatures = [];
|
|
952
980
|
// partial: [pubkey, sign]
|
|
953
981
|
for (const pub of pubkeys) {
|
|
954
|
-
const sign = input.partialSig.find((s) =>
|
|
982
|
+
const sign = input.partialSig.find((s) => equalBytes(pub, s[0]));
|
|
955
983
|
if (!sign) continue;
|
|
956
984
|
signatures.push(sign[1]);
|
|
957
985
|
}
|
|
@@ -1022,9 +1050,11 @@ export class Transaction {
|
|
|
1022
1050
|
);
|
|
1023
1051
|
}
|
|
1024
1052
|
}
|
|
1025
|
-
const thisUnsigned = this.global.unsignedTx ?
|
|
1026
|
-
const otherUnsigned = other.global.unsignedTx
|
|
1027
|
-
|
|
1053
|
+
const thisUnsigned = this.global.unsignedTx ? RawOldTx.encode(this.global.unsignedTx) : P.EMPTY;
|
|
1054
|
+
const otherUnsigned = other.global.unsignedTx
|
|
1055
|
+
? RawOldTx.encode(other.global.unsignedTx)
|
|
1056
|
+
: P.EMPTY;
|
|
1057
|
+
if (!equalBytes(thisUnsigned, otherUnsigned))
|
|
1028
1058
|
throw new Error(`Transaction/combine: different unsigned tx`);
|
|
1029
1059
|
this.global = psbt.mergeKeyMap(psbt.PSBTGlobal, this.global, other.global);
|
|
1030
1060
|
for (let i = 0; i < this.inputs.length; i++) this.updateInput(i, other.inputs[i], true);
|
package/src/utils.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { utils as packedUtils, U32LE } from 'micro-packed';
|
|
2
2
|
import { ripemd160 } from '@noble/hashes/ripemd160';
|
|
3
3
|
import { sha256 } from '@noble/hashes/sha256';
|
|
4
4
|
import { secp256k1 as secp, schnorr } from '@noble/curves/secp256k1';
|
|
@@ -7,7 +7,8 @@ export type Bytes = Uint8Array;
|
|
|
7
7
|
const Point = secp.ProjectivePoint;
|
|
8
8
|
const CURVE_ORDER = secp.CURVE.n;
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
const { isBytes, concatBytes, equalBytes } = packedUtils;
|
|
11
|
+
export { sha256, isBytes, concatBytes, equalBytes };
|
|
11
12
|
|
|
12
13
|
export const hash160 = (msg: Bytes) => ripemd160(sha256(msg));
|
|
13
14
|
export const sha256x2 = (...msgs: Bytes[]) => sha256(sha256(concatBytes(...msgs)));
|
package/src/utxo.ts
CHANGED
|
@@ -10,7 +10,15 @@ import {
|
|
|
10
10
|
SignatureHash,
|
|
11
11
|
Transaction,
|
|
12
12
|
} from './transaction.js'; // circular
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
NETWORK,
|
|
15
|
+
Bytes,
|
|
16
|
+
compareBytes,
|
|
17
|
+
equalBytes,
|
|
18
|
+
isBytes,
|
|
19
|
+
TAPROOT_UNSPENDABLE_KEY,
|
|
20
|
+
sha256,
|
|
21
|
+
} from './utils.js';
|
|
14
22
|
import { validatePubkey, PubT } from './utils.js';
|
|
15
23
|
|
|
16
24
|
// Normalizes input
|
|
@@ -153,7 +161,7 @@ function iterLeafs(tapLeafScript: TapLeafScript, sigSize: number, customScripts?
|
|
|
153
161
|
const csEncoded = c.encode(scriptDecoded);
|
|
154
162
|
if (csEncoded === undefined) continue;
|
|
155
163
|
const pubKeys = scriptDecoded.filter((i) => {
|
|
156
|
-
if (!
|
|
164
|
+
if (!isBytes(i)) return false;
|
|
157
165
|
try {
|
|
158
166
|
validatePubkey(i, PubT.schnorr);
|
|
159
167
|
return true;
|
|
@@ -187,7 +195,7 @@ function estimateInput(
|
|
|
187
195
|
// schnorr sig is always 64 bytes. except for cases when sighash is not default!
|
|
188
196
|
if (inputType.txType === 'taproot') {
|
|
189
197
|
const SCHNORR_SIG_SIZE = inputType.sighash !== SignatureHash.DEFAULT ? 65 : 64;
|
|
190
|
-
if (input.tapInternalKey && !
|
|
198
|
+
if (input.tapInternalKey && !equalBytes(input.tapInternalKey, TAPROOT_UNSPENDABLE_KEY)) {
|
|
191
199
|
witness = [new Uint8Array(SCHNORR_SIG_SIZE)];
|
|
192
200
|
} else if (input.tapLeafScript) {
|
|
193
201
|
witness = iterLeafs(input.tapLeafScript, SCHNORR_SIG_SIZE, opts.customScripts);
|
|
@@ -260,7 +268,10 @@ export type EstimatorOpts = TxOpts & {
|
|
|
260
268
|
bip69?: boolean; // https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki
|
|
261
269
|
network?: typeof NETWORK;
|
|
262
270
|
dust?: number; // how much vbytes considered dust?
|
|
271
|
+
dustRelayFeeRate?: bigint; // fee per dust byte (DUST_RELAY_TX_FEE)
|
|
263
272
|
createTx?: boolean; // Create tx inside selection
|
|
273
|
+
requiredInputs?: psbt.TransactionInputUpdate[]; // these inputs always will be used
|
|
274
|
+
allowSameUtxo?: boolean; // allow using UTXO multiple times (for test purposes)
|
|
264
275
|
};
|
|
265
276
|
|
|
266
277
|
function getScript(o: Output, opts: TxOpts = {}, network = NETWORK) {
|
|
@@ -274,7 +285,12 @@ function getScript(o: Output, opts: TxOpts = {}, network = NETWORK) {
|
|
|
274
285
|
script = OutScript.encode(Address(network).decode(o.address));
|
|
275
286
|
}
|
|
276
287
|
if (!script) throw new Error('Estimator: wrong output script');
|
|
277
|
-
if (typeof o.amount !== 'bigint')
|
|
288
|
+
if (typeof o.amount !== 'bigint')
|
|
289
|
+
throw new Error(
|
|
290
|
+
`Estimator: wrong output amount=${
|
|
291
|
+
o.amount
|
|
292
|
+
}, should be of type bigint but got ${typeof o.amount}.`
|
|
293
|
+
);
|
|
278
294
|
if (script && !opts.allowUnknownOutputs && OutScript.decode(script).type === 'unknown') {
|
|
279
295
|
throw new Error(
|
|
280
296
|
'Estimator: unknown output script type, there is a chance that input is unspendable. Pass allowUnknownOutputs=true, if you sure'
|
|
@@ -302,6 +318,7 @@ export class _Estimator {
|
|
|
302
318
|
private baseWeight: number;
|
|
303
319
|
private changeWeight: number;
|
|
304
320
|
private amount: bigint;
|
|
321
|
+
private requiredIndices: number[] = [];
|
|
305
322
|
private normalizedInputs: {
|
|
306
323
|
inputType: ReturnType<typeof getInputType>;
|
|
307
324
|
normalized: ReturnType<typeof normalizeInput>;
|
|
@@ -309,24 +326,51 @@ export class _Estimator {
|
|
|
309
326
|
value: bigint;
|
|
310
327
|
estimate: { weight: number; hasWitnesses: boolean };
|
|
311
328
|
}[];
|
|
312
|
-
// https://github.com/bitcoin/bitcoin/blob/f90603ac6d24f5263649675d51233f1fce8b2ecd/src/policy/policy.cpp#L44
|
|
313
|
-
// 32 + 4 + 1 + 107 + 4
|
|
314
329
|
// Dust used in accumExact + change address algo
|
|
315
330
|
// - change address: can be smaller for segwit
|
|
316
331
|
// - accumExact: ???
|
|
317
|
-
private dust
|
|
318
|
-
|
|
332
|
+
private dust: bigint; // total dust limit (3||opts.dustRelayFeeRate * 182||opts.dust). Default: 546
|
|
319
333
|
constructor(
|
|
320
|
-
|
|
334
|
+
inputs: psbt.TransactionInputUpdate[],
|
|
321
335
|
private outputs: Output[],
|
|
322
336
|
private opts: EstimatorOpts
|
|
323
337
|
) {
|
|
324
338
|
if (typeof opts.feePerByte !== 'bigint')
|
|
325
|
-
throw new Error(
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
339
|
+
throw new Error(
|
|
340
|
+
`Estimator: wrong feePerByte=${
|
|
341
|
+
opts.feePerByte
|
|
342
|
+
}, should be of type bigint but got ${typeof opts.feePerByte}.`
|
|
343
|
+
);
|
|
344
|
+
// Dust stuff
|
|
345
|
+
// TODO: think about this more:
|
|
346
|
+
// - current dust filters tx which cannot be relayed by core
|
|
347
|
+
// - but actual dust meaning is 'can be this amount spent?'
|
|
348
|
+
// - dust contains full tx size. but we can use other inputs to pay for outputDust (and parially inputsDust)?
|
|
349
|
+
// - not sure if we can spent anything with feePerByte: 3. It will be relayed, but will it be mined?
|
|
350
|
+
// - for now it works exactly as bitcoin-core. But will create change/outputs which cannot be spent (reasonable).
|
|
351
|
+
// Number of bytes needed to create and spend a UTXO.
|
|
352
|
+
// https://github.com/bitcoin/bitcoin/blob/27a770b34b8f1dbb84760f442edb3e23a0c2420b/src/policy/policy.cpp#L28-L41
|
|
353
|
+
const inputsDust = 32 + 4 + 1 + 107 + 4; // NOTE: can be smaller for segwit tx?
|
|
354
|
+
const outputDust = 34; // NOTE: 'nSize = GetSerializeSize(txout)'
|
|
355
|
+
const dustBytes = opts.dust === undefined ? BigInt(inputsDust + outputDust) : opts.dust;
|
|
356
|
+
if (typeof dustBytes !== 'bigint') {
|
|
357
|
+
throw new Error(
|
|
358
|
+
`Estimator: wrong dust=${opts.dust}, should be of type bigint but got ${typeof opts.dust}.`
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
// 3 sat/vb is the default minimum fee rate used to calculate dust thresholds by bitcoin core.
|
|
362
|
+
// 3000 sat/kvb -> 3 sat/vb.
|
|
363
|
+
// https://github.com/bitcoin/bitcoin/blob/27a770b34b8f1dbb84760f442edb3e23a0c2420b/src/policy/policy.h#L55
|
|
364
|
+
const dustFee = opts.dustRelayFeeRate === undefined ? 3n : opts.dustRelayFeeRate;
|
|
365
|
+
if (typeof dustFee !== 'bigint') {
|
|
366
|
+
throw new Error(
|
|
367
|
+
`Estimator: wrong dustRelayFeeRate=${opts.dustRelayFeeRate}, should be of type bigint but got ${typeof opts.dustRelayFeeRate}.`
|
|
368
|
+
);
|
|
329
369
|
}
|
|
370
|
+
// Dust uses feePerbyte by default, but we allow separate dust fee if needed
|
|
371
|
+
this.dust = dustBytes * dustFee;
|
|
372
|
+
if (opts.requiredInputs !== undefined && !Array.isArray(opts.requiredInputs))
|
|
373
|
+
throw new Error(`Estimator: wrong required inputs=${opts.requiredInputs}`);
|
|
330
374
|
const network = opts.network || NETWORK;
|
|
331
375
|
let amount = 0n;
|
|
332
376
|
// Base weight: tx with outputs, no inputs
|
|
@@ -348,9 +392,19 @@ export class _Estimator {
|
|
|
348
392
|
this.baseWeight = baseWeight;
|
|
349
393
|
this.changeWeight = changeWeight;
|
|
350
394
|
this.amount = amount;
|
|
351
|
-
|
|
395
|
+
const allInputs = Array.from(inputs);
|
|
396
|
+
if (opts.requiredInputs) {
|
|
397
|
+
for (let i = 0; i < opts.requiredInputs.length; i++)
|
|
398
|
+
this.requiredIndices.push(allInputs.push(opts.requiredInputs[i]) - 1);
|
|
399
|
+
}
|
|
400
|
+
const inputKeys = new Set();
|
|
401
|
+
this.normalizedInputs = allInputs.map((i) => {
|
|
352
402
|
const normalized = normalizeInput(i, undefined, undefined, opts.disableScriptCheck);
|
|
353
403
|
inputBeforeSign(normalized); // check fields
|
|
404
|
+
const key = `${hex.encode(normalized.txid!)}:${normalized.index}`;
|
|
405
|
+
if (!opts.allowSameUtxo && inputKeys.has(key))
|
|
406
|
+
throw new Error(`Estimator: same input passed multiple times: ${key}`);
|
|
407
|
+
inputKeys.add(key);
|
|
354
408
|
const inputType = getInputType(normalized, opts.allowLegacyWitnessUtxo);
|
|
355
409
|
const prev = getPrevOut(normalized);
|
|
356
410
|
const estimate = estimateInput(inputType, normalized, this.opts);
|
|
@@ -359,7 +413,7 @@ export class _Estimator {
|
|
|
359
413
|
});
|
|
360
414
|
}
|
|
361
415
|
private checkInputIdx(idx: number) {
|
|
362
|
-
if (!Number.isSafeInteger(idx) || 0 > idx || idx >= this.
|
|
416
|
+
if (!Number.isSafeInteger(idx) || 0 > idx || idx >= this.normalizedInputs.length)
|
|
363
417
|
throw new Error(`Wrong input index=${idx}`);
|
|
364
418
|
return idx;
|
|
365
419
|
}
|
|
@@ -389,7 +443,7 @@ export class _Estimator {
|
|
|
389
443
|
|
|
390
444
|
// Sort by value instead of amount
|
|
391
445
|
get biggest() {
|
|
392
|
-
return this.
|
|
446
|
+
return this.normalizedInputs
|
|
393
447
|
.map((_i, j) => j)
|
|
394
448
|
.sort((a, b) => _cmpBig(this.normalizedInputs[b].value, this.normalizedInputs[a].value));
|
|
395
449
|
}
|
|
@@ -400,7 +454,7 @@ export class _Estimator {
|
|
|
400
454
|
// Otherwise, we have no way to know which tx is oldest
|
|
401
455
|
// Explorers usually give UTXO in this order.
|
|
402
456
|
get oldest() {
|
|
403
|
-
return this.
|
|
457
|
+
return this.normalizedInputs.map((_i, j) => j);
|
|
404
458
|
}
|
|
405
459
|
get newest() {
|
|
406
460
|
return this.oldest.reverse();
|
|
@@ -409,7 +463,6 @@ export class _Estimator {
|
|
|
409
463
|
// exact(biggest) will select one big utxo which is closer to targetValue+dust, if possible.
|
|
410
464
|
// If not, it will accumulate largest utxo until value is close to targetValue+dust.
|
|
411
465
|
accumulate(indices: number[], exact = false, skipNegative = true, all = false) {
|
|
412
|
-
const { feePerByte } = this.opts;
|
|
413
466
|
// TODO: how to handle change addresses?
|
|
414
467
|
// - cost of input
|
|
415
468
|
// - cost of change output (if input requires change)
|
|
@@ -425,6 +478,22 @@ export class _Estimator {
|
|
|
425
478
|
const targetAmount = this.amount;
|
|
426
479
|
const res = [];
|
|
427
480
|
let fee;
|
|
481
|
+
for (const idx of this.requiredIndices) {
|
|
482
|
+
this.checkInputIdx(idx);
|
|
483
|
+
const { estimate, amount } = this.normalizedInputs[idx];
|
|
484
|
+
let newWeight = weight + estimate.weight;
|
|
485
|
+
if (!hasWitnesses && estimate.hasWitnesses) newWeight += 2; // enable witness if needed
|
|
486
|
+
const totalWeight = newWeight + 4 * CompactSizeLen.encode(num).length; // number of outputs can change weight
|
|
487
|
+
fee = this.getSatoshi(totalWeight);
|
|
488
|
+
weight = newWeight;
|
|
489
|
+
if (estimate.hasWitnesses) hasWitnesses = true;
|
|
490
|
+
num++;
|
|
491
|
+
inputsAmount += amount;
|
|
492
|
+
res.push(idx);
|
|
493
|
+
// inputsAmount is enough to cover cost of tx
|
|
494
|
+
if (!all && targetAmount + fee <= inputsAmount)
|
|
495
|
+
return { indices: res, fee, weight: totalWeight, total: inputsAmount };
|
|
496
|
+
}
|
|
428
497
|
for (const idx of indices) {
|
|
429
498
|
this.checkInputIdx(idx);
|
|
430
499
|
const { estimate, amount, value } = this.normalizedInputs[idx];
|
|
@@ -433,11 +502,7 @@ export class _Estimator {
|
|
|
433
502
|
const totalWeight = newWeight + 4 * CompactSizeLen.encode(num).length; // number of outputs can change weight
|
|
434
503
|
fee = this.getSatoshi(totalWeight);
|
|
435
504
|
// Best case scenario exact(biggest) -> we find biggest output, less than target+threshold
|
|
436
|
-
if (exact)
|
|
437
|
-
const dust = this.dust * feePerByte;
|
|
438
|
-
// skip if added value is bigger than dust
|
|
439
|
-
if (amount + inputsAmount > targetAmount + fee + dust) continue;
|
|
440
|
-
}
|
|
505
|
+
if (exact && amount + inputsAmount > targetAmount + fee + this.dust) continue; // skip if added value is bigger than dust
|
|
441
506
|
// Negative: cost of using input is more than value provided (negative)
|
|
442
507
|
// By default 'blackjack' mode in coinselect doesn't use that, which means
|
|
443
508
|
// it will use negative output if sorted by 'smallest'
|
|
@@ -448,7 +513,7 @@ export class _Estimator {
|
|
|
448
513
|
inputsAmount += amount;
|
|
449
514
|
res.push(idx);
|
|
450
515
|
// inputsAmount is enough to cover cost of tx
|
|
451
|
-
if (!all && targetAmount + fee
|
|
516
|
+
if (!all && targetAmount + fee <= inputsAmount)
|
|
452
517
|
return { indices: res, fee, weight: totalWeight, total: inputsAmount };
|
|
453
518
|
}
|
|
454
519
|
if (all) {
|
|
@@ -469,7 +534,7 @@ export class _Estimator {
|
|
|
469
534
|
private select(strategy: SelectionStrategy) {
|
|
470
535
|
if (strategy === 'all') {
|
|
471
536
|
return this.accumulate(
|
|
472
|
-
this.
|
|
537
|
+
this.normalizedInputs.map((_, j) => j),
|
|
473
538
|
false,
|
|
474
539
|
true,
|
|
475
540
|
true
|
|
@@ -523,7 +588,7 @@ export class _Estimator {
|
|
|
523
588
|
outputs = this.sortOutputs(outputs).map((i) => outputs[i]);
|
|
524
589
|
}
|
|
525
590
|
const res = {
|
|
526
|
-
inputs: inputs.map((i) => this.
|
|
591
|
+
inputs: inputs.map((i) => this.normalizedInputs[i].normalized),
|
|
527
592
|
outputs,
|
|
528
593
|
fee,
|
|
529
594
|
weight: this.opts.alwaysChange ? s.weight : changeWeight,
|
package/transaction.d.ts
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import * as P from 'micro-packed';
|
|
2
|
+
import { CustomScript } from './payment.js';
|
|
3
|
+
import * as psbt from './psbt.js';
|
|
4
|
+
import { Bytes } from './utils.js';
|
|
5
|
+
interface HDKey {
|
|
6
|
+
publicKey: Bytes;
|
|
7
|
+
privateKey: Bytes;
|
|
8
|
+
fingerprint: number;
|
|
9
|
+
derive(path: string): HDKey;
|
|
10
|
+
deriveChild(index: number): HDKey;
|
|
11
|
+
sign(hash: Bytes): Bytes;
|
|
12
|
+
}
|
|
13
|
+
export type Signer = Bytes | HDKey;
|
|
14
|
+
export declare const PRECISION = 8;
|
|
15
|
+
export declare const DEFAULT_VERSION = 2;
|
|
16
|
+
export declare const DEFAULT_LOCKTIME = 0;
|
|
17
|
+
export declare const DEFAULT_SEQUENCE = 4294967295;
|
|
18
|
+
export declare const Decimal: {
|
|
19
|
+
encode: (from: bigint) => string;
|
|
20
|
+
decode: (to: string) => bigint;
|
|
21
|
+
};
|
|
22
|
+
export declare const def: <T>(value: T | undefined, def: T) => T;
|
|
23
|
+
export declare function cloneDeep<T>(obj: T): T;
|
|
24
|
+
export type TxOpts = {
|
|
25
|
+
version?: number;
|
|
26
|
+
lockTime?: number;
|
|
27
|
+
PSBTVersion?: number;
|
|
28
|
+
/** @deprecated Use `allowUnknownOutputs` */
|
|
29
|
+
allowUnknowOutput?: boolean;
|
|
30
|
+
allowUnknownOutputs?: boolean;
|
|
31
|
+
/** @deprecated Use `allowUnknownInputs` */
|
|
32
|
+
allowUnknowInput?: boolean;
|
|
33
|
+
allowUnknownInputs?: boolean;
|
|
34
|
+
disableScriptCheck?: boolean;
|
|
35
|
+
bip174jsCompat?: boolean;
|
|
36
|
+
allowLegacyWitnessUtxo?: boolean;
|
|
37
|
+
lowR?: boolean;
|
|
38
|
+
customScripts?: CustomScript[];
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Internal, exported only for backwards-compat. Use `SigHash` instead.
|
|
42
|
+
* @deprecated
|
|
43
|
+
*/
|
|
44
|
+
export declare enum SignatureHash {
|
|
45
|
+
DEFAULT = 0,
|
|
46
|
+
ALL = 1,
|
|
47
|
+
NONE = 2,
|
|
48
|
+
SINGLE = 3,
|
|
49
|
+
ANYONECANPAY = 128
|
|
50
|
+
}
|
|
51
|
+
export declare enum SigHash {
|
|
52
|
+
DEFAULT = 0,
|
|
53
|
+
ALL = 1,
|
|
54
|
+
NONE = 2,
|
|
55
|
+
SINGLE = 3,
|
|
56
|
+
DEFAULT_ANYONECANPAY = 128,
|
|
57
|
+
ALL_ANYONECANPAY = 129,
|
|
58
|
+
NONE_ANYONECANPAY = 130,
|
|
59
|
+
SINGLE_ANYONECANPAY = 131
|
|
60
|
+
}
|
|
61
|
+
export type TransactionInputRequired = {
|
|
62
|
+
txid: Bytes;
|
|
63
|
+
index: number;
|
|
64
|
+
sequence: number;
|
|
65
|
+
finalScriptSig: Bytes;
|
|
66
|
+
};
|
|
67
|
+
export declare function inputBeforeSign(i: psbt.TransactionInput): TransactionInputRequired;
|
|
68
|
+
declare function validateOpts(opts: TxOpts): Readonly<{
|
|
69
|
+
version: number;
|
|
70
|
+
lockTime: number;
|
|
71
|
+
PSBTVersion: number;
|
|
72
|
+
/** @deprecated Use `allowUnknownOutputs` */
|
|
73
|
+
allowUnknowOutput?: boolean;
|
|
74
|
+
allowUnknownOutputs?: boolean;
|
|
75
|
+
/** @deprecated Use `allowUnknownInputs` */
|
|
76
|
+
allowUnknowInput?: boolean;
|
|
77
|
+
allowUnknownInputs?: boolean;
|
|
78
|
+
disableScriptCheck?: boolean;
|
|
79
|
+
bip174jsCompat?: boolean;
|
|
80
|
+
allowLegacyWitnessUtxo?: boolean;
|
|
81
|
+
lowR?: boolean;
|
|
82
|
+
customScripts?: CustomScript[];
|
|
83
|
+
}>;
|
|
84
|
+
export declare class Transaction {
|
|
85
|
+
private global;
|
|
86
|
+
private inputs;
|
|
87
|
+
private outputs;
|
|
88
|
+
readonly opts: ReturnType<typeof validateOpts>;
|
|
89
|
+
constructor(opts?: TxOpts);
|
|
90
|
+
static fromRaw(raw: Bytes, opts?: TxOpts): Transaction;
|
|
91
|
+
static fromPSBT(psbt_: Bytes, opts?: TxOpts): Transaction;
|
|
92
|
+
toPSBT(PSBTVersion?: number): Uint8Array;
|
|
93
|
+
get lockTime(): number;
|
|
94
|
+
get version(): number;
|
|
95
|
+
private inputStatus;
|
|
96
|
+
private inputSighash;
|
|
97
|
+
private signStatus;
|
|
98
|
+
get isFinal(): boolean;
|
|
99
|
+
get hasWitnesses(): boolean;
|
|
100
|
+
get weight(): number;
|
|
101
|
+
get vsize(): number;
|
|
102
|
+
toBytes(withScriptSig?: boolean, withWitness?: boolean): Uint8Array;
|
|
103
|
+
get unsignedTx(): Bytes;
|
|
104
|
+
get hex(): string;
|
|
105
|
+
get hash(): string;
|
|
106
|
+
get id(): string;
|
|
107
|
+
private checkInputIdx;
|
|
108
|
+
getInput(idx: number): psbt.PSBTKeyMapKeys<{
|
|
109
|
+
readonly nonWitnessUtxo: readonly [0, false, P.CoderType<P.StructInput<{
|
|
110
|
+
version: number;
|
|
111
|
+
segwitFlag: boolean | undefined;
|
|
112
|
+
inputs: P.StructInput<{
|
|
113
|
+
txid: any;
|
|
114
|
+
index: any;
|
|
115
|
+
finalScriptSig: any;
|
|
116
|
+
sequence: any;
|
|
117
|
+
}>[];
|
|
118
|
+
outputs: P.StructInput<{
|
|
119
|
+
amount: any;
|
|
120
|
+
script: any;
|
|
121
|
+
}>[];
|
|
122
|
+
witnesses: P.Option<Uint8Array[][]>;
|
|
123
|
+
lockTime: number;
|
|
124
|
+
}>>, readonly [], readonly [0, 2], false];
|
|
125
|
+
readonly witnessUtxo: readonly [1, false, P.CoderType<P.StructInput<{
|
|
126
|
+
amount: bigint;
|
|
127
|
+
script: Uint8Array;
|
|
128
|
+
}>>, readonly [], readonly [0, 2], false];
|
|
129
|
+
readonly partialSig: readonly [2, P.CoderType<Uint8Array>, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
130
|
+
readonly sighashType: readonly [3, false, P.CoderType<number>, readonly [], readonly [0, 2], false];
|
|
131
|
+
readonly redeemScript: readonly [4, false, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
132
|
+
readonly witnessScript: readonly [5, false, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
133
|
+
readonly bip32Derivation: readonly [6, P.CoderType<Uint8Array>, P.CoderType<P.StructInput<{
|
|
134
|
+
fingerprint: number;
|
|
135
|
+
path: number[];
|
|
136
|
+
}>>, readonly [], readonly [0, 2], false];
|
|
137
|
+
readonly finalScriptSig: readonly [7, false, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
138
|
+
readonly finalScriptWitness: readonly [8, false, P.CoderType<Uint8Array[]>, readonly [], readonly [0, 2], false];
|
|
139
|
+
readonly porCommitment: readonly [9, false, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
140
|
+
readonly ripemd160: readonly [10, P.CoderType<Uint8Array>, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
141
|
+
readonly sha256: readonly [11, P.CoderType<Uint8Array>, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
142
|
+
readonly hash160: readonly [12, P.CoderType<Uint8Array>, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
143
|
+
readonly hash256: readonly [13, P.CoderType<Uint8Array>, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
144
|
+
readonly txid: readonly [14, false, P.CoderType<Uint8Array>, readonly [2], readonly [2], true];
|
|
145
|
+
readonly index: readonly [15, false, P.CoderType<number>, readonly [2], readonly [2], true];
|
|
146
|
+
readonly sequence: readonly [16, false, P.CoderType<number>, readonly [], readonly [2], true];
|
|
147
|
+
readonly requiredTimeLocktime: readonly [17, false, P.CoderType<number>, readonly [], readonly [2], false];
|
|
148
|
+
readonly requiredHeightLocktime: readonly [18, false, P.CoderType<number>, readonly [], readonly [2], false];
|
|
149
|
+
readonly tapKeySig: readonly [19, false, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
150
|
+
readonly tapScriptSig: readonly [20, P.CoderType<P.StructInput<{
|
|
151
|
+
pubKey: Uint8Array;
|
|
152
|
+
leafHash: Uint8Array;
|
|
153
|
+
}>>, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
154
|
+
readonly tapLeafScript: readonly [21, P.CoderType<P.StructInput<{
|
|
155
|
+
version: number;
|
|
156
|
+
internalKey: Uint8Array;
|
|
157
|
+
merklePath: Uint8Array[];
|
|
158
|
+
}>>, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
159
|
+
readonly tapBip32Derivation: readonly [22, P.CoderType<Uint8Array>, P.CoderType<P.StructInput<{
|
|
160
|
+
hashes: Uint8Array[];
|
|
161
|
+
der: P.StructInput<{
|
|
162
|
+
fingerprint: any;
|
|
163
|
+
path: any;
|
|
164
|
+
}>;
|
|
165
|
+
}>>, readonly [], readonly [0, 2], false];
|
|
166
|
+
readonly tapInternalKey: readonly [23, false, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
167
|
+
readonly tapMerkleRoot: readonly [24, false, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
168
|
+
readonly proprietary: readonly [252, P.CoderType<Uint8Array>, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
169
|
+
}>;
|
|
170
|
+
get inputsLength(): number;
|
|
171
|
+
addInput(input: psbt.TransactionInputUpdate, _ignoreSignStatus?: boolean): number;
|
|
172
|
+
updateInput(idx: number, input: psbt.TransactionInputUpdate, _ignoreSignStatus?: boolean): void;
|
|
173
|
+
private checkOutputIdx;
|
|
174
|
+
getOutput(idx: number): psbt.PSBTKeyMapKeys<{
|
|
175
|
+
readonly redeemScript: readonly [0, false, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
176
|
+
readonly witnessScript: readonly [1, false, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
177
|
+
readonly bip32Derivation: readonly [2, P.CoderType<Uint8Array>, P.CoderType<P.StructInput<{
|
|
178
|
+
fingerprint: number;
|
|
179
|
+
path: number[];
|
|
180
|
+
}>>, readonly [], readonly [0, 2], false];
|
|
181
|
+
readonly amount: readonly [3, false, P.CoderType<bigint>, readonly [2], readonly [2], true];
|
|
182
|
+
readonly script: readonly [4, false, P.CoderType<Uint8Array>, readonly [2], readonly [2], true];
|
|
183
|
+
readonly tapInternalKey: readonly [5, false, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
184
|
+
readonly tapTree: readonly [6, false, P.CoderType<P.StructInput<{
|
|
185
|
+
depth: number;
|
|
186
|
+
version: number;
|
|
187
|
+
script: Uint8Array;
|
|
188
|
+
}>[]>, readonly [], readonly [0, 2], false];
|
|
189
|
+
readonly tapBip32Derivation: readonly [7, P.CoderType<Uint8Array>, P.CoderType<P.StructInput<{
|
|
190
|
+
hashes: Uint8Array[];
|
|
191
|
+
der: P.StructInput<{
|
|
192
|
+
fingerprint: any;
|
|
193
|
+
path: any;
|
|
194
|
+
}>;
|
|
195
|
+
}>>, readonly [], readonly [0, 2], false];
|
|
196
|
+
readonly proprietary: readonly [252, P.CoderType<Uint8Array>, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
197
|
+
}>;
|
|
198
|
+
getOutputAddress(idx: number, network?: {
|
|
199
|
+
bech32: string;
|
|
200
|
+
pubKeyHash: number;
|
|
201
|
+
scriptHash: number;
|
|
202
|
+
wif: number;
|
|
203
|
+
}): string | undefined;
|
|
204
|
+
get outputsLength(): number;
|
|
205
|
+
private normalizeOutput;
|
|
206
|
+
addOutput(o: psbt.TransactionOutputUpdate, _ignoreSignStatus?: boolean): number;
|
|
207
|
+
updateOutput(idx: number, output: psbt.TransactionOutputUpdate, _ignoreSignStatus?: boolean): void;
|
|
208
|
+
addOutputAddress(address: string, amount: bigint, network?: {
|
|
209
|
+
bech32: string;
|
|
210
|
+
pubKeyHash: number;
|
|
211
|
+
scriptHash: number;
|
|
212
|
+
wif: number;
|
|
213
|
+
}): number;
|
|
214
|
+
get fee(): bigint;
|
|
215
|
+
private preimageLegacy;
|
|
216
|
+
preimageWitnessV0(idx: number, prevOutScript: Bytes, hashType: number, amount: bigint): Uint8Array;
|
|
217
|
+
preimageWitnessV1(idx: number, prevOutScript: Bytes[], hashType: number, amount: bigint[], codeSeparator?: number, leafScript?: Bytes, leafVer?: number, annex?: Bytes): Uint8Array;
|
|
218
|
+
signIdx(privateKey: Signer, idx: number, allowedSighash?: SigHash[], _auxRand?: Bytes): boolean;
|
|
219
|
+
sign(privateKey: Signer, allowedSighash?: number[], _auxRand?: Bytes): number;
|
|
220
|
+
finalizeIdx(idx: number): void;
|
|
221
|
+
finalize(): void;
|
|
222
|
+
extract(): Uint8Array;
|
|
223
|
+
combine(other: Transaction): this;
|
|
224
|
+
clone(): Transaction;
|
|
225
|
+
}
|
|
226
|
+
export declare function PSBTCombine(psbts: Bytes[]): Bytes;
|
|
227
|
+
export declare function bip32Path(path: string): number[];
|
|
228
|
+
export {};
|
|
229
|
+
//# sourceMappingURL=transaction.d.ts.map
|