@btc-vision/transaction 1.2.1 → 1.2.3
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/crypto/crypto-browser.d.ts +1 -1
- package/browser/generators/builders/CalldataGenerator.d.ts +1 -1
- package/browser/generators/builders/DeploymentGenerator.d.ts +1 -1
- package/browser/generators/builders/MineableReward.d.ts +7 -0
- package/browser/index.js +1 -1
- package/browser/opnet.d.ts +4 -0
- package/browser/transaction/ContractAddress.d.ts +1 -0
- package/browser/transaction/TransactionFactory.d.ts +19 -4
- package/browser/transaction/browser/WalletConnection.d.ts +18 -0
- package/browser/transaction/browser/types/Xverse.d.ts +24 -10
- package/browser/transaction/builders/ChallengeSolutionTransaction.d.ts +18 -0
- package/browser/transaction/builders/DeploymentTransaction.d.ts +4 -0
- package/browser/transaction/builders/SharedInteractionTransaction.d.ts +5 -0
- package/browser/transaction/builders/TransactionBuilder.d.ts +2 -0
- package/browser/transaction/enums/TransactionType.d.ts +3 -4
- package/browser/transaction/interfaces/ITransactionParameters.d.ts +6 -0
- package/browser/transaction/mineable/ChallengeGenerator.d.ts +9 -0
- package/browser/utxo/interfaces/IUTXO.d.ts +1 -1
- package/browser/verification/TapscriptVerificator.d.ts +1 -1
- package/build/_version.d.ts +1 -1
- package/build/_version.js +1 -1
- package/build/generators/Generator.js +1 -1
- package/build/generators/builders/CalldataGenerator.d.ts +1 -1
- package/build/generators/builders/CalldataGenerator.js +7 -26
- package/build/generators/builders/DeploymentGenerator.d.ts +1 -1
- package/build/generators/builders/DeploymentGenerator.js +9 -6
- package/build/generators/builders/LegacyCalldataGenerator.js +5 -1
- package/build/generators/builders/MineableReward.d.ts +7 -0
- package/build/generators/builders/MineableReward.js +47 -0
- package/build/opnet.d.ts +4 -0
- package/build/opnet.js +4 -0
- package/build/transaction/ContractAddress.d.ts +1 -0
- package/build/transaction/ContractAddress.js +4 -1
- package/build/transaction/TransactionFactory.d.ts +19 -4
- package/build/transaction/TransactionFactory.js +32 -0
- package/build/transaction/browser/WalletConnection.d.ts +18 -0
- package/build/transaction/browser/WalletConnection.js +95 -0
- package/build/transaction/browser/extensions/UnisatSigner.js +5 -2
- package/build/transaction/browser/extensions/XverseSigner.js +15 -9
- package/build/transaction/browser/types/Xverse.d.ts +24 -10
- package/build/transaction/builders/ChallengeSolutionTransaction.d.ts +18 -0
- package/build/transaction/builders/ChallengeSolutionTransaction.js +51 -0
- package/build/transaction/builders/DeploymentTransaction.d.ts +4 -0
- package/build/transaction/builders/DeploymentTransaction.js +23 -4
- package/build/transaction/builders/InteractionTransaction.js +1 -1
- package/build/transaction/builders/SharedInteractionTransaction.d.ts +5 -0
- package/build/transaction/builders/SharedInteractionTransaction.js +35 -13
- package/build/transaction/builders/TransactionBuilder.d.ts +2 -0
- package/build/transaction/builders/TransactionBuilder.js +2 -0
- package/build/transaction/enums/TransactionType.d.ts +3 -4
- package/build/transaction/enums/TransactionType.js +3 -4
- package/build/transaction/interfaces/ITransactionParameters.d.ts +6 -0
- package/build/transaction/mineable/ChallengeGenerator.d.ts +9 -0
- package/build/transaction/mineable/ChallengeGenerator.js +28 -0
- package/build/transaction/shared/TweakedTransaction.js +1 -1
- package/build/utxo/interfaces/IUTXO.d.ts +1 -1
- package/build/verification/TapscriptVerificator.d.ts +1 -1
- package/build/verification/TapscriptVerificator.js +2 -8
- package/package.json +3 -3
- package/src/_version.ts +1 -1
- package/src/generators/Generator.ts +1 -1
- package/src/generators/builders/CalldataGenerator.ts +10 -41
- package/src/generators/builders/DeploymentGenerator.ts +18 -7
- package/src/generators/builders/LegacyCalldataGenerator.ts +5 -1
- package/src/generators/builders/MineableReward.ts +63 -0
- package/src/opnet.ts +5 -0
- package/src/transaction/ContractAddress.ts +5 -1
- package/src/transaction/TransactionFactory.ts +66 -3
- package/src/transaction/browser/WalletConnection.ts +110 -0
- package/src/transaction/browser/extensions/UnisatSigner.ts +7 -3
- package/src/transaction/browser/extensions/XverseSigner.ts +24 -23
- package/src/transaction/browser/types/Xverse.ts +50 -36
- package/src/transaction/builders/ChallengeSolutionTransaction.ts +88 -0
- package/src/transaction/builders/DeploymentTransaction.ts +46 -3
- package/src/transaction/builders/InteractionTransaction.ts +1 -0
- package/src/transaction/builders/SharedInteractionTransaction.ts +54 -14
- package/src/transaction/builders/TransactionBuilder.ts +3 -0
- package/src/transaction/enums/TransactionType.ts +3 -4
- package/src/transaction/interfaces/ITransactionParameters.ts +8 -15
- package/src/transaction/mineable/ChallengeGenerator.ts +39 -0
- package/src/transaction/shared/TweakedTransaction.ts +1 -1
- package/src/utxo/interfaces/IUTXO.ts +1 -1
- package/src/verification/TapscriptVerificator.ts +3 -18
|
@@ -11,12 +11,14 @@ import { InteractionTransaction } from './builders/InteractionTransaction.js';
|
|
|
11
11
|
import { TransactionBuilder } from './builders/TransactionBuilder.js';
|
|
12
12
|
import { TransactionType } from './enums/TransactionType.js';
|
|
13
13
|
import {
|
|
14
|
+
IChallengeSolutionTransactionParameters,
|
|
14
15
|
IDeploymentParameters,
|
|
15
16
|
IFundingTransactionParameters,
|
|
16
17
|
IInteractionParameters,
|
|
17
18
|
ITransactionParameters,
|
|
18
19
|
} from './interfaces/ITransactionParameters.js';
|
|
19
20
|
import { PSBTTypes } from './psbt/PSBTTypes.js';
|
|
21
|
+
import { ChallengeSolutionTransaction } from './builders/ChallengeSolutionTransaction.js';
|
|
20
22
|
|
|
21
23
|
export interface DeploymentResult {
|
|
22
24
|
readonly transaction: [string, string];
|
|
@@ -25,6 +27,8 @@ export interface DeploymentResult {
|
|
|
25
27
|
readonly contractPubKey: string;
|
|
26
28
|
readonly p2trAddress: string;
|
|
27
29
|
|
|
30
|
+
readonly preimage: string;
|
|
31
|
+
|
|
28
32
|
readonly utxos: UTXO[];
|
|
29
33
|
}
|
|
30
34
|
|
|
@@ -43,13 +47,27 @@ export interface FundingTransactionResponse {
|
|
|
43
47
|
readonly nextUTXOs: UTXO[];
|
|
44
48
|
}
|
|
45
49
|
|
|
46
|
-
export interface
|
|
50
|
+
export interface ChallengeSolutionResponse {
|
|
51
|
+
readonly tx: Transaction;
|
|
52
|
+
readonly original: ChallengeSolutionTransaction;
|
|
53
|
+
readonly estimatedFees: bigint;
|
|
54
|
+
readonly nextUTXOs: UTXO[];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface BitcoinTransferBase {
|
|
47
58
|
readonly tx: string;
|
|
48
|
-
readonly original: FundingTransaction;
|
|
49
59
|
readonly estimatedFees: bigint;
|
|
50
60
|
readonly nextUTXOs: UTXO[];
|
|
51
61
|
}
|
|
52
62
|
|
|
63
|
+
export interface ChallengeSolution extends BitcoinTransferBase {
|
|
64
|
+
readonly original: ChallengeSolutionTransaction;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface BitcoinTransferResponse extends BitcoinTransferBase {
|
|
68
|
+
readonly original: FundingTransaction;
|
|
69
|
+
}
|
|
70
|
+
|
|
53
71
|
export class TransactionFactory {
|
|
54
72
|
/**
|
|
55
73
|
* @description Generate a transaction with a custom script.
|
|
@@ -127,7 +145,7 @@ export class TransactionFactory {
|
|
|
127
145
|
*/
|
|
128
146
|
public async signInteraction(
|
|
129
147
|
interactionParameters: IInteractionParameters,
|
|
130
|
-
): Promise<[string, string, UTXO[]]> {
|
|
148
|
+
): Promise<[string, string, UTXO[], string]> {
|
|
131
149
|
if (!interactionParameters.to) {
|
|
132
150
|
throw new Error('Field "to" not provided.');
|
|
133
151
|
}
|
|
@@ -185,6 +203,7 @@ export class TransactionFactory {
|
|
|
185
203
|
...interactionParameters,
|
|
186
204
|
utxos: this.getUTXOAsTransaction(signedTransaction.tx, interactionParameters.to, 0), // always 0
|
|
187
205
|
randomBytes: preTransaction.getRndBytes(),
|
|
206
|
+
preimage: preTransaction.getPreimage(),
|
|
188
207
|
nonWitnessUtxo: signedTransaction.tx.toBuffer(),
|
|
189
208
|
estimatedFees: preTransaction.estimatedFees,
|
|
190
209
|
};
|
|
@@ -197,6 +216,7 @@ export class TransactionFactory {
|
|
|
197
216
|
signedTransaction.tx.toHex(),
|
|
198
217
|
outTx.toHex(),
|
|
199
218
|
this.getUTXOAsTransaction(signedTransaction.tx, interactionParameters.from, 1), // always 1
|
|
219
|
+
preTransaction.getPreimage().toString('hex'),
|
|
200
220
|
];
|
|
201
221
|
}
|
|
202
222
|
|
|
@@ -244,6 +264,7 @@ export class TransactionFactory {
|
|
|
244
264
|
...deploymentParameters,
|
|
245
265
|
utxos: [newUtxo],
|
|
246
266
|
randomBytes: preTransaction.getRndBytes(),
|
|
267
|
+
preimage: preTransaction.getPreimage(),
|
|
247
268
|
nonWitnessUtxo: signedTransaction.toBuffer(),
|
|
248
269
|
optionalOutputs: [],
|
|
249
270
|
};
|
|
@@ -270,6 +291,7 @@ export class TransactionFactory {
|
|
|
270
291
|
contractPubKey: finalTransaction.contractPubKey,
|
|
271
292
|
p2trAddress: finalTransaction.p2trAddress,
|
|
272
293
|
utxos: [refundUTXO],
|
|
294
|
+
preimage: preTransaction.getPreimage().toString('hex'),
|
|
273
295
|
};
|
|
274
296
|
}
|
|
275
297
|
|
|
@@ -286,7 +308,27 @@ export class TransactionFactory {
|
|
|
286
308
|
}
|
|
287
309
|
|
|
288
310
|
const resp = await this.createFundTransaction(parameters);
|
|
311
|
+
return {
|
|
312
|
+
estimatedFees: resp.estimatedFees,
|
|
313
|
+
original: resp.original,
|
|
314
|
+
tx: resp.tx.toHex(),
|
|
315
|
+
nextUTXOs: this.getAllNewUTXOs(resp.original, resp.tx, parameters.from),
|
|
316
|
+
};
|
|
317
|
+
}
|
|
289
318
|
|
|
319
|
+
/**
|
|
320
|
+
* @description Creates a challenge solution transaction.
|
|
321
|
+
* @param {IChallengeSolutionTransactionParameters} parameters - The challenge solution transaction parameters
|
|
322
|
+
* @returns {Promise<ChallengeSolution>} - The signed transaction
|
|
323
|
+
*/
|
|
324
|
+
public async createChallengeSolution(
|
|
325
|
+
parameters: IChallengeSolutionTransactionParameters,
|
|
326
|
+
): Promise<ChallengeSolution> {
|
|
327
|
+
if (!parameters.from) {
|
|
328
|
+
throw new Error('Field "from" not provided.');
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const resp = await this._createChallengeSolution(parameters);
|
|
290
332
|
return {
|
|
291
333
|
estimatedFees: resp.estimatedFees,
|
|
292
334
|
original: resp.original,
|
|
@@ -323,6 +365,27 @@ export class TransactionFactory {
|
|
|
323
365
|
return utxos;
|
|
324
366
|
}
|
|
325
367
|
|
|
368
|
+
private async _createChallengeSolution(
|
|
369
|
+
parameters: IChallengeSolutionTransactionParameters,
|
|
370
|
+
): Promise<ChallengeSolutionResponse> {
|
|
371
|
+
if (!parameters.to) throw new Error('Field "to" not provided.');
|
|
372
|
+
|
|
373
|
+
const challengeTransaction: ChallengeSolutionTransaction = new ChallengeSolutionTransaction(
|
|
374
|
+
parameters,
|
|
375
|
+
);
|
|
376
|
+
const signedTransaction: Transaction = await challengeTransaction.signTransaction();
|
|
377
|
+
if (!signedTransaction) {
|
|
378
|
+
throw new Error('Could not sign funding transaction.');
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return {
|
|
382
|
+
tx: signedTransaction,
|
|
383
|
+
original: challengeTransaction,
|
|
384
|
+
estimatedFees: challengeTransaction.estimatedFees,
|
|
385
|
+
nextUTXOs: this.getUTXOAsTransaction(signedTransaction, parameters.to, 0),
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
|
|
326
389
|
private async createFundTransaction(
|
|
327
390
|
parameters: IFundingTransactionParameters,
|
|
328
391
|
): Promise<FundingTransactionResponse> {
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { Address } from '../../opnet.js';
|
|
2
|
+
import { UnisatSigner } from './extensions/UnisatSigner.js';
|
|
3
|
+
import { XverseSigner } from './extensions/XverseSigner.js';
|
|
4
|
+
|
|
5
|
+
export enum SupportedWallets {
|
|
6
|
+
Unisat = 'unisat',
|
|
7
|
+
Xverse = 'xverse',
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class WalletConnection {
|
|
11
|
+
public wallet_type: SupportedWallets | null = null;
|
|
12
|
+
|
|
13
|
+
private unisatSigner: UnisatSigner | null = null; // OP_WALLET and Unisat wallet
|
|
14
|
+
private xverseSigner: XverseSigner | null = null;
|
|
15
|
+
|
|
16
|
+
public async connect(): Promise<void> {
|
|
17
|
+
if (this.wallet_type) {
|
|
18
|
+
throw new Error('Wallet already connected');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
this.unisatSigner = new UnisatSigner();
|
|
22
|
+
this.xverseSigner = new XverseSigner();
|
|
23
|
+
|
|
24
|
+
if (window.opnet || window.unisat) {
|
|
25
|
+
try {
|
|
26
|
+
await this.unisatSigner.init();
|
|
27
|
+
this.wallet_type = SupportedWallets.Unisat;
|
|
28
|
+
return;
|
|
29
|
+
} catch (error: unknown) {
|
|
30
|
+
if (error instanceof Error) {
|
|
31
|
+
throw new Error(error.message);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
throw new Error('Error connecting wallet');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (window.BitcoinProvider) {
|
|
39
|
+
try {
|
|
40
|
+
await this.xverseSigner.init();
|
|
41
|
+
this.wallet_type = SupportedWallets.Xverse;
|
|
42
|
+
return;
|
|
43
|
+
} catch (error: unknown) {
|
|
44
|
+
if (error instanceof Error) {
|
|
45
|
+
throw new Error(error.message);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
throw new Error('Error connecting wallet');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
throw new Error('Wallet not found');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public async disconnect(): Promise<void> {
|
|
56
|
+
if (!this.unisatSigner || !this.xverseSigner) {
|
|
57
|
+
throw new Error('Wallet not connected');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (this.wallet_type === SupportedWallets.Unisat) {
|
|
61
|
+
this.unisatSigner.unisat.disconnect();
|
|
62
|
+
} else {
|
|
63
|
+
await this.xverseSigner.BitcoinProvider.request('wallet_disconnect', null);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
this.wallet_type = null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public async switchTo(walletType: SupportedWallets): Promise<void> {
|
|
70
|
+
if (!this.unisatSigner || !this.xverseSigner) {
|
|
71
|
+
throw new Error('Wallet not connected');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (this.wallet_type === walletType) return;
|
|
75
|
+
|
|
76
|
+
if (walletType === SupportedWallets.Unisat) {
|
|
77
|
+
await this.unisatSigner.init();
|
|
78
|
+
this.wallet_type = SupportedWallets.Unisat;
|
|
79
|
+
} else {
|
|
80
|
+
await this.xverseSigner.init();
|
|
81
|
+
this.wallet_type = SupportedWallets.Xverse;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
public getAddress(): Address {
|
|
86
|
+
if (!this.unisatSigner || !this.xverseSigner) {
|
|
87
|
+
throw new Error('Wallet not connected');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (this.wallet_type === SupportedWallets.Unisat) {
|
|
91
|
+
return Address.fromString(this.unisatSigner.getPublicKey().toString('hex'));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return Address.fromString(this.xverseSigner.getPublicKey().toString('hex'));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
public getSigner(): UnisatSigner | XverseSigner {
|
|
98
|
+
if (!this.unisatSigner || !this.xverseSigner) {
|
|
99
|
+
throw new Error('Wallet not connected');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (this.wallet_type === SupportedWallets.Unisat) {
|
|
103
|
+
return this.unisatSigner;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return this.xverseSigner;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export default WalletConnection;
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
crypto as bitCrypto,
|
|
3
|
+
script as bitScript,
|
|
3
4
|
Network,
|
|
4
5
|
networks,
|
|
5
6
|
Psbt,
|
|
6
|
-
script as bitScript,
|
|
7
7
|
TapScriptSig,
|
|
8
8
|
toXOnly,
|
|
9
9
|
} from '@btc-vision/bitcoin';
|
|
10
|
+
import { PartialSig } from 'bip174/src/lib/interfaces.js';
|
|
10
11
|
import { ECPairInterface } from 'ecpair';
|
|
11
12
|
import { EcKeyPair } from '../../../keypair/EcKeyPair.js';
|
|
13
|
+
import { canSignNonTaprootInput, isTaprootInput } from '../../../signer/SignerUtils.js';
|
|
12
14
|
import { CustomKeypair } from '../BrowserSignerBase.js';
|
|
13
15
|
import { PsbtSignatureOptions, Unisat, UnisatNetwork } from '../types/Unisat.js';
|
|
14
|
-
import { PartialSig } from 'bip174/src/lib/interfaces.js';
|
|
15
|
-
import { canSignNonTaprootInput, isTaprootInput } from '../../../signer/SignerUtils.js';
|
|
16
16
|
|
|
17
17
|
declare global {
|
|
18
18
|
interface Window {
|
|
@@ -112,6 +112,10 @@ export class UnisatSigner extends CustomKeypair {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
const publicKey = await this.unisat.getPublicKey();
|
|
115
|
+
if (publicKey === '') {
|
|
116
|
+
throw new Error('Unlock your wallet first');
|
|
117
|
+
}
|
|
118
|
+
|
|
115
119
|
this._publicKey = Buffer.from(publicKey, 'hex');
|
|
116
120
|
|
|
117
121
|
this._p2wpkh = EcKeyPair.getP2WPKHAddress(this as unknown as ECPairInterface, this.network);
|
|
@@ -2,14 +2,14 @@ import { Network, networks, Psbt, TapScriptSig, toXOnly } from '@btc-vision/bitc
|
|
|
2
2
|
import { PartialSig } from 'bip174/src/lib/interfaces.js';
|
|
3
3
|
import { ECPairInterface } from 'ecpair';
|
|
4
4
|
import { EcKeyPair } from '../../../keypair/EcKeyPair.js';
|
|
5
|
-
import { CustomKeypair } from '../BrowserSignerBase.js';
|
|
6
|
-
import { PsbtSignatureOptions } from '../types/Unisat.js';
|
|
7
|
-
import { Xverse, XverseRPCGetAccountResponse, XverseRPCSignPsbtResponse } from '../types/Xverse.js';
|
|
8
5
|
import {
|
|
9
6
|
canSignNonTaprootInput,
|
|
10
7
|
isTaprootInput,
|
|
11
8
|
pubkeyInScript,
|
|
12
9
|
} from '../../../signer/SignerUtils.js';
|
|
10
|
+
import { CustomKeypair } from '../BrowserSignerBase.js';
|
|
11
|
+
import { PsbtSignatureOptions } from '../types/Unisat.js';
|
|
12
|
+
import { Xverse } from '../types/Xverse.js';
|
|
13
13
|
|
|
14
14
|
declare global {
|
|
15
15
|
interface Window {
|
|
@@ -90,10 +90,7 @@ export class XverseSigner extends CustomKeypair {
|
|
|
90
90
|
public async init(): Promise<void> {
|
|
91
91
|
if (this.isInitialized) return;
|
|
92
92
|
|
|
93
|
-
const connectResult =
|
|
94
|
-
'wallet_connect',
|
|
95
|
-
null,
|
|
96
|
-
)) as XverseRPCGetAccountResponse;
|
|
93
|
+
const connectResult = await this.BitcoinProvider.request('wallet_connect', null);
|
|
97
94
|
|
|
98
95
|
if ('error' in connectResult) throw new Error(connectResult.error.message);
|
|
99
96
|
|
|
@@ -193,7 +190,7 @@ export class XverseSigner extends CustomKeypair {
|
|
|
193
190
|
const options: PsbtSignatureOptions[] = [];
|
|
194
191
|
|
|
195
192
|
for (const psbt of transactions) {
|
|
196
|
-
const hex = psbt.
|
|
193
|
+
const hex = psbt.toBase64();
|
|
197
194
|
toSignPsbts.push(hex);
|
|
198
195
|
|
|
199
196
|
const toSignInputs = psbt.data.inputs
|
|
@@ -245,23 +242,20 @@ export class XverseSigner extends CustomKeypair {
|
|
|
245
242
|
});
|
|
246
243
|
}
|
|
247
244
|
|
|
248
|
-
|
|
245
|
+
const toSignInputs: {
|
|
246
|
+
[x: string]: number[];
|
|
247
|
+
} = {
|
|
248
|
+
[this.p2wpkh]: options[0].toSignInputs?.map((input) => input.index) || [],
|
|
249
|
+
};
|
|
249
250
|
|
|
250
|
-
const callSign =
|
|
251
|
+
const callSign = await this.BitcoinProvider.request('signPsbt', {
|
|
251
252
|
psbt: toSignPsbts[0],
|
|
252
|
-
signInputs:
|
|
253
|
-
})
|
|
253
|
+
signInputs: toSignInputs,
|
|
254
|
+
});
|
|
254
255
|
|
|
255
256
|
if ('error' in callSign) throw new Error(callSign.error.message);
|
|
256
257
|
|
|
257
|
-
const signedPsbts = Psbt.fromBase64(callSign.result.psbt);
|
|
258
|
-
|
|
259
|
-
/*for (let i = 0; i < signedPsbts.length; i++) {
|
|
260
|
-
const psbtOriginal = transactions[i];
|
|
261
|
-
const psbtSigned = signedPsbts[i];
|
|
262
|
-
|
|
263
|
-
psbtOriginal.combine(psbtSigned);
|
|
264
|
-
}*/
|
|
258
|
+
const signedPsbts = Psbt.fromBase64(callSign.result.psbt);
|
|
265
259
|
|
|
266
260
|
transactions[0].combine(signedPsbts);
|
|
267
261
|
}
|
|
@@ -342,10 +336,17 @@ export class XverseSigner extends CustomKeypair {
|
|
|
342
336
|
};
|
|
343
337
|
|
|
344
338
|
const psbt = transaction.toBase64();
|
|
345
|
-
|
|
339
|
+
|
|
340
|
+
const toSignInputs: {
|
|
341
|
+
[x: string]: number[];
|
|
342
|
+
} = {
|
|
343
|
+
[this.p2wpkh]: opts.toSignInputs?.map((input) => input.index) || [],
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
const callSign = await this.BitcoinProvider.request('signPsbt', {
|
|
346
347
|
psbt,
|
|
347
|
-
signInputs:
|
|
348
|
-
})
|
|
348
|
+
signInputs: toSignInputs,
|
|
349
|
+
});
|
|
349
350
|
|
|
350
351
|
if ('error' in callSign) throw new Error(callSign.error.message);
|
|
351
352
|
|
|
@@ -4,38 +4,50 @@ export enum XverseNetwork {
|
|
|
4
4
|
signet = 'Signet',
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
7
|
+
type XverseRPCResponse<T = unknown> =
|
|
8
|
+
| {
|
|
9
|
+
id: string;
|
|
10
|
+
jsonrpc: string;
|
|
11
|
+
result: T;
|
|
12
|
+
}
|
|
13
|
+
| {
|
|
14
|
+
id: string;
|
|
15
|
+
jsonrpc: string;
|
|
16
|
+
error: {
|
|
17
|
+
code: number;
|
|
18
|
+
message: string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
type XverseRPCGetAccountResponse = XverseRPCResponse<{
|
|
23
|
+
addresses: {
|
|
24
|
+
address: string;
|
|
25
|
+
addressType: string;
|
|
26
|
+
publicKey: string;
|
|
27
|
+
purpose: 'stacks' | 'payment' | 'ordinals'; // we only care about payment
|
|
28
|
+
}[];
|
|
29
|
+
walletType: string;
|
|
30
|
+
}>;
|
|
31
|
+
|
|
32
|
+
type XverseRPCSignPsbtResponse = XverseRPCResponse<{
|
|
33
|
+
psbt: string;
|
|
34
|
+
}>;
|
|
35
|
+
|
|
36
|
+
type XverseRPCGetBalanceResponse = XverseRPCResponse<{
|
|
37
|
+
confirmed: string;
|
|
38
|
+
total: string;
|
|
39
|
+
unconfirmed: string;
|
|
40
|
+
}>;
|
|
41
|
+
|
|
42
|
+
export type XVersePSBTInput = {
|
|
43
|
+
psbt: string;
|
|
44
|
+
signInputs:
|
|
45
|
+
| {
|
|
46
|
+
[x: string]: number[];
|
|
47
|
+
}
|
|
48
|
+
| undefined;
|
|
20
49
|
};
|
|
21
50
|
|
|
22
|
-
export type XverseRPCGetAccountResponse =
|
|
23
|
-
| XverseRPCResponse<{
|
|
24
|
-
addresses: {
|
|
25
|
-
address: string;
|
|
26
|
-
addressType: string;
|
|
27
|
-
publicKey: string;
|
|
28
|
-
purpose: string; // ordinals, payment or stacks (we only care about payment)
|
|
29
|
-
}[];
|
|
30
|
-
}>
|
|
31
|
-
| XverseRPCError;
|
|
32
|
-
|
|
33
|
-
export type XverseRPCSignPsbtResponse =
|
|
34
|
-
| XverseRPCResponse<{
|
|
35
|
-
psbt: string;
|
|
36
|
-
}>
|
|
37
|
-
| XverseRPCError;
|
|
38
|
-
|
|
39
51
|
interface InscriptionData {
|
|
40
52
|
address: string;
|
|
41
53
|
amount: number;
|
|
@@ -82,23 +94,25 @@ interface SignedTransactionResult {
|
|
|
82
94
|
}
|
|
83
95
|
|
|
84
96
|
export interface Xverse {
|
|
85
|
-
|
|
97
|
+
request(method: string, params: unknown): Promise<XverseRPCResponse>;
|
|
98
|
+
request(
|
|
99
|
+
method: 'wallet_connect' | 'wallet_getAccount',
|
|
100
|
+
params: null,
|
|
101
|
+
): Promise<XverseRPCGetAccountResponse>;
|
|
102
|
+
request(method: 'wallet_disconnect', params: null): Promise<XverseRPCResponse<null>>;
|
|
103
|
+
request(method: 'getBalance', params: null): Promise<XverseRPCGetBalanceResponse>;
|
|
104
|
+
request(method: 'signPsbt', params: XVersePSBTInput): Promise<XverseRPCSignPsbtResponse>;
|
|
86
105
|
|
|
87
106
|
addListener: (event: string, callback: (...args: unknown[]) => void) => void;
|
|
88
107
|
|
|
89
108
|
createInscription: (data: InscriptionData) => Promise<InscriptionResult>;
|
|
90
|
-
|
|
91
109
|
createRepeatInscriptions: (data: RepeatInscriptionsData) => Promise<InscriptionResult[]>;
|
|
92
110
|
|
|
93
|
-
request: (method: string, params: unknown) => Promise<XverseRPCResponse>;
|
|
94
|
-
|
|
95
111
|
sendBtcTransaction: (transaction: BtcTransaction) => Promise<TransactionResult>;
|
|
96
112
|
|
|
97
113
|
signMessage: (message: string) => Promise<SignedMessageResult>;
|
|
98
|
-
|
|
99
114
|
signMultipleTransactions: (
|
|
100
115
|
transactions: BtcTransaction[],
|
|
101
116
|
) => Promise<SignedTransactionResult[]>;
|
|
102
|
-
|
|
103
117
|
signTransaction: (transaction: BtcTransaction) => Promise<SignedTransactionResult>;
|
|
104
118
|
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { TransactionType } from '../enums/TransactionType.js';
|
|
2
|
+
import { IChallengeSolutionTransactionParameters } from '../interfaces/ITransactionParameters.js';
|
|
3
|
+
import { getFinalScripts, opcodes, Psbt, PsbtInput, script, Signer } from '@btc-vision/bitcoin';
|
|
4
|
+
import { TransactionBuilder } from './TransactionBuilder.js';
|
|
5
|
+
import { ECPairInterface } from 'ecpair';
|
|
6
|
+
|
|
7
|
+
export class ChallengeSolutionTransaction extends TransactionBuilder<TransactionType.CHALLENGE_SOLUTION> {
|
|
8
|
+
public readonly type: TransactionType.CHALLENGE_SOLUTION = TransactionType.CHALLENGE_SOLUTION;
|
|
9
|
+
|
|
10
|
+
protected amount: bigint;
|
|
11
|
+
protected readonly challengeSolution: Buffer;
|
|
12
|
+
|
|
13
|
+
constructor(parameters: IChallengeSolutionTransactionParameters) {
|
|
14
|
+
super(parameters);
|
|
15
|
+
|
|
16
|
+
this.amount = parameters.amount;
|
|
17
|
+
this.challengeSolution = parameters.challengeSolution;
|
|
18
|
+
|
|
19
|
+
this.internalInit();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
protected override async buildTransaction(): Promise<void> {
|
|
23
|
+
if (!this.to) {
|
|
24
|
+
throw new Error('Recipient address is required');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
this.addInputsFromUTXO();
|
|
28
|
+
|
|
29
|
+
if (this.isPubKeyDestination) {
|
|
30
|
+
const pubKeyScript = script.compile([
|
|
31
|
+
Buffer.from(this.to.replace('0x', ''), 'hex'),
|
|
32
|
+
opcodes.OP_CHECKSIG,
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
this.addOutput({
|
|
36
|
+
value: Number(this.amount),
|
|
37
|
+
script: pubKeyScript,
|
|
38
|
+
});
|
|
39
|
+
} else {
|
|
40
|
+
this.addOutput({
|
|
41
|
+
value: Number(this.amount),
|
|
42
|
+
address: this.to,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
await this.addRefundOutput(this.amount + this.addOptionalOutputsAndGetAmount());
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
protected override async signInput(
|
|
50
|
+
transaction: Psbt,
|
|
51
|
+
input: PsbtInput,
|
|
52
|
+
i: number,
|
|
53
|
+
signer: Signer | ECPairInterface,
|
|
54
|
+
reverse: boolean = false,
|
|
55
|
+
errored: boolean = false,
|
|
56
|
+
): Promise<void> {
|
|
57
|
+
// do nothing.
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
protected override customFinalizerP2SH = (
|
|
61
|
+
inputIndex: number,
|
|
62
|
+
input: PsbtInput,
|
|
63
|
+
scriptA: Buffer,
|
|
64
|
+
isSegwit: boolean,
|
|
65
|
+
isP2SH: boolean,
|
|
66
|
+
isP2WSH: boolean,
|
|
67
|
+
): {
|
|
68
|
+
finalScriptSig: Buffer | undefined;
|
|
69
|
+
finalScriptWitness: Buffer | undefined;
|
|
70
|
+
} => {
|
|
71
|
+
const inputDecoded = this.inputs[inputIndex];
|
|
72
|
+
|
|
73
|
+
if (isP2SH && inputDecoded && inputDecoded.redeemScript) {
|
|
74
|
+
const scriptSig = script.compile([this.challengeSolution, inputDecoded.redeemScript]);
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
finalScriptSig: scriptSig,
|
|
78
|
+
finalScriptWitness: undefined,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return getFinalScripts(inputIndex, input, scriptA, isSegwit, isP2SH, isP2WSH, false);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
protected override getSignerKey(): Signer | ECPairInterface {
|
|
86
|
+
return this.signer;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -9,7 +9,11 @@ import {
|
|
|
9
9
|
Taptree,
|
|
10
10
|
toXOnly,
|
|
11
11
|
} from '@btc-vision/bitcoin';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
MINIMUM_AMOUNT_CA,
|
|
14
|
+
MINIMUM_AMOUNT_REWARD,
|
|
15
|
+
TransactionBuilder,
|
|
16
|
+
} from './TransactionBuilder.js';
|
|
13
17
|
import { TapLeafScript } from '../interfaces/Tap.js';
|
|
14
18
|
import { DeploymentGenerator } from '../../generators/builders/DeploymentGenerator.js';
|
|
15
19
|
import { EcKeyPair } from '../../keypair/EcKeyPair.js';
|
|
@@ -19,12 +23,17 @@ import { SharedInteractionTransaction } from './SharedInteractionTransaction.js'
|
|
|
19
23
|
import { ECPairInterface } from 'ecpair';
|
|
20
24
|
import { Address } from '../../keypair/Address.js';
|
|
21
25
|
import { UnisatSigner } from '../browser/extensions/UnisatSigner.js';
|
|
26
|
+
import { ChallengeGenerator, IMineableReward } from '../mineable/ChallengeGenerator.js';
|
|
22
27
|
|
|
23
28
|
const p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fn;
|
|
24
29
|
|
|
25
30
|
export class DeploymentTransaction extends TransactionBuilder<TransactionType.DEPLOYMENT> {
|
|
26
31
|
public static readonly MAXIMUM_CONTRACT_SIZE = 128 * 1024;
|
|
27
32
|
public type: TransactionType.DEPLOYMENT = TransactionType.DEPLOYMENT;
|
|
33
|
+
|
|
34
|
+
protected readonly preimage: Buffer; // ALWAYS 128 bytes for the preimage
|
|
35
|
+
protected readonly rewardChallenge: IMineableReward;
|
|
36
|
+
|
|
28
37
|
/**
|
|
29
38
|
* The contract address
|
|
30
39
|
* @protected
|
|
@@ -110,6 +119,12 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
|
|
|
110
119
|
}
|
|
111
120
|
|
|
112
121
|
this.randomBytes = parameters.randomBytes || BitcoinUtils.rndBytes();
|
|
122
|
+
this.preimage = parameters.preimage || BitcoinUtils.getSafeRandomValues(128);
|
|
123
|
+
|
|
124
|
+
this.rewardChallenge = ChallengeGenerator.generateMineableReward(
|
|
125
|
+
this.preimage,
|
|
126
|
+
this.network,
|
|
127
|
+
);
|
|
113
128
|
|
|
114
129
|
this.contractSeed = this.getContractSeed();
|
|
115
130
|
this.contractSigner = EcKeyPair.fromSeedKeyPair(this.contractSeed, this.network);
|
|
@@ -123,6 +138,7 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
|
|
|
123
138
|
this.compiledTargetScript = this.deploymentGenerator.compile(
|
|
124
139
|
this.bytecode,
|
|
125
140
|
this.randomBytes,
|
|
141
|
+
this.preimage,
|
|
126
142
|
this.calldata,
|
|
127
143
|
);
|
|
128
144
|
|
|
@@ -163,6 +179,14 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
|
|
|
163
179
|
return this.randomBytes;
|
|
164
180
|
}
|
|
165
181
|
|
|
182
|
+
/**
|
|
183
|
+
* Get the contract bytecode
|
|
184
|
+
* @returns {Buffer} The contract bytecode
|
|
185
|
+
*/
|
|
186
|
+
public getPreimage(): Buffer {
|
|
187
|
+
return this.preimage;
|
|
188
|
+
}
|
|
189
|
+
|
|
166
190
|
/**
|
|
167
191
|
* Get the contract signer public key
|
|
168
192
|
* @protected
|
|
@@ -205,11 +229,31 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
|
|
|
205
229
|
this.addInputsFromUTXO();
|
|
206
230
|
|
|
207
231
|
const amountSpent: bigint = this.getTransactionOPNetFee();
|
|
232
|
+
|
|
233
|
+
let amountToCA: bigint;
|
|
234
|
+
if (amountSpent > MINIMUM_AMOUNT_REWARD + MINIMUM_AMOUNT_CA) {
|
|
235
|
+
amountToCA = MINIMUM_AMOUNT_CA;
|
|
236
|
+
} else {
|
|
237
|
+
amountToCA = amountSpent;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ALWAYS THE FIRST INPUT.
|
|
208
241
|
this.addOutput({
|
|
209
|
-
value: Number(
|
|
242
|
+
value: Number(amountToCA),
|
|
210
243
|
address: this.contractAddress.p2tr(this.network),
|
|
211
244
|
});
|
|
212
245
|
|
|
246
|
+
// ALWAYS SECOND.
|
|
247
|
+
if (
|
|
248
|
+
amountToCA === MINIMUM_AMOUNT_CA &&
|
|
249
|
+
amountSpent - MINIMUM_AMOUNT_CA > MINIMUM_AMOUNT_REWARD
|
|
250
|
+
) {
|
|
251
|
+
this.addOutput({
|
|
252
|
+
value: Number(amountSpent - amountToCA),
|
|
253
|
+
address: this.rewardChallenge.address,
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
213
257
|
await this.addRefundOutput(amountSpent + this.addOptionalOutputsAndGetAmount());
|
|
214
258
|
}
|
|
215
259
|
|
|
@@ -351,7 +395,6 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
|
|
|
351
395
|
|
|
352
396
|
const scriptSolution = [
|
|
353
397
|
this.randomBytes,
|
|
354
|
-
this.internalPubKeyToXOnly(),
|
|
355
398
|
input.tapScriptSig[0].signature,
|
|
356
399
|
input.tapScriptSig[1].signature,
|
|
357
400
|
];
|