@btc-vision/transaction 1.7.18 → 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.
- package/LICENSE +190 -21
- package/README.md +1 -1
- package/browser/_version.d.ts +1 -1
- package/browser/generators/builders/HashCommitmentGenerator.d.ts +49 -0
- package/browser/index.js +1 -1
- package/browser/keypair/Address.d.ts +3 -1
- package/browser/opnet.d.ts +6 -1
- package/browser/signer/AddressRotation.d.ts +12 -0
- package/browser/transaction/TransactionFactory.d.ts +14 -0
- package/browser/transaction/builders/ConsolidatedInteractionTransaction.d.ts +44 -0
- package/browser/transaction/enums/TransactionType.d.ts +3 -1
- package/browser/transaction/interfaces/IConsolidatedTransactionParameters.d.ts +31 -0
- package/browser/transaction/interfaces/ITransactionParameters.d.ts +2 -0
- package/browser/transaction/offline/OfflineTransactionManager.d.ts +69 -0
- package/browser/transaction/offline/TransactionReconstructor.d.ts +28 -0
- package/browser/transaction/offline/TransactionSerializer.d.ts +50 -0
- package/browser/transaction/offline/TransactionStateCapture.d.ts +52 -0
- package/browser/transaction/offline/index.d.ts +5 -0
- package/browser/transaction/offline/interfaces/ISerializableState.d.ts +62 -0
- package/browser/transaction/offline/interfaces/ITypeSpecificData.d.ts +62 -0
- package/browser/transaction/offline/interfaces/index.d.ts +2 -0
- package/browser/transaction/shared/TweakedTransaction.d.ts +12 -1
- package/browser/utxo/interfaces/IUTXO.d.ts +2 -0
- package/build/_version.d.ts +1 -1
- package/build/_version.js +1 -1
- package/build/generators/builders/HashCommitmentGenerator.d.ts +49 -0
- package/build/generators/builders/HashCommitmentGenerator.js +229 -0
- package/build/keypair/Address.d.ts +3 -1
- package/build/keypair/Address.js +87 -54
- package/build/opnet.d.ts +6 -1
- package/build/opnet.js +6 -1
- package/build/signer/AddressRotation.d.ts +12 -0
- package/build/signer/AddressRotation.js +16 -0
- package/build/transaction/TransactionFactory.d.ts +14 -0
- package/build/transaction/TransactionFactory.js +36 -0
- package/build/transaction/builders/ConsolidatedInteractionTransaction.d.ts +44 -0
- package/build/transaction/builders/ConsolidatedInteractionTransaction.js +259 -0
- package/build/transaction/builders/TransactionBuilder.js +2 -0
- package/build/transaction/enums/TransactionType.d.ts +3 -1
- package/build/transaction/enums/TransactionType.js +2 -0
- package/build/transaction/interfaces/IConsolidatedTransactionParameters.d.ts +31 -0
- package/build/transaction/interfaces/IConsolidatedTransactionParameters.js +1 -0
- package/build/transaction/interfaces/ITransactionParameters.d.ts +2 -0
- package/build/transaction/offline/OfflineTransactionManager.d.ts +69 -0
- package/build/transaction/offline/OfflineTransactionManager.js +255 -0
- package/build/transaction/offline/TransactionReconstructor.d.ts +28 -0
- package/build/transaction/offline/TransactionReconstructor.js +243 -0
- package/build/transaction/offline/TransactionSerializer.d.ts +50 -0
- package/build/transaction/offline/TransactionSerializer.js +700 -0
- package/build/transaction/offline/TransactionStateCapture.d.ts +52 -0
- package/build/transaction/offline/TransactionStateCapture.js +275 -0
- package/build/transaction/offline/index.d.ts +5 -0
- package/build/transaction/offline/index.js +5 -0
- package/build/transaction/offline/interfaces/ISerializableState.d.ts +62 -0
- package/build/transaction/offline/interfaces/ISerializableState.js +2 -0
- package/build/transaction/offline/interfaces/ITypeSpecificData.d.ts +62 -0
- package/build/transaction/offline/interfaces/ITypeSpecificData.js +19 -0
- package/build/transaction/offline/interfaces/index.d.ts +2 -0
- package/build/transaction/offline/interfaces/index.js +2 -0
- package/build/transaction/shared/TweakedTransaction.d.ts +12 -1
- package/build/transaction/shared/TweakedTransaction.js +75 -8
- package/build/utxo/interfaces/IUTXO.d.ts +2 -0
- package/documentation/README.md +5 -0
- package/documentation/offline-transaction-signing.md +650 -0
- package/documentation/transaction-building.md +603 -0
- package/package.json +2 -2
- package/src/_version.ts +1 -1
- package/src/generators/builders/HashCommitmentGenerator.ts +495 -0
- package/src/keypair/Address.ts +123 -70
- package/src/opnet.ts +8 -1
- package/src/signer/AddressRotation.ts +72 -0
- package/src/transaction/TransactionFactory.ts +94 -1
- package/src/transaction/builders/CancelTransaction.ts +4 -2
- package/src/transaction/builders/ConsolidatedInteractionTransaction.ts +568 -0
- package/src/transaction/builders/CustomScriptTransaction.ts +4 -2
- package/src/transaction/builders/MultiSignTransaction.ts +4 -2
- package/src/transaction/builders/TransactionBuilder.ts +8 -2
- package/src/transaction/enums/TransactionType.ts +2 -0
- package/src/transaction/interfaces/IConsolidatedTransactionParameters.ts +78 -0
- package/src/transaction/interfaces/ITransactionParameters.ts +8 -0
- package/src/transaction/offline/OfflineTransactionManager.ts +630 -0
- package/src/transaction/offline/TransactionReconstructor.ts +402 -0
- package/src/transaction/offline/TransactionSerializer.ts +920 -0
- package/src/transaction/offline/TransactionStateCapture.ts +469 -0
- package/src/transaction/offline/index.ts +8 -0
- package/src/transaction/offline/interfaces/ISerializableState.ts +141 -0
- package/src/transaction/offline/interfaces/ITypeSpecificData.ts +172 -0
- package/src/transaction/offline/interfaces/index.ts +2 -0
- package/src/transaction/shared/TweakedTransaction.ts +156 -9
- package/src/utxo/interfaces/IUTXO.ts +8 -0
- package/test/address-rotation.test.ts +553 -0
- package/test/offline-transaction.test.ts +2065 -0
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
import { Network, PsbtOutputExtended } from '@btc-vision/bitcoin';
|
|
2
|
+
import { UTXO } from '../../utxo/interfaces/IUTXO.js';
|
|
3
|
+
import { ChainId } from '../../network/ChainId.js';
|
|
4
|
+
import { currentConsensus } from '../../consensus/ConsensusConfig.js';
|
|
5
|
+
import { TransactionType } from '../enums/TransactionType.js';
|
|
6
|
+
import {
|
|
7
|
+
ISerializableTransactionState,
|
|
8
|
+
PrecomputedData,
|
|
9
|
+
SERIALIZATION_FORMAT_VERSION,
|
|
10
|
+
SerializationHeader,
|
|
11
|
+
SerializedBaseParams,
|
|
12
|
+
SerializedOutput,
|
|
13
|
+
SerializedSignerMapping,
|
|
14
|
+
SerializedUTXO,
|
|
15
|
+
} from './interfaces/ISerializableState.js';
|
|
16
|
+
import {
|
|
17
|
+
CancelSpecificData,
|
|
18
|
+
CustomScriptSpecificData,
|
|
19
|
+
DeploymentSpecificData,
|
|
20
|
+
FundingSpecificData,
|
|
21
|
+
InteractionSpecificData,
|
|
22
|
+
MultiSigSpecificData,
|
|
23
|
+
SerializedScriptElement,
|
|
24
|
+
TypeSpecificData,
|
|
25
|
+
} from './interfaces/ITypeSpecificData.js';
|
|
26
|
+
import {
|
|
27
|
+
IDeploymentParameters,
|
|
28
|
+
IFundingTransactionParameters,
|
|
29
|
+
IInteractionParameters,
|
|
30
|
+
ITransactionParameters,
|
|
31
|
+
} from '../interfaces/ITransactionParameters.js';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Parameters required to capture state from any transaction builder
|
|
35
|
+
*/
|
|
36
|
+
export interface CaptureParams {
|
|
37
|
+
/** The original transaction parameters */
|
|
38
|
+
params: ITransactionParameters;
|
|
39
|
+
/** The transaction type */
|
|
40
|
+
type: TransactionType;
|
|
41
|
+
/** Pre-computed data from the builder */
|
|
42
|
+
precomputed?: Partial<PrecomputedData>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Captures transaction state from builders for offline signing.
|
|
47
|
+
* This class creates serializable state objects from transaction parameters.
|
|
48
|
+
*/
|
|
49
|
+
export class TransactionStateCapture {
|
|
50
|
+
/**
|
|
51
|
+
* Capture state from a FundingTransaction
|
|
52
|
+
*/
|
|
53
|
+
public static fromFunding(
|
|
54
|
+
params: IFundingTransactionParameters,
|
|
55
|
+
precomputed?: Partial<PrecomputedData>,
|
|
56
|
+
): ISerializableTransactionState {
|
|
57
|
+
return this.captureState({
|
|
58
|
+
params,
|
|
59
|
+
type: TransactionType.FUNDING,
|
|
60
|
+
precomputed,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Capture state from a DeploymentTransaction
|
|
66
|
+
*/
|
|
67
|
+
public static fromDeployment(
|
|
68
|
+
params: IDeploymentParameters,
|
|
69
|
+
precomputed: Partial<PrecomputedData> & {
|
|
70
|
+
compiledTargetScript: string;
|
|
71
|
+
randomBytes: string;
|
|
72
|
+
},
|
|
73
|
+
): ISerializableTransactionState {
|
|
74
|
+
return this.captureState({
|
|
75
|
+
params: params as ITransactionParameters,
|
|
76
|
+
type: TransactionType.DEPLOYMENT,
|
|
77
|
+
precomputed,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Capture state from an InteractionTransaction
|
|
83
|
+
*/
|
|
84
|
+
public static fromInteraction(
|
|
85
|
+
params: IInteractionParameters,
|
|
86
|
+
precomputed: Partial<PrecomputedData> & {
|
|
87
|
+
compiledTargetScript: string;
|
|
88
|
+
randomBytes: string;
|
|
89
|
+
},
|
|
90
|
+
): ISerializableTransactionState {
|
|
91
|
+
return this.captureState({
|
|
92
|
+
params,
|
|
93
|
+
type: TransactionType.INTERACTION,
|
|
94
|
+
precomputed,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Capture state from a MultiSignTransaction
|
|
100
|
+
*/
|
|
101
|
+
public static fromMultiSig(
|
|
102
|
+
params: ITransactionParameters & {
|
|
103
|
+
pubkeys: Buffer[];
|
|
104
|
+
minimumSignatures: number;
|
|
105
|
+
receiver: string;
|
|
106
|
+
requestedAmount: bigint;
|
|
107
|
+
refundVault: string;
|
|
108
|
+
originalInputCount?: number;
|
|
109
|
+
existingPsbtBase64?: string;
|
|
110
|
+
},
|
|
111
|
+
precomputed?: Partial<PrecomputedData>,
|
|
112
|
+
): ISerializableTransactionState {
|
|
113
|
+
return this.captureState({
|
|
114
|
+
params,
|
|
115
|
+
type: TransactionType.MULTI_SIG,
|
|
116
|
+
precomputed,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Capture state from a CustomScriptTransaction
|
|
122
|
+
*/
|
|
123
|
+
public static fromCustomScript(
|
|
124
|
+
params: ITransactionParameters & {
|
|
125
|
+
scriptElements: (Buffer | number)[];
|
|
126
|
+
witnesses: Buffer[];
|
|
127
|
+
annex?: Buffer;
|
|
128
|
+
},
|
|
129
|
+
precomputed?: Partial<PrecomputedData>,
|
|
130
|
+
): ISerializableTransactionState {
|
|
131
|
+
return this.captureState({
|
|
132
|
+
params,
|
|
133
|
+
type: TransactionType.CUSTOM_CODE,
|
|
134
|
+
precomputed,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Capture state from a CancelTransaction
|
|
140
|
+
*/
|
|
141
|
+
public static fromCancel(
|
|
142
|
+
params: ITransactionParameters & {
|
|
143
|
+
compiledTargetScript: Buffer | string;
|
|
144
|
+
},
|
|
145
|
+
precomputed?: Partial<PrecomputedData>,
|
|
146
|
+
): ISerializableTransactionState {
|
|
147
|
+
return this.captureState({
|
|
148
|
+
params,
|
|
149
|
+
type: TransactionType.CANCEL,
|
|
150
|
+
precomputed,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Main state capture method
|
|
156
|
+
*/
|
|
157
|
+
private static captureState(capture: CaptureParams): ISerializableTransactionState {
|
|
158
|
+
const { params, type, precomputed } = capture;
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
header: this.createHeader(type, params.network, params.chainId),
|
|
162
|
+
baseParams: this.extractBaseParams(params),
|
|
163
|
+
utxos: this.serializeUTXOs(params.utxos),
|
|
164
|
+
optionalInputs: this.serializeUTXOs(params.optionalInputs || []),
|
|
165
|
+
optionalOutputs: this.serializeOutputs(params.optionalOutputs || []),
|
|
166
|
+
addressRotationEnabled: params.addressRotation?.enabled ?? false,
|
|
167
|
+
signerMappings: this.extractSignerMappings(params),
|
|
168
|
+
typeSpecificData: this.extractTypeSpecificData(type, params),
|
|
169
|
+
precomputedData: this.buildPrecomputedData(precomputed),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Create serialization header
|
|
175
|
+
*/
|
|
176
|
+
private static createHeader(
|
|
177
|
+
type: TransactionType,
|
|
178
|
+
network: Network,
|
|
179
|
+
chainId?: ChainId,
|
|
180
|
+
): SerializationHeader {
|
|
181
|
+
return {
|
|
182
|
+
formatVersion: SERIALIZATION_FORMAT_VERSION,
|
|
183
|
+
consensusVersion: currentConsensus,
|
|
184
|
+
transactionType: type,
|
|
185
|
+
chainId: chainId ?? this.networkToChainId(network),
|
|
186
|
+
timestamp: Date.now(),
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Extract base parameters common to all transaction types
|
|
192
|
+
*/
|
|
193
|
+
private static extractBaseParams(params: ITransactionParameters): SerializedBaseParams {
|
|
194
|
+
const note = params.note
|
|
195
|
+
? Buffer.isBuffer(params.note)
|
|
196
|
+
? params.note.toString('hex')
|
|
197
|
+
: Buffer.from(params.note).toString('hex')
|
|
198
|
+
: undefined;
|
|
199
|
+
|
|
200
|
+
// Handle optional priorityFee and gasSatFee (not present in MultiSig)
|
|
201
|
+
const priorityFee = params.priorityFee ?? 0n;
|
|
202
|
+
const gasSatFee = params.gasSatFee ?? 0n;
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
from: params.from || '',
|
|
206
|
+
to: params.to,
|
|
207
|
+
feeRate: params.feeRate,
|
|
208
|
+
priorityFee: priorityFee.toString(),
|
|
209
|
+
gasSatFee: gasSatFee.toString(),
|
|
210
|
+
networkName: this.networkToName(params.network),
|
|
211
|
+
txVersion: params.txVersion ?? 2,
|
|
212
|
+
note,
|
|
213
|
+
anchor: params.anchor ?? false,
|
|
214
|
+
debugFees: params.debugFees,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Extract signer mappings for address rotation mode
|
|
220
|
+
*/
|
|
221
|
+
private static extractSignerMappings(
|
|
222
|
+
params: ITransactionParameters,
|
|
223
|
+
): SerializedSignerMapping[] {
|
|
224
|
+
if (!params.addressRotation?.enabled) {
|
|
225
|
+
return [];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const mappings: SerializedSignerMapping[] = [];
|
|
229
|
+
const addressToIndices = new Map<string, number[]>();
|
|
230
|
+
|
|
231
|
+
// Build mapping from UTXOs
|
|
232
|
+
params.utxos.forEach((utxo, index) => {
|
|
233
|
+
const address = utxo.scriptPubKey?.address;
|
|
234
|
+
if (address) {
|
|
235
|
+
const existing = addressToIndices.get(address);
|
|
236
|
+
if (existing) {
|
|
237
|
+
existing.push(index);
|
|
238
|
+
} else {
|
|
239
|
+
addressToIndices.set(address, [index]);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// Add optional inputs
|
|
245
|
+
const utxoCount = params.utxos.length;
|
|
246
|
+
(params.optionalInputs || []).forEach((utxo, index) => {
|
|
247
|
+
const address = utxo.scriptPubKey?.address;
|
|
248
|
+
if (address) {
|
|
249
|
+
const existing = addressToIndices.get(address);
|
|
250
|
+
if (existing) {
|
|
251
|
+
existing.push(utxoCount + index);
|
|
252
|
+
} else {
|
|
253
|
+
addressToIndices.set(address, [utxoCount + index]);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// Convert to serializable format
|
|
259
|
+
addressToIndices.forEach((indices, address) => {
|
|
260
|
+
mappings.push({ address, inputIndices: indices });
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
return mappings;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Extract type-specific data based on transaction type
|
|
268
|
+
*/
|
|
269
|
+
private static extractTypeSpecificData(
|
|
270
|
+
type: TransactionType,
|
|
271
|
+
params: ITransactionParameters,
|
|
272
|
+
): TypeSpecificData {
|
|
273
|
+
switch (type) {
|
|
274
|
+
case TransactionType.FUNDING:
|
|
275
|
+
return this.extractFundingData(params as IFundingTransactionParameters);
|
|
276
|
+
case TransactionType.DEPLOYMENT:
|
|
277
|
+
return this.extractDeploymentData(params as unknown as IDeploymentParameters);
|
|
278
|
+
case TransactionType.INTERACTION:
|
|
279
|
+
return this.extractInteractionData(params as IInteractionParameters);
|
|
280
|
+
case TransactionType.MULTI_SIG:
|
|
281
|
+
return this.extractMultiSigData(params);
|
|
282
|
+
case TransactionType.CUSTOM_CODE:
|
|
283
|
+
return this.extractCustomScriptData(params);
|
|
284
|
+
case TransactionType.CANCEL:
|
|
285
|
+
return this.extractCancelData(params);
|
|
286
|
+
default:
|
|
287
|
+
throw new Error(`Unsupported transaction type: ${type}`);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
private static extractFundingData(params: IFundingTransactionParameters): FundingSpecificData {
|
|
292
|
+
return {
|
|
293
|
+
type: TransactionType.FUNDING,
|
|
294
|
+
amount: params.amount.toString(),
|
|
295
|
+
splitInputsInto: params.splitInputsInto ?? 1,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
private static extractDeploymentData(params: IDeploymentParameters): DeploymentSpecificData {
|
|
300
|
+
return {
|
|
301
|
+
type: TransactionType.DEPLOYMENT,
|
|
302
|
+
bytecode: params.bytecode.toString('hex'),
|
|
303
|
+
calldata: params.calldata?.toString('hex'),
|
|
304
|
+
challenge: params.challenge.toRaw(),
|
|
305
|
+
revealMLDSAPublicKey: params.revealMLDSAPublicKey,
|
|
306
|
+
linkMLDSAPublicKeyToAddress: params.linkMLDSAPublicKeyToAddress,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
private static extractInteractionData(params: IInteractionParameters): InteractionSpecificData {
|
|
311
|
+
return {
|
|
312
|
+
type: TransactionType.INTERACTION,
|
|
313
|
+
calldata: params.calldata.toString('hex'),
|
|
314
|
+
contract: params.contract,
|
|
315
|
+
challenge: params.challenge.toRaw(),
|
|
316
|
+
loadedStorage: params.loadedStorage,
|
|
317
|
+
isCancellation: params.isCancellation,
|
|
318
|
+
disableAutoRefund: params.disableAutoRefund,
|
|
319
|
+
revealMLDSAPublicKey: params.revealMLDSAPublicKey,
|
|
320
|
+
linkMLDSAPublicKeyToAddress: params.linkMLDSAPublicKeyToAddress,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
private static extractMultiSigData(
|
|
325
|
+
params: ITransactionParameters & {
|
|
326
|
+
pubkeys?: Buffer[];
|
|
327
|
+
minimumSignatures?: number;
|
|
328
|
+
receiver?: string;
|
|
329
|
+
requestedAmount?: bigint;
|
|
330
|
+
refundVault?: string;
|
|
331
|
+
originalInputCount?: number;
|
|
332
|
+
existingPsbtBase64?: string;
|
|
333
|
+
},
|
|
334
|
+
): MultiSigSpecificData {
|
|
335
|
+
return {
|
|
336
|
+
type: TransactionType.MULTI_SIG,
|
|
337
|
+
pubkeys: (params.pubkeys || []).map((pk) => pk.toString('hex')),
|
|
338
|
+
minimumSignatures: params.minimumSignatures || 0,
|
|
339
|
+
receiver: params.receiver || '',
|
|
340
|
+
requestedAmount: (params.requestedAmount || 0n).toString(),
|
|
341
|
+
refundVault: params.refundVault || '',
|
|
342
|
+
originalInputCount: params.originalInputCount || params.utxos.length,
|
|
343
|
+
existingPsbtBase64: params.existingPsbtBase64,
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
private static extractCustomScriptData(
|
|
348
|
+
params: ITransactionParameters & {
|
|
349
|
+
scriptElements?: (Buffer | number)[];
|
|
350
|
+
witnesses?: Buffer[];
|
|
351
|
+
annex?: Buffer;
|
|
352
|
+
},
|
|
353
|
+
): CustomScriptSpecificData {
|
|
354
|
+
const scriptElements: SerializedScriptElement[] = (params.scriptElements || []).map(
|
|
355
|
+
(element) => {
|
|
356
|
+
if (Buffer.isBuffer(element)) {
|
|
357
|
+
return {
|
|
358
|
+
elementType: 'buffer' as const,
|
|
359
|
+
value: element.toString('hex'),
|
|
360
|
+
};
|
|
361
|
+
} else {
|
|
362
|
+
return {
|
|
363
|
+
elementType: 'opcode' as const,
|
|
364
|
+
value: element,
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
},
|
|
368
|
+
);
|
|
369
|
+
|
|
370
|
+
return {
|
|
371
|
+
type: TransactionType.CUSTOM_CODE,
|
|
372
|
+
scriptElements,
|
|
373
|
+
witnesses: (params.witnesses || []).map((w) => w.toString('hex')),
|
|
374
|
+
annex: params.annex?.toString('hex'),
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
private static extractCancelData(
|
|
379
|
+
params: ITransactionParameters & {
|
|
380
|
+
compiledTargetScript?: Buffer | string;
|
|
381
|
+
},
|
|
382
|
+
): CancelSpecificData {
|
|
383
|
+
const script = params.compiledTargetScript;
|
|
384
|
+
const scriptHex = script ? (Buffer.isBuffer(script) ? script.toString('hex') : script) : '';
|
|
385
|
+
|
|
386
|
+
return {
|
|
387
|
+
type: TransactionType.CANCEL,
|
|
388
|
+
compiledTargetScript: scriptHex,
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Build precomputed data object
|
|
394
|
+
*/
|
|
395
|
+
private static buildPrecomputedData(precomputed?: Partial<PrecomputedData>): PrecomputedData {
|
|
396
|
+
return {
|
|
397
|
+
compiledTargetScript: precomputed?.compiledTargetScript,
|
|
398
|
+
randomBytes: precomputed?.randomBytes,
|
|
399
|
+
estimatedFees: precomputed?.estimatedFees,
|
|
400
|
+
contractSeed: precomputed?.contractSeed,
|
|
401
|
+
contractAddress: precomputed?.contractAddress,
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Serialize UTXOs array
|
|
407
|
+
*/
|
|
408
|
+
private static serializeUTXOs(utxos: UTXO[]): SerializedUTXO[] {
|
|
409
|
+
return utxos.map((utxo) => ({
|
|
410
|
+
transactionId: utxo.transactionId,
|
|
411
|
+
outputIndex: utxo.outputIndex,
|
|
412
|
+
value: utxo.value.toString(),
|
|
413
|
+
scriptPubKeyHex: utxo.scriptPubKey.hex,
|
|
414
|
+
scriptPubKeyAddress: utxo.scriptPubKey.address,
|
|
415
|
+
redeemScript: utxo.redeemScript
|
|
416
|
+
? Buffer.isBuffer(utxo.redeemScript)
|
|
417
|
+
? utxo.redeemScript.toString('hex')
|
|
418
|
+
: utxo.redeemScript
|
|
419
|
+
: undefined,
|
|
420
|
+
witnessScript: utxo.witnessScript
|
|
421
|
+
? Buffer.isBuffer(utxo.witnessScript)
|
|
422
|
+
? utxo.witnessScript.toString('hex')
|
|
423
|
+
: utxo.witnessScript
|
|
424
|
+
: undefined,
|
|
425
|
+
nonWitnessUtxo: utxo.nonWitnessUtxo
|
|
426
|
+
? Buffer.isBuffer(utxo.nonWitnessUtxo)
|
|
427
|
+
? utxo.nonWitnessUtxo.toString('hex')
|
|
428
|
+
: utxo.nonWitnessUtxo
|
|
429
|
+
: undefined,
|
|
430
|
+
}));
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Serialize outputs array
|
|
435
|
+
*/
|
|
436
|
+
private static serializeOutputs(outputs: PsbtOutputExtended[]): SerializedOutput[] {
|
|
437
|
+
return outputs.map((output) => {
|
|
438
|
+
// PsbtOutputExtended is a union - handle both address and script variants
|
|
439
|
+
const address = 'address' in output ? output.address : undefined;
|
|
440
|
+
const script = 'script' in output ? output.script : undefined;
|
|
441
|
+
|
|
442
|
+
return {
|
|
443
|
+
value: output.value,
|
|
444
|
+
address,
|
|
445
|
+
script: script ? script.toString('hex') : undefined,
|
|
446
|
+
tapInternalKey: output.tapInternalKey
|
|
447
|
+
? output.tapInternalKey.toString('hex')
|
|
448
|
+
: undefined,
|
|
449
|
+
};
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Convert network to name string
|
|
455
|
+
*/
|
|
456
|
+
private static networkToName(network: Network): 'mainnet' | 'testnet' | 'regtest' {
|
|
457
|
+
if (network.bech32 === 'bc') return 'mainnet';
|
|
458
|
+
if (network.bech32 === 'tb') return 'testnet';
|
|
459
|
+
return 'regtest';
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Convert network to chain ID
|
|
464
|
+
*/
|
|
465
|
+
private static networkToChainId(network: Network): ChainId {
|
|
466
|
+
// Default to Bitcoin chain
|
|
467
|
+
return ChainId.Bitcoin;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Interfaces
|
|
2
|
+
export * from './interfaces/index.js';
|
|
3
|
+
|
|
4
|
+
// Core classes
|
|
5
|
+
export { TransactionSerializer } from './TransactionSerializer.js';
|
|
6
|
+
export { TransactionStateCapture, CaptureParams } from './TransactionStateCapture.js';
|
|
7
|
+
export { TransactionReconstructor, ReconstructionOptions } from './TransactionReconstructor.js';
|
|
8
|
+
export { OfflineTransactionManager, ExportOptions } from './OfflineTransactionManager.js';
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { TransactionType } from '../../enums/TransactionType.js';
|
|
2
|
+
import { ChainId } from '../../../network/ChainId.js';
|
|
3
|
+
import { TypeSpecificData } from './ITypeSpecificData.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Format version for serialization compatibility
|
|
7
|
+
*/
|
|
8
|
+
export const SERIALIZATION_FORMAT_VERSION = 1;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Magic byte for identifying serialized transaction state
|
|
12
|
+
*/
|
|
13
|
+
export const SERIALIZATION_MAGIC_BYTE = 0x42; // 'B' for Bitcoin
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Version header for forward compatibility
|
|
17
|
+
*/
|
|
18
|
+
export interface SerializationHeader {
|
|
19
|
+
/** Format version for migration support */
|
|
20
|
+
readonly formatVersion: number;
|
|
21
|
+
/** Consensus version at serialization time */
|
|
22
|
+
readonly consensusVersion: number;
|
|
23
|
+
/** Transaction type discriminant */
|
|
24
|
+
readonly transactionType: TransactionType;
|
|
25
|
+
/** Chain identifier */
|
|
26
|
+
readonly chainId: ChainId;
|
|
27
|
+
/** Timestamp of serialization (Unix epoch ms) */
|
|
28
|
+
readonly timestamp: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Serialized UTXO representation
|
|
33
|
+
*/
|
|
34
|
+
export interface SerializedUTXO {
|
|
35
|
+
/** Transaction ID (32 bytes hex) */
|
|
36
|
+
readonly transactionId: string;
|
|
37
|
+
/** Output index (vout) */
|
|
38
|
+
readonly outputIndex: number;
|
|
39
|
+
/** Value in satoshis */
|
|
40
|
+
readonly value: string; // bigint as string for JSON compatibility
|
|
41
|
+
/** Script pubkey hex */
|
|
42
|
+
readonly scriptPubKeyHex: string;
|
|
43
|
+
/** Address derived from script (for signer lookup in rotation mode) */
|
|
44
|
+
readonly scriptPubKeyAddress?: string;
|
|
45
|
+
/** P2SH redeem script (hex) */
|
|
46
|
+
readonly redeemScript?: string;
|
|
47
|
+
/** P2WSH witness script (hex) */
|
|
48
|
+
readonly witnessScript?: string;
|
|
49
|
+
/** Full previous transaction for legacy scripts (hex) */
|
|
50
|
+
readonly nonWitnessUtxo?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Serialized output representation
|
|
55
|
+
*/
|
|
56
|
+
export interface SerializedOutput {
|
|
57
|
+
/** Value in satoshis */
|
|
58
|
+
readonly value: number;
|
|
59
|
+
/** Destination address */
|
|
60
|
+
readonly address?: string;
|
|
61
|
+
/** Output script (hex) */
|
|
62
|
+
readonly script?: string;
|
|
63
|
+
/** Taproot internal key (hex) */
|
|
64
|
+
readonly tapInternalKey?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Serialized address-to-input-index mapping for address rotation
|
|
69
|
+
*/
|
|
70
|
+
export interface SerializedSignerMapping {
|
|
71
|
+
/** Address that should sign these inputs */
|
|
72
|
+
readonly address: string;
|
|
73
|
+
/** Input indices this address should sign */
|
|
74
|
+
readonly inputIndices: number[];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Base transaction parameters (common to all types)
|
|
79
|
+
*/
|
|
80
|
+
export interface SerializedBaseParams {
|
|
81
|
+
/** Sender address */
|
|
82
|
+
readonly from: string;
|
|
83
|
+
/** Recipient address (optional for some tx types) */
|
|
84
|
+
readonly to?: string;
|
|
85
|
+
/** Fee rate in sat/vB */
|
|
86
|
+
readonly feeRate: number;
|
|
87
|
+
/** OPNet priority fee */
|
|
88
|
+
readonly priorityFee: string; // bigint as string
|
|
89
|
+
/** OPNet gas sat fee */
|
|
90
|
+
readonly gasSatFee: string; // bigint as string
|
|
91
|
+
/** Network identifier */
|
|
92
|
+
readonly networkName: 'mainnet' | 'testnet' | 'regtest';
|
|
93
|
+
/** Transaction version (1, 2, or 3) */
|
|
94
|
+
readonly txVersion: number;
|
|
95
|
+
/** Optional note data (hex) */
|
|
96
|
+
readonly note?: string;
|
|
97
|
+
/** Whether to include anchor output */
|
|
98
|
+
readonly anchor: boolean;
|
|
99
|
+
/** Debug fee logging */
|
|
100
|
+
readonly debugFees?: boolean;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Pre-computed data that must be preserved for deterministic rebuild
|
|
105
|
+
*/
|
|
106
|
+
export interface PrecomputedData {
|
|
107
|
+
/** Compiled target script (hex) - saves recomputation */
|
|
108
|
+
readonly compiledTargetScript?: string;
|
|
109
|
+
/** Random bytes used (hex) - MUST be preserved for determinism */
|
|
110
|
+
readonly randomBytes?: string;
|
|
111
|
+
/** Estimated fees from initial build */
|
|
112
|
+
readonly estimatedFees?: string; // bigint as string
|
|
113
|
+
/** Contract seed for deployment (hex) */
|
|
114
|
+
readonly contractSeed?: string;
|
|
115
|
+
/** Contract address for deployment */
|
|
116
|
+
readonly contractAddress?: string;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Complete serializable transaction state
|
|
121
|
+
*/
|
|
122
|
+
export interface ISerializableTransactionState {
|
|
123
|
+
/** Version and type header */
|
|
124
|
+
readonly header: SerializationHeader;
|
|
125
|
+
/** Base transaction parameters */
|
|
126
|
+
readonly baseParams: SerializedBaseParams;
|
|
127
|
+
/** Primary UTXOs */
|
|
128
|
+
readonly utxos: SerializedUTXO[];
|
|
129
|
+
/** Optional additional inputs */
|
|
130
|
+
readonly optionalInputs: SerializedUTXO[];
|
|
131
|
+
/** Optional additional outputs */
|
|
132
|
+
readonly optionalOutputs: SerializedOutput[];
|
|
133
|
+
/** Whether address rotation mode is enabled */
|
|
134
|
+
readonly addressRotationEnabled: boolean;
|
|
135
|
+
/** Address to input indices mapping for rotation mode */
|
|
136
|
+
readonly signerMappings: SerializedSignerMapping[];
|
|
137
|
+
/** Type-specific data (discriminated by header.transactionType) */
|
|
138
|
+
readonly typeSpecificData: TypeSpecificData;
|
|
139
|
+
/** Pre-computed data for deterministic rebuild */
|
|
140
|
+
readonly precomputedData: PrecomputedData;
|
|
141
|
+
}
|