@btc-vision/transaction 1.7.19 → 1.7.22

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 (92) hide show
  1. package/LICENSE +190 -21
  2. package/README.md +1 -1
  3. package/browser/_version.d.ts +1 -1
  4. package/browser/generators/builders/HashCommitmentGenerator.d.ts +49 -0
  5. package/browser/index.js +1 -1
  6. package/browser/keypair/Address.d.ts +3 -1
  7. package/browser/opnet.d.ts +6 -1
  8. package/browser/signer/AddressRotation.d.ts +12 -0
  9. package/browser/transaction/TransactionFactory.d.ts +14 -0
  10. package/browser/transaction/builders/ConsolidatedInteractionTransaction.d.ts +44 -0
  11. package/browser/transaction/enums/TransactionType.d.ts +3 -1
  12. package/browser/transaction/interfaces/IConsolidatedTransactionParameters.d.ts +31 -0
  13. package/browser/transaction/interfaces/ITransactionParameters.d.ts +2 -0
  14. package/browser/transaction/offline/OfflineTransactionManager.d.ts +69 -0
  15. package/browser/transaction/offline/TransactionReconstructor.d.ts +28 -0
  16. package/browser/transaction/offline/TransactionSerializer.d.ts +50 -0
  17. package/browser/transaction/offline/TransactionStateCapture.d.ts +52 -0
  18. package/browser/transaction/offline/index.d.ts +5 -0
  19. package/browser/transaction/offline/interfaces/ISerializableState.d.ts +62 -0
  20. package/browser/transaction/offline/interfaces/ITypeSpecificData.d.ts +62 -0
  21. package/browser/transaction/offline/interfaces/index.d.ts +2 -0
  22. package/browser/transaction/shared/TweakedTransaction.d.ts +12 -1
  23. package/browser/utxo/interfaces/IUTXO.d.ts +2 -0
  24. package/build/_version.d.ts +1 -1
  25. package/build/_version.js +1 -1
  26. package/build/generators/builders/HashCommitmentGenerator.d.ts +49 -0
  27. package/build/generators/builders/HashCommitmentGenerator.js +229 -0
  28. package/build/keypair/Address.d.ts +3 -1
  29. package/build/keypair/Address.js +87 -54
  30. package/build/opnet.d.ts +6 -1
  31. package/build/opnet.js +6 -1
  32. package/build/signer/AddressRotation.d.ts +12 -0
  33. package/build/signer/AddressRotation.js +16 -0
  34. package/build/transaction/TransactionFactory.d.ts +14 -0
  35. package/build/transaction/TransactionFactory.js +36 -0
  36. package/build/transaction/builders/ConsolidatedInteractionTransaction.d.ts +44 -0
  37. package/build/transaction/builders/ConsolidatedInteractionTransaction.js +259 -0
  38. package/build/transaction/builders/TransactionBuilder.js +2 -0
  39. package/build/transaction/enums/TransactionType.d.ts +3 -1
  40. package/build/transaction/enums/TransactionType.js +2 -0
  41. package/build/transaction/interfaces/IConsolidatedTransactionParameters.d.ts +31 -0
  42. package/build/transaction/interfaces/IConsolidatedTransactionParameters.js +1 -0
  43. package/build/transaction/interfaces/ITransactionParameters.d.ts +2 -0
  44. package/build/transaction/offline/OfflineTransactionManager.d.ts +69 -0
  45. package/build/transaction/offline/OfflineTransactionManager.js +255 -0
  46. package/build/transaction/offline/TransactionReconstructor.d.ts +28 -0
  47. package/build/transaction/offline/TransactionReconstructor.js +243 -0
  48. package/build/transaction/offline/TransactionSerializer.d.ts +50 -0
  49. package/build/transaction/offline/TransactionSerializer.js +700 -0
  50. package/build/transaction/offline/TransactionStateCapture.d.ts +52 -0
  51. package/build/transaction/offline/TransactionStateCapture.js +275 -0
  52. package/build/transaction/offline/index.d.ts +5 -0
  53. package/build/transaction/offline/index.js +5 -0
  54. package/build/transaction/offline/interfaces/ISerializableState.d.ts +62 -0
  55. package/build/transaction/offline/interfaces/ISerializableState.js +2 -0
  56. package/build/transaction/offline/interfaces/ITypeSpecificData.d.ts +62 -0
  57. package/build/transaction/offline/interfaces/ITypeSpecificData.js +19 -0
  58. package/build/transaction/offline/interfaces/index.d.ts +2 -0
  59. package/build/transaction/offline/interfaces/index.js +2 -0
  60. package/build/transaction/shared/TweakedTransaction.d.ts +12 -1
  61. package/build/transaction/shared/TweakedTransaction.js +75 -8
  62. package/build/utxo/interfaces/IUTXO.d.ts +2 -0
  63. package/documentation/README.md +5 -0
  64. package/documentation/offline-transaction-signing.md +650 -0
  65. package/documentation/transaction-building.md +603 -0
  66. package/package.json +2 -2
  67. package/src/_version.ts +1 -1
  68. package/src/generators/builders/HashCommitmentGenerator.ts +495 -0
  69. package/src/keypair/Address.ts +123 -70
  70. package/src/opnet.ts +8 -1
  71. package/src/signer/AddressRotation.ts +72 -0
  72. package/src/transaction/TransactionFactory.ts +90 -0
  73. package/src/transaction/builders/CancelTransaction.ts +4 -2
  74. package/src/transaction/builders/ConsolidatedInteractionTransaction.ts +568 -0
  75. package/src/transaction/builders/CustomScriptTransaction.ts +4 -2
  76. package/src/transaction/builders/MultiSignTransaction.ts +4 -2
  77. package/src/transaction/builders/TransactionBuilder.ts +8 -2
  78. package/src/transaction/enums/TransactionType.ts +2 -0
  79. package/src/transaction/interfaces/IConsolidatedTransactionParameters.ts +78 -0
  80. package/src/transaction/interfaces/ITransactionParameters.ts +8 -0
  81. package/src/transaction/offline/OfflineTransactionManager.ts +630 -0
  82. package/src/transaction/offline/TransactionReconstructor.ts +402 -0
  83. package/src/transaction/offline/TransactionSerializer.ts +920 -0
  84. package/src/transaction/offline/TransactionStateCapture.ts +469 -0
  85. package/src/transaction/offline/index.ts +8 -0
  86. package/src/transaction/offline/interfaces/ISerializableState.ts +141 -0
  87. package/src/transaction/offline/interfaces/ITypeSpecificData.ts +172 -0
  88. package/src/transaction/offline/interfaces/index.ts +2 -0
  89. package/src/transaction/shared/TweakedTransaction.ts +156 -9
  90. package/src/utxo/interfaces/IUTXO.ts +8 -0
  91. package/test/address-rotation.test.ts +553 -0
  92. package/test/offline-transaction.test.ts +2065 -0
