@btc-vision/transaction 1.1.2 → 1.1.4
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/transaction/browser/extensions/UnisatSigner.d.ts +4 -4
- package/browser/transaction/browser/types/Unisat.d.ts +8 -4
- package/browser/transaction/builders/DeploymentTransaction.d.ts +1 -0
- package/browser/transaction/builders/SharedInteractionTransaction.d.ts +2 -0
- package/browser/transaction/builders/TransactionBuilder.d.ts +2 -1
- package/browser/transaction/shared/TweakedTransaction.d.ts +6 -3
- package/browser/utils/BitcoinUtils.d.ts +1 -1
- package/build/_version.d.ts +1 -1
- package/build/_version.js +1 -1
- package/build/buffer/BinaryWriter.js +0 -1
- package/build/transaction/browser/extensions/UnisatSigner.d.ts +4 -4
- package/build/transaction/browser/extensions/UnisatSigner.js +103 -20
- package/build/transaction/browser/types/Unisat.d.ts +8 -4
- package/build/transaction/builders/DeploymentTransaction.d.ts +1 -0
- package/build/transaction/builders/DeploymentTransaction.js +17 -0
- package/build/transaction/builders/SharedInteractionTransaction.d.ts +2 -0
- package/build/transaction/builders/SharedInteractionTransaction.js +31 -10
- package/build/transaction/builders/TransactionBuilder.d.ts +2 -1
- package/build/transaction/shared/TweakedTransaction.d.ts +6 -3
- package/build/transaction/shared/TweakedTransaction.js +61 -43
- package/build/utils/BitcoinUtils.d.ts +1 -1
- package/build/utils/BitcoinUtils.js +6 -3
- package/package.json +1 -1
- package/src/_version.ts +1 -1
- package/src/buffer/BinaryWriter.ts +0 -2
- package/src/transaction/browser/extensions/UnisatSigner.ts +139 -28
- package/src/transaction/browser/types/Unisat.ts +12 -4
- package/src/transaction/builders/DeploymentTransaction.ts +25 -0
- package/src/transaction/builders/SharedInteractionTransaction.ts +51 -21
- package/src/transaction/builders/TransactionBuilder.ts +2 -1
- package/src/transaction/shared/TweakedTransaction.ts +90 -49
- package/src/utils/BitcoinUtils.ts +12 -3
|
@@ -154,47 +154,24 @@ export class TweakedTransaction extends Logger {
|
|
|
154
154
|
getSignerKey() {
|
|
155
155
|
return this.signer;
|
|
156
156
|
}
|
|
157
|
-
async signInput(transaction, input, i, signer) {
|
|
157
|
+
async signInput(transaction, input, i, signer, reverse = false) {
|
|
158
158
|
const publicKey = signer.publicKey;
|
|
159
|
-
|
|
159
|
+
let isTaproot = this.isTaprootInput(input);
|
|
160
|
+
if (reverse) {
|
|
161
|
+
isTaproot = !isTaproot;
|
|
162
|
+
}
|
|
160
163
|
let signed = false;
|
|
161
164
|
if (isTaproot) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
await this.signTaprootInput(signer, transaction, i);
|
|
166
|
-
signed = true;
|
|
167
|
-
}
|
|
168
|
-
catch (e) {
|
|
169
|
-
this.error(`Failed to sign Taproot script path input ${i}: ${e}`);
|
|
170
|
-
}
|
|
165
|
+
try {
|
|
166
|
+
await this.attemptSignTaproot(transaction, input, i, signer, publicKey);
|
|
167
|
+
signed = true;
|
|
171
168
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
if (signer !== this.signer) {
|
|
175
|
-
tweakedSigner = this.getTweakedSigner(true, signer);
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
if (!this.tweakedSigner)
|
|
179
|
-
this.tweakSigner();
|
|
180
|
-
tweakedSigner = this.tweakedSigner;
|
|
181
|
-
}
|
|
182
|
-
if (tweakedSigner) {
|
|
183
|
-
try {
|
|
184
|
-
await this.signTaprootInput(tweakedSigner, transaction, i);
|
|
185
|
-
signed = true;
|
|
186
|
-
}
|
|
187
|
-
catch (e) {
|
|
188
|
-
this.error(`Failed to sign Taproot key path input ${i}: ${e}`);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
else {
|
|
192
|
-
this.error(`Failed to obtain tweaked signer for input ${i}.`);
|
|
193
|
-
}
|
|
169
|
+
catch (e) {
|
|
170
|
+
this.error(`Failed to sign Taproot script path input ${i}: ${e}`);
|
|
194
171
|
}
|
|
195
172
|
}
|
|
196
173
|
else {
|
|
197
|
-
if (this.canSignNonTaprootInput(input, publicKey)) {
|
|
174
|
+
if (!reverse ? this.canSignNonTaprootInput(input, publicKey) : true) {
|
|
198
175
|
try {
|
|
199
176
|
await this.signNonTaprootInput(signer, transaction, i);
|
|
200
177
|
signed = true;
|
|
@@ -205,7 +182,12 @@ export class TweakedTransaction extends Logger {
|
|
|
205
182
|
}
|
|
206
183
|
}
|
|
207
184
|
if (!signed) {
|
|
208
|
-
|
|
185
|
+
try {
|
|
186
|
+
await this.signInput(transaction, input, i, signer, true);
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
throw new Error(`Cannot sign input ${i} with the provided signer.`);
|
|
190
|
+
}
|
|
209
191
|
}
|
|
210
192
|
}
|
|
211
193
|
splitArray(arr, chunkSize) {
|
|
@@ -219,6 +201,10 @@ export class TweakedTransaction extends Logger {
|
|
|
219
201
|
return result;
|
|
220
202
|
}
|
|
221
203
|
async signInputs(transaction) {
|
|
204
|
+
if ('multiSignPsbt' in this.signer) {
|
|
205
|
+
await this.signInputsWalletBased(transaction);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
222
208
|
const txs = transaction.data.inputs;
|
|
223
209
|
const batchSize = 20;
|
|
224
210
|
const batches = this.splitArray(txs, batchSize);
|
|
@@ -238,14 +224,10 @@ export class TweakedTransaction extends Logger {
|
|
|
238
224
|
}
|
|
239
225
|
await Promise.all(promises);
|
|
240
226
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
transaction.finalizeAllInputs();
|
|
244
|
-
this.finalized = true;
|
|
245
|
-
}
|
|
246
|
-
catch (e) {
|
|
247
|
-
this.finalized = false;
|
|
227
|
+
for (let i = 0; i < transaction.data.inputs.length; i++) {
|
|
228
|
+
transaction.finalizeInput(i, this.customFinalizerP2SH);
|
|
248
229
|
}
|
|
230
|
+
this.finalized = true;
|
|
249
231
|
}
|
|
250
232
|
internalPubKeyToXOnly() {
|
|
251
233
|
return toXOnly(Buffer.from(this.signer.publicKey));
|
|
@@ -373,6 +355,37 @@ export class TweakedTransaction extends Logger {
|
|
|
373
355
|
}
|
|
374
356
|
return input;
|
|
375
357
|
}
|
|
358
|
+
async signInputsWalletBased(transaction) {
|
|
359
|
+
const signer = this.signer;
|
|
360
|
+
await signer.multiSignPsbt([transaction]);
|
|
361
|
+
for (let i = 0; i < transaction.data.inputs.length; i++) {
|
|
362
|
+
transaction.finalizeInput(i, this.customFinalizerP2SH);
|
|
363
|
+
}
|
|
364
|
+
this.finalized = true;
|
|
365
|
+
}
|
|
366
|
+
async attemptSignTaproot(transaction, input, i, signer, publicKey) {
|
|
367
|
+
const isScriptSpend = this.isTaprootScriptSpend(input, publicKey);
|
|
368
|
+
if (isScriptSpend) {
|
|
369
|
+
await this.signTaprootInput(signer, transaction, i);
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
let tweakedSigner;
|
|
373
|
+
if (signer !== this.signer) {
|
|
374
|
+
tweakedSigner = this.getTweakedSigner(true, signer);
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
if (!this.tweakedSigner)
|
|
378
|
+
this.tweakSigner();
|
|
379
|
+
tweakedSigner = this.tweakedSigner;
|
|
380
|
+
}
|
|
381
|
+
if (tweakedSigner) {
|
|
382
|
+
await this.signTaprootInput(tweakedSigner, transaction, i);
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
this.error(`Failed to obtain tweaked signer for input ${i}.`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
376
389
|
isTaprootScriptSpend(input, publicKey) {
|
|
377
390
|
if (input.tapLeafScript && input.tapLeafScript.length > 0) {
|
|
378
391
|
for (const tapLeafScript of input.tapLeafScript) {
|
|
@@ -432,7 +445,12 @@ export class TweakedTransaction extends Logger {
|
|
|
432
445
|
}
|
|
433
446
|
async signTaprootInput(signer, transaction, i, tapLeafHash) {
|
|
434
447
|
if ('signTaprootInput' in signer) {
|
|
435
|
-
|
|
448
|
+
try {
|
|
449
|
+
await signer.signTaprootInput(transaction, i, tapLeafHash);
|
|
450
|
+
}
|
|
451
|
+
catch {
|
|
452
|
+
throw new Error('Failed to sign Taproot input with provided signer.');
|
|
453
|
+
}
|
|
436
454
|
}
|
|
437
455
|
else {
|
|
438
456
|
transaction.signTaprootInput(i, signer);
|
|
@@ -4,11 +4,13 @@ export class BitcoinUtils {
|
|
|
4
4
|
return BigInt(btc * 100000000);
|
|
5
5
|
}
|
|
6
6
|
static rndBytes() {
|
|
7
|
-
const buf = BitcoinUtils.
|
|
7
|
+
const buf = BitcoinUtils.getSafeRandomValues(64);
|
|
8
8
|
return Buffer.from(buf);
|
|
9
9
|
}
|
|
10
|
-
static
|
|
11
|
-
if (typeof window !== 'undefined' &&
|
|
10
|
+
static getSafeRandomValues(length) {
|
|
11
|
+
if (typeof globalThis.window !== 'undefined' &&
|
|
12
|
+
globalThis.window.crypto &&
|
|
13
|
+
typeof globalThis.window.crypto.getRandomValues === 'function') {
|
|
12
14
|
const array = new Uint8Array(length);
|
|
13
15
|
window.crypto.getRandomValues(array);
|
|
14
16
|
return Buffer.from(array);
|
|
@@ -19,6 +21,7 @@ export class BitcoinUtils {
|
|
|
19
21
|
return Buffer.from(array);
|
|
20
22
|
}
|
|
21
23
|
else {
|
|
24
|
+
console.log(`No secure random number generator available. Please upgrade your environment.`, globalThis.window.crypto, crypto);
|
|
22
25
|
throw new Error('No secure random number generator available. Please upgrade your environment.');
|
|
23
26
|
}
|
|
24
27
|
}
|
package/package.json
CHANGED
package/src/_version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '1.1.
|
|
1
|
+
export const version = '1.1.4';
|
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
crypto as bitCrypto,
|
|
3
|
+
Network,
|
|
4
|
+
networks,
|
|
5
|
+
opcodes,
|
|
6
|
+
Psbt,
|
|
7
|
+
PsbtInput,
|
|
8
|
+
script as bitScript,
|
|
9
|
+
TapScriptSig,
|
|
10
|
+
} from '@btc-vision/bitcoin';
|
|
2
11
|
import { ECPairInterface } from 'ecpair';
|
|
3
12
|
import { EcKeyPair } from '../../../keypair/EcKeyPair.js';
|
|
4
13
|
import { CustomKeypair } from '../BrowserSignerBase.js';
|
|
5
14
|
import { PsbtSignatureOptions, Unisat, UnisatNetwork } from '../types/Unisat.js';
|
|
6
15
|
import { PartialSig } from 'bip174/src/lib/interfaces.js';
|
|
16
|
+
import { toXOnly } from '@btc-vision/bitcoin/src/psbt/bip371.js';
|
|
7
17
|
|
|
8
18
|
declare global {
|
|
9
19
|
interface Window {
|
|
@@ -122,15 +132,15 @@ export class UnisatSigner extends CustomKeypair {
|
|
|
122
132
|
return this.publicKey;
|
|
123
133
|
}
|
|
124
134
|
|
|
125
|
-
public sign(
|
|
135
|
+
public sign(_hash: Buffer, _lowR?: boolean): Buffer {
|
|
126
136
|
throw new Error('Not implemented: sign');
|
|
127
137
|
}
|
|
128
138
|
|
|
129
|
-
public signSchnorr(
|
|
139
|
+
public signSchnorr(_hash: Buffer): Buffer {
|
|
130
140
|
throw new Error('Not implemented: signSchnorr');
|
|
131
141
|
}
|
|
132
142
|
|
|
133
|
-
public verify(
|
|
143
|
+
public verify(_hash: Buffer, _signature: Buffer): boolean {
|
|
134
144
|
throw new Error('Not implemented: verify');
|
|
135
145
|
}
|
|
136
146
|
|
|
@@ -176,6 +186,80 @@ export class UnisatSigner extends CustomKeypair {
|
|
|
176
186
|
this.combine(transaction, firstSignature, i);
|
|
177
187
|
}
|
|
178
188
|
|
|
189
|
+
public async multiSignPsbt(transactions: Psbt[]): Promise<void> {
|
|
190
|
+
const toSignPsbts: string[] = [];
|
|
191
|
+
const options: PsbtSignatureOptions[] = [];
|
|
192
|
+
|
|
193
|
+
for (const psbt of transactions) {
|
|
194
|
+
const hex = psbt.toHex();
|
|
195
|
+
toSignPsbts.push(hex);
|
|
196
|
+
|
|
197
|
+
const toSignInputs = psbt.data.inputs
|
|
198
|
+
.map((input, i) => {
|
|
199
|
+
let needsToSign = false;
|
|
200
|
+
let viaTaproot = false;
|
|
201
|
+
|
|
202
|
+
if (isTaprootInput(input)) {
|
|
203
|
+
if (input.tapLeafScript && input.tapLeafScript.length > 0) {
|
|
204
|
+
for (const tapLeafScript of input.tapLeafScript) {
|
|
205
|
+
if (pubkeyInScript(this.publicKey, tapLeafScript.script)) {
|
|
206
|
+
needsToSign = true;
|
|
207
|
+
viaTaproot = false; // for opnet, we use original keys.
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (!needsToSign && input.tapInternalKey) {
|
|
214
|
+
const tapInternalKey = input.tapInternalKey;
|
|
215
|
+
const xOnlyPubKey = toXOnly(this.publicKey);
|
|
216
|
+
|
|
217
|
+
if (tapInternalKey.equals(xOnlyPubKey)) {
|
|
218
|
+
needsToSign = true;
|
|
219
|
+
viaTaproot = true;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
} else {
|
|
223
|
+
// Non-Taproot input
|
|
224
|
+
const script = getInputRelevantScript(input);
|
|
225
|
+
|
|
226
|
+
if (script && pubkeyInScript(this.publicKey, script)) {
|
|
227
|
+
needsToSign = true;
|
|
228
|
+
viaTaproot = false;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (needsToSign) {
|
|
233
|
+
return {
|
|
234
|
+
index: i,
|
|
235
|
+
publicKey: this.publicKey.toString('hex'),
|
|
236
|
+
disableTweakSigner: !viaTaproot,
|
|
237
|
+
};
|
|
238
|
+
} else {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
})
|
|
242
|
+
.filter((v) => v !== null);
|
|
243
|
+
|
|
244
|
+
options.push({
|
|
245
|
+
autoFinalized: false,
|
|
246
|
+
toSignInputs: toSignInputs,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const signed = await this.unisat.signPsbt(toSignPsbts[0], options[0]);
|
|
251
|
+
const signedPsbts = Psbt.fromHex(signed); //signed.map((hex) => Psbt.fromHex(hex));
|
|
252
|
+
|
|
253
|
+
/*for (let i = 0; i < signedPsbts.length; i++) {
|
|
254
|
+
const psbtOriginal = transactions[i];
|
|
255
|
+
const psbtSigned = signedPsbts[i];
|
|
256
|
+
|
|
257
|
+
psbtOriginal.combine(psbtSigned);
|
|
258
|
+
}*/
|
|
259
|
+
|
|
260
|
+
transactions[0].combine(signedPsbts);
|
|
261
|
+
}
|
|
262
|
+
|
|
179
263
|
private hasAlreadySignedTapScriptSig(input: TapScriptSig[]): boolean {
|
|
180
264
|
for (let i = 0; i < input.length; i++) {
|
|
181
265
|
const item = input[i];
|
|
@@ -257,30 +341,6 @@ export class UnisatSigner extends CustomKeypair {
|
|
|
257
341
|
return Psbt.fromHex(signed);
|
|
258
342
|
}
|
|
259
343
|
|
|
260
|
-
private async signTweaked(
|
|
261
|
-
transaction: Psbt,
|
|
262
|
-
i: number,
|
|
263
|
-
sighashTypes: number[],
|
|
264
|
-
disableTweakSigner: boolean = false,
|
|
265
|
-
): Promise<Psbt> {
|
|
266
|
-
const opts: PsbtSignatureOptions = {
|
|
267
|
-
autoFinalized: false,
|
|
268
|
-
toSignInputs: [
|
|
269
|
-
{
|
|
270
|
-
index: i,
|
|
271
|
-
publicKey: this.publicKey.toString('hex'),
|
|
272
|
-
sighashTypes,
|
|
273
|
-
disableTweakSigner: disableTweakSigner,
|
|
274
|
-
},
|
|
275
|
-
],
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
const psbt = transaction.toHex();
|
|
279
|
-
const signed = await this.unisat.signPsbt(psbt, opts);
|
|
280
|
-
|
|
281
|
-
return Psbt.fromHex(signed);
|
|
282
|
-
}
|
|
283
|
-
|
|
284
344
|
private getNonDuplicateScriptSig(
|
|
285
345
|
scriptSig1: TapScriptSig[],
|
|
286
346
|
scriptSig2: TapScriptSig[],
|
|
@@ -296,3 +356,54 @@ export class UnisatSigner extends CustomKeypair {
|
|
|
296
356
|
return nonDuplicate;
|
|
297
357
|
}
|
|
298
358
|
}
|
|
359
|
+
|
|
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
|
+
function pubkeyInScript(pubkey: Buffer, script: Buffer): boolean {
|
|
392
|
+
return pubkeyPositionInScript(pubkey, script) !== -1;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function pubkeyPositionInScript(pubkey: Buffer, script: Buffer): number {
|
|
396
|
+
const pubkeyHash = bitCrypto.hash160(pubkey);
|
|
397
|
+
const pubkeyXOnly = toXOnly(pubkey);
|
|
398
|
+
|
|
399
|
+
const decompiled = bitScript.decompile(script);
|
|
400
|
+
if (decompiled === null) throw new Error('Unknown script error');
|
|
401
|
+
|
|
402
|
+
return decompiled.findIndex((element) => {
|
|
403
|
+
if (typeof element === 'number') return false;
|
|
404
|
+
return (
|
|
405
|
+
Buffer.isBuffer(element) &&
|
|
406
|
+
(element.equals(pubkey) || element.equals(pubkeyHash) || element.equals(pubkeyXOnly))
|
|
407
|
+
);
|
|
408
|
+
});
|
|
409
|
+
}
|
|
@@ -67,7 +67,7 @@ export interface Unisat {
|
|
|
67
67
|
|
|
68
68
|
getNetwork(): Promise<UnisatNetwork>;
|
|
69
69
|
|
|
70
|
-
getChain(): Promise<
|
|
70
|
+
getChain(): Promise<UnisatChainInfo>;
|
|
71
71
|
|
|
72
72
|
getAccounts(): Promise<string[]>;
|
|
73
73
|
|
|
@@ -83,15 +83,23 @@ export interface Unisat {
|
|
|
83
83
|
|
|
84
84
|
signPsbt(psbtHex: string, psbtOptions: PsbtSignatureOptions): Promise<string>;
|
|
85
85
|
|
|
86
|
-
signPsbts(psbtHex: string[], psbtOptions: PsbtSignatureOptions): Promise<string[]>;
|
|
86
|
+
signPsbts(psbtHex: string[], psbtOptions: PsbtSignatureOptions[]): Promise<string[]>;
|
|
87
87
|
|
|
88
88
|
pushPsbt(psbtHex: string): Promise<string>;
|
|
89
89
|
|
|
90
90
|
on(event: 'accountsChanged', listener: (accounts: string[]) => void): void;
|
|
91
91
|
|
|
92
|
-
on(event: 'chainChanged'
|
|
92
|
+
on(event: 'chainChanged', listener: (chain: UnisatChainInfo) => void): void;
|
|
93
|
+
|
|
94
|
+
on(event: 'networkChanged', listener: (network: UnisatChainInfo) => void): void;
|
|
95
|
+
|
|
96
|
+
on(event: 'disconnect', listener: () => void): void;
|
|
93
97
|
|
|
94
98
|
removeListener(event: 'accountsChanged', listener: (accounts: string[]) => void): void;
|
|
95
99
|
|
|
96
|
-
removeListener(event: '
|
|
100
|
+
removeListener(event: 'chainChanged', listener: (chain: UnisatChainInfo) => void): void;
|
|
101
|
+
|
|
102
|
+
removeListener(event: 'networkChanged', listener: (network: UnisatChainInfo) => void): void;
|
|
103
|
+
|
|
104
|
+
removeListener(event: 'disconnect', listener: () => void): void;
|
|
97
105
|
}
|
|
@@ -12,6 +12,7 @@ import { Compressor } from '../../bytecode/Compressor.js';
|
|
|
12
12
|
import { SharedInteractionTransaction } from './SharedInteractionTransaction.js';
|
|
13
13
|
import { ECPairInterface } from 'ecpair';
|
|
14
14
|
import { Address } from '../../keypair/Address.js';
|
|
15
|
+
import { UnisatSigner } from '../browser/extensions/UnisatSigner.js';
|
|
15
16
|
|
|
16
17
|
export class DeploymentTransaction extends TransactionBuilder<TransactionType.DEPLOYMENT> {
|
|
17
18
|
public static readonly MAXIMUM_CONTRACT_SIZE = 128 * 1024;
|
|
@@ -203,6 +204,25 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
|
|
|
203
204
|
await this.addRefundOutput(amountSpent);
|
|
204
205
|
}
|
|
205
206
|
|
|
207
|
+
protected override async signInputsWalletBased(transaction: Psbt): Promise<void> {
|
|
208
|
+
const signer: UnisatSigner = this.signer as UnisatSigner;
|
|
209
|
+
|
|
210
|
+
// first, we sign the first input with the script signer.
|
|
211
|
+
await this.signInput(transaction, transaction.data.inputs[0], 0, this.contractSigner);
|
|
212
|
+
|
|
213
|
+
// then, we sign all the remaining inputs with the wallet signer.
|
|
214
|
+
await signer.multiSignPsbt([transaction]);
|
|
215
|
+
|
|
216
|
+
// Then, we finalize every input.
|
|
217
|
+
for (let i = 0; i < transaction.data.inputs.length; i++) {
|
|
218
|
+
if (i === 0) {
|
|
219
|
+
transaction.finalizeInput(i, this.customFinalizer);
|
|
220
|
+
} else {
|
|
221
|
+
transaction.finalizeInput(i);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
206
226
|
/**
|
|
207
227
|
* Sign the inputs
|
|
208
228
|
* @param {Psbt} transaction The transaction to sign
|
|
@@ -215,6 +235,11 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
|
|
|
215
235
|
return;
|
|
216
236
|
}
|
|
217
237
|
|
|
238
|
+
if ('multiSignPsbt' in this.signer) {
|
|
239
|
+
await this.signInputsWalletBased(transaction);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
218
243
|
for (let i = 0; i < transaction.data.inputs.length; i++) {
|
|
219
244
|
if (i === 0) {
|
|
220
245
|
// multi sig input
|
|
@@ -9,6 +9,7 @@ import { Compressor } from '../../bytecode/Compressor.js';
|
|
|
9
9
|
import { EcKeyPair } from '../../keypair/EcKeyPair.js';
|
|
10
10
|
import { BitcoinUtils } from '../../utils/BitcoinUtils.js';
|
|
11
11
|
import { toXOnly } from '@btc-vision/bitcoin/src/psbt/bip371.js';
|
|
12
|
+
import { UnisatSigner } from '../browser/extensions/UnisatSigner.js';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Shared interaction transaction
|
|
@@ -186,27 +187,10 @@ export abstract class SharedInteractionTransaction<
|
|
|
186
187
|
return;
|
|
187
188
|
}
|
|
188
189
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
transaction,
|
|
194
|
-
transaction.data.inputs[i],
|
|
195
|
-
i,
|
|
196
|
-
this.getSignerKey(),
|
|
197
|
-
);
|
|
198
|
-
|
|
199
|
-
transaction.finalizeInput(i, this.customFinalizer);
|
|
200
|
-
} else {
|
|
201
|
-
await this.signInput(
|
|
202
|
-
transaction,
|
|
203
|
-
transaction.data.inputs[i],
|
|
204
|
-
i,
|
|
205
|
-
this.getSignerKey(),
|
|
206
|
-
);
|
|
207
|
-
|
|
208
|
-
transaction.finalizeInput(i);
|
|
209
|
-
}
|
|
190
|
+
if ('multiSignPsbt' in this.signer) {
|
|
191
|
+
await this.signInputsWalletBased(transaction);
|
|
192
|
+
} else {
|
|
193
|
+
await this.signInputsNonWalletBased(transaction);
|
|
210
194
|
}
|
|
211
195
|
}
|
|
212
196
|
|
|
@@ -308,6 +292,52 @@ export abstract class SharedInteractionTransaction<
|
|
|
308
292
|
};
|
|
309
293
|
};
|
|
310
294
|
|
|
295
|
+
// custom for interactions
|
|
296
|
+
protected override async signInputsWalletBased(transaction: Psbt): Promise<void> {
|
|
297
|
+
const signer: UnisatSigner = this.signer as UnisatSigner;
|
|
298
|
+
|
|
299
|
+
// first, we sign the first input with the script signer.
|
|
300
|
+
await this.signInput(transaction, transaction.data.inputs[0], 0, this.scriptSigner);
|
|
301
|
+
|
|
302
|
+
// then, we sign all the remaining inputs with the wallet signer.
|
|
303
|
+
await signer.multiSignPsbt([transaction]);
|
|
304
|
+
|
|
305
|
+
// Then, we finalize every input.
|
|
306
|
+
for (let i = 0; i < transaction.data.inputs.length; i++) {
|
|
307
|
+
if (i === 0) {
|
|
308
|
+
transaction.finalizeInput(i, this.customFinalizer);
|
|
309
|
+
} else {
|
|
310
|
+
transaction.finalizeInput(i);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
private async signInputsNonWalletBased(transaction: Psbt): Promise<void> {
|
|
316
|
+
for (let i = 0; i < transaction.data.inputs.length; i++) {
|
|
317
|
+
if (i === 0) {
|
|
318
|
+
await this.signInput(transaction, transaction.data.inputs[i], i, this.scriptSigner);
|
|
319
|
+
|
|
320
|
+
await this.signInput(
|
|
321
|
+
transaction,
|
|
322
|
+
transaction.data.inputs[i],
|
|
323
|
+
i,
|
|
324
|
+
this.getSignerKey(),
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
transaction.finalizeInput(i, this.customFinalizer);
|
|
328
|
+
} else {
|
|
329
|
+
await this.signInput(
|
|
330
|
+
transaction,
|
|
331
|
+
transaction.data.inputs[i],
|
|
332
|
+
i,
|
|
333
|
+
this.getSignerKey(),
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
transaction.finalizeInput(i);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
311
341
|
/**
|
|
312
342
|
* Get the public keys
|
|
313
343
|
* @private
|
|
@@ -22,6 +22,7 @@ import { UTXO } from '../../utxo/interfaces/IUTXO.js';
|
|
|
22
22
|
import { ECPairInterface } from 'ecpair';
|
|
23
23
|
import { AddressVerificator } from '../../keypair/AddressVerificator.js';
|
|
24
24
|
import { TweakedTransaction } from '../shared/TweakedTransaction.js';
|
|
25
|
+
import { UnisatSigner } from '../browser/extensions/UnisatSigner.js';
|
|
25
26
|
|
|
26
27
|
initEccLib(ecc);
|
|
27
28
|
|
|
@@ -91,7 +92,7 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
|
|
|
91
92
|
/**
|
|
92
93
|
* @description The signer of the transaction
|
|
93
94
|
*/
|
|
94
|
-
protected readonly signer: Signer | ECPairInterface;
|
|
95
|
+
protected readonly signer: Signer | ECPairInterface | UnisatSigner;
|
|
95
96
|
|
|
96
97
|
/**
|
|
97
98
|
* @description The network where the transaction will be broadcasted
|