@btc-vision/transaction 1.3.4 → 1.3.6
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/generators/Features.d.ts +9 -4
- package/browser/generators/Generator.d.ts +5 -2
- package/browser/generators/builders/CalldataGenerator.d.ts +2 -2
- package/browser/generators/builders/LegacyCalldataGenerator.d.ts +2 -2
- package/browser/index.js +1 -1
- package/browser/opnet.d.ts +7 -0
- package/browser/transaction/TransactionFactory.d.ts +2 -0
- package/browser/transaction/browser/extensions/UnisatSigner.d.ts +3 -5
- package/browser/transaction/builders/InteractionTransaction.d.ts +1 -0
- package/browser/transaction/interfaces/ITransactionParameters.d.ts +4 -0
- package/build/_version.d.ts +1 -1
- package/build/_version.js +1 -1
- package/build/generators/Features.d.ts +9 -4
- package/build/generators/Features.js +1 -5
- package/build/generators/Generator.d.ts +5 -2
- package/build/generators/Generator.js +40 -5
- package/build/generators/builders/CalldataGenerator.d.ts +2 -2
- package/build/generators/builders/CalldataGenerator.js +10 -4
- package/build/generators/builders/DeploymentGenerator.js +13 -2
- package/build/generators/builders/LegacyCalldataGenerator.d.ts +2 -2
- package/build/generators/builders/LegacyCalldataGenerator.js +10 -4
- package/build/opnet.d.ts +7 -0
- package/build/transaction/TransactionFactory.d.ts +2 -0
- package/build/transaction/TransactionFactory.js +65 -18
- package/build/transaction/browser/extensions/UnisatSigner.d.ts +3 -5
- package/build/transaction/builders/DeploymentTransaction.js +12 -2
- package/build/transaction/builders/InteractionTransaction.d.ts +1 -0
- package/build/transaction/builders/InteractionTransaction.js +12 -1
- package/build/transaction/interfaces/ITransactionParameters.d.ts +4 -0
- package/build/transaction/shared/TweakedTransaction.js +3 -3
- package/eslint.config.js +1 -0
- package/package.json +1 -1
- package/src/_version.ts +1 -1
- package/src/generators/Features.ts +10 -5
- package/src/generators/Generator.ts +54 -5
- package/src/generators/builders/CalldataGenerator.ts +16 -9
- package/src/generators/builders/DeploymentGenerator.ts +17 -1
- package/src/generators/builders/LegacyCalldataGenerator.ts +14 -6
- package/src/opnet.ts +9 -0
- package/src/transaction/TransactionFactory.ts +95 -31
- package/src/transaction/browser/extensions/UnisatSigner.ts +4 -6
- package/src/transaction/builders/DeploymentTransaction.ts +12 -3
- package/src/transaction/builders/InteractionTransaction.ts +15 -0
- package/src/transaction/interfaces/ITransactionParameters.ts +7 -1
- package/src/transaction/shared/TweakedTransaction.ts +3 -4
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { Network, networks, toXOnly } from '@btc-vision/bitcoin';
|
|
2
2
|
import { BinaryWriter } from '../buffer/BinaryWriter.js';
|
|
3
|
+
import { AccessListFeature, Feature, Features } from './Features.js';
|
|
4
|
+
import { Address } from '../keypair/Address.js';
|
|
5
|
+
import { Compressor } from '../bytecode/Compressor.js';
|
|
3
6
|
|
|
4
7
|
/** Bitcoin Script Generator */
|
|
5
8
|
export abstract class Generator {
|
|
@@ -48,13 +51,22 @@ export abstract class Generator {
|
|
|
48
51
|
this.xSenderPubKey = toXOnly(senderPubKey);
|
|
49
52
|
}
|
|
50
53
|
|
|
51
|
-
public
|
|
52
|
-
|
|
54
|
+
public buildHeader(features: Features[]): Buffer {
|
|
55
|
+
let flags: number = 0;
|
|
56
|
+
|
|
57
|
+
for (const feature of features) {
|
|
58
|
+
flags |= feature;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const bytesU24 = Buffer.alloc(3);
|
|
62
|
+
bytesU24.writeUIntBE(flags, 0, 3);
|
|
63
|
+
|
|
64
|
+
return Buffer.from([this.senderPubKey[0], ...bytesU24]);
|
|
53
65
|
}
|
|
54
66
|
|
|
55
|
-
public getHeader(maxPriority: bigint): Buffer {
|
|
56
|
-
const writer = new BinaryWriter(
|
|
57
|
-
writer.writeBytes(this.
|
|
67
|
+
public getHeader(maxPriority: bigint, features: Features[] = []): Buffer {
|
|
68
|
+
const writer = new BinaryWriter(12);
|
|
69
|
+
writer.writeBytes(this.buildHeader(features));
|
|
58
70
|
writer.writeU64(maxPriority);
|
|
59
71
|
|
|
60
72
|
return Buffer.from(writer.getBuffer());
|
|
@@ -92,4 +104,41 @@ export abstract class Generator {
|
|
|
92
104
|
|
|
93
105
|
return chunks;
|
|
94
106
|
}
|
|
107
|
+
|
|
108
|
+
protected encodeFeature(feature: Feature<Features>): Buffer[][] {
|
|
109
|
+
switch (feature.opcode) {
|
|
110
|
+
case Features.ACCESS_LIST:
|
|
111
|
+
return this.splitBufferIntoChunks(
|
|
112
|
+
this.encodeAccessListFeature(feature as AccessListFeature),
|
|
113
|
+
);
|
|
114
|
+
default:
|
|
115
|
+
throw new Error(`Unknown feature type: ${feature.opcode}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private encodeAccessListFeature(feature: AccessListFeature): Buffer {
|
|
120
|
+
const writer = new BinaryWriter();
|
|
121
|
+
|
|
122
|
+
writer.writeU16(Object.keys(feature.data).length);
|
|
123
|
+
|
|
124
|
+
for (const contract in feature.data) {
|
|
125
|
+
const parsedContract = Address.fromString(contract);
|
|
126
|
+
const data = feature.data[contract];
|
|
127
|
+
|
|
128
|
+
writer.writeAddress(parsedContract);
|
|
129
|
+
writer.writeU32(data.length);
|
|
130
|
+
|
|
131
|
+
for (const pointer of data) {
|
|
132
|
+
const pointerBuffer = Buffer.from(pointer, 'base64');
|
|
133
|
+
|
|
134
|
+
if (pointerBuffer.length !== 32) {
|
|
135
|
+
throw new Error(`Invalid pointer length: ${pointerBuffer.length}`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
writer.writeBytes(pointerBuffer);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return Compressor.compress(Buffer.from(writer.getBuffer()));
|
|
143
|
+
}
|
|
95
144
|
}
|
|
@@ -2,9 +2,8 @@ import { crypto, Network, networks, opcodes, script } from '@btc-vision/bitcoin'
|
|
|
2
2
|
import { ECPairInterface } from 'ecpair';
|
|
3
3
|
import { Compressor } from '../../bytecode/Compressor.js';
|
|
4
4
|
import { EcKeyPair } from '../../keypair/EcKeyPair.js';
|
|
5
|
-
import {
|
|
5
|
+
import { Feature, Features } from '../Features.js';
|
|
6
6
|
import { Generator } from '../Generator.js';
|
|
7
|
-
import { BinaryWriter } from '../../buffer/BinaryWriter.js';
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* Class to generate bitcoin script for interaction transactions
|
|
@@ -59,7 +58,7 @@ export class CalldataGenerator extends Generator {
|
|
|
59
58
|
* @param {Buffer} contractSecret - The contract secret
|
|
60
59
|
* @param preimage
|
|
61
60
|
* @param maxPriority - Amount of satoshis to spend max on priority fee
|
|
62
|
-
* @param {
|
|
61
|
+
* @param {Feature<Features>[]} features - The features to use
|
|
63
62
|
* @returns {Buffer} - The compiled script
|
|
64
63
|
* @throws {Error} - If something goes wrong
|
|
65
64
|
*/
|
|
@@ -68,15 +67,25 @@ export class CalldataGenerator extends Generator {
|
|
|
68
67
|
contractSecret: Buffer,
|
|
69
68
|
preimage: Buffer,
|
|
70
69
|
maxPriority: bigint,
|
|
71
|
-
features: Features[] = [],
|
|
70
|
+
features: Feature<Features>[] = [],
|
|
72
71
|
): Buffer {
|
|
73
72
|
if (!this.contractSaltPubKey) throw new Error('Contract salt public key not set');
|
|
74
73
|
|
|
75
74
|
const dataChunks: Buffer[][] = this.splitBufferIntoChunks(calldata);
|
|
76
75
|
if (!dataChunks.length) throw new Error('No data chunks found');
|
|
77
76
|
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
const featuresList: Features[] = [];
|
|
78
|
+
const featureData: (number | Buffer | Buffer[])[] = [];
|
|
79
|
+
for (let i = 0; i < features.length; i++) {
|
|
80
|
+
const feature = features[i];
|
|
81
|
+
featuresList.push(feature.opcode);
|
|
82
|
+
|
|
83
|
+
const data = this.encodeFeature(feature);
|
|
84
|
+
featureData.push(...data);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let compiledData: (number | Buffer | Buffer[])[] = [
|
|
88
|
+
this.getHeader(maxPriority, featuresList),
|
|
80
89
|
opcodes.OP_TOALTSTACK,
|
|
81
90
|
|
|
82
91
|
// CHALLENGE PREIMAGE FOR REWARD,
|
|
@@ -105,11 +114,9 @@ export class CalldataGenerator extends Generator {
|
|
|
105
114
|
Generator.MAGIC,
|
|
106
115
|
];
|
|
107
116
|
|
|
108
|
-
const featureOpcodes = features.map((feature) => FeatureOpCodes[feature]); // Get the opcodes for the features
|
|
109
|
-
|
|
110
117
|
// Write calldata
|
|
111
118
|
compiledData = compiledData.concat(
|
|
112
|
-
...
|
|
119
|
+
...featureData,
|
|
113
120
|
...[opcodes.OP_1NEGATE, ...dataChunks, opcodes.OP_ELSE, opcodes.OP_1, opcodes.OP_ENDIF],
|
|
114
121
|
);
|
|
115
122
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { crypto, Network, networks, opcodes, script } from '@btc-vision/bitcoin';
|
|
2
2
|
import { Generator } from '../Generator.js';
|
|
3
|
+
import { Feature, Features } from '../Features.js';
|
|
3
4
|
|
|
4
5
|
export class DeploymentGenerator extends Generator {
|
|
5
6
|
constructor(
|
|
@@ -46,14 +47,28 @@ export class DeploymentGenerator extends Generator {
|
|
|
46
47
|
preimage: Buffer,
|
|
47
48
|
maxPriority: bigint,
|
|
48
49
|
calldata?: Buffer,
|
|
50
|
+
features?: Feature<Features>[],
|
|
49
51
|
): (number | Buffer)[] {
|
|
50
52
|
if (!this.contractSaltPubKey) throw new Error('Contract salt public key not set');
|
|
51
53
|
|
|
52
54
|
const dataChunks: Buffer[][] = this.splitBufferIntoChunks(contractBytecode);
|
|
53
55
|
const calldataChunks: Buffer[][] = calldata ? this.splitBufferIntoChunks(calldata) : [];
|
|
54
56
|
|
|
57
|
+
const featuresList: Features[] = [];
|
|
58
|
+
const featureData: (number | Buffer | Buffer[])[] = [];
|
|
59
|
+
|
|
60
|
+
if (features) {
|
|
61
|
+
for (let i = 0; i < features.length; i++) {
|
|
62
|
+
const feature = features[i];
|
|
63
|
+
featuresList.push(feature.opcode);
|
|
64
|
+
|
|
65
|
+
const data = this.encodeFeature(feature);
|
|
66
|
+
featureData.push(...data);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
55
70
|
const compiledData = [
|
|
56
|
-
this.getHeader(maxPriority),
|
|
71
|
+
this.getHeader(maxPriority, featuresList),
|
|
57
72
|
opcodes.OP_TOALTSTACK,
|
|
58
73
|
|
|
59
74
|
// CHALLENGE PREIMAGE FOR REWARD,
|
|
@@ -80,6 +95,7 @@ export class DeploymentGenerator extends Generator {
|
|
|
80
95
|
opcodes.OP_IF,
|
|
81
96
|
|
|
82
97
|
Generator.MAGIC,
|
|
98
|
+
...featureData,
|
|
83
99
|
opcodes.OP_0,
|
|
84
100
|
...calldataChunks,
|
|
85
101
|
opcodes.OP_1NEGATE,
|
|
@@ -2,8 +2,8 @@ import { crypto, Network, networks, opcodes, script } from '@btc-vision/bitcoin'
|
|
|
2
2
|
import { ECPairInterface } from 'ecpair';
|
|
3
3
|
import { Compressor } from '../../bytecode/Compressor.js';
|
|
4
4
|
import { EcKeyPair } from '../../keypair/EcKeyPair.js';
|
|
5
|
-
import { FeatureOpCodes, Features } from '../Features.js';
|
|
6
5
|
import { Generator } from '../Generator.js';
|
|
6
|
+
import { Feature, Features } from '../Features.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Class to generate bitcoin script for interaction transactions
|
|
@@ -63,13 +63,23 @@ export class LegacyCalldataGenerator extends Generator {
|
|
|
63
63
|
contractSecret: Buffer,
|
|
64
64
|
preimage: Buffer,
|
|
65
65
|
maxPriority: bigint,
|
|
66
|
-
features: Features[] = [],
|
|
66
|
+
features: Feature<Features>[] = [],
|
|
67
67
|
): Buffer {
|
|
68
68
|
const dataChunks: Buffer[][] = this.splitBufferIntoChunks(calldata);
|
|
69
69
|
if (!dataChunks.length) throw new Error('No data chunks found');
|
|
70
70
|
|
|
71
|
+
const featuresList: Features[] = [];
|
|
72
|
+
const featureData: (number | Buffer | Buffer[])[] = [];
|
|
73
|
+
for (let i = 0; i < features.length; i++) {
|
|
74
|
+
const feature = features[i];
|
|
75
|
+
featuresList.push(feature.opcode);
|
|
76
|
+
|
|
77
|
+
const data = this.encodeFeature(feature);
|
|
78
|
+
featureData.push(...data);
|
|
79
|
+
}
|
|
80
|
+
|
|
71
81
|
let compiledData = [
|
|
72
|
-
this.getHeader(maxPriority),
|
|
82
|
+
this.getHeader(maxPriority, featuresList),
|
|
73
83
|
opcodes.OP_TOALTSTACK,
|
|
74
84
|
|
|
75
85
|
// CHALLENGE PREIMAGE FOR REWARD,
|
|
@@ -94,11 +104,9 @@ export class LegacyCalldataGenerator extends Generator {
|
|
|
94
104
|
Generator.MAGIC,
|
|
95
105
|
];
|
|
96
106
|
|
|
97
|
-
const featureOpcodes = features.map((feature) => FeatureOpCodes[feature]); // Get the opcodes for the features
|
|
98
|
-
|
|
99
107
|
// Write calldata
|
|
100
108
|
compiledData = compiledData.concat(
|
|
101
|
-
...
|
|
109
|
+
...featureData,
|
|
102
110
|
...[opcodes.OP_1NEGATE, ...dataChunks, opcodes.OP_ELSE, opcodes.OP_1, opcodes.OP_ENDIF],
|
|
103
111
|
);
|
|
104
112
|
|
package/src/opnet.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Unisat } from './transaction/browser/types/Unisat.js';
|
|
2
|
+
|
|
1
3
|
export { version } from './_version.js';
|
|
2
4
|
|
|
3
5
|
/** Bytecode */
|
|
@@ -97,3 +99,10 @@ export * from './transaction/browser/Web3Provider.js';
|
|
|
97
99
|
|
|
98
100
|
export * from './keypair/Secp256k1PointDeriver.js';
|
|
99
101
|
export * from './transaction/ContractAddress.js';
|
|
102
|
+
|
|
103
|
+
declare global {
|
|
104
|
+
interface Window {
|
|
105
|
+
unisat?: Unisat;
|
|
106
|
+
opnet?: Unisat;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -19,7 +19,11 @@ import {
|
|
|
19
19
|
} from './interfaces/ITransactionParameters.js';
|
|
20
20
|
import { PSBTTypes } from './psbt/PSBTTypes.js';
|
|
21
21
|
import { ChallengeSolutionTransaction } from './builders/ChallengeSolutionTransaction.js';
|
|
22
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
IDeploymentParametersWithoutSigner,
|
|
24
|
+
InteractionParametersWithoutSigner,
|
|
25
|
+
} from './browser/Web3Provider.js';
|
|
26
|
+
import { WindowWithWallets } from './browser/extensions/UnisatSigner.js';
|
|
23
27
|
|
|
24
28
|
export interface DeploymentResult {
|
|
25
29
|
readonly transaction: [string, string];
|
|
@@ -174,26 +178,7 @@ export class TransactionFactory {
|
|
|
174
178
|
throw new Error('Field "signer" not provided, OP_WALLET not detected.');
|
|
175
179
|
}
|
|
176
180
|
|
|
177
|
-
const inputs = (interactionParameters.optionalInputs
|
|
178
|
-
let nonWitness = input.nonWitnessUtxo;
|
|
179
|
-
if (
|
|
180
|
-
nonWitness &&
|
|
181
|
-
!(nonWitness instanceof Uint8Array) &&
|
|
182
|
-
typeof nonWitness === 'object'
|
|
183
|
-
) {
|
|
184
|
-
nonWitness = Buffer.from(
|
|
185
|
-
Uint8Array.from(
|
|
186
|
-
Object.values(input.nonWitnessUtxo as unknown as Record<number, number>),
|
|
187
|
-
),
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return {
|
|
192
|
-
...input,
|
|
193
|
-
nonWitnessUtxo: nonWitness,
|
|
194
|
-
};
|
|
195
|
-
});
|
|
196
|
-
|
|
181
|
+
const inputs = this.parseOptionalInputs(interactionParameters.optionalInputs);
|
|
197
182
|
const preTransaction: InteractionTransaction = new InteractionTransaction({
|
|
198
183
|
...interactionParameters,
|
|
199
184
|
utxos: [interactionParameters.utxos[0]], // we simulate one input here.
|
|
@@ -277,21 +262,46 @@ export class TransactionFactory {
|
|
|
277
262
|
public async signDeployment(
|
|
278
263
|
deploymentParameters: IDeploymentParameters,
|
|
279
264
|
): Promise<DeploymentResult> {
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
|
|
265
|
+
const opWalletDeployment = await this.detectDeploymentOPWallet(deploymentParameters);
|
|
266
|
+
if (opWalletDeployment) {
|
|
267
|
+
return opWalletDeployment;
|
|
268
|
+
}
|
|
283
269
|
|
|
284
|
-
|
|
285
|
-
|
|
270
|
+
if (!('signer' in deploymentParameters)) {
|
|
271
|
+
throw new Error('Field "signer" not provided, OP_WALLET not detected.');
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const inputs = this.parseOptionalInputs(deploymentParameters.optionalInputs);
|
|
275
|
+
const preTransaction: DeploymentTransaction = new DeploymentTransaction({
|
|
276
|
+
...deploymentParameters,
|
|
277
|
+
utxos: [deploymentParameters.utxos[0]], // we simulate one input here.
|
|
278
|
+
optionalInputs: inputs,
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// we don't sign that transaction, we just need the parameters.
|
|
282
|
+
await preTransaction.generateTransactionMinimalSignatures();
|
|
286
283
|
|
|
287
284
|
const parameters: IFundingTransactionParameters =
|
|
288
285
|
await preTransaction.getFundingTransactionParameters();
|
|
289
286
|
|
|
287
|
+
parameters.utxos = deploymentParameters.utxos;
|
|
290
288
|
parameters.amount =
|
|
291
289
|
(await preTransaction.estimateTransactionFees()) +
|
|
292
290
|
this.getPriorityFee(deploymentParameters) +
|
|
293
291
|
preTransaction.getOptionalOutputValue();
|
|
294
292
|
|
|
293
|
+
const feeEstimationFundingTransaction = await this.createFundTransaction({
|
|
294
|
+
...parameters,
|
|
295
|
+
optionalOutputs: [],
|
|
296
|
+
optionalInputs: [],
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
if (!feeEstimationFundingTransaction) {
|
|
300
|
+
throw new Error('Could not sign funding transaction.');
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
parameters.estimatedFees = feeEstimationFundingTransaction.estimatedFees;
|
|
304
|
+
|
|
295
305
|
const fundingTransaction: FundingTransaction = new FundingTransaction({
|
|
296
306
|
...parameters,
|
|
297
307
|
optionalInputs: [],
|
|
@@ -316,12 +326,12 @@ export class TransactionFactory {
|
|
|
316
326
|
|
|
317
327
|
const newParams: IDeploymentParameters = {
|
|
318
328
|
...deploymentParameters,
|
|
319
|
-
utxos: [newUtxo],
|
|
329
|
+
utxos: [newUtxo], // always 0
|
|
320
330
|
randomBytes: preTransaction.getRndBytes(),
|
|
321
331
|
preimage: preTransaction.getPreimage(),
|
|
322
332
|
nonWitnessUtxo: signedTransaction.toBuffer(),
|
|
323
|
-
|
|
324
|
-
optionalInputs:
|
|
333
|
+
estimatedFees: preTransaction.estimatedFees,
|
|
334
|
+
optionalInputs: inputs,
|
|
325
335
|
};
|
|
326
336
|
|
|
327
337
|
const finalTransaction: DeploymentTransaction = new DeploymentTransaction(newParams);
|
|
@@ -420,14 +430,41 @@ export class TransactionFactory {
|
|
|
420
430
|
return utxos;
|
|
421
431
|
}
|
|
422
432
|
|
|
433
|
+
private parseOptionalInputs(optionalInputs?: UTXO[]): UTXO[] {
|
|
434
|
+
return (optionalInputs || []).map((input) => {
|
|
435
|
+
let nonWitness = input.nonWitnessUtxo;
|
|
436
|
+
if (
|
|
437
|
+
nonWitness &&
|
|
438
|
+
!(nonWitness instanceof Uint8Array) &&
|
|
439
|
+
typeof nonWitness === 'object'
|
|
440
|
+
) {
|
|
441
|
+
nonWitness = Buffer.from(
|
|
442
|
+
Uint8Array.from(
|
|
443
|
+
Object.values(input.nonWitnessUtxo as unknown as Record<number, number>),
|
|
444
|
+
),
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
return {
|
|
449
|
+
...input,
|
|
450
|
+
nonWitnessUtxo: nonWitness,
|
|
451
|
+
};
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
|
|
423
455
|
private async detectInteractionOPWallet(
|
|
424
456
|
interactionParameters: IInteractionParameters | InteractionParametersWithoutSigner,
|
|
425
457
|
): Promise<InteractionResponse | null> {
|
|
426
|
-
if (typeof window === 'undefined'
|
|
458
|
+
if (typeof window === 'undefined') {
|
|
459
|
+
return null;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const _window = window as WindowWithWallets;
|
|
463
|
+
if (!_window || !_window.opnet || !_window.opnet.web3) {
|
|
427
464
|
return null;
|
|
428
465
|
}
|
|
429
466
|
|
|
430
|
-
const opnet =
|
|
467
|
+
const opnet = _window.opnet.web3;
|
|
431
468
|
const interaction = await opnet.signInteraction({
|
|
432
469
|
...interactionParameters,
|
|
433
470
|
|
|
@@ -442,6 +479,33 @@ export class TransactionFactory {
|
|
|
442
479
|
return interaction;
|
|
443
480
|
}
|
|
444
481
|
|
|
482
|
+
private async detectDeploymentOPWallet(
|
|
483
|
+
deploymentParameters: IDeploymentParameters | IDeploymentParametersWithoutSigner,
|
|
484
|
+
): Promise<DeploymentResult | null> {
|
|
485
|
+
if (typeof window === 'undefined') {
|
|
486
|
+
return null;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const _window = window as WindowWithWallets;
|
|
490
|
+
if (!_window || !_window.opnet || !_window.opnet.web3) {
|
|
491
|
+
return null;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
const opnet = _window.opnet.web3;
|
|
495
|
+
const deployment = await opnet.deployContract({
|
|
496
|
+
...deploymentParameters,
|
|
497
|
+
|
|
498
|
+
// @ts-expect-error no, this is ok
|
|
499
|
+
signer: undefined,
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
if (!deployment) {
|
|
503
|
+
throw new Error('Could not sign interaction transaction.');
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
return deployment;
|
|
507
|
+
}
|
|
508
|
+
|
|
445
509
|
private async _createChallengeSolution(
|
|
446
510
|
parameters: IChallengeSolutionTransactionParameters,
|
|
447
511
|
): Promise<ChallengeSolutionResponse> {
|
|
@@ -14,11 +14,9 @@ import { canSignNonTaprootInput, isTaprootInput } from '../../../signer/SignerUt
|
|
|
14
14
|
import { CustomKeypair } from '../BrowserSignerBase.js';
|
|
15
15
|
import { PsbtSignatureOptions, SignatureType, Unisat, UnisatNetwork } from '../types/Unisat.js';
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
opnet?: Unisat;
|
|
21
|
-
}
|
|
17
|
+
export interface WindowWithWallets {
|
|
18
|
+
unisat?: Unisat;
|
|
19
|
+
opnet?: Unisat;
|
|
22
20
|
}
|
|
23
21
|
|
|
24
22
|
export class UnisatSigner extends CustomKeypair {
|
|
@@ -85,7 +83,7 @@ export class UnisatSigner extends CustomKeypair {
|
|
|
85
83
|
public get unisat(): Unisat {
|
|
86
84
|
if (!window) throw new Error('Window not found');
|
|
87
85
|
|
|
88
|
-
const module = window.unisat;
|
|
86
|
+
const module = (window as WindowWithWallets).unisat;
|
|
89
87
|
if (!module) {
|
|
90
88
|
throw new Error('Unisat extension not found');
|
|
91
89
|
}
|
|
@@ -118,7 +118,7 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
|
|
|
118
118
|
this.verifyCalldata();
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
if(!parameters.preimage) throw new Error('Preimage is required');
|
|
121
|
+
if (!parameters.preimage) throw new Error('Preimage is required');
|
|
122
122
|
|
|
123
123
|
this.randomBytes = parameters.randomBytes || BitcoinUtils.rndBytes();
|
|
124
124
|
this.preimage = parameters.preimage;
|
|
@@ -274,7 +274,11 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
|
|
|
274
274
|
if (i === 0) {
|
|
275
275
|
transaction.finalizeInput(i, this.customFinalizer);
|
|
276
276
|
} else {
|
|
277
|
-
|
|
277
|
+
try {
|
|
278
|
+
transaction.finalizeInput(i, this.customFinalizerP2SH);
|
|
279
|
+
} catch (e) {
|
|
280
|
+
transaction.finalizeInput(i);
|
|
281
|
+
}
|
|
278
282
|
}
|
|
279
283
|
}
|
|
280
284
|
}
|
|
@@ -305,7 +309,12 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
|
|
|
305
309
|
transaction.finalizeInput(0, this.customFinalizer);
|
|
306
310
|
} else {
|
|
307
311
|
transaction.signInput(i, this.getSignerKey());
|
|
308
|
-
|
|
312
|
+
|
|
313
|
+
try {
|
|
314
|
+
transaction.finalizeInput(i, this.customFinalizerP2SH);
|
|
315
|
+
} catch (e) {
|
|
316
|
+
transaction.finalizeInput(i);
|
|
317
|
+
}
|
|
309
318
|
}
|
|
310
319
|
}
|
|
311
320
|
}
|
|
@@ -3,6 +3,7 @@ import { TransactionType } from '../enums/TransactionType.js';
|
|
|
3
3
|
import { TapLeafScript } from '../interfaces/Tap.js';
|
|
4
4
|
import { IInteractionParameters } from '../interfaces/ITransactionParameters.js';
|
|
5
5
|
import { SharedInteractionTransaction } from './SharedInteractionTransaction.js';
|
|
6
|
+
import { Feature, Features } from '../../generators/Features.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Class for interaction transactions
|
|
@@ -32,9 +33,23 @@ export class InteractionTransaction extends SharedInteractionTransaction<Transac
|
|
|
32
33
|
this.contractSecret,
|
|
33
34
|
this.preimage,
|
|
34
35
|
this.priorityFee,
|
|
36
|
+
this.generateFeatures(parameters),
|
|
35
37
|
);
|
|
36
38
|
|
|
37
39
|
this.scriptTree = this.getScriptTree();
|
|
38
40
|
this.internalInit();
|
|
39
41
|
}
|
|
42
|
+
|
|
43
|
+
private generateFeatures(parameters: IInteractionParameters): Feature<Features>[] {
|
|
44
|
+
const features: Feature<Features>[] = [];
|
|
45
|
+
|
|
46
|
+
if (parameters.loadedStorage) {
|
|
47
|
+
features.push({
|
|
48
|
+
opcode: Features.ACCESS_LIST,
|
|
49
|
+
data: parameters.loadedStorage,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return features;
|
|
54
|
+
}
|
|
40
55
|
}
|
|
@@ -3,6 +3,10 @@ import { ITweakedTransactionData } from '../shared/TweakedTransaction.js';
|
|
|
3
3
|
import { ChainId } from '../../network/ChainId.js';
|
|
4
4
|
import { PsbtOutputExtended } from '@btc-vision/bitcoin';
|
|
5
5
|
|
|
6
|
+
export interface LoadedStorage {
|
|
7
|
+
[key: string]: string[];
|
|
8
|
+
}
|
|
9
|
+
|
|
6
10
|
export interface ITransactionParameters extends ITweakedTransactionData {
|
|
7
11
|
readonly from?: string;
|
|
8
12
|
readonly to?: string;
|
|
@@ -11,7 +15,7 @@ export interface ITransactionParameters extends ITweakedTransactionData {
|
|
|
11
15
|
|
|
12
16
|
nonWitnessUtxo?: Buffer;
|
|
13
17
|
estimatedFees?: bigint;
|
|
14
|
-
|
|
18
|
+
|
|
15
19
|
optionalInputs?: UTXO[];
|
|
16
20
|
optionalOutputs?: PsbtOutputExtended[];
|
|
17
21
|
|
|
@@ -40,6 +44,8 @@ export interface SharedInteractionParameters extends ITransactionParameters {
|
|
|
40
44
|
|
|
41
45
|
readonly preimage: Buffer;
|
|
42
46
|
readonly randomBytes?: Buffer;
|
|
47
|
+
|
|
48
|
+
readonly loadedStorage?: LoadedStorage;
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
export interface IInteractionParameters extends SharedInteractionParameters {
|
|
@@ -802,11 +802,10 @@ export abstract class TweakedTransaction extends Logger {
|
|
|
802
802
|
if (this.tapLeafScript) {
|
|
803
803
|
input.tapLeafScript = [this.tapLeafScript];
|
|
804
804
|
}
|
|
805
|
-
}
|
|
806
805
|
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
806
|
+
if (this.nonWitnessUtxo) {
|
|
807
|
+
input.nonWitnessUtxo = this.nonWitnessUtxo;
|
|
808
|
+
}
|
|
810
809
|
}
|
|
811
810
|
|
|
812
811
|
/*if (utxo.nonWitnessUtxo && extra) {
|