@@ -0,0 +1,650 @@
1
+ # Offline Transaction Signing
2
+
3
+ This module enables secure offline transaction signing workflows. Transactions can be built in an online environment, exported to an air-gapped offline server for signing, then broadcast from the online environment.
4
+
5
+ ## Overview
6
+
7
+ The offline signing workflow separates transaction construction from signing:
8
+
9
+ ```mermaid
10
+ flowchart LR
11
+ subgraph Online["Phase 1 (Online)"]
12
+ A[Build Transaction] --> B[Export State]
13
+ B --> C["No Private Keys"]
14
+ end
15
+
16
+ subgraph Offline["Phase 2 (Offline)"]
17
+ D[Import State] --> E[Provide Signers]
18
+ E --> F[Sign Transaction]
19
+ F --> G[Export Signed TX]
20
+ end
21
+
22
+ C -->|base64| D
23
+ ```
24
+
25
+ ## Quick Start
26
+
27
+ ### Basic Usage
28
+
29
+ ```typescript
30
+ import {
31
+ OfflineTransactionManager,
32
+ IFundingTransactionParameters
33
+ } from '@btc-vision/transaction';
34
+ import { networks } from '@btc-vision/bitcoin';
35
+
36
+ // Phase 1: Online - Export transaction state
37
+ const params: IFundingTransactionParameters = {
38
+ signer: onlineSigner,
39
+ mldsaSigner: null,
40
+ network: networks.bitcoin,
41
+ utxos: [...],
42
+ from: 'bc1p...',
43
+ to: 'bc1p...',
44
+ feeRate: 10,
45
+ priorityFee: 1000n,
46
+ gasSatFee: 500n,
47
+ amount: 50000n,
48
+ };
49
+
50
+ const exportedState = OfflineTransactionManager.exportFunding(params);
51
+ // Send exportedState (base64 string) to offline environment
52
+
53
+ // Phase 2: Offline - Sign and export
54
+ const signedTxHex = await OfflineTransactionManager.importSignAndExport(
55
+ exportedState,
56
+ { signer: offlineSigner }
57
+ );
58
+ // Send signedTxHex back to online environment for broadcast
59
+ ```
60
+
61
+ ### Fee Bumping (RBF)
62
+
63
+ ```mermaid
64
+ flowchart LR
65
+ A["Original State<br/>(10 sat/vB)"] --> B[rebuildWithNewFees]
66
+ B --> C["New State<br/>(50 sat/vB)"]
67
+ C --> D[Sign & Export]
68
+ D --> E[Signed TX Hex]
69
+ ```
70
+
71
+ ```typescript
72
+ // Rebuild with higher fee rate (returns new state, not signed)
73
+ const bumpedState = OfflineTransactionManager.rebuildWithNewFees(
74
+ originalState,
75
+ 50, // New fee rate in sat/vB
76
+ );
77
+
78
+ // Or rebuild and sign in one step
79
+ const signedBumpedTx = await OfflineTransactionManager.rebuildSignAndExport(
80
+ originalState,
81
+ 50,
82
+ { signer: offlineSigner }
83
+ );
84
+ ```
85
+
86
+ ## API Reference
87
+
88
+ ### OfflineTransactionManager
89
+
90
+ The main entry point for offline transaction workflows.
91
+
92
+ #### Export Methods
93
+
94
+ ```typescript
95
+ // Export a FundingTransaction
96
+ static exportFunding(
97
+ params: IFundingTransactionParameters,
98
+ precomputed?: Partial<PrecomputedData>
99
+ ): string;
100
+
101
+ // Export a DeploymentTransaction
102
+ static exportDeployment(
103
+ params: IDeploymentParameters,
104
+ precomputed: { compiledTargetScript: string; randomBytes: string; }
105
+ ): string;
106
+
107
+ // Export an InteractionTransaction
108
+ static exportInteraction(
109
+ params: IInteractionParameters,
110
+ precomputed: { compiledTargetScript: string; randomBytes: string; }
111
+ ): string;
112
+
113
+ // Export a MultiSignTransaction
114
+ static exportMultiSig(
115
+ params: MultiSigParams,
116
+ precomputed?: Partial<PrecomputedData>
117
+ ): string;
118
+
119
+ // Export a CustomScriptTransaction
120
+ static exportCustomScript(
121
+ params: CustomScriptParams,
122
+ precomputed?: Partial<PrecomputedData>
123
+ ): string;
124
+
125
+ // Export a CancelTransaction
126
+ static exportCancel(
127
+ params: CancelParams,
128
+ precomputed?: Partial<PrecomputedData>
129
+ ): string;
130
+ ```
131
+
132
+ #### Import and Sign Methods
133
+
134
+ ```typescript
135
+ // Import state and prepare for signing
136
+ static importForSigning(
137
+ serializedState: string,
138
+ options: ReconstructionOptions
139
+ ): TransactionBuilder<TransactionType>;
140
+
141
+ // Sign a reconstructed builder
142
+ static async signAndExport(
143
+ builder: TransactionBuilder<TransactionType>
144
+ ): Promise<string>;
145
+
146
+ // Convenience: Import, sign, and export in one call
147
+ static async importSignAndExport(
148
+ serializedState: string,
149
+ options: ReconstructionOptions
150
+ ): Promise<string>;
151
+ ```
152
+
153
+ #### Fee Bumping Methods
154
+
155
+ ```typescript
156
+ // Rebuild state with new fee rate (returns new state, not signed)
157
+ static rebuildWithNewFees(
158
+ serializedState: string,
159
+ newFeeRate: number
160
+ ): string;
161
+
162
+ // Rebuild, sign, and export with new fee rate
163
+ static async rebuildSignAndExport(
164
+ serializedState: string,
165
+ newFeeRate: number,
166
+ options: ReconstructionOptions
167
+ ): Promise<string>;
168
+ ```
169
+
170
+ #### Utility Methods
171
+
172
+ ```typescript
173
+ // Inspect serialized state without signing
174
+ static inspect(serializedState: string): ISerializableTransactionState;
175
+
176
+ // Validate state integrity (checksum verification)
177
+ static validate(serializedState: string): boolean;
178
+
179
+ // Get transaction type from state
180
+ static getType(serializedState: string): TransactionType;
181
+
182
+ // Parse/serialize state objects
183
+ static fromBase64(base64State: string): ISerializableTransactionState;
184
+ static toBase64(state: ISerializableTransactionState): string;
185
+
186
+ // Format conversion (base64 <-> hex)
187
+ static toHex(serializedState: string): string;
188
+ static fromHex(hexState: string): string;
189
+ ```
190
+
191
+ ### ReconstructionOptions
192
+
193
+ Options for reconstructing a transaction from serialized state:
194
+
195
+ ```typescript
196
+ interface ReconstructionOptions {
197
+ // Primary signer (required)
198
+ signer: Signer | ECPairInterface;
199
+
200
+ // Optional: Override fee rate for fee bumping
201
+ newFeeRate?: number;
202
+
203
+ // Optional: Override priority fee
204
+ newPriorityFee?: bigint;
205
+
206
+ // Optional: Override gas sat fee
207
+ newGasSatFee?: bigint;
208
+
209
+ // Signer map for address rotation mode
210
+ signerMap?: SignerMap;
211
+
212
+ // MLDSA signer for quantum-resistant features
213
+ mldsaSigner?: QuantumBIP32Interface | null;
214
+ }
215
+ ```
216
+
217
+ ## Address Rotation Mode
218
+
219
+ For wallets with multiple addresses (different signers per UTXO):
220
+
221
+ ```mermaid
222
+ flowchart TB
223
+ subgraph UTXOs["Input UTXOs"]
224
+ U1["UTXO 1<br/>address1"]
225
+ U2["UTXO 2<br/>address2"]
226
+ U3["UTXO 3<br/>address1"]
227
+ end
228
+
229
+ subgraph SignerMap["Signer Map"]
230
+ S1["address1 → signer1"]
231
+ S2["address2 → signer2"]
232
+ end
233
+
234
+ U1 --> S1
235
+ U2 --> S2
236
+ U3 --> S1
237
+
238
+ S1 --> TX[Signed Transaction]
239
+ S2 --> TX
240
+ ```
241
+
242
+ ```typescript
243
+ import {
244
+ OfflineTransactionManager,
245
+ createSignerMap,
246
+ createAddressRotation
247
+ } from '@btc-vision/transaction';
248
+
249
+ // Phase 1: Export with address rotation enabled
250
+ // createSignerMap takes an array of [address, signer] tuples
251
+ const signerMap = createSignerMap([
252
+ ['bc1p...address1', signer1],
253
+ ['bc1p...address2', signer2],
254
+ ]);
255
+
256
+ const params: IFundingTransactionParameters = {
257
+ signer: signer1,
258
+ mldsaSigner: null,
259
+ network,
260
+ utxos: [
261
+ { /* UTXO from address1 */ },
262
+ { /* UTXO from address2 */ },
263
+ ],
264
+ from: 'bc1p...address1',
265
+ to: 'bc1p...recipient',
266
+ feeRate: 10,
267
+ priorityFee: 1000n,
268
+ gasSatFee: 500n,
269
+ amount: 50000n,
270
+ addressRotation: createAddressRotation(signerMap),
271
+ };
272
+
273
+ const exported = OfflineTransactionManager.exportFunding(params);
274
+
275
+ // Phase 2: Provide signers for each address
276
+ const offlineSignerMap = createSignerMap([
277
+ { address: 'bc1p...address1', signer: offlineSigner1 },
278
+ { address: 'bc1p...address2', signer: offlineSigner2 },
279
+ ], network);
280
+
281
+ const signedTx = await OfflineTransactionManager.importSignAndExport(
282
+ exported,
283
+ {
284
+ signer: offlineSigner1,
285
+ signerMap: offlineSignerMap,
286
+ }
287
+ );
288
+ ```
289
+
290
+ ## Serialization Format
291
+
292
+ The serialized state uses a compact binary format with the following structure:
293
+
294
+ ```
295
+ ┌─────────────────────────────────────────────────────────────────┐
296
+ │ HEADER (16 bytes) │
297
+ ├────────┬────────┬───────────┬────────┬───────────┬─────────────┤
298
+ │ 0x42 │ Format │ Consensus │ Type │ Chain ID │ Timestamp │
299
+ │ 1B │ 1B │ 1B │ 1B │ 4B │ 8B │
300
+ ├────────┴────────┴───────────┴────────┴───────────┴─────────────┤
301
+ │ BODY (variable) │
302
+ ├─────────────────────────────────────────────────────────────────┤
303
+ │ Base Params (from, to, feeRate, priorityFee, gasSatFee) │
304
+ ├─────────────────────────────────────────────────────────────────┤
305
+ │ UTXOs Array │
306
+ ├─────────────────────────────────────────────────────────────────┤
307
+ │ Optional Inputs │
308
+ ├─────────────────────────────────────────────────────────────────┤
309
+ │ Optional Outputs │
310
+ ├─────────────────────────────────────────────────────────────────┤
311
+ │ Signer Mappings (address → input indices) │
312
+ ├─────────────────────────────────────────────────────────────────┤
313
+ │ Type-Specific Data │
314
+ ├─────────────────────────────────────────────────────────────────┤
315
+ │ Precomputed Data │
316
+ ├─────────────────────────────────────────────────────────────────┤
317
+ │ CHECKSUM (32 bytes) │
318
+ ├─────────────────────────────────────────────────────────────────┤
319
+ │ Double SHA256 Hash │
320
+ └─────────────────────────────────────────────────────────────────┘
321
+ ```
322
+
323
+ ### Header Fields
324
+
325
+ | Offset | Size | Field |
326
+ |--------|------|-------|
327
+ | 0 | 1 | Magic byte (0x42) |
328
+ | 1 | 1 | Format version |
329
+ | 2 | 1 | Consensus version |
330
+ | 3 | 1 | Transaction type |
331
+ | 4-7 | 4 | Chain ID |
332
+ | 8-15 | 8 | Timestamp |
333
+
334
+ ## Supported Transaction Types
335
+
336
+ | Type | Export Method | Type-Specific Data |
337
+ |------|---------------|-------------------|
338
+ | Funding | `exportFunding()` | amount, splitInputsInto |
339
+ | Deployment | `exportDeployment()` | bytecode, calldata, challenge |
340
+ | Interaction | `exportInteraction()` | calldata, contract, challenge, loadedStorage |
341
+ | MultiSig | `exportMultiSig()` | pubkeys, minimumSignatures, receiver, existingPsbtBase64 |
342
+ | CustomScript | `exportCustomScript()` | scriptElements, witnesses, annex |
343
+ | Cancel | `exportCancel()` | compiledTargetScript |
344
+
345
+ ## MultiSig Transactions
346
+
347
+ MultiSig transactions require collecting signatures from multiple parties before broadcasting. The offline signing module provides specialized methods for this workflow.
348
+
349
+ ```mermaid
350
+ flowchart LR
351
+ subgraph Create["1. Create"]
352
+ A[Export MultiSig State]
353
+ end
354
+
355
+ subgraph Sign["2. Collect Signatures"]
356
+ B[Signer 1] --> C[Updated State]
357
+ C --> D[Signer 2]
358
+ D --> E[Updated State]
359
+ E --> F[Signer N]
360
+ end
361
+
362
+ subgraph Finalize["3. Finalize"]
363
+ G[Check Complete] --> H[Extract TX Hex]
364
+ end
365
+
366
+ A --> B
367
+ F --> G
368
+ ```
369
+
370
+ ### MultiSig API Methods
371
+
372
+ ```typescript
373
+ // Add a signature from one signer
374
+ static async multiSigAddSignature(
375
+ serializedState: string,
376
+ signer: Signer | ECPairInterface
377
+ ): Promise<{
378
+ state: string; // Updated state with new signature
379
+ signed: boolean; // Whether signing succeeded
380
+ final: boolean; // Whether all signatures collected
381
+ psbtBase64: string; // Current PSBT state
382
+ }>;
383
+
384
+ // Check if a public key has already signed
385
+ static multiSigHasSigned(
386
+ serializedState: string,
387
+ signerPubKey: Buffer | string
388
+ ): boolean;
389
+
390
+ // Get current signature status
391
+ static multiSigGetSignatureStatus(serializedState: string): {
392
+ required: number; // Minimum signatures needed
393
+ collected: number; // Current signature count
394
+ isComplete: boolean;
395
+ signers: string[]; // Public keys that have signed
396
+ };
397
+
398
+ // Finalize and extract transaction hex
399
+ static multiSigFinalize(serializedState: string): string;
400
+
401
+ // Get PSBT for external signing tools
402
+ static multiSigGetPsbt(serializedState: string): string | null;
403
+
404
+ // Update PSBT after external signing
405
+ static multiSigUpdatePsbt(
406
+ serializedState: string,
407
+ psbtBase64: string
408
+ ): string;
409
+ ```
410
+
411
+ ### MultiSig Example
412
+
413
+ ```typescript
414
+ import {
415
+ OfflineTransactionManager,
416
+ EcKeyPair,
417
+ } from '@btc-vision/transaction';
418
+ import { networks } from '@btc-vision/bitcoin';
419
+
420
+ const network = networks.regtest;
421
+
422
+ // Create 3 signers for a 2-of-3 multisig
423
+ const signer1 = EcKeyPair.generateRandomKeyPair(network);
424
+ const signer2 = EcKeyPair.generateRandomKeyPair(network);
425
+ const signer3 = EcKeyPair.generateRandomKeyPair(network);
426
+
427
+ const pubkeys = [
428
+ signer1.publicKey,
429
+ signer2.publicKey,
430
+ signer3.publicKey,
431
+ ];
432
+
433
+ // Export initial multisig state
434
+ const params = {
435
+ network,
436
+ mldsaSigner: null,
437
+ utxos: [/* vault UTXOs */],
438
+ feeRate: 10,
439
+ pubkeys,
440
+ minimumSignatures: 2,
441
+ receiver: 'bcrt1q...recipient',
442
+ requestedAmount: 50000n,
443
+ refundVault: 'bcrt1q...vault',
444
+ };
445
+
446
+ let state = OfflineTransactionManager.exportMultiSig(params);
447
+
448
+ // Signer 1 adds their signature
449
+ const result1 = await OfflineTransactionManager.multiSigAddSignature(state, signer1);
450
+ console.log('Signer 1 signed:', result1.signed);
451
+ console.log('Complete:', result1.final);
452
+ state = result1.state;
453
+
454
+ // Check status
455
+ const status = OfflineTransactionManager.multiSigGetSignatureStatus(state);
456
+ console.log(`Signatures: ${status.collected}/${status.required}`);
457
+
458
+ // Signer 2 adds their signature
459
+ const result2 = await OfflineTransactionManager.multiSigAddSignature(state, signer2);
460
+ console.log('Signer 2 signed:', result2.signed);
461
+ console.log('Complete:', result2.final); // true - we have 2 of 3
462
+ state = result2.state;
463
+
464
+ // Finalize and get transaction hex
465
+ if (OfflineTransactionManager.multiSigGetSignatureStatus(state).isComplete) {
466
+ const txHex = OfflineTransactionManager.multiSigFinalize(state);
467
+ console.log('Ready to broadcast:', txHex);
468
+ }
469
+ ```
470
+
471
+ ### External Signing Tools
472
+
473
+ For hardware wallets or external signing tools, you can extract and update the PSBT directly:
474
+
475
+ ```typescript
476
+ // Get PSBT for external tool
477
+ const psbtBase64 = OfflineTransactionManager.multiSigGetPsbt(state);
478
+
479
+ // Send psbtBase64 to hardware wallet / external tool
480
+ // ... external signing happens ...
481
+
482
+ // Update state with signed PSBT
483
+ const signedPsbtBase64 = '...'; // From external tool
484
+ state = OfflineTransactionManager.multiSigUpdatePsbt(state, signedPsbtBase64);
485
+ ```
486
+
487
+ ## Precomputed Data
488
+
489
+ Some transaction types require precomputed data that must be preserved for deterministic rebuilds:
490
+
491
+ ```typescript
492
+ interface PrecomputedData {
493
+ // Script signer seed - changing this changes signatures
494
+ randomBytes?: string;
495
+
496
+ // Complex scripts that are expensive to recompute
497
+ compiledTargetScript?: string;
498
+
499
+ // For deployment transactions
500
+ contractSeed?: string;
501
+ contractAddress?: string;
502
+
503
+ // Estimated fees
504
+ estimatedFees?: string;
505
+ }
506
+ ```
507
+
508
+ For Deployment and Interaction transactions, `randomBytes` and `compiledTargetScript` are required:
509
+
510
+ ```typescript
511
+ const exported = OfflineTransactionManager.exportDeployment(params, {
512
+ randomBytes: builder.getRandomBytes().toString('hex'),
513
+ compiledTargetScript: builder.getCompiledScript().toString('hex'),
514
+ });
515
+ ```
516
+
517
+ ## State Manipulation
518
+
519
+ You can parse, modify, and re-serialize state objects:
520
+
521
+ ```typescript
522
+ // Parse state from base64
523
+ const state = OfflineTransactionManager.fromBase64(exportedState);
524
+
525
+ // Inspect or modify the state
526
+ console.log('Original fee rate:', state.baseParams.feeRate);
527
+ console.log('Transaction type:', state.header.transactionType);
528
+
529
+ // Modify state (e.g., update fee rate manually)
530
+ state.baseParams.feeRate = 30;
531
+
532
+ // Re-serialize to base64
533
+ const modifiedState = OfflineTransactionManager.toBase64(state);
534
+
535
+ // Sign the modified state
536
+ const signedTx = await OfflineTransactionManager.importSignAndExport(
537
+ modifiedState,
538
+ { signer: offlineSigner }
539
+ );
540
+ ```
541
+
542
+ ## Security Considerations
543
+
544
+ 1. **Private keys are never serialized** - Only public keys and addresses are stored
545
+ 2. **Signers must be provided at reconstruction time** by the offline device
546
+ 3. **Checksum verification** prevents tampering with serialized state
547
+ 4. **Format versioning** allows future security improvements
548
+
549
+ ## Error Handling
550
+
551
+ ```typescript
552
+ try {
553
+ const state = OfflineTransactionManager.inspect(serializedState);
554
+ } catch (error) {
555
+ if (error.message.includes('Invalid magic byte')) {
556
+ // Not a valid offline transaction state
557
+ } else if (error.message.includes('Invalid checksum')) {
558
+ // Data corrupted or tampered with
559
+ } else if (error.message.includes('Unsupported format version')) {
560
+ // State created with newer version
561
+ }
562
+ }
563
+
564
+ // Validate before processing
565
+ if (!OfflineTransactionManager.validate(serializedState)) {
566
+ throw new Error('Invalid transaction state');
567
+ }
568
+ ```
569
+
570
+ ## Complete Example
571
+
572
+ ```typescript
573
+ import {
574
+ OfflineTransactionManager,
575
+ IFundingTransactionParameters,
576
+ TransactionType,
577
+ EcKeyPair,
578
+ } from '@btc-vision/transaction';
579
+ import { networks } from '@btc-vision/bitcoin';
580
+
581
+ // === ONLINE ENVIRONMENT ===
582
+
583
+ const network = networks.bitcoin;
584
+ const signer = EcKeyPair.generateRandomKeyPair(network);
585
+ const address = EcKeyPair.getTaprootAddress(signer, network);
586
+
587
+ // Create transaction parameters
588
+ const params: IFundingTransactionParameters = {
589
+ signer,
590
+ mldsaSigner: null,
591
+ network,
592
+ utxos: [{
593
+ transactionId: 'abc123...'.padEnd(64, '0'),
594
+ outputIndex: 0,
595
+ value: 100000n,
596
+ scriptPubKey: {
597
+ hex: '5120...',
598
+ address,
599
+ },
600
+ }],
601
+ from: address,
602
+ to: 'bc1p...recipient',
603
+ feeRate: 10,
604
+ priorityFee: 1000n,
605
+ gasSatFee: 500n,
606
+ amount: 50000n,
607
+ };
608
+
609
+ // Export state (send this to offline environment)
610
+ const exportedState = OfflineTransactionManager.exportFunding(params);
611
+ console.log('Exported state length:', exportedState.length);
612
+
613
+ // Validate the export
614
+ console.log('Valid:', OfflineTransactionManager.validate(exportedState));
615
+
616
+ // Inspect metadata
617
+ const metadata = OfflineTransactionManager.inspect(exportedState);
618
+ console.log('Transaction type:', TransactionType[metadata.header.transactionType]);
619
+ console.log('Fee rate:', metadata.baseParams.feeRate);
620
+
621
+ // === OFFLINE ENVIRONMENT ===
622
+
623
+ // Import and sign (using the same signer for this example)
624
+ const signedTxHex = await OfflineTransactionManager.importSignAndExport(
625
+ exportedState,
626
+ { signer }
627
+ );
628
+
629
+ console.log('Signed transaction:', signedTxHex);
630
+
631
+ // === FEE BUMPING (if needed) ===
632
+
633
+ // Create new state with higher fee
634
+ const bumpedState = OfflineTransactionManager.rebuildWithNewFees(
635
+ exportedState,
636
+ 50, // 5x higher fee rate
637
+ );
638
+
639
+ // Verify the new fee rate
640
+ const bumpedMetadata = OfflineTransactionManager.inspect(bumpedState);
641
+ console.log('New fee rate:', bumpedMetadata.baseParams.feeRate); // 50
642
+
643
+ // Sign the bumped transaction
644
+ const signedBumpedTx = await OfflineTransactionManager.importSignAndExport(
645
+ bumpedState,
646
+ { signer }
647
+ );
648
+
649
+ console.log('Signed bumped transaction:', signedBumpedTx);
650
+ ```