@btc-vision/transaction 1.1.16 → 1.1.17
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/browser/_version.d.ts +1 -1
- package/browser/index.js +1 -1
- package/browser/keypair/Address.d.ts +2 -0
- package/browser/signer/SignerUtils.d.ts +6 -0
- package/browser/transaction/shared/TweakedTransaction.d.ts +5 -6
- package/browser/utxo/interfaces/IUTXO.d.ts +1 -0
- package/build/_version.d.ts +1 -1
- package/build/_version.js +1 -1
- package/build/keypair/Address.d.ts +2 -0
- package/build/keypair/Address.js +9 -0
- package/build/signer/SignerUtils.d.ts +6 -0
- package/build/signer/SignerUtils.js +56 -0
- package/build/transaction/browser/extensions/UnisatSigner.js +5 -32
- package/build/transaction/browser/extensions/XverseSigner.js +5 -48
- package/build/transaction/builders/FundingTransaction.js +6 -1
- package/build/transaction/builders/TransactionBuilder.js +3 -1
- package/build/transaction/shared/TweakedTransaction.d.ts +5 -6
- package/build/transaction/shared/TweakedTransaction.js +121 -91
- package/build/utils/BitcoinUtils.js +4 -4
- package/build/utxo/OPNetLimitedProvider.js +1 -0
- package/build/utxo/interfaces/IUTXO.d.ts +1 -0
- package/package.json +2 -5
- package/src/_version.ts +1 -1
- package/src/keypair/Address.ts +15 -0
- package/src/signer/SignerUtils.ts +78 -0
- package/src/transaction/TransactionFactory.ts +0 -253
- package/src/transaction/browser/extensions/UnisatSigner.ts +4 -40
- package/src/transaction/browser/extensions/XverseSigner.ts +9 -68
- package/src/transaction/builders/FundingTransaction.ts +7 -2
- package/src/transaction/builders/TransactionBuilder.ts +3 -1
- package/src/transaction/shared/TweakedTransaction.ts +224 -77
- package/src/utils/BitcoinUtils.ts +4 -4
- package/src/utxo/OPNetLimitedProvider.ts +1 -0
- package/src/utxo/interfaces/IUTXO.ts +2 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createHash } from 'crypto';
|
|
2
2
|
export class BitcoinUtils {
|
|
3
3
|
static btcToSatoshi(btc) {
|
|
4
4
|
return BigInt(btc * 100000000);
|
|
@@ -15,13 +15,13 @@ export class BitcoinUtils {
|
|
|
15
15
|
window.crypto.getRandomValues(array);
|
|
16
16
|
return Buffer.from(array);
|
|
17
17
|
}
|
|
18
|
-
else if (crypto && typeof crypto.getRandomValues === 'function') {
|
|
18
|
+
else if (globalThis.crypto && typeof globalThis.crypto.getRandomValues === 'function') {
|
|
19
19
|
const array = new Uint8Array(length);
|
|
20
|
-
crypto.getRandomValues(array);
|
|
20
|
+
globalThis.crypto.getRandomValues(array);
|
|
21
21
|
return Buffer.from(array);
|
|
22
22
|
}
|
|
23
23
|
else {
|
|
24
|
-
console.log(`No secure random number generator available. Please upgrade your environment.`, globalThis.window.crypto, crypto);
|
|
24
|
+
console.log(`No secure random number generator available. Please upgrade your environment.`, globalThis.window.crypto, globalThis.crypto);
|
|
25
25
|
throw new Error('No secure random number generator available. Please upgrade your environment.');
|
|
26
26
|
}
|
|
27
27
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@btc-vision/transaction",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.17",
|
|
5
5
|
"author": "BlobMaster41",
|
|
6
6
|
"description": "OPNet transaction library allows you to create and sign transactions for the OPNet network.",
|
|
7
7
|
"engines": {
|
|
@@ -63,9 +63,6 @@
|
|
|
63
63
|
"browserBuild": "webpack --mode production",
|
|
64
64
|
"docs": "typedoc --out docs --exclude 'src/tests/*.ts' --tsconfig tsconfig.json --readme README.md --name OPNet --plugin typedoc-material-theme --themeColor '#cb9820' --exclude src/tests/test.ts --exclude src/index.ts src"
|
|
65
65
|
},
|
|
66
|
-
"peerDependencies": {
|
|
67
|
-
"@btc-vision/bitcoin": "^6.3.0"
|
|
68
|
-
},
|
|
69
66
|
"devDependencies": {
|
|
70
67
|
"@babel/core": "^7.26.0",
|
|
71
68
|
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
|
@@ -94,7 +91,7 @@
|
|
|
94
91
|
"dependencies": {
|
|
95
92
|
"@babel/plugin-proposal-object-rest-spread": "^7.20.7",
|
|
96
93
|
"@bitcoinerlab/secp256k1": "^1.1.1",
|
|
97
|
-
"@btc-vision/bitcoin": "^6.3.
|
|
94
|
+
"@btc-vision/bitcoin": "^6.3.1",
|
|
98
95
|
"@btc-vision/bsi-bitcoin-rpc": "^1.0.29",
|
|
99
96
|
"@btc-vision/logger": "^1.0.6",
|
|
100
97
|
"@eslint/js": "^9.14.0",
|
package/src/_version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '1.1.
|
|
1
|
+
export const version = '1.1.17';
|
package/src/keypair/Address.ts
CHANGED
|
@@ -104,6 +104,14 @@ export class Address extends Uint8Array {
|
|
|
104
104
|
return Buffer.from(this);
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
public originalPublicKeyBuffer(): Buffer {
|
|
108
|
+
if (!this.#originalPublicKey) {
|
|
109
|
+
throw new Error('Public key not set');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return Buffer.from(this.#originalPublicKey);
|
|
113
|
+
}
|
|
114
|
+
|
|
107
115
|
public equals(a: Address): boolean {
|
|
108
116
|
const b: Address = this as Address;
|
|
109
117
|
|
|
@@ -200,6 +208,13 @@ export class Address extends Uint8Array {
|
|
|
200
208
|
return AddressVerificator.isValidPublicKey(Buffer.from(this).toString('hex'), network);
|
|
201
209
|
}
|
|
202
210
|
|
|
211
|
+
/**
|
|
212
|
+
* Get the public key as address
|
|
213
|
+
*/
|
|
214
|
+
public p2pk(): string {
|
|
215
|
+
return this.toHex();
|
|
216
|
+
}
|
|
217
|
+
|
|
203
218
|
/**
|
|
204
219
|
* Get the address in p2wpkh format
|
|
205
220
|
* @param {Network} network The network
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// Helper functions
|
|
2
|
+
import { crypto as bitCrypto, PsbtInput } from '@btc-vision/bitcoin';
|
|
3
|
+
import { isP2TR } from '@btc-vision/bitcoin/src/psbt/psbtutils.js';
|
|
4
|
+
import { toXOnly } from '@btc-vision/bitcoin/src/psbt/bip371.js';
|
|
5
|
+
import * as bscript from '@btc-vision/bitcoin/src/script.js';
|
|
6
|
+
|
|
7
|
+
export function isTaprootInput(input: PsbtInput): boolean {
|
|
8
|
+
return (
|
|
9
|
+
input &&
|
|
10
|
+
!!(
|
|
11
|
+
input.tapInternalKey ||
|
|
12
|
+
input.tapMerkleRoot ||
|
|
13
|
+
(input.tapLeafScript && input.tapLeafScript.length) ||
|
|
14
|
+
(input.tapBip32Derivation && input.tapBip32Derivation.length) ||
|
|
15
|
+
(input.witnessUtxo && isP2TR(input.witnessUtxo.script))
|
|
16
|
+
)
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function getInputRelevantScript(input: PsbtInput): Buffer | null {
|
|
21
|
+
if (input.redeemScript) {
|
|
22
|
+
return input.redeemScript;
|
|
23
|
+
}
|
|
24
|
+
if (input.witnessScript) {
|
|
25
|
+
return input.witnessScript;
|
|
26
|
+
}
|
|
27
|
+
if (input.witnessUtxo) {
|
|
28
|
+
return input.witnessUtxo.script;
|
|
29
|
+
}
|
|
30
|
+
if (input.nonWitnessUtxo) {
|
|
31
|
+
// Parse the full transaction from nonWitnessUtxo
|
|
32
|
+
/*const tx = Transaction.fromBuffer(input.nonWitnessUtxo);
|
|
33
|
+
// Retrieve the output referenced by the input index
|
|
34
|
+
const out = tx.outs[input.index];
|
|
35
|
+
if (!out) {
|
|
36
|
+
throw new Error(`No output at index ${input.index} in nonWitnessUtxo`);
|
|
37
|
+
}
|
|
38
|
+
return out.script;*/
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function canSignNonTaprootInput(input: PsbtInput, publicKey: Buffer): boolean {
|
|
44
|
+
if (
|
|
45
|
+
(input.nonWitnessUtxo &&
|
|
46
|
+
!input.redeemScript &&
|
|
47
|
+
!input.witnessScript &&
|
|
48
|
+
!input.witnessUtxo) ||
|
|
49
|
+
input.redeemScript
|
|
50
|
+
) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const script = getInputRelevantScript(input);
|
|
55
|
+
if (script) {
|
|
56
|
+
return pubkeyInScript(publicKey, script);
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function pubkeyPositionInScript(pubkey: Buffer, script: Buffer): number {
|
|
62
|
+
const pubkeyHash = bitCrypto.hash160(pubkey);
|
|
63
|
+
const pubkeyXOnly = toXOnly(pubkey);
|
|
64
|
+
|
|
65
|
+
const decompiled = bscript.decompile(script);
|
|
66
|
+
if (decompiled === null) throw new Error('Unknown script error');
|
|
67
|
+
|
|
68
|
+
const a = decompiled.findIndex((element) => {
|
|
69
|
+
if (typeof element === 'number') return false;
|
|
70
|
+
return element.equals(pubkey) || element.equals(pubkeyHash) || element.equals(pubkeyXOnly);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
return a;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function pubkeyInScript(pubkey: Buffer, script: Buffer): boolean {
|
|
77
|
+
return pubkeyPositionInScript(pubkey, script) !== -1;
|
|
78
|
+
}
|
|
@@ -51,15 +51,6 @@ export interface BitcoinTransferResponse {
|
|
|
51
51
|
readonly nextUTXOs: UTXO[];
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
/*export interface UnwrapResult {
|
|
55
|
-
readonly fundingTransaction: string;
|
|
56
|
-
readonly psbt: string;
|
|
57
|
-
|
|
58
|
-
readonly feeRefundOrLoss: bigint;
|
|
59
|
-
|
|
60
|
-
readonly utxos: UTXO[];
|
|
61
|
-
}*/
|
|
62
|
-
|
|
63
54
|
export class TransactionFactory {
|
|
64
55
|
/**
|
|
65
56
|
* @description Generate a transaction with a custom script.
|
|
@@ -283,220 +274,6 @@ export class TransactionFactory {
|
|
|
283
274
|
};
|
|
284
275
|
}
|
|
285
276
|
|
|
286
|
-
/**
|
|
287
|
-
* Basically it's fun to manage UTXOs.
|
|
288
|
-
* @param {IWrapParameters} wrapParameters - The wrap parameters
|
|
289
|
-
* @returns {Promise<WrapResult>} - The signed transaction
|
|
290
|
-
* @throws {Error} - If the transaction could not be signed
|
|
291
|
-
*/
|
|
292
|
-
/*public async wrap(wrapParameters: Omit<IWrapParameters, 'calldata'>): Promise<WrapResult> {
|
|
293
|
-
if (wrapParameters.amount < currentConsensusConfig.VAULT_MINIMUM_AMOUNT) {
|
|
294
|
-
throw new Error(
|
|
295
|
-
`Amount is too low. Minimum consolidation is ${currentConsensusConfig.VAULT_MINIMUM_AMOUNT} sat. Received ${wrapParameters.amount} sat. Make sure that you cover the unwrap consolidation fees of ${currentConsensusConfig.UNWRAP_CONSOLIDATION_PREPAID_FEES_SAT}sat.`,
|
|
296
|
-
);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
const childTransactionRequiredValue: bigint =
|
|
300
|
-
wrapParameters.amount +
|
|
301
|
-
currentConsensusConfig.UNWRAP_CONSOLIDATION_PREPAID_FEES_SAT +
|
|
302
|
-
this.getPriorityFee(wrapParameters);
|
|
303
|
-
|
|
304
|
-
const wbtc: wBTC = new wBTC(wrapParameters.network, wrapParameters.chainId);
|
|
305
|
-
const to = wbtc.getAddress();
|
|
306
|
-
const fundingParameters: IFundingTransactionParameters = {
|
|
307
|
-
...wrapParameters,
|
|
308
|
-
amount: childTransactionRequiredValue,
|
|
309
|
-
to: wrapParameters.to ?? to,
|
|
310
|
-
};
|
|
311
|
-
|
|
312
|
-
const preFundingTransaction = await this.createFundTransaction(fundingParameters);
|
|
313
|
-
wrapParameters.utxos = this.getUTXOAsTransaction(preFundingTransaction.tx, to, 0);
|
|
314
|
-
|
|
315
|
-
const preTransaction: WrapTransaction = new WrapTransaction(wrapParameters);
|
|
316
|
-
|
|
317
|
-
// Initial generation
|
|
318
|
-
await preTransaction.signTransaction();
|
|
319
|
-
|
|
320
|
-
const parameters: IFundingTransactionParameters =
|
|
321
|
-
await preTransaction.getFundingTransactionParameters();
|
|
322
|
-
|
|
323
|
-
// We add the amount
|
|
324
|
-
parameters.amount += childTransactionRequiredValue;
|
|
325
|
-
parameters.utxos = fundingParameters.utxos;
|
|
326
|
-
|
|
327
|
-
const signedTransaction = await this.createFundTransaction(parameters);
|
|
328
|
-
if (!signedTransaction) {
|
|
329
|
-
throw new Error('Could not sign funding transaction.');
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
const newParams: IWrapParameters = {
|
|
333
|
-
...wrapParameters,
|
|
334
|
-
utxos: this.getUTXOAsTransaction(signedTransaction.tx, to, 0), // always 0
|
|
335
|
-
randomBytes: preTransaction.getRndBytes(),
|
|
336
|
-
nonWitnessUtxo: signedTransaction.tx.toBuffer(),
|
|
337
|
-
};
|
|
338
|
-
|
|
339
|
-
const finalTransaction: WrapTransaction = new WrapTransaction(newParams);
|
|
340
|
-
|
|
341
|
-
// We have to regenerate using the new utxo
|
|
342
|
-
const outTx: Transaction = await finalTransaction.signTransaction();
|
|
343
|
-
return {
|
|
344
|
-
transaction: [signedTransaction.tx.toHex(), outTx.toHex()],
|
|
345
|
-
vaultAddress: finalTransaction.vault,
|
|
346
|
-
amount: finalTransaction.amount,
|
|
347
|
-
receiverAddress: finalTransaction.receiver.p2tr(wrapParameters.network),
|
|
348
|
-
utxos: this.getUTXOAsTransaction(signedTransaction.tx, wrapParameters.from, 1),
|
|
349
|
-
};
|
|
350
|
-
}*/
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Unwrap bitcoin.
|
|
354
|
-
* @param {IUnwrapParameters} unwrapParameters - The unwrap parameters
|
|
355
|
-
* @returns {Promise<UnwrapResult>} - The signed transaction
|
|
356
|
-
* @throws {Error} - If the transaction could not be signed
|
|
357
|
-
* @deprecated
|
|
358
|
-
*/
|
|
359
|
-
/*public async unwrapSegwit(unwrapParameters: IUnwrapParameters): Promise<UnwrapResult> {
|
|
360
|
-
console.error('The "unwrap" method is deprecated. Use unwrapTap instead.');
|
|
361
|
-
|
|
362
|
-
const transaction: UnwrapSegwitTransaction = new UnwrapSegwitTransaction(unwrapParameters);
|
|
363
|
-
await transaction.signTransaction();
|
|
364
|
-
|
|
365
|
-
const to = transaction.toAddress();
|
|
366
|
-
if (!to) throw new Error('To address is required');
|
|
367
|
-
|
|
368
|
-
// Initial generation
|
|
369
|
-
const estimatedGas = await transaction.estimateTransactionFees();
|
|
370
|
-
const estimatedFees = transaction.preEstimateTransactionFees(
|
|
371
|
-
BigInt(unwrapParameters.feeRate),
|
|
372
|
-
this.calculateNumInputs(unwrapParameters.unwrapUTXOs),
|
|
373
|
-
2n,
|
|
374
|
-
this.calculateNumSignatures(unwrapParameters.unwrapUTXOs),
|
|
375
|
-
this.maxPubKeySize(unwrapParameters.unwrapUTXOs),
|
|
376
|
-
);
|
|
377
|
-
|
|
378
|
-
const fundingParameters: IFundingTransactionParameters = {
|
|
379
|
-
...unwrapParameters,
|
|
380
|
-
amount: estimatedGas + estimatedFees,
|
|
381
|
-
to: to,
|
|
382
|
-
};
|
|
383
|
-
|
|
384
|
-
const preFundingTransaction = await this.createFundTransaction(fundingParameters);
|
|
385
|
-
unwrapParameters.utxos = this.getUTXOAsTransaction(preFundingTransaction.tx, to, 0);
|
|
386
|
-
|
|
387
|
-
const preTransaction: UnwrapSegwitTransaction = new UnwrapSegwitTransaction({
|
|
388
|
-
...unwrapParameters,
|
|
389
|
-
randomBytes: transaction.getRndBytes(),
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
// Initial generation
|
|
393
|
-
await preTransaction.signTransaction();
|
|
394
|
-
|
|
395
|
-
const parameters: IFundingTransactionParameters =
|
|
396
|
-
await preTransaction.getFundingTransactionParameters();
|
|
397
|
-
|
|
398
|
-
parameters.utxos = fundingParameters.utxos;
|
|
399
|
-
parameters.amount = (await preTransaction.estimateTransactionFees()) + estimatedFees;
|
|
400
|
-
|
|
401
|
-
const signedTransaction = await this.createFundTransaction(parameters);
|
|
402
|
-
if (!signedTransaction) {
|
|
403
|
-
throw new Error('Could not sign funding transaction.');
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
const newParams: IUnwrapParameters = {
|
|
407
|
-
...unwrapParameters,
|
|
408
|
-
utxos: this.getUTXOAsTransaction(signedTransaction.tx, to, 0), // always 0
|
|
409
|
-
randomBytes: preTransaction.getRndBytes(),
|
|
410
|
-
nonWitnessUtxo: signedTransaction.tx.toBuffer(),
|
|
411
|
-
};
|
|
412
|
-
|
|
413
|
-
const finalTransaction: UnwrapSegwitTransaction = new UnwrapSegwitTransaction(newParams);
|
|
414
|
-
|
|
415
|
-
// We have to regenerate using the new utxo
|
|
416
|
-
const outTx: Psbt = await finalTransaction.signPSBT();
|
|
417
|
-
const asBase64 = outTx.toBase64();
|
|
418
|
-
const psbt = this.writePSBTHeader(PSBTTypes.UNWRAP, asBase64);
|
|
419
|
-
|
|
420
|
-
return {
|
|
421
|
-
fundingTransaction: signedTransaction.tx.toHex(),
|
|
422
|
-
psbt: psbt,
|
|
423
|
-
feeRefundOrLoss: estimatedFees,
|
|
424
|
-
utxos: [],
|
|
425
|
-
};
|
|
426
|
-
}*/
|
|
427
|
-
|
|
428
|
-
/**
|
|
429
|
-
* Unwrap bitcoin via taproot.
|
|
430
|
-
* @param {IUnwrapParameters} unwrapParameters - The unwrap parameters
|
|
431
|
-
* @returns {Promise<UnwrapResult>} - The signed transaction
|
|
432
|
-
* @throws {Error} - If the transaction could not be signed
|
|
433
|
-
*/
|
|
434
|
-
|
|
435
|
-
/*public async unwrap(unwrapParameters: IUnwrapParameters): Promise<UnwrapResult> {
|
|
436
|
-
if (!unwrapParameters.from) {
|
|
437
|
-
throw new Error('Field "from" not provided.');
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
const transaction: UnwrapTransaction = new UnwrapTransaction(unwrapParameters);
|
|
441
|
-
await transaction.signTransaction();
|
|
442
|
-
|
|
443
|
-
const to = transaction.toAddress();
|
|
444
|
-
if (!to) throw new Error('To address is required');
|
|
445
|
-
|
|
446
|
-
// Initial generation
|
|
447
|
-
const estimatedGas = await transaction.estimateTransactionFees();
|
|
448
|
-
const fundingParameters: IFundingTransactionParameters = {
|
|
449
|
-
...unwrapParameters,
|
|
450
|
-
amount: estimatedGas,
|
|
451
|
-
to: to,
|
|
452
|
-
};
|
|
453
|
-
|
|
454
|
-
const preFundingTransaction = await this.createFundTransaction(fundingParameters);
|
|
455
|
-
unwrapParameters.utxos = this.getUTXOAsTransaction(preFundingTransaction.tx, to, 0);
|
|
456
|
-
|
|
457
|
-
const preTransaction: UnwrapTransaction = new UnwrapTransaction({
|
|
458
|
-
...unwrapParameters,
|
|
459
|
-
randomBytes: transaction.getRndBytes(),
|
|
460
|
-
});
|
|
461
|
-
|
|
462
|
-
// Initial generation
|
|
463
|
-
await preTransaction.signTransaction();
|
|
464
|
-
|
|
465
|
-
const parameters: IFundingTransactionParameters =
|
|
466
|
-
await preTransaction.getFundingTransactionParameters();
|
|
467
|
-
|
|
468
|
-
parameters.utxos = fundingParameters.utxos;
|
|
469
|
-
parameters.amount =
|
|
470
|
-
(await preTransaction.estimateTransactionFees()) +
|
|
471
|
-
this.getPriorityFee(unwrapParameters);
|
|
472
|
-
|
|
473
|
-
const signedTransaction = await this.createFundTransaction(parameters);
|
|
474
|
-
if (!signedTransaction) {
|
|
475
|
-
throw new Error('Could not sign funding transaction.');
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
const newParams: IUnwrapParameters = {
|
|
479
|
-
...unwrapParameters,
|
|
480
|
-
utxos: this.getUTXOAsTransaction(signedTransaction.tx, to, 0), // always 0
|
|
481
|
-
randomBytes: preTransaction.getRndBytes(),
|
|
482
|
-
nonWitnessUtxo: signedTransaction.tx.toBuffer(),
|
|
483
|
-
};
|
|
484
|
-
|
|
485
|
-
const finalTransaction: UnwrapTransaction = new UnwrapTransaction(newParams);
|
|
486
|
-
|
|
487
|
-
// We have to regenerate using the new utxo
|
|
488
|
-
const outTx: Psbt = await finalTransaction.signPSBT();
|
|
489
|
-
const asBase64 = outTx.toBase64();
|
|
490
|
-
const psbt = this.writePSBTHeader(PSBTTypes.UNWRAP, asBase64);
|
|
491
|
-
|
|
492
|
-
return {
|
|
493
|
-
fundingTransaction: signedTransaction.tx.toHex(),
|
|
494
|
-
psbt: psbt,
|
|
495
|
-
feeRefundOrLoss: finalTransaction.getFeeLossOrRefund(),
|
|
496
|
-
utxos: this.getUTXOAsTransaction(signedTransaction.tx, unwrapParameters.from, 1),
|
|
497
|
-
};
|
|
498
|
-
}*/
|
|
499
|
-
|
|
500
277
|
/**
|
|
501
278
|
* @description Creates a funding transaction.
|
|
502
279
|
* @param {IFundingTransactionParameters} parameters - The funding transaction parameters
|
|
@@ -566,36 +343,6 @@ export class TransactionFactory {
|
|
|
566
343
|
};
|
|
567
344
|
}
|
|
568
345
|
|
|
569
|
-
/*private calculateNumSignatures(vault: VaultUTXOs[]): bigint {
|
|
570
|
-
let numSignatures = 0n;
|
|
571
|
-
|
|
572
|
-
for (const v of vault) {
|
|
573
|
-
numSignatures += BigInt(v.minimum * v.utxos.length);
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
return numSignatures;
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
private calculateNumInputs(vault: VaultUTXOs[]): bigint {
|
|
580
|
-
let numSignatures = 0n;
|
|
581
|
-
|
|
582
|
-
for (const v of vault) {
|
|
583
|
-
numSignatures += BigInt(v.utxos.length);
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
return numSignatures;
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
private maxPubKeySize(vault: VaultUTXOs[]): bigint {
|
|
590
|
-
let size = 0;
|
|
591
|
-
|
|
592
|
-
for (const v of vault) {
|
|
593
|
-
size = Math.max(size, v.publicKeys.length);
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
return BigInt(size);
|
|
597
|
-
}*/
|
|
598
|
-
|
|
599
346
|
private writePSBTHeader(type: PSBTTypes, psbt: string): string {
|
|
600
347
|
const buf = Buffer.from(psbt, 'base64');
|
|
601
348
|
|
|
@@ -2,9 +2,7 @@ import {
|
|
|
2
2
|
crypto as bitCrypto,
|
|
3
3
|
Network,
|
|
4
4
|
networks,
|
|
5
|
-
opcodes,
|
|
6
5
|
Psbt,
|
|
7
|
-
PsbtInput,
|
|
8
6
|
script as bitScript,
|
|
9
7
|
TapScriptSig,
|
|
10
8
|
} from '@btc-vision/bitcoin';
|
|
@@ -14,6 +12,7 @@ import { CustomKeypair } from '../BrowserSignerBase.js';
|
|
|
14
12
|
import { PsbtSignatureOptions, Unisat, UnisatNetwork } from '../types/Unisat.js';
|
|
15
13
|
import { PartialSig } from 'bip174/src/lib/interfaces.js';
|
|
16
14
|
import { toXOnly } from '@btc-vision/bitcoin/src/psbt/bip371.js';
|
|
15
|
+
import { canSignNonTaprootInput, isTaprootInput } from '../../../signer/SignerUtils.js';
|
|
17
16
|
|
|
18
17
|
declare global {
|
|
19
18
|
interface Window {
|
|
@@ -219,14 +218,10 @@ export class UnisatSigner extends CustomKeypair {
|
|
|
219
218
|
viaTaproot = true;
|
|
220
219
|
}
|
|
221
220
|
}
|
|
222
|
-
} else {
|
|
221
|
+
} else if (canSignNonTaprootInput(input, this.publicKey)) {
|
|
223
222
|
// Non-Taproot input
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
if (script && pubkeyInScript(this.publicKey, script)) {
|
|
227
|
-
needsToSign = true;
|
|
228
|
-
viaTaproot = false;
|
|
229
|
-
}
|
|
223
|
+
needsToSign = true;
|
|
224
|
+
viaTaproot = false;
|
|
230
225
|
}
|
|
231
226
|
|
|
232
227
|
if (needsToSign) {
|
|
@@ -357,37 +352,6 @@ export class UnisatSigner extends CustomKeypair {
|
|
|
357
352
|
}
|
|
358
353
|
}
|
|
359
354
|
|
|
360
|
-
// Helper functions
|
|
361
|
-
function isTaprootInput(input: PsbtInput): boolean {
|
|
362
|
-
if (input.tapInternalKey || input.tapKeySig || input.tapScriptSig || input.tapLeafScript) {
|
|
363
|
-
return true;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
if (input.witnessUtxo) {
|
|
367
|
-
const script = input.witnessUtxo.script;
|
|
368
|
-
return script.length === 34 && script[0] === opcodes.OP_1 && script[1] === 0x20;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
return false;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
function getInputRelevantScript(input: PsbtInput): Buffer | null {
|
|
375
|
-
if (input.redeemScript) {
|
|
376
|
-
return input.redeemScript;
|
|
377
|
-
}
|
|
378
|
-
if (input.witnessScript) {
|
|
379
|
-
return input.witnessScript;
|
|
380
|
-
}
|
|
381
|
-
if (input.witnessUtxo) {
|
|
382
|
-
return input.witnessUtxo.script;
|
|
383
|
-
}
|
|
384
|
-
if (input.nonWitnessUtxo) {
|
|
385
|
-
// Additional logic can be added here if needed
|
|
386
|
-
return null;
|
|
387
|
-
}
|
|
388
|
-
return null;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
355
|
function pubkeyInScript(pubkey: Buffer, script: Buffer): boolean {
|
|
392
356
|
return pubkeyPositionInScript(pubkey, script) !== -1;
|
|
393
357
|
}
|
|
@@ -1,13 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
crypto as bitCrypto,
|
|
3
|
-
script as bitScript,
|
|
4
|
-
Network,
|
|
5
|
-
networks,
|
|
6
|
-
opcodes,
|
|
7
|
-
Psbt,
|
|
8
|
-
PsbtInput,
|
|
9
|
-
TapScriptSig,
|
|
10
|
-
} from '@btc-vision/bitcoin';
|
|
1
|
+
import { Network, networks, Psbt, TapScriptSig } from '@btc-vision/bitcoin';
|
|
11
2
|
import { toXOnly } from '@btc-vision/bitcoin/src/psbt/bip371.js';
|
|
12
3
|
import { PartialSig } from 'bip174/src/lib/interfaces.js';
|
|
13
4
|
import { ECPairInterface } from 'ecpair';
|
|
@@ -15,6 +6,11 @@ import { EcKeyPair } from '../../../keypair/EcKeyPair.js';
|
|
|
15
6
|
import { CustomKeypair } from '../BrowserSignerBase.js';
|
|
16
7
|
import { PsbtSignatureOptions } from '../types/Unisat.js';
|
|
17
8
|
import { Xverse, XverseRPCGetAccountResponse, XverseRPCSignPsbtResponse } from '../types/Xverse.js';
|
|
9
|
+
import {
|
|
10
|
+
canSignNonTaprootInput,
|
|
11
|
+
isTaprootInput,
|
|
12
|
+
pubkeyInScript,
|
|
13
|
+
} from '../../../signer/SignerUtils.js';
|
|
18
14
|
|
|
19
15
|
declare global {
|
|
20
16
|
interface Window {
|
|
@@ -226,14 +222,10 @@ export class XverseSigner extends CustomKeypair {
|
|
|
226
222
|
viaTaproot = true;
|
|
227
223
|
}
|
|
228
224
|
}
|
|
229
|
-
} else {
|
|
225
|
+
} else if (canSignNonTaprootInput(input, this.publicKey)) {
|
|
230
226
|
// Non-Taproot input
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
if (script && pubkeyInScript(this.publicKey, script)) {
|
|
234
|
-
needsToSign = true;
|
|
235
|
-
viaTaproot = false;
|
|
236
|
-
}
|
|
227
|
+
needsToSign = true;
|
|
228
|
+
viaTaproot = false;
|
|
237
229
|
}
|
|
238
230
|
|
|
239
231
|
if (needsToSign) {
|
|
@@ -376,54 +368,3 @@ export class XverseSigner extends CustomKeypair {
|
|
|
376
368
|
return nonDuplicate;
|
|
377
369
|
}
|
|
378
370
|
}
|
|
379
|
-
|
|
380
|
-
// Helper functions
|
|
381
|
-
function isTaprootInput(input: PsbtInput): boolean {
|
|
382
|
-
if (input.tapInternalKey || input.tapKeySig || input.tapScriptSig || input.tapLeafScript) {
|
|
383
|
-
return true;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
if (input.witnessUtxo) {
|
|
387
|
-
const script = input.witnessUtxo.script;
|
|
388
|
-
return script.length === 34 && script[0] === opcodes.OP_1 && script[1] === 0x20;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
return false;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
function getInputRelevantScript(input: PsbtInput): Buffer | null {
|
|
395
|
-
if (input.redeemScript) {
|
|
396
|
-
return input.redeemScript;
|
|
397
|
-
}
|
|
398
|
-
if (input.witnessScript) {
|
|
399
|
-
return input.witnessScript;
|
|
400
|
-
}
|
|
401
|
-
if (input.witnessUtxo) {
|
|
402
|
-
return input.witnessUtxo.script;
|
|
403
|
-
}
|
|
404
|
-
if (input.nonWitnessUtxo) {
|
|
405
|
-
// Additional logic can be added here if needed
|
|
406
|
-
return null;
|
|
407
|
-
}
|
|
408
|
-
return null;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
function pubkeyInScript(pubkey: Buffer, script: Buffer): boolean {
|
|
412
|
-
return pubkeyPositionInScript(pubkey, script) !== -1;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
function pubkeyPositionInScript(pubkey: Buffer, script: Buffer): number {
|
|
416
|
-
const pubkeyHash = bitCrypto.hash160(pubkey);
|
|
417
|
-
const pubkeyXOnly = toXOnly(pubkey);
|
|
418
|
-
|
|
419
|
-
const decompiled = bitScript.decompile(script);
|
|
420
|
-
if (decompiled === null) throw new Error('Unknown script error');
|
|
421
|
-
|
|
422
|
-
return decompiled.findIndex((element) => {
|
|
423
|
-
if (typeof element === 'number') return false;
|
|
424
|
-
return (
|
|
425
|
-
Buffer.isBuffer(element) &&
|
|
426
|
-
(element.equals(pubkey) || element.equals(pubkeyHash) || element.equals(pubkeyXOnly))
|
|
427
|
-
);
|
|
428
|
-
});
|
|
429
|
-
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TransactionType } from '../enums/TransactionType.js';
|
|
2
2
|
import { IFundingTransactionParameters } from '../interfaces/ITransactionParameters.js';
|
|
3
|
-
import { Signer } from '@btc-vision/bitcoin';
|
|
3
|
+
import { opcodes, script, Signer } from '@btc-vision/bitcoin';
|
|
4
4
|
import { TransactionBuilder } from './TransactionBuilder.js';
|
|
5
5
|
import { ECPairInterface } from 'ecpair';
|
|
6
6
|
|
|
@@ -29,9 +29,14 @@ export class FundingTransaction extends TransactionBuilder<TransactionType.FUNDI
|
|
|
29
29
|
if (this.splitInputsInto > 1) {
|
|
30
30
|
this.splitInputs(this.amount);
|
|
31
31
|
} else if (this.isPubKeyDestination) {
|
|
32
|
+
const p2pkScript = script.compile([
|
|
33
|
+
Buffer.from(this.to.replace('0x', ''), 'hex'),
|
|
34
|
+
opcodes.OP_CHECKSIG,
|
|
35
|
+
]);
|
|
36
|
+
|
|
32
37
|
this.addOutput({
|
|
33
38
|
value: Number(this.amount),
|
|
34
|
-
script:
|
|
39
|
+
script: p2pkScript,
|
|
35
40
|
});
|
|
36
41
|
} else {
|
|
37
42
|
this.addOutput({
|
|
@@ -151,7 +151,9 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
|
|
|
151
151
|
this.utxos = parameters.utxos;
|
|
152
152
|
this.to = parameters.to || undefined;
|
|
153
153
|
|
|
154
|
-
this.isPubKeyDestination = this.to
|
|
154
|
+
this.isPubKeyDestination = this.to
|
|
155
|
+
? AddressVerificator.isValidPublicKey(this.to, this.network)
|
|
156
|
+
: false;
|
|
155
157
|
|
|
156
158
|
this.optionalOutputs = parameters.optionalOutputs;
|
|
157
159
|
|