@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,255 @@
|
|
|
1
|
+
import { Psbt } from '@btc-vision/bitcoin';
|
|
2
|
+
import { TransactionType } from '../enums/TransactionType.js';
|
|
3
|
+
import { TransactionBuilder } from '../builders/TransactionBuilder.js';
|
|
4
|
+
import { MultiSignTransaction } from '../builders/MultiSignTransaction.js';
|
|
5
|
+
import { TransactionSerializer } from './TransactionSerializer.js';
|
|
6
|
+
import { TransactionReconstructor } from './TransactionReconstructor.js';
|
|
7
|
+
import { TransactionStateCapture } from './TransactionStateCapture.js';
|
|
8
|
+
import { isMultiSigSpecificData } from './interfaces/ITypeSpecificData.js';
|
|
9
|
+
export class OfflineTransactionManager {
|
|
10
|
+
static exportFunding(params, precomputed) {
|
|
11
|
+
const state = TransactionStateCapture.fromFunding(params, precomputed);
|
|
12
|
+
return TransactionSerializer.toBase64(state);
|
|
13
|
+
}
|
|
14
|
+
static exportDeployment(params, precomputed) {
|
|
15
|
+
const state = TransactionStateCapture.fromDeployment(params, precomputed);
|
|
16
|
+
return TransactionSerializer.toBase64(state);
|
|
17
|
+
}
|
|
18
|
+
static exportInteraction(params, precomputed) {
|
|
19
|
+
const state = TransactionStateCapture.fromInteraction(params, precomputed);
|
|
20
|
+
return TransactionSerializer.toBase64(state);
|
|
21
|
+
}
|
|
22
|
+
static exportMultiSig(params, precomputed) {
|
|
23
|
+
const state = TransactionStateCapture.fromMultiSig(params, precomputed);
|
|
24
|
+
return TransactionSerializer.toBase64(state);
|
|
25
|
+
}
|
|
26
|
+
static exportCustomScript(params, precomputed) {
|
|
27
|
+
const state = TransactionStateCapture.fromCustomScript(params, precomputed);
|
|
28
|
+
return TransactionSerializer.toBase64(state);
|
|
29
|
+
}
|
|
30
|
+
static exportCancel(params, precomputed) {
|
|
31
|
+
const state = TransactionStateCapture.fromCancel(params, precomputed);
|
|
32
|
+
return TransactionSerializer.toBase64(state);
|
|
33
|
+
}
|
|
34
|
+
static exportFromBuilder(builder, params, precomputed) {
|
|
35
|
+
const type = builder.type;
|
|
36
|
+
let state;
|
|
37
|
+
switch (type) {
|
|
38
|
+
case TransactionType.FUNDING:
|
|
39
|
+
state = TransactionStateCapture.fromFunding(params, precomputed);
|
|
40
|
+
break;
|
|
41
|
+
case TransactionType.DEPLOYMENT:
|
|
42
|
+
state = TransactionStateCapture.fromDeployment(params, precomputed);
|
|
43
|
+
break;
|
|
44
|
+
case TransactionType.INTERACTION:
|
|
45
|
+
state = TransactionStateCapture.fromInteraction(params, precomputed);
|
|
46
|
+
break;
|
|
47
|
+
default:
|
|
48
|
+
throw new Error(`Unsupported transaction type for export: ${type}`);
|
|
49
|
+
}
|
|
50
|
+
return TransactionSerializer.toBase64(state);
|
|
51
|
+
}
|
|
52
|
+
static importForSigning(serializedState, options) {
|
|
53
|
+
const state = TransactionSerializer.fromBase64(serializedState);
|
|
54
|
+
return TransactionReconstructor.reconstruct(state, options);
|
|
55
|
+
}
|
|
56
|
+
static async signAndExport(builder) {
|
|
57
|
+
const tx = await builder.signTransaction();
|
|
58
|
+
return tx.toHex();
|
|
59
|
+
}
|
|
60
|
+
static async importSignAndExport(serializedState, options) {
|
|
61
|
+
const builder = this.importForSigning(serializedState, options);
|
|
62
|
+
return this.signAndExport(builder);
|
|
63
|
+
}
|
|
64
|
+
static rebuildWithNewFees(serializedState, newFeeRate) {
|
|
65
|
+
const state = TransactionSerializer.fromBase64(serializedState);
|
|
66
|
+
const newState = {
|
|
67
|
+
...state,
|
|
68
|
+
baseParams: {
|
|
69
|
+
...state.baseParams,
|
|
70
|
+
feeRate: newFeeRate,
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
return TransactionSerializer.toBase64(newState);
|
|
74
|
+
}
|
|
75
|
+
static async rebuildSignAndExport(serializedState, newFeeRate, options) {
|
|
76
|
+
const builder = this.importForSigning(serializedState, {
|
|
77
|
+
...options,
|
|
78
|
+
newFeeRate,
|
|
79
|
+
});
|
|
80
|
+
return this.signAndExport(builder);
|
|
81
|
+
}
|
|
82
|
+
static inspect(serializedState) {
|
|
83
|
+
return TransactionSerializer.fromBase64(serializedState);
|
|
84
|
+
}
|
|
85
|
+
static validate(serializedState) {
|
|
86
|
+
try {
|
|
87
|
+
TransactionSerializer.fromBase64(serializedState);
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
static getType(serializedState) {
|
|
95
|
+
const state = TransactionSerializer.fromBase64(serializedState);
|
|
96
|
+
return state.header.transactionType;
|
|
97
|
+
}
|
|
98
|
+
static fromBase64(base64State) {
|
|
99
|
+
return TransactionSerializer.fromBase64(base64State);
|
|
100
|
+
}
|
|
101
|
+
static toBase64(state) {
|
|
102
|
+
return TransactionSerializer.toBase64(state);
|
|
103
|
+
}
|
|
104
|
+
static toHex(serializedState) {
|
|
105
|
+
const state = TransactionSerializer.fromBase64(serializedState);
|
|
106
|
+
return TransactionSerializer.toHex(state);
|
|
107
|
+
}
|
|
108
|
+
static fromHex(hexState) {
|
|
109
|
+
const state = TransactionSerializer.fromHex(hexState);
|
|
110
|
+
return TransactionSerializer.toBase64(state);
|
|
111
|
+
}
|
|
112
|
+
static async multiSigAddSignature(serializedState, signer) {
|
|
113
|
+
const state = TransactionSerializer.fromBase64(serializedState);
|
|
114
|
+
if (!isMultiSigSpecificData(state.typeSpecificData)) {
|
|
115
|
+
throw new Error('State is not a multisig transaction');
|
|
116
|
+
}
|
|
117
|
+
const typeData = state.typeSpecificData;
|
|
118
|
+
const pubkeys = typeData.pubkeys.map((pk) => Buffer.from(pk, 'hex'));
|
|
119
|
+
let psbt;
|
|
120
|
+
const network = TransactionReconstructor['nameToNetwork'](state.baseParams.networkName);
|
|
121
|
+
if (typeData.existingPsbtBase64) {
|
|
122
|
+
psbt = Psbt.fromBase64(typeData.existingPsbtBase64, { network });
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
const builder = this.importForSigning(serializedState, {
|
|
126
|
+
signer,
|
|
127
|
+
});
|
|
128
|
+
psbt = await builder.signPSBT();
|
|
129
|
+
}
|
|
130
|
+
const minimums = [];
|
|
131
|
+
for (let i = typeData.originalInputCount; i < psbt.data.inputs.length; i++) {
|
|
132
|
+
minimums.push(typeData.minimumSignatures);
|
|
133
|
+
}
|
|
134
|
+
const result = MultiSignTransaction.signPartial(psbt, signer, typeData.originalInputCount, minimums);
|
|
135
|
+
const orderedPubKeys = [];
|
|
136
|
+
for (let i = typeData.originalInputCount; i < psbt.data.inputs.length; i++) {
|
|
137
|
+
orderedPubKeys.push(pubkeys);
|
|
138
|
+
}
|
|
139
|
+
MultiSignTransaction.attemptFinalizeInputs(psbt, typeData.originalInputCount, orderedPubKeys, result.final);
|
|
140
|
+
const newPsbtBase64 = psbt.toBase64();
|
|
141
|
+
const newState = {
|
|
142
|
+
...state,
|
|
143
|
+
typeSpecificData: {
|
|
144
|
+
...typeData,
|
|
145
|
+
existingPsbtBase64: newPsbtBase64,
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
return {
|
|
149
|
+
state: TransactionSerializer.toBase64(newState),
|
|
150
|
+
signed: result.signed,
|
|
151
|
+
final: result.final,
|
|
152
|
+
psbtBase64: newPsbtBase64,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
static multiSigHasSigned(serializedState, signerPubKey) {
|
|
156
|
+
const state = TransactionSerializer.fromBase64(serializedState);
|
|
157
|
+
if (!isMultiSigSpecificData(state.typeSpecificData)) {
|
|
158
|
+
throw new Error('State is not a multisig transaction');
|
|
159
|
+
}
|
|
160
|
+
const typeData = state.typeSpecificData;
|
|
161
|
+
if (!typeData.existingPsbtBase64) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
const network = TransactionReconstructor['nameToNetwork'](state.baseParams.networkName);
|
|
165
|
+
const psbt = Psbt.fromBase64(typeData.existingPsbtBase64, { network });
|
|
166
|
+
const pubKeyBuffer = Buffer.isBuffer(signerPubKey)
|
|
167
|
+
? signerPubKey
|
|
168
|
+
: Buffer.from(signerPubKey, 'hex');
|
|
169
|
+
return MultiSignTransaction.verifyIfSigned(psbt, pubKeyBuffer);
|
|
170
|
+
}
|
|
171
|
+
static multiSigGetSignatureStatus(serializedState) {
|
|
172
|
+
const state = TransactionSerializer.fromBase64(serializedState);
|
|
173
|
+
if (!isMultiSigSpecificData(state.typeSpecificData)) {
|
|
174
|
+
throw new Error('State is not a multisig transaction');
|
|
175
|
+
}
|
|
176
|
+
const typeData = state.typeSpecificData;
|
|
177
|
+
const required = typeData.minimumSignatures;
|
|
178
|
+
if (!typeData.existingPsbtBase64) {
|
|
179
|
+
return {
|
|
180
|
+
required,
|
|
181
|
+
collected: 0,
|
|
182
|
+
isComplete: false,
|
|
183
|
+
signers: [],
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
const network = TransactionReconstructor['nameToNetwork'](state.baseParams.networkName);
|
|
187
|
+
const psbt = Psbt.fromBase64(typeData.existingPsbtBase64, { network });
|
|
188
|
+
const signerSet = new Set();
|
|
189
|
+
for (let i = typeData.originalInputCount; i < psbt.data.inputs.length; i++) {
|
|
190
|
+
const input = psbt.data.inputs[i];
|
|
191
|
+
if (input.tapScriptSig) {
|
|
192
|
+
for (const sig of input.tapScriptSig) {
|
|
193
|
+
signerSet.add(sig.pubkey.toString('hex'));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (input.finalScriptWitness) {
|
|
197
|
+
const decoded = TransactionBuilder.readScriptWitnessToWitnessStack(input.finalScriptWitness);
|
|
198
|
+
for (let j = 0; j < decoded.length - 2; j += 3) {
|
|
199
|
+
const pubKey = decoded[j + 2];
|
|
200
|
+
signerSet.add(pubKey.toString('hex'));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const signers = Array.from(signerSet);
|
|
205
|
+
return {
|
|
206
|
+
required,
|
|
207
|
+
collected: signers.length,
|
|
208
|
+
isComplete: signers.length >= required,
|
|
209
|
+
signers,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
static multiSigFinalize(serializedState) {
|
|
213
|
+
const state = TransactionSerializer.fromBase64(serializedState);
|
|
214
|
+
if (!isMultiSigSpecificData(state.typeSpecificData)) {
|
|
215
|
+
throw new Error('State is not a multisig transaction');
|
|
216
|
+
}
|
|
217
|
+
const typeData = state.typeSpecificData;
|
|
218
|
+
if (!typeData.existingPsbtBase64) {
|
|
219
|
+
throw new Error('No PSBT found in state - transaction has not been signed');
|
|
220
|
+
}
|
|
221
|
+
const network = TransactionReconstructor['nameToNetwork'](state.baseParams.networkName);
|
|
222
|
+
const psbt = Psbt.fromBase64(typeData.existingPsbtBase64, { network });
|
|
223
|
+
const pubkeys = typeData.pubkeys.map((pk) => Buffer.from(pk, 'hex'));
|
|
224
|
+
const orderedPubKeys = [];
|
|
225
|
+
for (let i = typeData.originalInputCount; i < psbt.data.inputs.length; i++) {
|
|
226
|
+
orderedPubKeys.push(pubkeys);
|
|
227
|
+
}
|
|
228
|
+
const success = MultiSignTransaction.attemptFinalizeInputs(psbt, typeData.originalInputCount, orderedPubKeys, true);
|
|
229
|
+
if (!success) {
|
|
230
|
+
throw new Error('Failed to finalize multisig transaction - not enough signatures');
|
|
231
|
+
}
|
|
232
|
+
return psbt.extractTransaction(true, true).toHex();
|
|
233
|
+
}
|
|
234
|
+
static multiSigGetPsbt(serializedState) {
|
|
235
|
+
const state = TransactionSerializer.fromBase64(serializedState);
|
|
236
|
+
if (!isMultiSigSpecificData(state.typeSpecificData)) {
|
|
237
|
+
throw new Error('State is not a multisig transaction');
|
|
238
|
+
}
|
|
239
|
+
return state.typeSpecificData.existingPsbtBase64 || null;
|
|
240
|
+
}
|
|
241
|
+
static multiSigUpdatePsbt(serializedState, psbtBase64) {
|
|
242
|
+
const state = TransactionSerializer.fromBase64(serializedState);
|
|
243
|
+
if (!isMultiSigSpecificData(state.typeSpecificData)) {
|
|
244
|
+
throw new Error('State is not a multisig transaction');
|
|
245
|
+
}
|
|
246
|
+
const newState = {
|
|
247
|
+
...state,
|
|
248
|
+
typeSpecificData: {
|
|
249
|
+
...state.typeSpecificData,
|
|
250
|
+
existingPsbtBase64: psbtBase64,
|
|
251
|
+
},
|
|
252
|
+
};
|
|
253
|
+
return TransactionSerializer.toBase64(newState);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Signer } from '@btc-vision/bitcoin';
|
|
2
|
+
import { ECPairInterface } from 'ecpair';
|
|
3
|
+
import { QuantumBIP32Interface } from '@btc-vision/bip32';
|
|
4
|
+
import { SignerMap } from '../../signer/AddressRotation.js';
|
|
5
|
+
import { TransactionType } from '../enums/TransactionType.js';
|
|
6
|
+
import { TransactionBuilder } from '../builders/TransactionBuilder.js';
|
|
7
|
+
import { ISerializableTransactionState } from './interfaces/ISerializableState.js';
|
|
8
|
+
export interface ReconstructionOptions {
|
|
9
|
+
signer: Signer | ECPairInterface;
|
|
10
|
+
newFeeRate?: number;
|
|
11
|
+
newPriorityFee?: bigint;
|
|
12
|
+
newGasSatFee?: bigint;
|
|
13
|
+
signerMap?: SignerMap;
|
|
14
|
+
mldsaSigner?: QuantumBIP32Interface | null;
|
|
15
|
+
}
|
|
16
|
+
export declare class TransactionReconstructor {
|
|
17
|
+
static reconstruct(state: ISerializableTransactionState, options: ReconstructionOptions): TransactionBuilder<TransactionType>;
|
|
18
|
+
private static reconstructFunding;
|
|
19
|
+
private static reconstructDeployment;
|
|
20
|
+
private static reconstructInteraction;
|
|
21
|
+
private static reconstructMultiSig;
|
|
22
|
+
private static reconstructCustomScript;
|
|
23
|
+
private static reconstructCancel;
|
|
24
|
+
private static buildAddressRotationConfig;
|
|
25
|
+
private static deserializeUTXOs;
|
|
26
|
+
private static deserializeOutputs;
|
|
27
|
+
private static nameToNetwork;
|
|
28
|
+
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { networks } from '@btc-vision/bitcoin';
|
|
2
|
+
import { ChallengeSolution } from '../../epoch/ChallengeSolution.js';
|
|
3
|
+
import { FundingTransaction } from '../builders/FundingTransaction.js';
|
|
4
|
+
import { DeploymentTransaction } from '../builders/DeploymentTransaction.js';
|
|
5
|
+
import { InteractionTransaction } from '../builders/InteractionTransaction.js';
|
|
6
|
+
import { MultiSignTransaction } from '../builders/MultiSignTransaction.js';
|
|
7
|
+
import { CustomScriptTransaction } from '../builders/CustomScriptTransaction.js';
|
|
8
|
+
import { CancelTransaction } from '../builders/CancelTransaction.js';
|
|
9
|
+
import { isCancelSpecificData, isCustomScriptSpecificData, isDeploymentSpecificData, isFundingSpecificData, isInteractionSpecificData, isMultiSigSpecificData, } from './interfaces/ITypeSpecificData.js';
|
|
10
|
+
export class TransactionReconstructor {
|
|
11
|
+
static reconstruct(state, options) {
|
|
12
|
+
const network = this.nameToNetwork(state.baseParams.networkName);
|
|
13
|
+
const utxos = this.deserializeUTXOs(state.utxos);
|
|
14
|
+
const optionalInputs = this.deserializeUTXOs(state.optionalInputs);
|
|
15
|
+
const optionalOutputs = this.deserializeOutputs(state.optionalOutputs);
|
|
16
|
+
const addressRotation = this.buildAddressRotationConfig(state.addressRotationEnabled, options.signerMap);
|
|
17
|
+
const feeRate = options.newFeeRate ?? state.baseParams.feeRate;
|
|
18
|
+
const priorityFee = options.newPriorityFee ?? BigInt(state.baseParams.priorityFee);
|
|
19
|
+
const gasSatFee = options.newGasSatFee ?? BigInt(state.baseParams.gasSatFee);
|
|
20
|
+
const baseParams = {
|
|
21
|
+
signer: options.signer,
|
|
22
|
+
mldsaSigner: options.mldsaSigner ?? null,
|
|
23
|
+
network,
|
|
24
|
+
chainId: state.header.chainId,
|
|
25
|
+
utxos,
|
|
26
|
+
optionalInputs,
|
|
27
|
+
optionalOutputs,
|
|
28
|
+
from: state.baseParams.from,
|
|
29
|
+
to: state.baseParams.to,
|
|
30
|
+
feeRate,
|
|
31
|
+
priorityFee,
|
|
32
|
+
gasSatFee,
|
|
33
|
+
txVersion: state.baseParams.txVersion,
|
|
34
|
+
note: state.baseParams.note ? Buffer.from(state.baseParams.note, 'hex') : undefined,
|
|
35
|
+
anchor: state.baseParams.anchor,
|
|
36
|
+
debugFees: state.baseParams.debugFees,
|
|
37
|
+
addressRotation,
|
|
38
|
+
estimatedFees: state.precomputedData.estimatedFees
|
|
39
|
+
? BigInt(state.precomputedData.estimatedFees)
|
|
40
|
+
: undefined,
|
|
41
|
+
compiledTargetScript: state.precomputedData.compiledTargetScript
|
|
42
|
+
? Buffer.from(state.precomputedData.compiledTargetScript, 'hex')
|
|
43
|
+
: undefined,
|
|
44
|
+
};
|
|
45
|
+
const typeData = state.typeSpecificData;
|
|
46
|
+
if (isFundingSpecificData(typeData)) {
|
|
47
|
+
return this.reconstructFunding(baseParams, typeData);
|
|
48
|
+
}
|
|
49
|
+
else if (isDeploymentSpecificData(typeData)) {
|
|
50
|
+
return this.reconstructDeployment(baseParams, typeData, state);
|
|
51
|
+
}
|
|
52
|
+
else if (isInteractionSpecificData(typeData)) {
|
|
53
|
+
return this.reconstructInteraction(baseParams, typeData, state);
|
|
54
|
+
}
|
|
55
|
+
else if (isMultiSigSpecificData(typeData)) {
|
|
56
|
+
return this.reconstructMultiSig(baseParams, typeData);
|
|
57
|
+
}
|
|
58
|
+
else if (isCustomScriptSpecificData(typeData)) {
|
|
59
|
+
return this.reconstructCustomScript(baseParams, typeData, state);
|
|
60
|
+
}
|
|
61
|
+
else if (isCancelSpecificData(typeData)) {
|
|
62
|
+
return this.reconstructCancel(baseParams, typeData);
|
|
63
|
+
}
|
|
64
|
+
throw new Error(`Unsupported transaction type: ${state.header.transactionType}`);
|
|
65
|
+
}
|
|
66
|
+
static reconstructFunding(baseParams, data) {
|
|
67
|
+
const params = {
|
|
68
|
+
...baseParams,
|
|
69
|
+
amount: BigInt(data.amount),
|
|
70
|
+
splitInputsInto: data.splitInputsInto,
|
|
71
|
+
};
|
|
72
|
+
return new FundingTransaction(params);
|
|
73
|
+
}
|
|
74
|
+
static reconstructDeployment(baseParams, data, state) {
|
|
75
|
+
const challenge = new ChallengeSolution(data.challenge);
|
|
76
|
+
const params = {
|
|
77
|
+
...baseParams,
|
|
78
|
+
bytecode: Buffer.from(data.bytecode, 'hex'),
|
|
79
|
+
calldata: data.calldata ? Buffer.from(data.calldata, 'hex') : undefined,
|
|
80
|
+
challenge,
|
|
81
|
+
randomBytes: state.precomputedData.randomBytes
|
|
82
|
+
? Buffer.from(state.precomputedData.randomBytes, 'hex')
|
|
83
|
+
: undefined,
|
|
84
|
+
revealMLDSAPublicKey: data.revealMLDSAPublicKey,
|
|
85
|
+
linkMLDSAPublicKeyToAddress: data.linkMLDSAPublicKeyToAddress,
|
|
86
|
+
};
|
|
87
|
+
return new DeploymentTransaction(params);
|
|
88
|
+
}
|
|
89
|
+
static reconstructInteraction(baseParams, data, state) {
|
|
90
|
+
const challenge = new ChallengeSolution(data.challenge);
|
|
91
|
+
if (!baseParams.to) {
|
|
92
|
+
throw new Error('InteractionTransaction requires a "to" address');
|
|
93
|
+
}
|
|
94
|
+
const params = {
|
|
95
|
+
...baseParams,
|
|
96
|
+
to: baseParams.to,
|
|
97
|
+
calldata: Buffer.from(data.calldata, 'hex'),
|
|
98
|
+
contract: data.contract,
|
|
99
|
+
challenge,
|
|
100
|
+
randomBytes: state.precomputedData.randomBytes
|
|
101
|
+
? Buffer.from(state.precomputedData.randomBytes, 'hex')
|
|
102
|
+
: undefined,
|
|
103
|
+
loadedStorage: data.loadedStorage,
|
|
104
|
+
isCancellation: data.isCancellation,
|
|
105
|
+
disableAutoRefund: data.disableAutoRefund,
|
|
106
|
+
revealMLDSAPublicKey: data.revealMLDSAPublicKey,
|
|
107
|
+
linkMLDSAPublicKeyToAddress: data.linkMLDSAPublicKeyToAddress,
|
|
108
|
+
};
|
|
109
|
+
return new InteractionTransaction(params);
|
|
110
|
+
}
|
|
111
|
+
static reconstructMultiSig(baseParams, data) {
|
|
112
|
+
const pubkeys = data.pubkeys.map((pk) => Buffer.from(pk, 'hex'));
|
|
113
|
+
if (data.existingPsbtBase64) {
|
|
114
|
+
return MultiSignTransaction.fromBase64({
|
|
115
|
+
mldsaSigner: baseParams.mldsaSigner,
|
|
116
|
+
network: baseParams.network,
|
|
117
|
+
chainId: baseParams.chainId,
|
|
118
|
+
utxos: baseParams.utxos,
|
|
119
|
+
optionalInputs: baseParams.optionalInputs,
|
|
120
|
+
optionalOutputs: baseParams.optionalOutputs,
|
|
121
|
+
feeRate: baseParams.feeRate,
|
|
122
|
+
pubkeys,
|
|
123
|
+
minimumSignatures: data.minimumSignatures,
|
|
124
|
+
receiver: data.receiver,
|
|
125
|
+
requestedAmount: BigInt(data.requestedAmount),
|
|
126
|
+
refundVault: data.refundVault,
|
|
127
|
+
psbt: data.existingPsbtBase64,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
const params = {
|
|
131
|
+
mldsaSigner: baseParams.mldsaSigner,
|
|
132
|
+
network: baseParams.network,
|
|
133
|
+
chainId: baseParams.chainId,
|
|
134
|
+
utxos: baseParams.utxos,
|
|
135
|
+
optionalInputs: baseParams.optionalInputs,
|
|
136
|
+
optionalOutputs: baseParams.optionalOutputs,
|
|
137
|
+
feeRate: baseParams.feeRate,
|
|
138
|
+
pubkeys,
|
|
139
|
+
minimumSignatures: data.minimumSignatures,
|
|
140
|
+
receiver: data.receiver,
|
|
141
|
+
requestedAmount: BigInt(data.requestedAmount),
|
|
142
|
+
refundVault: data.refundVault,
|
|
143
|
+
};
|
|
144
|
+
return new MultiSignTransaction(params);
|
|
145
|
+
}
|
|
146
|
+
static reconstructCustomScript(baseParams, data, state) {
|
|
147
|
+
const scriptElements = data.scriptElements.map((el) => {
|
|
148
|
+
if (el.elementType === 'buffer') {
|
|
149
|
+
return Buffer.from(el.value, 'hex');
|
|
150
|
+
}
|
|
151
|
+
return [el.value];
|
|
152
|
+
});
|
|
153
|
+
const witnesses = data.witnesses.map((w) => Buffer.from(w, 'hex'));
|
|
154
|
+
const annex = data.annex ? Buffer.from(data.annex, 'hex') : undefined;
|
|
155
|
+
if (!baseParams.to) {
|
|
156
|
+
throw new Error('CustomScriptTransaction requires a "to" address');
|
|
157
|
+
}
|
|
158
|
+
const params = {
|
|
159
|
+
...baseParams,
|
|
160
|
+
to: baseParams.to,
|
|
161
|
+
script: scriptElements,
|
|
162
|
+
witnesses,
|
|
163
|
+
annex,
|
|
164
|
+
randomBytes: state.precomputedData.randomBytes
|
|
165
|
+
? Buffer.from(state.precomputedData.randomBytes, 'hex')
|
|
166
|
+
: undefined,
|
|
167
|
+
};
|
|
168
|
+
return new CustomScriptTransaction(params);
|
|
169
|
+
}
|
|
170
|
+
static reconstructCancel(baseParams, data) {
|
|
171
|
+
const params = {
|
|
172
|
+
...baseParams,
|
|
173
|
+
compiledTargetScript: Buffer.from(data.compiledTargetScript, 'hex'),
|
|
174
|
+
};
|
|
175
|
+
return new CancelTransaction(params);
|
|
176
|
+
}
|
|
177
|
+
static buildAddressRotationConfig(enabled, signerMap) {
|
|
178
|
+
if (!enabled) {
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
if (!signerMap || signerMap.size === 0) {
|
|
182
|
+
throw new Error('Address rotation enabled but no signerMap provided in reconstruction options');
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
enabled: true,
|
|
186
|
+
signerMap,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
static deserializeUTXOs(serialized) {
|
|
190
|
+
return serialized.map((s) => ({
|
|
191
|
+
transactionId: s.transactionId,
|
|
192
|
+
outputIndex: s.outputIndex,
|
|
193
|
+
value: BigInt(s.value),
|
|
194
|
+
scriptPubKey: {
|
|
195
|
+
hex: s.scriptPubKeyHex,
|
|
196
|
+
address: s.scriptPubKeyAddress,
|
|
197
|
+
},
|
|
198
|
+
redeemScript: s.redeemScript ? Buffer.from(s.redeemScript, 'hex') : undefined,
|
|
199
|
+
witnessScript: s.witnessScript ? Buffer.from(s.witnessScript, 'hex') : undefined,
|
|
200
|
+
nonWitnessUtxo: s.nonWitnessUtxo ? Buffer.from(s.nonWitnessUtxo, 'hex') : undefined,
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
static deserializeOutputs(serialized) {
|
|
204
|
+
return serialized.map((s) => {
|
|
205
|
+
const tapInternalKey = s.tapInternalKey
|
|
206
|
+
? Buffer.from(s.tapInternalKey, 'hex')
|
|
207
|
+
: undefined;
|
|
208
|
+
if (s.address) {
|
|
209
|
+
return {
|
|
210
|
+
value: s.value,
|
|
211
|
+
address: s.address,
|
|
212
|
+
tapInternalKey,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
else if (s.script) {
|
|
216
|
+
return {
|
|
217
|
+
value: s.value,
|
|
218
|
+
script: Buffer.from(s.script, 'hex'),
|
|
219
|
+
tapInternalKey,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
return {
|
|
224
|
+
value: s.value,
|
|
225
|
+
address: '',
|
|
226
|
+
tapInternalKey,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
static nameToNetwork(name) {
|
|
232
|
+
switch (name) {
|
|
233
|
+
case 'mainnet':
|
|
234
|
+
return networks.bitcoin;
|
|
235
|
+
case 'testnet':
|
|
236
|
+
return networks.testnet;
|
|
237
|
+
case 'regtest':
|
|
238
|
+
return networks.regtest;
|
|
239
|
+
default:
|
|
240
|
+
throw new Error(`Unknown network: ${name}`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ISerializableTransactionState } from './interfaces/ISerializableState.js';
|
|
2
|
+
export declare class TransactionSerializer {
|
|
3
|
+
static serialize(state: ISerializableTransactionState): Buffer;
|
|
4
|
+
static deserialize(data: Buffer): ISerializableTransactionState;
|
|
5
|
+
static toBase64(state: ISerializableTransactionState): string;
|
|
6
|
+
static fromBase64(base64: string): ISerializableTransactionState;
|
|
7
|
+
static toHex(state: ISerializableTransactionState): string;
|
|
8
|
+
static fromHex(hex: string): ISerializableTransactionState;
|
|
9
|
+
private static writeHeader;
|
|
10
|
+
private static readHeader;
|
|
11
|
+
private static writeBaseParams;
|
|
12
|
+
private static readBaseParams;
|
|
13
|
+
private static writeUTXOArray;
|
|
14
|
+
private static writeUTXO;
|
|
15
|
+
private static readUTXOArray;
|
|
16
|
+
private static readUTXO;
|
|
17
|
+
private static writeOutputArray;
|
|
18
|
+
private static writeOutput;
|
|
19
|
+
private static readOutputArray;
|
|
20
|
+
private static readOutput;
|
|
21
|
+
private static writeSignerMappings;
|
|
22
|
+
private static readSignerMappings;
|
|
23
|
+
private static writeTypeSpecificData;
|
|
24
|
+
private static readTypeSpecificData;
|
|
25
|
+
private static writeFundingData;
|
|
26
|
+
private static readFundingData;
|
|
27
|
+
private static writeDeploymentData;
|
|
28
|
+
private static readDeploymentData;
|
|
29
|
+
private static writeInteractionData;
|
|
30
|
+
private static readInteractionData;
|
|
31
|
+
private static writeMultiSigData;
|
|
32
|
+
private static readMultiSigData;
|
|
33
|
+
private static writeCustomScriptData;
|
|
34
|
+
private static writeScriptElement;
|
|
35
|
+
private static readCustomScriptData;
|
|
36
|
+
private static readScriptElement;
|
|
37
|
+
private static writeCancelData;
|
|
38
|
+
private static readCancelData;
|
|
39
|
+
private static writeChallenge;
|
|
40
|
+
private static writeChallengeVerification;
|
|
41
|
+
private static readChallenge;
|
|
42
|
+
private static readChallengeVerification;
|
|
43
|
+
private static writeLoadedStorage;
|
|
44
|
+
private static readLoadedStorage;
|
|
45
|
+
private static writePrecomputedData;
|
|
46
|
+
private static readPrecomputedData;
|
|
47
|
+
private static calculateChecksum;
|
|
48
|
+
private static networkNameToU8;
|
|
49
|
+
private static u8ToNetworkName;
|
|
50
|
+
}
|