@btc-vision/transaction 1.8.0-rc.9 → 1.8.2

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 (79) hide show
  1. package/browser/_version.d.ts +1 -1
  2. package/browser/_version.d.ts.map +1 -1
  3. package/browser/btc-vision-bitcoin.js +5000 -8302
  4. package/browser/generators/builders/HashCommitmentGenerator.d.ts.map +1 -1
  5. package/browser/index.js +4778 -8637
  6. package/browser/keypair/MessageSigner.d.ts +5 -1
  7. package/browser/keypair/MessageSigner.d.ts.map +1 -1
  8. package/browser/mnemonic/Mnemonic.d.ts +1 -1
  9. package/browser/mnemonic/Mnemonic.d.ts.map +1 -1
  10. package/browser/noble-curves.js +1842 -1010
  11. package/browser/noble-hashes.js +854 -1512
  12. package/browser/rolldown-runtime.js +27 -0
  13. package/browser/transaction/TransactionFactory.d.ts +12 -10
  14. package/browser/transaction/TransactionFactory.d.ts.map +1 -1
  15. package/browser/transaction/browser/Web3Provider.d.ts +19 -3
  16. package/browser/transaction/browser/Web3Provider.d.ts.map +1 -1
  17. package/browser/transaction/browser/types/Unisat.d.ts +2 -6
  18. package/browser/transaction/browser/types/Unisat.d.ts.map +1 -1
  19. package/browser/transaction/builders/DeploymentTransaction.d.ts.map +1 -1
  20. package/browser/transaction/builders/FundingTransaction.d.ts.map +1 -1
  21. package/browser/transaction/builders/SharedInteractionTransaction.d.ts.map +1 -1
  22. package/browser/transaction/interfaces/ITransactionResponses.d.ts +6 -0
  23. package/browser/transaction/interfaces/ITransactionResponses.d.ts.map +1 -1
  24. package/browser/transaction/interfaces/IWeb3ProviderTypes.d.ts +2 -1
  25. package/browser/transaction/interfaces/IWeb3ProviderTypes.d.ts.map +1 -1
  26. package/browser/vendors.js +7359 -9101
  27. package/build/_version.d.ts +1 -1
  28. package/build/_version.d.ts.map +1 -1
  29. package/build/_version.js +1 -1
  30. package/build/_version.js.map +1 -1
  31. package/build/generators/builders/HashCommitmentGenerator.d.ts.map +1 -1
  32. package/build/generators/builders/HashCommitmentGenerator.js.map +1 -1
  33. package/build/keypair/MessageSigner.d.ts +5 -1
  34. package/build/keypair/MessageSigner.d.ts.map +1 -1
  35. package/build/keypair/MessageSigner.js +56 -2
  36. package/build/keypair/MessageSigner.js.map +1 -1
  37. package/build/mnemonic/Mnemonic.d.ts +1 -1
  38. package/build/mnemonic/Mnemonic.d.ts.map +1 -1
  39. package/build/mnemonic/Mnemonic.js +1 -1
  40. package/build/mnemonic/Mnemonic.js.map +1 -1
  41. package/build/transaction/TransactionFactory.d.ts +12 -10
  42. package/build/transaction/TransactionFactory.d.ts.map +1 -1
  43. package/build/transaction/TransactionFactory.js +40 -3
  44. package/build/transaction/TransactionFactory.js.map +1 -1
  45. package/build/transaction/browser/Web3Provider.d.ts +19 -3
  46. package/build/transaction/browser/Web3Provider.d.ts.map +1 -1
  47. package/build/transaction/browser/types/Unisat.d.ts +2 -6
  48. package/build/transaction/browser/types/Unisat.d.ts.map +1 -1
  49. package/build/transaction/builders/DeploymentTransaction.d.ts.map +1 -1
  50. package/build/transaction/builders/DeploymentTransaction.js +1 -1
  51. package/build/transaction/builders/DeploymentTransaction.js.map +1 -1
  52. package/build/transaction/builders/FundingTransaction.d.ts.map +1 -1
  53. package/build/transaction/builders/FundingTransaction.js +30 -18
  54. package/build/transaction/builders/FundingTransaction.js.map +1 -1
  55. package/build/transaction/builders/SharedInteractionTransaction.d.ts.map +1 -1
  56. package/build/transaction/builders/SharedInteractionTransaction.js +1 -1
  57. package/build/transaction/builders/SharedInteractionTransaction.js.map +1 -1
  58. package/build/transaction/interfaces/ITransactionResponses.d.ts +6 -0
  59. package/build/transaction/interfaces/ITransactionResponses.d.ts.map +1 -1
  60. package/build/transaction/interfaces/IWeb3ProviderTypes.d.ts +2 -1
  61. package/build/transaction/interfaces/IWeb3ProviderTypes.d.ts.map +1 -1
  62. package/build/transaction/interfaces/IWeb3ProviderTypes.js.map +1 -1
  63. package/build/tsconfig.build.tsbuildinfo +1 -1
  64. package/documentation/keypair/mnemonic.md +2 -2
  65. package/package.json +17 -11
  66. package/src/_version.ts +1 -1
  67. package/src/generators/builders/HashCommitmentGenerator.ts +8 -0
  68. package/src/keypair/MessageSigner.ts +101 -3
  69. package/src/mnemonic/Mnemonic.ts +1 -1
  70. package/src/transaction/TransactionFactory.ts +55 -11
  71. package/src/transaction/browser/Web3Provider.ts +21 -1
  72. package/src/transaction/browser/types/Unisat.ts +3 -7
  73. package/src/transaction/builders/DeploymentTransaction.ts +1 -1
  74. package/src/transaction/builders/FundingTransaction.ts +32 -18
  75. package/src/transaction/builders/SharedInteractionTransaction.ts +1 -1
  76. package/src/transaction/interfaces/ITransactionResponses.ts +7 -0
  77. package/src/transaction/interfaces/IWeb3ProviderTypes.ts +10 -1
  78. package/test/derivePath.test.ts +4 -4
  79. package/test/split-fee-bug.test.ts +827 -0
