@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.
Files changed (84) hide show
  1. package/browser/_version.d.ts +1 -1
  2. package/browser/crypto/crypto-browser.d.ts +1 -1
  3. package/browser/generators/builders/CalldataGenerator.d.ts +1 -1
  4. package/browser/generators/builders/DeploymentGenerator.d.ts +1 -1
  5. package/browser/generators/builders/MineableReward.d.ts +7 -0
  6. package/browser/index.js +1 -1
  7. package/browser/opnet.d.ts +4 -0
  8. package/browser/transaction/ContractAddress.d.ts +1 -0
  9. package/browser/transaction/TransactionFactory.d.ts +19 -4
  10. package/browser/transaction/browser/WalletConnection.d.ts +18 -0
  11. package/browser/transaction/browser/types/Xverse.d.ts +24 -10
  12. package/browser/transaction/builders/ChallengeSolutionTransaction.d.ts +18 -0
  13. package/browser/transaction/builders/DeploymentTransaction.d.ts +4 -0
  14. package/browser/transaction/builders/SharedInteractionTransaction.d.ts +5 -0
  15. package/browser/transaction/builders/TransactionBuilder.d.ts +2 -0
  16. package/browser/transaction/enums/TransactionType.d.ts +3 -4
  17. package/browser/transaction/interfaces/ITransactionParameters.d.ts +6 -0
  18. package/browser/transaction/mineable/ChallengeGenerator.d.ts +9 -0
  19. package/browser/utxo/interfaces/IUTXO.d.ts +1 -1
  20. package/browser/verification/TapscriptVerificator.d.ts +1 -1
  21. package/build/_version.d.ts +1 -1
  22. package/build/_version.js +1 -1
  23. package/build/generators/Generator.js +1 -1
  24. package/build/generators/builders/CalldataGenerator.d.ts +1 -1
  25. package/build/generators/builders/CalldataGenerator.js +7 -26
  26. package/build/generators/builders/DeploymentGenerator.d.ts +1 -1
  27. package/build/generators/builders/DeploymentGenerator.js +9 -6
  28. package/build/generators/builders/LegacyCalldataGenerator.js +5 -1
  29. package/build/generators/builders/MineableReward.d.ts +7 -0
  30. package/build/generators/builders/MineableReward.js +47 -0
  31. package/build/opnet.d.ts +4 -0
  32. package/build/opnet.js +4 -0
  33. package/build/transaction/ContractAddress.d.ts +1 -0
  34. package/build/transaction/ContractAddress.js +4 -1
  35. package/build/transaction/TransactionFactory.d.ts +19 -4
  36. package/build/transaction/TransactionFactory.js +32 -0
  37. package/build/transaction/browser/WalletConnection.d.ts +18 -0
  38. package/build/transaction/browser/WalletConnection.js +95 -0
  39. package/build/transaction/browser/extensions/UnisatSigner.js +5 -2
  40. package/build/transaction/browser/extensions/XverseSigner.js +15 -9
  41. package/build/transaction/browser/types/Xverse.d.ts +24 -10
  42. package/build/transaction/builders/ChallengeSolutionTransaction.d.ts +18 -0
  43. package/build/transaction/builders/ChallengeSolutionTransaction.js +51 -0
  44. package/build/transaction/builders/DeploymentTransaction.d.ts +4 -0
  45. package/build/transaction/builders/DeploymentTransaction.js +23 -4
  46. package/build/transaction/builders/InteractionTransaction.js +1 -1
  47. package/build/transaction/builders/SharedInteractionTransaction.d.ts +5 -0
  48. package/build/transaction/builders/SharedInteractionTransaction.js +35 -13
  49. package/build/transaction/builders/TransactionBuilder.d.ts +2 -0
  50. package/build/transaction/builders/TransactionBuilder.js +2 -0
  51. package/build/transaction/enums/TransactionType.d.ts +3 -4
  52. package/build/transaction/enums/TransactionType.js +3 -4
  53. package/build/transaction/interfaces/ITransactionParameters.d.ts +6 -0
  54. package/build/transaction/mineable/ChallengeGenerator.d.ts +9 -0
  55. package/build/transaction/mineable/ChallengeGenerator.js +28 -0
  56. package/build/transaction/shared/TweakedTransaction.js +1 -1
  57. package/build/utxo/interfaces/IUTXO.d.ts +1 -1
  58. package/build/verification/TapscriptVerificator.d.ts +1 -1
  59. package/build/verification/TapscriptVerificator.js +2 -8
  60. package/package.json +3 -3
  61. package/src/_version.ts +1 -1
  62. package/src/generators/Generator.ts +1 -1
  63. package/src/generators/builders/CalldataGenerator.ts +10 -41
  64. package/src/generators/builders/DeploymentGenerator.ts +18 -7
  65. package/src/generators/builders/LegacyCalldataGenerator.ts +5 -1
  66. package/src/generators/builders/MineableReward.ts +63 -0
  67. package/src/opnet.ts +5 -0
  68. package/src/transaction/ContractAddress.ts +5 -1
  69. package/src/transaction/TransactionFactory.ts +66 -3
  70. package/src/transaction/browser/WalletConnection.ts +110 -0
  71. package/src/transaction/browser/extensions/UnisatSigner.ts +7 -3
  72. package/src/transaction/browser/extensions/XverseSigner.ts +24 -23
  73. package/src/transaction/browser/types/Xverse.ts +50 -36
  74. package/src/transaction/builders/ChallengeSolutionTransaction.ts +88 -0
  75. package/src/transaction/builders/DeploymentTransaction.ts +46 -3
  76. package/src/transaction/builders/InteractionTransaction.ts +1 -0
  77. package/src/transaction/builders/SharedInteractionTransaction.ts +54 -14
  78. package/src/transaction/builders/TransactionBuilder.ts +3 -0
  79. package/src/transaction/enums/TransactionType.ts +3 -4
  80. package/src/transaction/interfaces/ITransactionParameters.ts +8 -15
  81. package/src/transaction/mineable/ChallengeGenerator.ts +39 -0
  82. package/src/transaction/shared/TweakedTransaction.ts +1 -1
  83. package/src/utxo/interfaces/IUTXO.ts +1 -1
  84. 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 BitcoinTransferResponse {
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 = (await this.BitcoinProvider.request(
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.toHex();
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
- // const signed = await this.unisat.signPsbt(toSignPsbts[0], options[0]);
245
+ const toSignInputs: {
246
+ [x: string]: number[];
247
+ } = {
248
+ [this.p2wpkh]: options[0].toSignInputs?.map((input) => input.index) || [],
249
+ };
249
250
 
250
- const callSign = (await this.BitcoinProvider.request('signPsbt', {
251
+ const callSign = await this.BitcoinProvider.request('signPsbt', {
251
252
  psbt: toSignPsbts[0],
252
- signInputs: options[0].toSignInputs,
253
- })) as XverseRPCSignPsbtResponse;
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); //signed.map((hex) => Psbt.fromHex(hex));
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
- const callSign = (await this.BitcoinProvider.request('signPsbt', {
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: opts.toSignInputs,
348
- })) as XverseRPCSignPsbtResponse;
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
- export type XverseRPCResponse<T = unknown> = {
8
- id: string;
9
- jsonrpc: string;
10
- result: T;
11
- };
12
-
13
- export type XverseRPCError = {
14
- id: string;
15
- jsonrpc: string;
16
- error: {
17
- code: number;
18
- message: string;
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
- connect: () => Promise<void>;
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 { TransactionBuilder } from './TransactionBuilder.js';
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(amountSpent),
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
  ];