@@ -268,10 +268,10 @@ for (const w of wallets) {
268
268
  }
269
269
  ```
270
270
 
271
- ### deriveMultipleUnisat()
271
+ ### deriveMultipleOPWallet()
272
272
 
273
273
  ```typescript
274
- deriveMultipleUnisat(
274
+ deriveMultipleOPWallet(
275
275
  addressType?: AddressTypes,
276
276
  count?: number,
277
277
  startIndex?: number,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@btc-vision/transaction",
3
3
  "type": "module",
4
- "version": "1.8.0-rc.9",
4
+ "version": "1.8.2",
5
5
  "author": "BlobMaster41",
6
6
  "description": "OPNet transaction library allows you to create and sign transactions for the OPNet network.",
7
7
  "engines": {
@@ -145,30 +145,30 @@
145
145
  "prebuild": "npm run check:circular"
146
146
  },
147
147
  "devDependencies": {
148
- "@types/node": "^25.2.3",
148
+ "@types/node": "^25.5.0",
149
149
  "@types/sha.js": "^2.4.4",
150
- "@vitest/browser": "^4.0.18",
151
- "@vitest/browser-playwright": "^4.0.18",
152
- "@vitest/ui": "^4.0.18",
150
+ "@vitest/browser": "^4.1.0",
151
+ "@vitest/browser-playwright": "^4.1.0",
152
+ "@vitest/ui": "^4.1.0",
153
153
  "browserify-zlib": "^0.2.0",
154
154
  "buffer": "^6.0.3",
155
- "eslint": "^10.0.0",
155
+ "eslint": "^10.0.3",
156
156
  "madge": "^8.0.0",
157
157
  "playwright": "^1.58.2",
158
158
  "prettier": "^3.8.1",
159
159
  "process": "^0.11.10",
160
160
  "stream-browserify": "^3.0.0",
161
161
  "typedoc": "^0.28.17",
162
- "typescript-eslint": "^8.56.0",
163
- "vite": "^7.3.1",
162
+ "typescript-eslint": "^8.57.0",
163
+ "vite": "^8.0.0",
164
164
  "vite-plugin-dts": "^4.5.4",
165
165
  "vite-plugin-node-polyfills": "^0.25.0",
166
- "vitest": "^4.0.18"
166
+ "vitest": "^4.1.0"
167
167
  },
168
168
  "dependencies": {
169
169
  "@btc-vision/bip32": "^7.1.2",
170
- "@btc-vision/bitcoin": "^7.0.0-rc.6",
171
- "@btc-vision/bitcoin-rpc": "^1.0.6",
170
+ "@btc-vision/bitcoin": "^7.0.0",
171
+ "@btc-vision/bitcoin-rpc": "^1.1.2",
172
172
  "@btc-vision/ecpair": "^4.0.5",
173
173
  "@btc-vision/logger": "^1.0.8",
174
174
  "@eslint/js": "^10.0.1",
@@ -177,8 +177,14 @@
177
177
  "bech32": "^2.0.0",
178
178
  "bip174": "^3.0.0",
179
179
  "bip39": "^3.1.0",
180
+ "esbuild": "^0.27.4",
180
181
  "pako": "^2.1.0",
181
182
  "sha.js": "^2.4.12",
182
183
  "typescript": "^5.9.3"
184
+ },
185
+ "overrides": {
186
+ "vite-plugin-node-polyfills": {
187
+ "vite": "$vite"
188
+ }
183
189
  }
184
190
  }
package/src/_version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '1.8.0-rc.9';
1
+ export const version = '1.8.2';
@@ -35,13 +35,16 @@ export class HashCommitmentGenerator extends Logger {
35
35
 
36
36
  /** Maximum weight per standard transaction */
37
37
  public static readonly MAX_STANDARD_WEIGHT: number = 400000;
38
+
38
39
  /** Minimum satoshis per output (dust limit) */
39
40
  public static readonly MIN_OUTPUT_VALUE: bigint = 330n;
41
+
40
42
  /**
41
43
  * Bytes per hash commitment in witness script.
42
44
  * OP_HASH160 (1) + push (1) + hash (20) + OP_EQUALVERIFY (1) = 23 bytes
43
45
  */
44
46
  private static readonly BYTES_PER_COMMITMENT: number = 23;
47
+
45
48
  /**
46
49
  * Fixed overhead in witness serialization:
47
50
  * - Stack item count: 1 byte
@@ -50,6 +53,7 @@ export class HashCommitmentGenerator extends Logger {
50
53
  * - Script base (pubkey + checksig): 35 bytes
51
54
  */
52
55
  private static readonly WITNESS_FIXED_OVERHEAD: number = 1 + 73 + 3 + 35;
56
+
53
57
  /**
54
58
  * Per-chunk overhead in witness:
55
59
  * - Data: 81 bytes (80 + 1 length prefix)
@@ -58,6 +62,7 @@ export class HashCommitmentGenerator extends Logger {
58
62
  */
59
63
  private static readonly WITNESS_PER_CHUNK_OVERHEAD: number =
60
64
  HashCommitmentGenerator.MAX_CHUNK_SIZE + 1 + HashCommitmentGenerator.BYTES_PER_COMMITMENT;
65
+
61
66
  /**
62
67
  * Maximum data chunks per P2WSH output.
63
68
  * Limited by total witness size: (1650 - 112) / 104 = 14 chunks
@@ -67,6 +72,7 @@ export class HashCommitmentGenerator extends Logger {
67
72
  HashCommitmentGenerator.WITNESS_FIXED_OVERHEAD) /
68
73
  HashCommitmentGenerator.WITNESS_PER_CHUNK_OVERHEAD,
69
74
  );
75
+
70
76
  /** Base weight per input (non-witness): 41 bytes * 4 = 164 */
71
77
  private static readonly INPUT_BASE_WEIGHT: number = 164;
72
78
 
@@ -82,7 +88,9 @@ export class HashCommitmentGenerator extends Logger {
82
88
  public static readonly WEIGHT_PER_INPUT: number =
83
89
  HashCommitmentGenerator.INPUT_BASE_WEIGHT +
84
90
  HashCommitmentGenerator.INPUT_WITNESS_WEIGHT_MAX;
91
+
85
92
  public override readonly logColor: string = '#4a90d9';
93
+
86
94
  private readonly publicKey: Uint8Array;
87
95
  private readonly network: Network;
88
96
 
@@ -2,6 +2,7 @@ import {
2
2
  type MessageHash,
3
3
  type PublicKey,
4
4
  type SchnorrSignature,
5
+ type Signature,
5
6
  type UniversalSigner,
6
7
  } from '@btc-vision/ecpair';
7
8
  import { backend } from '../ecc/backend.js';
@@ -11,6 +12,7 @@ import { EcKeyPair } from './EcKeyPair.js';
11
12
  import { MLDSASecurityLevel, type QuantumBIP32Interface } from '@btc-vision/bip32';
12
13
  import { isOPWallet, type OPWallet } from '../transaction/browser/types/OPWallet.js';
13
14
  import type { MLDSASignature } from '../transaction/interfaces/IWeb3ProviderTypes.js';
15
+ import { SignatureType } from '../transaction/browser/types/Unisat.js';
14
16
 
15
17
  export interface SignedMessage {
16
18
  readonly signature: Uint8Array;
@@ -47,7 +49,38 @@ class MessageSignerBase {
47
49
  const hashedMessage = this.sha256(messageBuffer);
48
50
  const messageHex = toHex(hashedMessage);
49
51
 
50
- const signatureHex = await wallet.web3.signSchnorr(messageHex);
52
+ const signatureHex = await wallet.signData(
53
+ messageHex,
54
+ SignatureType.schnorr,
55
+ typeof message === 'string' ? message : undefined,
56
+ );
57
+
58
+ return {
59
+ signature: fromHex(signatureHex),
60
+ message: hashedMessage,
61
+ };
62
+ }
63
+
64
+ public async trySignECDSAWithOPWallet(
65
+ message: Uint8Array | string,
66
+ ): Promise<SignedMessage | null> {
67
+ const wallet = this.getOPWallet();
68
+ if (!wallet) {
69
+ return null;
70
+ }
71
+
72
+ const messageBuffer =
73
+ typeof message === 'string' ? new TextEncoder().encode(message) : message;
74
+
75
+ const hashedMessage = this.sha256(messageBuffer);
76
+ const messageHex = toHex(hashedMessage);
77
+
78
+ const signatureHex = await wallet.signData(
79
+ messageHex,
80
+ SignatureType.ecdsa,
81
+ typeof message === 'string' ? message : undefined,
82
+ );
83
+
51
84
  return {
52
85
  signature: fromHex(signatureHex),
53
86
  message: hashedMessage,
@@ -68,7 +101,11 @@ class MessageSignerBase {
68
101
  const hashedMessage = this.sha256(messageBuffer);
69
102
  const messageHex = toHex(hashedMessage);
70
103
 
71
- const result: MLDSASignature = await wallet.web3.signMLDSAMessage(messageHex);
104
+ const result: MLDSASignature = await wallet.web3.signMLDSAMessage(
105
+ messageHex,
106
+ typeof message === 'string' ? message : undefined,
107
+ );
108
+
72
109
  return {
73
110
  signature: fromHex(result.signature),
74
111
  message: hashedMessage,
@@ -93,6 +130,22 @@ class MessageSignerBase {
93
130
  return this.signMessage(keypair, message);
94
131
  }
95
132
 
133
+ public async signMessageECDSAAuto(
134
+ message: Uint8Array | string,
135
+ keypair?: UniversalSigner,
136
+ ): Promise<SignedMessage> {
137
+ if (!keypair) {
138
+ const walletResult = await this.trySignECDSAWithOPWallet(message);
139
+ if (walletResult) {
140
+ return walletResult;
141
+ }
142
+
143
+ throw new Error('No keypair provided and OP_WALLET is not available.');
144
+ }
145
+
146
+ return this.signECDSA(keypair, message);
147
+ }
148
+
96
149
  public async tweakAndSignMessageAuto(
97
150
  message: Uint8Array | string,
98
151
  keypair?: UniversalSigner,
@@ -194,6 +247,52 @@ class MessageSignerBase {
194
247
  };
195
248
  }
196
249
 
250
+ public signECDSA(keypair: UniversalSigner, message: Uint8Array | string): SignedMessage {
251
+ if (typeof message === 'string') {
252
+ message = new TextEncoder().encode(message);
253
+ }
254
+
255
+ if (!keypair.privateKey) {
256
+ throw new Error('Private key not found in keypair.');
257
+ }
258
+
259
+ const hashedMessage = this.sha256(message);
260
+
261
+ if (!backend.sign) {
262
+ throw new Error('backend.signSchnorr is not available.');
263
+ }
264
+
265
+ return {
266
+ signature: backend.sign(hashedMessage as MessageHash, keypair.privateKey),
267
+ message: hashedMessage,
268
+ };
269
+ }
270
+
271
+ public verifyECDSASignature(
272
+ publicKey: Uint8Array | PublicKey,
273
+ message: Uint8Array | string,
274
+ signature: Uint8Array | Signature,
275
+ ): boolean {
276
+ if (typeof message === 'string') {
277
+ message = new TextEncoder().encode(message);
278
+ }
279
+
280
+ if (signature.length !== 64) {
281
+ throw new Error('Invalid signature length.');
282
+ }
283
+
284
+ const hashedMessage = this.sha256(message);
285
+ if (!backend.verify) {
286
+ throw new Error('backend.verifySchnorr is not available.');
287
+ }
288
+
289
+ return backend.verify(
290
+ hashedMessage as MessageHash,
291
+ publicKey as PublicKey,
292
+ signature as Signature,
293
+ );
294
+ }
295
+
197
296
  public verifySignature(
198
297
  publicKey: Uint8Array,
199
298
  message: Uint8Array | string,
@@ -208,7 +307,6 @@ class MessageSignerBase {
208
307
  }
209
308
 
210
309
  const hashedMessage = this.sha256(message);
211
-
212
310
  if (!backend.verifySchnorr) {
213
311
  throw new Error('backend.verifySchnorr is not available.');
214
312
  }
@@ -187,7 +187,7 @@ export class Mnemonic implements Disposable {
187
187
  );
188
188
  }
189
189
 
190
- public deriveMultipleUnisat(
190
+ public deriveMultipleOPWallet(
191
191
  addressType: AddressTypes = AddressTypes.P2TR,
192
192
  count: number = 5,
193
193
  startIndex: number = 0,
@@ -23,6 +23,7 @@ import type {
23
23
  ICancelTransactionParametersWithoutSigner,
24
24
  ICustomTransactionWithoutSigner,
25
25
  IDeploymentParametersWithoutSigner,
26
+ IFundingTransactionParametersWithoutSigner,
26
27
  InteractionParametersWithoutSigner,
27
28
  } from './interfaces/IWeb3ProviderTypes.js';
28
29
  import type { WindowWithWallets } from './browser/extensions/UnisatSigner.js';
@@ -35,6 +36,7 @@ import { CancelTransaction } from './builders/CancelTransaction.js';
35
36
  import { ConsolidatedInteractionTransaction } from './builders/ConsolidatedInteractionTransaction.js';
36
37
  import type { IConsolidatedInteractionParameters } from './interfaces/IConsolidatedTransactionParameters.js';
37
38
  import type {
39
+ BitcoinTransferBase,
38
40
  CancelledTransaction,
39
41
  DeploymentResult,
40
42
  InteractionResponse,
@@ -50,12 +52,7 @@ export interface FundingTransactionResponse {
50
52
  readonly inputUtxos: UTXO[];
51
53
  }
52
54
 
53
- export interface BitcoinTransferBase {
54
- readonly tx: string;
55
- readonly estimatedFees: bigint;
56
- readonly nextUTXOs: UTXO[];
57
- readonly inputUtxos: UTXO[];
58
- }
55
+ export type { BitcoinTransferBase } from './interfaces/ITransactionResponses.js';
59
56
 
60
57
  export interface BitcoinTransferResponse extends BitcoinTransferBase {
61
58
  readonly original: FundingTransaction;
@@ -348,7 +345,7 @@ export class TransactionFactory {
348
345
  1,
349
346
  ),
350
347
  challenge: challenge.toRaw(),
351
- fundingUTXOs: fundingUTXO,
348
+ fundingUTXOs: [...fundingUTXO, ...inputs],
352
349
  fundingInputUtxos: interactionParameters.utxos,
353
350
  compiledTargetScript: toHex(interactionTx.exportCompiledTargetScript()),
354
351
  };
@@ -529,19 +526,31 @@ export class TransactionFactory {
529
526
  /**
530
527
  * @description Creates a funding transaction.
531
528
  * @param {IFundingTransactionParameters} parameters - The funding transaction parameters
532
- * @returns {Promise<BitcoinTransferResponse>} - The signed transaction
529
+ * @returns {Promise<BitcoinTransferBase>} - The signed transaction
533
530
  */
534
531
  public async createBTCTransfer(
535
- parameters: IFundingTransactionParameters,
536
- ): Promise<BitcoinTransferResponse> {
532
+ parameters: IFundingTransactionParameters | IFundingTransactionParametersWithoutSigner,
533
+ ): Promise<BitcoinTransferBase> {
534
+ if (!parameters.to) {
535
+ throw new Error('Field "to" not provided.');
536
+ }
537
+
537
538
  if (!parameters.from) {
538
539
  throw new Error('Field "from" not provided.');
539
540
  }
540
541
 
542
+ const opWalletInteraction = await this.detectFundingOPWallet(parameters);
543
+ if (opWalletInteraction) {
544
+ return opWalletInteraction;
545
+ }
546
+
547
+ if (!('signer' in parameters)) {
548
+ throw new Error('Field "signer" not provided, OP_WALLET not detected.');
549
+ }
550
+
541
551
  const resp = await this.createFundTransaction(parameters);
542
552
  return {
543
553
  estimatedFees: resp.estimatedFees,
544
- original: resp.original,
545
554
  tx: resp.tx.toHex(),
546
555
  nextUTXOs: this.getAllNewUTXOs(resp.original, resp.tx, parameters.from),
547
556
  inputUtxos: parameters.utxos,
@@ -600,6 +609,41 @@ export class TransactionFactory {
600
609
  });
601
610
  }
602
611
 
612
+ /**
613
+ * Detect and use OP_WALLET for funding transactions if available.
614
+ *
615
+ * @param {IFundingTransactionParameters | IFundingTransactionParametersWithoutSigner} fundingParams - The funding transaction parameters
616
+ * @return {Promise<BitcoinTransferBase | null>} - The funding transaction response or null if OP_WALLET not available
617
+ */
618
+ private async detectFundingOPWallet(
619
+ fundingParams: IFundingTransactionParameters | IFundingTransactionParametersWithoutSigner,
620
+ ): Promise<BitcoinTransferBase | null> {
621
+ if (typeof window === 'undefined') {
622
+ return null;
623
+ }
624
+
625
+ const _window = window as WindowWithWallets;
626
+ if (!_window || !_window.opnet || !_window.opnet.web3) {
627
+ return null;
628
+ }
629
+
630
+ const opnet = _window.opnet.web3;
631
+ const result = await opnet.sendBitcoin({
632
+ ...fundingParams,
633
+ // @ts-expect-error signer is stripped by the wallet
634
+ signer: undefined,
635
+ });
636
+
637
+ if (!result) {
638
+ throw new Error('Could not sign funding transaction.');
639
+ }
640
+
641
+ return {
642
+ ...result,
643
+ inputUtxos: result.inputUtxos ?? fundingParams.utxos,
644
+ };
645
+ }
646
+
603
647
  /**
604
648
  * Detect and use OP_WALLET for cancel transactions if available.
605
649
  * @param {ICancelTransactionParameters | ICancelTransactionParametersWithoutSigner} interactionParameters - The cancel parameters
@@ -1,5 +1,6 @@
1
1
  import type { UTXO } from '../../utxo/interfaces/IUTXO.js';
2
2
  import type {
3
+ BitcoinTransferBase,
3
4
  CancelledTransaction,
4
5
  DeploymentResult,
5
6
  InteractionResponse,
@@ -10,11 +11,22 @@ import type {
10
11
  ICancelTransactionParametersWithoutSigner,
11
12
  ICustomTransactionWithoutSigner,
12
13
  IDeploymentParametersWithoutSigner,
14
+ IFundingTransactionParametersWithoutSigner,
13
15
  InteractionParametersWithoutSigner,
14
16
  MLDSASignature,
15
17
  } from '../interfaces/IWeb3ProviderTypes.js';
16
18
 
17
19
  export interface Web3Provider {
20
+ /**
21
+ * Build, sign, and broadcast a BTC funding transaction.
22
+ * The wallet provides signer, network, and MLDSA internally.
23
+ * The confirmation flow is handled by TxOpnetConfirmScreen.
24
+ *
25
+ * @param params - Funding transaction parameters (amount, to, feeRate, etc.)
26
+ * @returns The BitcoinTransferBase with tx hex, fees, and UTXOs
27
+ */
28
+ sendBitcoin(params: IFundingTransactionParametersWithoutSigner): Promise<BitcoinTransferBase>;
29
+
18
30
  signInteraction(
19
31
  interactionParameters: InteractionParametersWithoutSigner,
20
32
  ): Promise<InteractionResponse>;
@@ -33,6 +45,13 @@ export interface Web3Provider {
33
45
 
34
46
  broadcast(transactions: BroadcastTransactionOptions[]): Promise<BroadcastedTransaction[]>;
35
47
 
48
+ /**
49
+ * Sign a PSBT (Partially Signed Bitcoin Transaction).
50
+ *
51
+ * NOT IMPLEMENTED YET — will throw an error if called.
52
+ */
53
+ signPsbt(psbtHex: string, options?: object): Promise<string>;
54
+
36
55
  /**
37
56
  * Sign a message using Schnorr signature
38
57
  * @param message - Hexadecimal string message to sign
@@ -53,10 +72,11 @@ export interface Web3Provider {
53
72
  * Sign a message using ML-DSA signature
54
73
  *
55
74
  * @param message - The message to sign as a hexadecimal string
75
+ * @param [originalMessage] - (Optional) The original message before hashing, used for ML-DSA signature verification. If not provided, the message will be hashed internally.
56
76
  * @returns The ML-DSA signature
57
77
  * @throws {Error} If signing fails or wallet is not connected
58
78
  */
59
- signMLDSAMessage(message: string): Promise<MLDSASignature>;
79
+ signMLDSAMessage(message: string, originalMessage?: string): Promise<MLDSASignature>;
60
80
 
61
81
  /**
62
82
  * Verify an ML-DSA signature
@@ -54,12 +54,6 @@ export interface Unisat {
54
54
  disconnect: () => Promise<void>;
55
55
  connect: () => Promise<void>;
56
56
 
57
- sendBitcoin(
58
- toAddress: string,
59
- satoshis: number,
60
- options: { feeRate: number; memo?: string; memos?: string[] },
61
- ): Promise<string>;
62
-
63
57
  requestAccounts(): Promise<string[]>;
64
58
 
65
59
  getNetwork(): Promise<WalletNetworks>;
@@ -70,13 +64,15 @@ export interface Unisat {
70
64
 
71
65
  switchNetwork(network: WalletNetworks): Promise<void>;
72
66
 
67
+ switchChain(network: UnisatChainType): Promise<void>;
68
+
73
69
  getPublicKey(): Promise<string>;
74
70
 
75
71
  getBalance(): Promise<Balance>;
76
72
 
77
73
  signMessage(message: string | Uint8Array, type?: MessageType): Promise<string>;
78
74
 
79
- signData(hex: string, type?: SignatureType): Promise<string>;
75
+ signData(hex: string, type?: SignatureType, originalMessage?: string): Promise<string>;
80
76
 
81
77
  pushTx(options: { rawtx: string }): Promise<string>;
82
78
 
@@ -38,7 +38,7 @@ import { type Feature, FeaturePriority, Features } from '../../generators/Featur
38
38
  import type { IP2WSHAddress } from '../mineable/IP2WSHAddress.js';
39
39
 
40
40
  export class DeploymentTransaction extends TransactionBuilder<TransactionType.DEPLOYMENT> {
41
- public static readonly MAXIMUM_CONTRACT_SIZE = 128 * 1024;
41
+ public static readonly MAXIMUM_CONTRACT_SIZE = 1536 * 1024;
42
42
 
43
43
  public type: TransactionType.DEPLOYMENT = TransactionType.DEPLOYMENT;
44
44
 
@@ -34,29 +34,43 @@ export class FundingTransaction extends TransactionBuilder<TransactionType.FUNDI
34
34
  // When autoAdjustAmount is enabled and the amount would leave no room for fees,
35
35
  // estimate the fee first and reduce the output amount accordingly.
36
36
  if (this.autoAdjustAmount && this.amount >= this.totalInputAmount) {
37
- // Add a temporary output at full amount to get an accurate fee estimate
38
- if (this.isPubKeyDestination) {
39
- const toHexClean = this.to.startsWith('0x') ? this.to.slice(2) : this.to;
40
- const pubKeyScript: Script = script.compile([
41
- fromHex(toHexClean),
42
- opcodes.OP_CHECKSIG,
43
- ]);
37
+ // Add temporary outputs matching the ACTUAL final transaction shape
38
+ // so the fee estimate accounts for the real vsize.
39
+ const numOutputs = this.splitInputsInto > 1 ? this.splitInputsInto : 1;
40
+ const perOutputAmount = this.amount / BigInt(numOutputs);
41
+
42
+ for (let i = 0; i < numOutputs; i++) {
43
+ if (this.isPubKeyDestination) {
44
+ const toHexClean = this.to.startsWith('0x') ? this.to.slice(2) : this.to;
45
+ const pubKeyScript: Script = script.compile([
46
+ fromHex(toHexClean),
47
+ opcodes.OP_CHECKSIG,
48
+ ]);
49
+
50
+ this.addOutput({
51
+ value: toSatoshi(perOutputAmount),
52
+ script: pubKeyScript,
53
+ });
54
+ } else {
55
+ this.addOutput({
56
+ value: toSatoshi(perOutputAmount),
57
+ address: this.to,
58
+ });
59
+ }
60
+ }
44
61
 
45
- this.addOutput({
46
- value: toSatoshi(this.amount),
47
- script: pubKeyScript,
48
- });
49
- } else {
50
- this.addOutput({
51
- value: toSatoshi(this.amount),
52
- address: this.to,
53
- });
62
+ // If a note is present, add a temporary OP_RETURN since it affects vsize.
63
+ if (this.note) {
64
+ this.addOPReturn(this.note);
54
65
  }
55
66
 
56
67
  const estimatedFee = await this.estimateTransactionFees();
57
68
 
58
- // Remove the temporary output
59
- this.outputs.pop();
69
+ // Remove all temporary outputs.
70
+ const tempCount = numOutputs + (this.note ? 1 : 0);
71
+ for (let i = 0; i < tempCount; i++) {
72
+ this.outputs.pop();
73
+ }
60
74
 
61
75
  const adjustedAmount = this.totalInputAmount - estimatedFee;
62
76
  if (adjustedAmount < TransactionBuilder.MINIMUM_DUST) {
@@ -33,7 +33,7 @@ import type { IP2WSHAddress } from '../mineable/IP2WSHAddress.js';
33
33
  export abstract class SharedInteractionTransaction<
34
34
  T extends TransactionType,
35
35
  > extends TransactionBuilder<T> {
36
- public static readonly MAXIMUM_CALLDATA_SIZE = 1024 * 1024; // 1MB
36
+ public static readonly MAXIMUM_CALLDATA_SIZE = 380 * 1024; // 1MB
37
37
 
38
38
  /**
39
39
  * Random salt for the interaction
@@ -1,6 +1,13 @@
1
1
  import type { RawChallenge } from '../../epoch/interfaces/IChallengeSolution.js';
2
2
  import type { UTXO } from '../../utxo/interfaces/IUTXO.js';
3
3
 
4
+ export interface BitcoinTransferBase {
5
+ readonly tx: string;
6
+ readonly estimatedFees: bigint;
7
+ readonly nextUTXOs: UTXO[];
8
+ readonly inputUtxos: UTXO[];
9
+ }
10
+
4
11
  export interface DeploymentResult {
5
12
  readonly transaction: [string, string];
6
13
  readonly contractAddress: string;
@@ -1,4 +1,8 @@
1
- import type { IDeploymentParameters, IInteractionParameters } from './ITransactionParameters.js';
1
+ import type {
2
+ IDeploymentParameters,
3
+ IFundingTransactionParameters,
4
+ IInteractionParameters,
5
+ } from './ITransactionParameters.js';
2
6
  import type { ICustomTransactionParameters } from './ICustomTransactionParameters.js';
3
7
  import type { ICancelTransactionParameters } from './ICancelTransactionParameters.js';
4
8
  import { MLDSASecurityLevel } from '@btc-vision/bip32';
@@ -23,6 +27,11 @@ export type ICancelTransactionParametersWithoutSigner = Omit<
23
27
  'signer' | 'challenge' | 'network' | 'mldsaSigner'
24
28
  >;
25
29
 
30
+ export type IFundingTransactionParametersWithoutSigner = Omit<
31
+ IFundingTransactionParameters,
32
+ 'signer' | 'network' | 'mldsaSigner' | 'gasSatFee'
33
+ >;
34
+
26
35
  export interface BroadcastTransactionOptions {
27
36
  raw: string;
28
37
  psbt: boolean;
@@ -420,7 +420,7 @@ describe('Mnemonic.deriveOPWallet', () => {
420
420
  });
421
421
  });
422
422
 
423
- describe('deriveMultipleUnisat', () => {
423
+ describe('deriveMultipleOPWallet', () => {
424
424
  it('should derive multiple wallets', () => {
425
425
  const mnemonic = new Mnemonic(
426
426
  testMnemonic,
@@ -429,7 +429,7 @@ describe('Mnemonic.deriveOPWallet', () => {
429
429
  MLDSASecurityLevel.LEVEL2,
430
430
  );
431
431
 
432
- const wallets = mnemonic.deriveMultipleUnisat(AddressTypes.P2TR, 5);
432
+ const wallets = mnemonic.deriveMultipleOPWallet(AddressTypes.P2TR, 5);
433
433
 
434
434
  expect(wallets.length).toBe(5);
435
435
  expect((wallets[0] as Wallet).p2tr).toBeDefined();
@@ -444,7 +444,7 @@ describe('Mnemonic.deriveOPWallet', () => {
444
444
  MLDSASecurityLevel.LEVEL2,
445
445
  );
446
446
 
447
- const wallets = mnemonic.deriveMultipleUnisat(AddressTypes.P2TR, 3);
447
+ const wallets = mnemonic.deriveMultipleOPWallet(AddressTypes.P2TR, 3);
448
448
 
449
449
  const addresses = wallets.map((w) => w.p2tr);
450
450
  const uniqueAddresses = new Set(addresses);
@@ -460,7 +460,7 @@ describe('Mnemonic.deriveOPWallet', () => {
460
460
  MLDSASecurityLevel.LEVEL2,
461
461
  );
462
462
 
463
- const wallets = mnemonic.deriveMultipleUnisat(AddressTypes.P2TR, 2, 5);
463
+ const wallets = mnemonic.deriveMultipleOPWallet(AddressTypes.P2TR, 2, 5);
464
464
  const wallet5 = mnemonic.deriveOPWallet(AddressTypes.P2TR, 5);
465
465
 
466
466
  expect((wallets[0] as Wallet).p2tr).toBe(wallet5.p2tr);