@dynamic-labs-wallet/node-btc 0.0.353 → 1.0.0-beta
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/index.cjs +107 -134
- package/index.esm.js +108 -135
- package/package.json +4 -4
- package/src/client/client.d.ts +23 -24
- package/src/client/client.d.ts.map +1 -1
package/index.cjs
CHANGED
|
@@ -66,24 +66,33 @@ class DynamicBtcWalletClient extends node.DynamicWalletClient {
|
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
|
-
*
|
|
70
|
-
* @param
|
|
71
|
-
* @returns The
|
|
72
|
-
*/
|
|
73
|
-
const
|
|
74
|
-
if (!walletProperties) {
|
|
75
|
-
throw new Error('Wallet not found in walletMap');
|
|
76
|
-
}
|
|
77
|
-
const derivationPath = walletProperties.derivationPath;
|
|
69
|
+
* Extracts derivation path and address type from walletMetadata.
|
|
70
|
+
* @param walletMetadata - The wallet metadata
|
|
71
|
+
* @returns The derivation path and derived address type
|
|
72
|
+
*/ getDerivationInfoFromMetadata(walletMetadata) {
|
|
73
|
+
const derivationPath = walletMetadata.derivationPath;
|
|
78
74
|
if (!derivationPath) {
|
|
79
|
-
throw new Error('Derivation path missing in
|
|
75
|
+
throw new Error('Derivation path missing in walletMetadata');
|
|
80
76
|
}
|
|
81
77
|
return {
|
|
82
|
-
walletProperties,
|
|
83
78
|
derivationPath,
|
|
84
79
|
addressType: btcUtils.getAddressTypeFromDerivationPath(derivationPath)
|
|
85
80
|
};
|
|
86
81
|
}
|
|
82
|
+
buildWalletMetadata({ walletId, accountAddress, thresholdSignatureScheme, addressType, bitcoinConfig }) {
|
|
83
|
+
const chainConfig = node.getMPCChainConfig(this.chainName, bitcoinConfig);
|
|
84
|
+
return {
|
|
85
|
+
walletId,
|
|
86
|
+
accountAddress,
|
|
87
|
+
chainName: this.chainName,
|
|
88
|
+
thresholdSignatureScheme,
|
|
89
|
+
derivationPath: JSON.stringify(Object.fromEntries(chainConfig.derivationPath.map((value, index)=>[
|
|
90
|
+
index,
|
|
91
|
+
value
|
|
92
|
+
]))),
|
|
93
|
+
addressType
|
|
94
|
+
};
|
|
95
|
+
}
|
|
87
96
|
/**
|
|
88
97
|
* Verifies that the derived address matches the expected address
|
|
89
98
|
* @param rawPublicKey - The raw public key
|
|
@@ -102,10 +111,10 @@ class DynamicBtcWalletClient extends node.DynamicWalletClient {
|
|
|
102
111
|
* @param thresholdSignatureScheme - The threshold signature scheme to use for the wallet.
|
|
103
112
|
* @param password - The password to use for the wallet.
|
|
104
113
|
* @param onError - The function to call if an error occurs.
|
|
105
|
-
* @param
|
|
114
|
+
* @param backUpToDynamic - Whether to back up the external server key shares to the client share service. By default, it is false.
|
|
106
115
|
* @param bitcoinConfig - Bitcoin configuration (addressType, network)
|
|
107
116
|
* @returns The account address, public key, raw public key, external server key shares, and wallet id.
|
|
108
|
-
*/ async createWalletAccount({ thresholdSignatureScheme, password
|
|
117
|
+
*/ async createWalletAccount({ thresholdSignatureScheme, password, onError, backUpToDynamic = false, bitcoinConfig }) {
|
|
109
118
|
try {
|
|
110
119
|
if (!(bitcoinConfig == null ? void 0 : bitcoinConfig.addressType)) {
|
|
111
120
|
this.logger.warn('[BTC Node Client] addressType not provided for createWalletAccount, defaulting to native_segwit');
|
|
@@ -118,6 +127,7 @@ class DynamicBtcWalletClient extends node.DynamicWalletClient {
|
|
|
118
127
|
addressType,
|
|
119
128
|
network
|
|
120
129
|
};
|
|
130
|
+
let resolvedWalletId;
|
|
121
131
|
let ceremonyCeremonyCompleteResolver;
|
|
122
132
|
let ceremonyAccountAddress;
|
|
123
133
|
const ceremonyCompletePromise = new Promise((resolve)=>{
|
|
@@ -129,35 +139,17 @@ class DynamicBtcWalletClient extends node.DynamicWalletClient {
|
|
|
129
139
|
thresholdSignatureScheme,
|
|
130
140
|
skipLock: true,
|
|
131
141
|
bitcoinConfig: resolvedBitcoinConfig,
|
|
142
|
+
password,
|
|
143
|
+
backUpToDynamic,
|
|
132
144
|
onError,
|
|
133
145
|
onCeremonyComplete: (accountAddress, walletId)=>{
|
|
134
|
-
// Store the ceremony account address to ensure consistency
|
|
135
146
|
ceremonyAccountAddress = accountAddress;
|
|
136
|
-
|
|
137
|
-
const chainConfig = node.getMPCChainConfig(this.chainName, resolvedBitcoinConfig);
|
|
138
|
-
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
|
|
139
|
-
accountAddress,
|
|
140
|
-
walletId,
|
|
141
|
-
chainName: this.chainName,
|
|
142
|
-
thresholdSignatureScheme,
|
|
143
|
-
derivationPath: JSON.stringify(Object.fromEntries(chainConfig.derivationPath.map((value, index)=>[
|
|
144
|
-
index,
|
|
145
|
-
value
|
|
146
|
-
]))),
|
|
147
|
-
externalServerKeySharesBackupInfo: node.getExternalServerKeyShareBackupInfo()
|
|
148
|
-
});
|
|
149
|
-
this.logger.debug('walletMap updated for wallet', {
|
|
150
|
-
context: {
|
|
151
|
-
accountAddress,
|
|
152
|
-
walletId,
|
|
153
|
-
walletMap: this.walletMap
|
|
154
|
-
}
|
|
155
|
-
});
|
|
147
|
+
resolvedWalletId = walletId;
|
|
156
148
|
ceremonyCeremonyCompleteResolver(undefined);
|
|
157
149
|
}
|
|
158
150
|
});
|
|
159
151
|
await ceremonyCompletePromise;
|
|
160
|
-
if (!rawPublicKey || !externalServerKeyShares) {
|
|
152
|
+
if (!rawPublicKey || !externalServerKeyShares || !resolvedWalletId) {
|
|
161
153
|
throw new Error(ERROR_KEYGEN_FAILED);
|
|
162
154
|
}
|
|
163
155
|
const accountAddress = ceremonyAccountAddress || this.deriveAccountAddress({
|
|
@@ -165,19 +157,28 @@ class DynamicBtcWalletClient extends node.DynamicWalletClient {
|
|
|
165
157
|
addressType,
|
|
166
158
|
network
|
|
167
159
|
}).accountAddress;
|
|
168
|
-
const
|
|
160
|
+
const walletMetadata = this.buildWalletMetadata({
|
|
161
|
+
walletId: resolvedWalletId,
|
|
162
|
+
accountAddress,
|
|
163
|
+
thresholdSignatureScheme,
|
|
164
|
+
addressType,
|
|
165
|
+
bitcoinConfig: resolvedBitcoinConfig
|
|
166
|
+
});
|
|
167
|
+
const { keySharesWithBackupStatus, backupInfo } = await this.storeEncryptedBackupByWalletWithRetry({
|
|
169
168
|
accountAddress,
|
|
170
169
|
externalServerKeyShares,
|
|
171
170
|
password,
|
|
172
|
-
|
|
171
|
+
backUpToDynamic,
|
|
172
|
+
walletMetadata
|
|
173
173
|
});
|
|
174
|
+
walletMetadata.externalServerKeySharesBackupInfo = backupInfo;
|
|
174
175
|
const publicKeyHex = btcUtils.extractPublicKeyHex(rawPublicKey);
|
|
175
176
|
return {
|
|
176
|
-
|
|
177
|
+
walletMetadata,
|
|
177
178
|
rawPublicKey,
|
|
178
179
|
publicKeyHex,
|
|
179
180
|
externalServerKeyShares,
|
|
180
|
-
externalKeySharesWithBackupStatus
|
|
181
|
+
externalKeySharesWithBackupStatus: keySharesWithBackupStatus
|
|
181
182
|
};
|
|
182
183
|
} catch (error) {
|
|
183
184
|
logError({
|
|
@@ -203,32 +204,29 @@ class DynamicBtcWalletClient extends node.DynamicWalletClient {
|
|
|
203
204
|
* @param onError - Optional. Error callback function
|
|
204
205
|
* @returns Promise resolving to the BIP-322 signature as a base64 string
|
|
205
206
|
* @throws Error if required parameters are missing, derivation path is invalid, or signing fails
|
|
206
|
-
*/ async signMessage({ message,
|
|
207
|
+
*/ async signMessage({ message, walletMetadata, network, password = undefined, externalServerKeyShares, context, onError }) {
|
|
208
|
+
const { accountAddress } = walletMetadata;
|
|
207
209
|
try {
|
|
208
|
-
var _this_walletMap_accountAddress;
|
|
209
210
|
if (!accountAddress) {
|
|
210
211
|
throw new Error(ERROR_ACCOUNT_ADDRESS_REQUIRED);
|
|
211
212
|
}
|
|
212
|
-
const { derivationPath, addressType } = this.
|
|
213
|
-
//
|
|
214
|
-
await this.
|
|
213
|
+
const { derivationPath, addressType } = this.getDerivationInfoFromMetadata(walletMetadata);
|
|
214
|
+
// Resolve key shares from param or backup
|
|
215
|
+
const resolvedKeyShares = await this.resolveKeyShares({
|
|
215
216
|
accountAddress,
|
|
216
217
|
password,
|
|
217
218
|
walletOperation: node.WalletOperation.SIGN_MESSAGE,
|
|
218
219
|
externalServerKeyShares,
|
|
219
|
-
errorMessage: 'External server key shares are required to sign a message. No backup shares available for recovery.'
|
|
220
|
+
errorMessage: 'External server key shares are required to sign a message. No backup shares available for recovery.',
|
|
221
|
+
walletMetadata
|
|
220
222
|
});
|
|
221
|
-
const resolvedExternalServerKeyShares = externalServerKeyShares != null ? externalServerKeyShares : (_this_walletMap_accountAddress = this.walletMap[accountAddress]) == null ? void 0 : _this_walletMap_accountAddress.externalServerKeyShares;
|
|
222
|
-
if (!resolvedExternalServerKeyShares || resolvedExternalServerKeyShares.length === 0) {
|
|
223
|
-
throw new Error('External server key shares are required to sign a message');
|
|
224
|
-
}
|
|
225
223
|
const bitcoinConfig = {
|
|
226
224
|
addressType,
|
|
227
225
|
network
|
|
228
226
|
};
|
|
229
227
|
const derivedPublicKey = await this.derivePublicKey({
|
|
230
228
|
chainName: this.chainName,
|
|
231
|
-
keyShare:
|
|
229
|
+
keyShare: resolvedKeyShares[0],
|
|
232
230
|
derivationPath: new Uint32Array(Object.values(JSON.parse(derivationPath))),
|
|
233
231
|
bitcoinConfig
|
|
234
232
|
});
|
|
@@ -255,13 +253,15 @@ class DynamicBtcWalletClient extends node.DynamicWalletClient {
|
|
|
255
253
|
accountAddress,
|
|
256
254
|
chainName: this.chainName,
|
|
257
255
|
password,
|
|
258
|
-
externalServerKeyShares:
|
|
256
|
+
externalServerKeyShares: resolvedKeyShares,
|
|
259
257
|
isFormatted: true,
|
|
260
258
|
context: context != null ? context : {
|
|
261
259
|
btcMessage: message
|
|
262
260
|
},
|
|
263
261
|
bitcoinConfig: completeBitcoinConfig,
|
|
264
|
-
onError
|
|
262
|
+
onError,
|
|
263
|
+
walletMetadata,
|
|
264
|
+
passwordPreVerified: !(externalServerKeyShares == null ? void 0 : externalServerKeyShares.length) && !!password
|
|
265
265
|
});
|
|
266
266
|
const bip322Signature = btcUtils.encodeBip322Signature(toSignPsbt, pubKey, signature, addressType);
|
|
267
267
|
return bip322Signature;
|
|
@@ -276,51 +276,43 @@ class DynamicBtcWalletClient extends node.DynamicWalletClient {
|
|
|
276
276
|
if (onError) {
|
|
277
277
|
onError(error);
|
|
278
278
|
}
|
|
279
|
-
throw new Error(ERROR_SIGN_MESSAGE
|
|
279
|
+
throw new Error(ERROR_SIGN_MESSAGE, {
|
|
280
|
+
cause: error
|
|
281
|
+
});
|
|
280
282
|
}
|
|
281
283
|
}
|
|
282
284
|
/**
|
|
283
285
|
* Signs a Bitcoin transaction (PSBT)
|
|
284
286
|
*
|
|
285
287
|
* The address type is automatically derived from the wallet's derivation path.
|
|
286
|
-
* Only inputs belonging to the
|
|
288
|
+
* Only inputs belonging to the account address are signed. Supports both TAPROOT
|
|
287
289
|
* (BIP-341) and Native SegWit (BIP-143) signing methods.
|
|
288
290
|
*
|
|
289
291
|
* @param transaction - The PSBT to sign as a base64 string
|
|
290
|
-
* @param
|
|
292
|
+
* @param accountAddress - The account address (must match inputs to be signed)
|
|
291
293
|
* @param network - The Bitcoin network (MAINNET or TESTNET)
|
|
292
294
|
* @param password - Optional password for encrypted backup shares
|
|
293
295
|
* @param externalServerKeyShares - Optional external server key shares
|
|
294
296
|
* @param context - Optional. Sign message context for API tracking
|
|
295
297
|
* @param onError - Optional. Error callback function
|
|
296
298
|
* @returns Promise resolving to the signed PSBT as a base64 string
|
|
297
|
-
* @throws Error if required parameters are missing, no inputs belong to
|
|
298
|
-
*/ async signTransaction({ transaction,
|
|
299
|
+
* @throws Error if required parameters are missing, no inputs belong to account address, or signing fails
|
|
300
|
+
*/ async signTransaction({ transaction, walletMetadata, network, password = undefined, externalServerKeyShares, context, onError }) {
|
|
301
|
+
const { accountAddress } = walletMetadata;
|
|
299
302
|
try {
|
|
300
|
-
|
|
301
|
-
accountAddress: senderAddress,
|
|
302
|
-
password
|
|
303
|
-
});
|
|
304
|
-
if (!senderAddress) {
|
|
303
|
+
if (!accountAddress) {
|
|
305
304
|
throw new Error(ERROR_ACCOUNT_ADDRESS_REQUIRED);
|
|
306
305
|
}
|
|
307
|
-
const { derivationPath, addressType } = this.
|
|
308
|
-
//
|
|
309
|
-
await this.
|
|
310
|
-
accountAddress
|
|
306
|
+
const { derivationPath, addressType } = this.getDerivationInfoFromMetadata(walletMetadata);
|
|
307
|
+
// Resolve key shares from param or backup
|
|
308
|
+
const resolvedKeyShares = await this.resolveKeyShares({
|
|
309
|
+
accountAddress,
|
|
311
310
|
password,
|
|
312
311
|
walletOperation: node.WalletOperation.SIGN_TRANSACTION,
|
|
313
312
|
externalServerKeyShares,
|
|
314
|
-
errorMessage: 'External server key shares are required to sign transaction. No backup shares available for recovery.'
|
|
313
|
+
errorMessage: 'External server key shares are required to sign transaction. No backup shares available for recovery.',
|
|
314
|
+
walletMetadata
|
|
315
315
|
});
|
|
316
|
-
const updatedWalletProperties = this.walletMap[senderAddress];
|
|
317
|
-
if (!updatedWalletProperties) {
|
|
318
|
-
throw new Error('Wallet not found in walletMap after key share recovery');
|
|
319
|
-
}
|
|
320
|
-
const resolvedExternalServerKeyShares = externalServerKeyShares || updatedWalletProperties.externalServerKeyShares;
|
|
321
|
-
if (!resolvedExternalServerKeyShares || resolvedExternalServerKeyShares.length === 0) {
|
|
322
|
-
throw new Error('External server key shares are required to sign transaction. No backup shares available for recovery.');
|
|
323
|
-
}
|
|
324
316
|
const bitcoinConfig = {
|
|
325
317
|
addressType,
|
|
326
318
|
network
|
|
@@ -328,7 +320,7 @@ class DynamicBtcWalletClient extends node.DynamicWalletClient {
|
|
|
328
320
|
const psbt = bitcoin__namespace.Psbt.fromBase64(transaction);
|
|
329
321
|
const derivedPublicKey = await this.derivePublicKey({
|
|
330
322
|
chainName: this.chainName,
|
|
331
|
-
keyShare:
|
|
323
|
+
keyShare: resolvedKeyShares[0],
|
|
332
324
|
derivationPath: new Uint32Array(Object.values(JSON.parse(derivationPath))),
|
|
333
325
|
bitcoinConfig
|
|
334
326
|
});
|
|
@@ -341,9 +333,9 @@ class DynamicBtcWalletClient extends node.DynamicWalletClient {
|
|
|
341
333
|
const inputsToSign = psbt.data.inputs.map((input, i)=>({
|
|
342
334
|
input,
|
|
343
335
|
index: i
|
|
344
|
-
})).filter(({ input })=>btcUtils.doesInputBelongToAddress(input,
|
|
336
|
+
})).filter(({ input })=>btcUtils.doesInputBelongToAddress(input, accountAddress, network));
|
|
345
337
|
if (inputsToSign.length === 0) {
|
|
346
|
-
throw new Error('No inputs found that belong to the
|
|
338
|
+
throw new Error('No inputs found that belong to the account address');
|
|
347
339
|
}
|
|
348
340
|
if (addressType === core.BitcoinAddressType.TAPROOT) {
|
|
349
341
|
const tweak = btcUtils.calculateTaprootTweak(pubKey);
|
|
@@ -359,14 +351,16 @@ class DynamicBtcWalletClient extends node.DynamicWalletClient {
|
|
|
359
351
|
const hash = Buffer.from(tx.hashForWitnessV1(i, prevOutScripts, values, bitcoin__namespace.Transaction.SIGHASH_DEFAULT));
|
|
360
352
|
const signature = await this.sign({
|
|
361
353
|
message: new Uint8Array(hash),
|
|
362
|
-
accountAddress
|
|
354
|
+
accountAddress,
|
|
363
355
|
chainName: this.chainName,
|
|
364
356
|
password,
|
|
365
|
-
externalServerKeyShares:
|
|
357
|
+
externalServerKeyShares: resolvedKeyShares,
|
|
366
358
|
isFormatted: true,
|
|
367
359
|
context,
|
|
368
360
|
bitcoinConfig: completeBitcoinConfig,
|
|
369
|
-
onError
|
|
361
|
+
onError,
|
|
362
|
+
walletMetadata,
|
|
363
|
+
passwordPreVerified: !(externalServerKeyShares == null ? void 0 : externalServerKeyShares.length) && !!password
|
|
370
364
|
});
|
|
371
365
|
const sigBuffer = btcUtils.convertSignatureToTaprootBuffer(signature);
|
|
372
366
|
psbt.updateInput(i, {
|
|
@@ -394,14 +388,16 @@ class DynamicBtcWalletClient extends node.DynamicWalletClient {
|
|
|
394
388
|
const hash = tx.hashForWitnessV0(i, scriptCode, value, bitcoin__namespace.Transaction.SIGHASH_ALL);
|
|
395
389
|
const signature = await this.sign({
|
|
396
390
|
message: new Uint8Array(hash),
|
|
397
|
-
accountAddress
|
|
391
|
+
accountAddress,
|
|
398
392
|
chainName: this.chainName,
|
|
399
393
|
password,
|
|
400
|
-
externalServerKeyShares:
|
|
394
|
+
externalServerKeyShares: resolvedKeyShares,
|
|
401
395
|
isFormatted: true,
|
|
402
396
|
context,
|
|
403
397
|
bitcoinConfig: completeBitcoinConfig,
|
|
404
|
-
onError
|
|
398
|
+
onError,
|
|
399
|
+
walletMetadata,
|
|
400
|
+
passwordPreVerified: !(externalServerKeyShares == null ? void 0 : externalServerKeyShares.length) && !!password
|
|
405
401
|
});
|
|
406
402
|
const derSignature = btcUtils.convertSignatureToDER(signature);
|
|
407
403
|
psbt.updateInput(i, {
|
|
@@ -421,7 +417,7 @@ class DynamicBtcWalletClient extends node.DynamicWalletClient {
|
|
|
421
417
|
message: ERROR_SIGN_TRANSACTION,
|
|
422
418
|
error: error,
|
|
423
419
|
context: {
|
|
424
|
-
|
|
420
|
+
accountAddress
|
|
425
421
|
}
|
|
426
422
|
});
|
|
427
423
|
if (onError) {
|
|
@@ -436,43 +432,21 @@ class DynamicBtcWalletClient extends node.DynamicWalletClient {
|
|
|
436
432
|
* @param password - The password for encrypted backup shares
|
|
437
433
|
* @param externalServerKeyShares - Optional external server key shares
|
|
438
434
|
* @returns The private key in WIF format
|
|
439
|
-
*/ async exportPrivateKey({
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
password
|
|
443
|
-
});
|
|
444
|
-
// Attempt to recover key shares from backup if not provided
|
|
445
|
-
await this.ensureKeySharesRecovered({
|
|
446
|
-
accountAddress,
|
|
447
|
-
password,
|
|
448
|
-
walletOperation: node.WalletOperation.EXPORT_PRIVATE_KEY,
|
|
449
|
-
externalServerKeyShares,
|
|
450
|
-
errorMessage: 'External server key shares are required to export private key. No backup shares available for recovery.'
|
|
451
|
-
});
|
|
452
|
-
// Re-read wallet from map after recovery (it may have been updated with recovered shares)
|
|
453
|
-
const updatedWalletProperties = this.walletMap[accountAddress];
|
|
454
|
-
if (!updatedWalletProperties) {
|
|
455
|
-
throw new Error('Wallet not found in walletMap after recovery');
|
|
456
|
-
}
|
|
457
|
-
const derivationPath = updatedWalletProperties.derivationPath;
|
|
458
|
-
if (!derivationPath) {
|
|
459
|
-
throw new Error('Derivation path missing in walletMap');
|
|
460
|
-
}
|
|
461
|
-
// Derive address type from derivation path for bitcoinConfig
|
|
462
|
-
const addressType = btcUtils.getAddressTypeFromDerivationPath(derivationPath);
|
|
435
|
+
*/ async exportPrivateKey({ walletMetadata, password = undefined, externalServerKeyShares }) {
|
|
436
|
+
const { accountAddress } = walletMetadata;
|
|
437
|
+
const { addressType } = this.getDerivationInfoFromMetadata(walletMetadata);
|
|
463
438
|
const network = core.BitcoinNetwork.MAINNET; // Default to mainnet, could be derived from wallet
|
|
464
439
|
const bitcoinConfig = {
|
|
465
440
|
addressType,
|
|
466
441
|
network
|
|
467
442
|
};
|
|
468
|
-
// Get key shares from wallet map if not provided (recovered from backup)
|
|
469
|
-
const resolvedExternalServerKeyShares = externalServerKeyShares != null ? externalServerKeyShares : updatedWalletProperties.externalServerKeyShares;
|
|
470
443
|
const { derivedPrivateKey } = await this.exportKey({
|
|
471
444
|
accountAddress,
|
|
472
445
|
chainName: this.chainName,
|
|
473
446
|
password,
|
|
474
|
-
externalServerKeyShares
|
|
475
|
-
bitcoinConfig
|
|
447
|
+
externalServerKeyShares,
|
|
448
|
+
bitcoinConfig,
|
|
449
|
+
walletMetadata
|
|
476
450
|
});
|
|
477
451
|
if (!derivedPrivateKey) {
|
|
478
452
|
throw new Error('Derived private key is undefined');
|
|
@@ -508,10 +482,10 @@ class DynamicBtcWalletClient extends node.DynamicWalletClient {
|
|
|
508
482
|
* @param thresholdSignatureScheme - The threshold signature scheme to use for the wallet
|
|
509
483
|
* @param password - The password to use for the wallet
|
|
510
484
|
* @param onError - The function to call if an error occurs
|
|
511
|
-
* @param
|
|
485
|
+
* @param backUpToDynamic - Whether to back up the external server key shares to the client share service. By default, it is false.
|
|
512
486
|
* @param bitcoinConfig - Bitcoin configuration (addressType, network)
|
|
513
487
|
* @returns The account address, public key, raw public key, external server key shares
|
|
514
|
-
*/ async importPrivateKey({ privateKey, chainName, thresholdSignatureScheme, password
|
|
488
|
+
*/ async importPrivateKey({ privateKey, chainName, thresholdSignatureScheme, password, backUpToDynamic = false, onError, bitcoinConfig }) {
|
|
515
489
|
try {
|
|
516
490
|
const { addressType, network = core.BitcoinNetwork.MAINNET } = bitcoinConfig;
|
|
517
491
|
if (!addressType) {
|
|
@@ -520,6 +494,7 @@ class DynamicBtcWalletClient extends node.DynamicWalletClient {
|
|
|
520
494
|
if (addressType !== core.BitcoinAddressType.NATIVE_SEGWIT && addressType !== core.BitcoinAddressType.TAPROOT) {
|
|
521
495
|
throw new Error(`Invalid addressType: ${addressType}. Must be one of: ${core.BitcoinAddressType.NATIVE_SEGWIT}, ${core.BitcoinAddressType.TAPROOT}`);
|
|
522
496
|
}
|
|
497
|
+
let resolvedWalletId;
|
|
523
498
|
let ceremonyCeremonyCompleteResolver;
|
|
524
499
|
let ceremonyAccountAddress;
|
|
525
500
|
const ceremonyCompletePromise = new Promise((resolve)=>{
|
|
@@ -539,33 +514,22 @@ class DynamicBtcWalletClient extends node.DynamicWalletClient {
|
|
|
539
514
|
privateKey: formattedPrivateKey,
|
|
540
515
|
thresholdSignatureScheme,
|
|
541
516
|
bitcoinConfig,
|
|
517
|
+
password,
|
|
518
|
+
backUpToDynamic,
|
|
542
519
|
onError,
|
|
543
520
|
onCeremonyComplete: (accountAddress, walletId)=>{
|
|
544
|
-
// Store the ceremony account address to ensure consistency
|
|
545
521
|
ceremonyAccountAddress = accountAddress;
|
|
522
|
+
resolvedWalletId = walletId;
|
|
546
523
|
// Verify address matches
|
|
547
524
|
if (accountAddress !== expectedAddress) {
|
|
548
525
|
throw new Error(`Public address mismatch: derived address ${accountAddress} !== expected address ${expectedAddress}`);
|
|
549
526
|
}
|
|
550
|
-
// update wallet map
|
|
551
|
-
const chainConfig = node.getMPCChainConfig(this.chainName, bitcoinConfig);
|
|
552
|
-
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
|
|
553
|
-
accountAddress,
|
|
554
|
-
walletId,
|
|
555
|
-
chainName: this.chainName,
|
|
556
|
-
thresholdSignatureScheme,
|
|
557
|
-
derivationPath: JSON.stringify(Object.fromEntries(chainConfig.derivationPath.map((value, index)=>[
|
|
558
|
-
index,
|
|
559
|
-
value
|
|
560
|
-
]))),
|
|
561
|
-
externalServerKeySharesBackupInfo: node.getExternalServerKeyShareBackupInfo()
|
|
562
|
-
});
|
|
563
527
|
ceremonyCeremonyCompleteResolver(undefined);
|
|
564
528
|
}
|
|
565
529
|
});
|
|
566
530
|
// Wait for the ceremony to complete before proceeding
|
|
567
531
|
await ceremonyCompletePromise;
|
|
568
|
-
if (!rawPublicKey || !externalServerKeyShares) {
|
|
532
|
+
if (!rawPublicKey || !externalServerKeyShares || !resolvedWalletId) {
|
|
569
533
|
throw new Error('Error creating wallet account');
|
|
570
534
|
}
|
|
571
535
|
// Use the ceremony account address if available, otherwise derive it from raw public key
|
|
@@ -577,19 +541,28 @@ class DynamicBtcWalletClient extends node.DynamicWalletClient {
|
|
|
577
541
|
if (accountAddress !== expectedAddress) {
|
|
578
542
|
throw new Error(`Public address mismatch: derived address ${accountAddress} !== expected address ${expectedAddress}`);
|
|
579
543
|
}
|
|
580
|
-
const
|
|
544
|
+
const walletMetadata = this.buildWalletMetadata({
|
|
545
|
+
walletId: resolvedWalletId,
|
|
546
|
+
accountAddress,
|
|
547
|
+
thresholdSignatureScheme,
|
|
548
|
+
addressType,
|
|
549
|
+
bitcoinConfig
|
|
550
|
+
});
|
|
551
|
+
const { keySharesWithBackupStatus, backupInfo } = await this.storeEncryptedBackupByWalletWithRetry({
|
|
581
552
|
accountAddress,
|
|
582
553
|
externalServerKeyShares,
|
|
583
554
|
password,
|
|
584
|
-
|
|
555
|
+
backUpToDynamic,
|
|
556
|
+
walletMetadata
|
|
585
557
|
});
|
|
558
|
+
walletMetadata.externalServerKeySharesBackupInfo = backupInfo;
|
|
586
559
|
const publicKeyHex = btcUtils.extractPublicKeyHex(rawPublicKey);
|
|
587
560
|
return {
|
|
588
|
-
|
|
561
|
+
walletMetadata,
|
|
589
562
|
rawPublicKey,
|
|
590
563
|
publicKeyHex,
|
|
591
564
|
externalServerKeyShares,
|
|
592
|
-
externalKeySharesWithBackupStatus
|
|
565
|
+
externalKeySharesWithBackupStatus: keySharesWithBackupStatus
|
|
593
566
|
};
|
|
594
567
|
} catch (error) {
|
|
595
568
|
logError({
|
package/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createLogError, DynamicWalletClient, getMPCChainConfig,
|
|
1
|
+
import { createLogError, DynamicWalletClient, getMPCChainConfig, WalletOperation } from '@dynamic-labs-wallet/node';
|
|
2
2
|
import { BitcoinAddressType, BitcoinNetwork } from '@dynamic-labs-wallet/core';
|
|
3
3
|
import { initEccLib, normalizePublicKey, publicKeyToBitcoinAddress, getAddressTypeFromDerivationPath, extractPublicKeyHex, calculateBip322Hash, calculateTaprootTweak, encodeBip322Signature, doesInputBelongToAddress, collectPSBTInputData, convertSignatureToTaprootBuffer, getBitcoinNetwork, convertSignatureToDER, privateKeyToWIF, wifToPrivateKey, getPublicKeyFromPrivateKey } from '@dynamic-labs-wallet/btc-utils';
|
|
4
4
|
import * as bitcoin from 'bitcoinjs-lib';
|
|
@@ -44,24 +44,33 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
46
|
/**
|
|
47
|
-
*
|
|
48
|
-
* @param
|
|
49
|
-
* @returns The
|
|
50
|
-
*/
|
|
51
|
-
const
|
|
52
|
-
if (!walletProperties) {
|
|
53
|
-
throw new Error('Wallet not found in walletMap');
|
|
54
|
-
}
|
|
55
|
-
const derivationPath = walletProperties.derivationPath;
|
|
47
|
+
* Extracts derivation path and address type from walletMetadata.
|
|
48
|
+
* @param walletMetadata - The wallet metadata
|
|
49
|
+
* @returns The derivation path and derived address type
|
|
50
|
+
*/ getDerivationInfoFromMetadata(walletMetadata) {
|
|
51
|
+
const derivationPath = walletMetadata.derivationPath;
|
|
56
52
|
if (!derivationPath) {
|
|
57
|
-
throw new Error('Derivation path missing in
|
|
53
|
+
throw new Error('Derivation path missing in walletMetadata');
|
|
58
54
|
}
|
|
59
55
|
return {
|
|
60
|
-
walletProperties,
|
|
61
56
|
derivationPath,
|
|
62
57
|
addressType: getAddressTypeFromDerivationPath(derivationPath)
|
|
63
58
|
};
|
|
64
59
|
}
|
|
60
|
+
buildWalletMetadata({ walletId, accountAddress, thresholdSignatureScheme, addressType, bitcoinConfig }) {
|
|
61
|
+
const chainConfig = getMPCChainConfig(this.chainName, bitcoinConfig);
|
|
62
|
+
return {
|
|
63
|
+
walletId,
|
|
64
|
+
accountAddress,
|
|
65
|
+
chainName: this.chainName,
|
|
66
|
+
thresholdSignatureScheme,
|
|
67
|
+
derivationPath: JSON.stringify(Object.fromEntries(chainConfig.derivationPath.map((value, index)=>[
|
|
68
|
+
index,
|
|
69
|
+
value
|
|
70
|
+
]))),
|
|
71
|
+
addressType
|
|
72
|
+
};
|
|
73
|
+
}
|
|
65
74
|
/**
|
|
66
75
|
* Verifies that the derived address matches the expected address
|
|
67
76
|
* @param rawPublicKey - The raw public key
|
|
@@ -80,10 +89,10 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
80
89
|
* @param thresholdSignatureScheme - The threshold signature scheme to use for the wallet.
|
|
81
90
|
* @param password - The password to use for the wallet.
|
|
82
91
|
* @param onError - The function to call if an error occurs.
|
|
83
|
-
* @param
|
|
92
|
+
* @param backUpToDynamic - Whether to back up the external server key shares to the client share service. By default, it is false.
|
|
84
93
|
* @param bitcoinConfig - Bitcoin configuration (addressType, network)
|
|
85
94
|
* @returns The account address, public key, raw public key, external server key shares, and wallet id.
|
|
86
|
-
*/ async createWalletAccount({ thresholdSignatureScheme, password
|
|
95
|
+
*/ async createWalletAccount({ thresholdSignatureScheme, password, onError, backUpToDynamic = false, bitcoinConfig }) {
|
|
87
96
|
try {
|
|
88
97
|
if (!(bitcoinConfig == null ? void 0 : bitcoinConfig.addressType)) {
|
|
89
98
|
this.logger.warn('[BTC Node Client] addressType not provided for createWalletAccount, defaulting to native_segwit');
|
|
@@ -96,6 +105,7 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
96
105
|
addressType,
|
|
97
106
|
network
|
|
98
107
|
};
|
|
108
|
+
let resolvedWalletId;
|
|
99
109
|
let ceremonyCeremonyCompleteResolver;
|
|
100
110
|
let ceremonyAccountAddress;
|
|
101
111
|
const ceremonyCompletePromise = new Promise((resolve)=>{
|
|
@@ -107,35 +117,17 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
107
117
|
thresholdSignatureScheme,
|
|
108
118
|
skipLock: true,
|
|
109
119
|
bitcoinConfig: resolvedBitcoinConfig,
|
|
120
|
+
password,
|
|
121
|
+
backUpToDynamic,
|
|
110
122
|
onError,
|
|
111
123
|
onCeremonyComplete: (accountAddress, walletId)=>{
|
|
112
|
-
// Store the ceremony account address to ensure consistency
|
|
113
124
|
ceremonyAccountAddress = accountAddress;
|
|
114
|
-
|
|
115
|
-
const chainConfig = getMPCChainConfig(this.chainName, resolvedBitcoinConfig);
|
|
116
|
-
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
|
|
117
|
-
accountAddress,
|
|
118
|
-
walletId,
|
|
119
|
-
chainName: this.chainName,
|
|
120
|
-
thresholdSignatureScheme,
|
|
121
|
-
derivationPath: JSON.stringify(Object.fromEntries(chainConfig.derivationPath.map((value, index)=>[
|
|
122
|
-
index,
|
|
123
|
-
value
|
|
124
|
-
]))),
|
|
125
|
-
externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo()
|
|
126
|
-
});
|
|
127
|
-
this.logger.debug('walletMap updated for wallet', {
|
|
128
|
-
context: {
|
|
129
|
-
accountAddress,
|
|
130
|
-
walletId,
|
|
131
|
-
walletMap: this.walletMap
|
|
132
|
-
}
|
|
133
|
-
});
|
|
125
|
+
resolvedWalletId = walletId;
|
|
134
126
|
ceremonyCeremonyCompleteResolver(undefined);
|
|
135
127
|
}
|
|
136
128
|
});
|
|
137
129
|
await ceremonyCompletePromise;
|
|
138
|
-
if (!rawPublicKey || !externalServerKeyShares) {
|
|
130
|
+
if (!rawPublicKey || !externalServerKeyShares || !resolvedWalletId) {
|
|
139
131
|
throw new Error(ERROR_KEYGEN_FAILED);
|
|
140
132
|
}
|
|
141
133
|
const accountAddress = ceremonyAccountAddress || this.deriveAccountAddress({
|
|
@@ -143,19 +135,28 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
143
135
|
addressType,
|
|
144
136
|
network
|
|
145
137
|
}).accountAddress;
|
|
146
|
-
const
|
|
138
|
+
const walletMetadata = this.buildWalletMetadata({
|
|
139
|
+
walletId: resolvedWalletId,
|
|
140
|
+
accountAddress,
|
|
141
|
+
thresholdSignatureScheme,
|
|
142
|
+
addressType,
|
|
143
|
+
bitcoinConfig: resolvedBitcoinConfig
|
|
144
|
+
});
|
|
145
|
+
const { keySharesWithBackupStatus, backupInfo } = await this.storeEncryptedBackupByWalletWithRetry({
|
|
147
146
|
accountAddress,
|
|
148
147
|
externalServerKeyShares,
|
|
149
148
|
password,
|
|
150
|
-
|
|
149
|
+
backUpToDynamic,
|
|
150
|
+
walletMetadata
|
|
151
151
|
});
|
|
152
|
+
walletMetadata.externalServerKeySharesBackupInfo = backupInfo;
|
|
152
153
|
const publicKeyHex = extractPublicKeyHex(rawPublicKey);
|
|
153
154
|
return {
|
|
154
|
-
|
|
155
|
+
walletMetadata,
|
|
155
156
|
rawPublicKey,
|
|
156
157
|
publicKeyHex,
|
|
157
158
|
externalServerKeyShares,
|
|
158
|
-
externalKeySharesWithBackupStatus
|
|
159
|
+
externalKeySharesWithBackupStatus: keySharesWithBackupStatus
|
|
159
160
|
};
|
|
160
161
|
} catch (error) {
|
|
161
162
|
logError({
|
|
@@ -181,32 +182,29 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
181
182
|
* @param onError - Optional. Error callback function
|
|
182
183
|
* @returns Promise resolving to the BIP-322 signature as a base64 string
|
|
183
184
|
* @throws Error if required parameters are missing, derivation path is invalid, or signing fails
|
|
184
|
-
*/ async signMessage({ message,
|
|
185
|
+
*/ async signMessage({ message, walletMetadata, network, password = undefined, externalServerKeyShares, context, onError }) {
|
|
186
|
+
const { accountAddress } = walletMetadata;
|
|
185
187
|
try {
|
|
186
|
-
var _this_walletMap_accountAddress;
|
|
187
188
|
if (!accountAddress) {
|
|
188
189
|
throw new Error(ERROR_ACCOUNT_ADDRESS_REQUIRED);
|
|
189
190
|
}
|
|
190
|
-
const { derivationPath, addressType } = this.
|
|
191
|
-
//
|
|
192
|
-
await this.
|
|
191
|
+
const { derivationPath, addressType } = this.getDerivationInfoFromMetadata(walletMetadata);
|
|
192
|
+
// Resolve key shares from param or backup
|
|
193
|
+
const resolvedKeyShares = await this.resolveKeyShares({
|
|
193
194
|
accountAddress,
|
|
194
195
|
password,
|
|
195
196
|
walletOperation: WalletOperation.SIGN_MESSAGE,
|
|
196
197
|
externalServerKeyShares,
|
|
197
|
-
errorMessage: 'External server key shares are required to sign a message. No backup shares available for recovery.'
|
|
198
|
+
errorMessage: 'External server key shares are required to sign a message. No backup shares available for recovery.',
|
|
199
|
+
walletMetadata
|
|
198
200
|
});
|
|
199
|
-
const resolvedExternalServerKeyShares = externalServerKeyShares != null ? externalServerKeyShares : (_this_walletMap_accountAddress = this.walletMap[accountAddress]) == null ? void 0 : _this_walletMap_accountAddress.externalServerKeyShares;
|
|
200
|
-
if (!resolvedExternalServerKeyShares || resolvedExternalServerKeyShares.length === 0) {
|
|
201
|
-
throw new Error('External server key shares are required to sign a message');
|
|
202
|
-
}
|
|
203
201
|
const bitcoinConfig = {
|
|
204
202
|
addressType,
|
|
205
203
|
network
|
|
206
204
|
};
|
|
207
205
|
const derivedPublicKey = await this.derivePublicKey({
|
|
208
206
|
chainName: this.chainName,
|
|
209
|
-
keyShare:
|
|
207
|
+
keyShare: resolvedKeyShares[0],
|
|
210
208
|
derivationPath: new Uint32Array(Object.values(JSON.parse(derivationPath))),
|
|
211
209
|
bitcoinConfig
|
|
212
210
|
});
|
|
@@ -233,13 +231,15 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
233
231
|
accountAddress,
|
|
234
232
|
chainName: this.chainName,
|
|
235
233
|
password,
|
|
236
|
-
externalServerKeyShares:
|
|
234
|
+
externalServerKeyShares: resolvedKeyShares,
|
|
237
235
|
isFormatted: true,
|
|
238
236
|
context: context != null ? context : {
|
|
239
237
|
btcMessage: message
|
|
240
238
|
},
|
|
241
239
|
bitcoinConfig: completeBitcoinConfig,
|
|
242
|
-
onError
|
|
240
|
+
onError,
|
|
241
|
+
walletMetadata,
|
|
242
|
+
passwordPreVerified: !(externalServerKeyShares == null ? void 0 : externalServerKeyShares.length) && !!password
|
|
243
243
|
});
|
|
244
244
|
const bip322Signature = encodeBip322Signature(toSignPsbt, pubKey, signature, addressType);
|
|
245
245
|
return bip322Signature;
|
|
@@ -254,51 +254,43 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
254
254
|
if (onError) {
|
|
255
255
|
onError(error);
|
|
256
256
|
}
|
|
257
|
-
throw new Error(ERROR_SIGN_MESSAGE
|
|
257
|
+
throw new Error(ERROR_SIGN_MESSAGE, {
|
|
258
|
+
cause: error
|
|
259
|
+
});
|
|
258
260
|
}
|
|
259
261
|
}
|
|
260
262
|
/**
|
|
261
263
|
* Signs a Bitcoin transaction (PSBT)
|
|
262
264
|
*
|
|
263
265
|
* The address type is automatically derived from the wallet's derivation path.
|
|
264
|
-
* Only inputs belonging to the
|
|
266
|
+
* Only inputs belonging to the account address are signed. Supports both TAPROOT
|
|
265
267
|
* (BIP-341) and Native SegWit (BIP-143) signing methods.
|
|
266
268
|
*
|
|
267
269
|
* @param transaction - The PSBT to sign as a base64 string
|
|
268
|
-
* @param
|
|
270
|
+
* @param accountAddress - The account address (must match inputs to be signed)
|
|
269
271
|
* @param network - The Bitcoin network (MAINNET or TESTNET)
|
|
270
272
|
* @param password - Optional password for encrypted backup shares
|
|
271
273
|
* @param externalServerKeyShares - Optional external server key shares
|
|
272
274
|
* @param context - Optional. Sign message context for API tracking
|
|
273
275
|
* @param onError - Optional. Error callback function
|
|
274
276
|
* @returns Promise resolving to the signed PSBT as a base64 string
|
|
275
|
-
* @throws Error if required parameters are missing, no inputs belong to
|
|
276
|
-
*/ async signTransaction({ transaction,
|
|
277
|
+
* @throws Error if required parameters are missing, no inputs belong to account address, or signing fails
|
|
278
|
+
*/ async signTransaction({ transaction, walletMetadata, network, password = undefined, externalServerKeyShares, context, onError }) {
|
|
279
|
+
const { accountAddress } = walletMetadata;
|
|
277
280
|
try {
|
|
278
|
-
|
|
279
|
-
accountAddress: senderAddress,
|
|
280
|
-
password
|
|
281
|
-
});
|
|
282
|
-
if (!senderAddress) {
|
|
281
|
+
if (!accountAddress) {
|
|
283
282
|
throw new Error(ERROR_ACCOUNT_ADDRESS_REQUIRED);
|
|
284
283
|
}
|
|
285
|
-
const { derivationPath, addressType } = this.
|
|
286
|
-
//
|
|
287
|
-
await this.
|
|
288
|
-
accountAddress
|
|
284
|
+
const { derivationPath, addressType } = this.getDerivationInfoFromMetadata(walletMetadata);
|
|
285
|
+
// Resolve key shares from param or backup
|
|
286
|
+
const resolvedKeyShares = await this.resolveKeyShares({
|
|
287
|
+
accountAddress,
|
|
289
288
|
password,
|
|
290
289
|
walletOperation: WalletOperation.SIGN_TRANSACTION,
|
|
291
290
|
externalServerKeyShares,
|
|
292
|
-
errorMessage: 'External server key shares are required to sign transaction. No backup shares available for recovery.'
|
|
291
|
+
errorMessage: 'External server key shares are required to sign transaction. No backup shares available for recovery.',
|
|
292
|
+
walletMetadata
|
|
293
293
|
});
|
|
294
|
-
const updatedWalletProperties = this.walletMap[senderAddress];
|
|
295
|
-
if (!updatedWalletProperties) {
|
|
296
|
-
throw new Error('Wallet not found in walletMap after key share recovery');
|
|
297
|
-
}
|
|
298
|
-
const resolvedExternalServerKeyShares = externalServerKeyShares || updatedWalletProperties.externalServerKeyShares;
|
|
299
|
-
if (!resolvedExternalServerKeyShares || resolvedExternalServerKeyShares.length === 0) {
|
|
300
|
-
throw new Error('External server key shares are required to sign transaction. No backup shares available for recovery.');
|
|
301
|
-
}
|
|
302
294
|
const bitcoinConfig = {
|
|
303
295
|
addressType,
|
|
304
296
|
network
|
|
@@ -306,7 +298,7 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
306
298
|
const psbt = bitcoin.Psbt.fromBase64(transaction);
|
|
307
299
|
const derivedPublicKey = await this.derivePublicKey({
|
|
308
300
|
chainName: this.chainName,
|
|
309
|
-
keyShare:
|
|
301
|
+
keyShare: resolvedKeyShares[0],
|
|
310
302
|
derivationPath: new Uint32Array(Object.values(JSON.parse(derivationPath))),
|
|
311
303
|
bitcoinConfig
|
|
312
304
|
});
|
|
@@ -319,9 +311,9 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
319
311
|
const inputsToSign = psbt.data.inputs.map((input, i)=>({
|
|
320
312
|
input,
|
|
321
313
|
index: i
|
|
322
|
-
})).filter(({ input })=>doesInputBelongToAddress(input,
|
|
314
|
+
})).filter(({ input })=>doesInputBelongToAddress(input, accountAddress, network));
|
|
323
315
|
if (inputsToSign.length === 0) {
|
|
324
|
-
throw new Error('No inputs found that belong to the
|
|
316
|
+
throw new Error('No inputs found that belong to the account address');
|
|
325
317
|
}
|
|
326
318
|
if (addressType === BitcoinAddressType.TAPROOT) {
|
|
327
319
|
const tweak = calculateTaprootTweak(pubKey);
|
|
@@ -337,14 +329,16 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
337
329
|
const hash = Buffer.from(tx.hashForWitnessV1(i, prevOutScripts, values, bitcoin.Transaction.SIGHASH_DEFAULT));
|
|
338
330
|
const signature = await this.sign({
|
|
339
331
|
message: new Uint8Array(hash),
|
|
340
|
-
accountAddress
|
|
332
|
+
accountAddress,
|
|
341
333
|
chainName: this.chainName,
|
|
342
334
|
password,
|
|
343
|
-
externalServerKeyShares:
|
|
335
|
+
externalServerKeyShares: resolvedKeyShares,
|
|
344
336
|
isFormatted: true,
|
|
345
337
|
context,
|
|
346
338
|
bitcoinConfig: completeBitcoinConfig,
|
|
347
|
-
onError
|
|
339
|
+
onError,
|
|
340
|
+
walletMetadata,
|
|
341
|
+
passwordPreVerified: !(externalServerKeyShares == null ? void 0 : externalServerKeyShares.length) && !!password
|
|
348
342
|
});
|
|
349
343
|
const sigBuffer = convertSignatureToTaprootBuffer(signature);
|
|
350
344
|
psbt.updateInput(i, {
|
|
@@ -372,14 +366,16 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
372
366
|
const hash = tx.hashForWitnessV0(i, scriptCode, value, bitcoin.Transaction.SIGHASH_ALL);
|
|
373
367
|
const signature = await this.sign({
|
|
374
368
|
message: new Uint8Array(hash),
|
|
375
|
-
accountAddress
|
|
369
|
+
accountAddress,
|
|
376
370
|
chainName: this.chainName,
|
|
377
371
|
password,
|
|
378
|
-
externalServerKeyShares:
|
|
372
|
+
externalServerKeyShares: resolvedKeyShares,
|
|
379
373
|
isFormatted: true,
|
|
380
374
|
context,
|
|
381
375
|
bitcoinConfig: completeBitcoinConfig,
|
|
382
|
-
onError
|
|
376
|
+
onError,
|
|
377
|
+
walletMetadata,
|
|
378
|
+
passwordPreVerified: !(externalServerKeyShares == null ? void 0 : externalServerKeyShares.length) && !!password
|
|
383
379
|
});
|
|
384
380
|
const derSignature = convertSignatureToDER(signature);
|
|
385
381
|
psbt.updateInput(i, {
|
|
@@ -399,7 +395,7 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
399
395
|
message: ERROR_SIGN_TRANSACTION,
|
|
400
396
|
error: error,
|
|
401
397
|
context: {
|
|
402
|
-
|
|
398
|
+
accountAddress
|
|
403
399
|
}
|
|
404
400
|
});
|
|
405
401
|
if (onError) {
|
|
@@ -414,43 +410,21 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
414
410
|
* @param password - The password for encrypted backup shares
|
|
415
411
|
* @param externalServerKeyShares - Optional external server key shares
|
|
416
412
|
* @returns The private key in WIF format
|
|
417
|
-
*/ async exportPrivateKey({
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
password
|
|
421
|
-
});
|
|
422
|
-
// Attempt to recover key shares from backup if not provided
|
|
423
|
-
await this.ensureKeySharesRecovered({
|
|
424
|
-
accountAddress,
|
|
425
|
-
password,
|
|
426
|
-
walletOperation: WalletOperation.EXPORT_PRIVATE_KEY,
|
|
427
|
-
externalServerKeyShares,
|
|
428
|
-
errorMessage: 'External server key shares are required to export private key. No backup shares available for recovery.'
|
|
429
|
-
});
|
|
430
|
-
// Re-read wallet from map after recovery (it may have been updated with recovered shares)
|
|
431
|
-
const updatedWalletProperties = this.walletMap[accountAddress];
|
|
432
|
-
if (!updatedWalletProperties) {
|
|
433
|
-
throw new Error('Wallet not found in walletMap after recovery');
|
|
434
|
-
}
|
|
435
|
-
const derivationPath = updatedWalletProperties.derivationPath;
|
|
436
|
-
if (!derivationPath) {
|
|
437
|
-
throw new Error('Derivation path missing in walletMap');
|
|
438
|
-
}
|
|
439
|
-
// Derive address type from derivation path for bitcoinConfig
|
|
440
|
-
const addressType = getAddressTypeFromDerivationPath(derivationPath);
|
|
413
|
+
*/ async exportPrivateKey({ walletMetadata, password = undefined, externalServerKeyShares }) {
|
|
414
|
+
const { accountAddress } = walletMetadata;
|
|
415
|
+
const { addressType } = this.getDerivationInfoFromMetadata(walletMetadata);
|
|
441
416
|
const network = BitcoinNetwork.MAINNET; // Default to mainnet, could be derived from wallet
|
|
442
417
|
const bitcoinConfig = {
|
|
443
418
|
addressType,
|
|
444
419
|
network
|
|
445
420
|
};
|
|
446
|
-
// Get key shares from wallet map if not provided (recovered from backup)
|
|
447
|
-
const resolvedExternalServerKeyShares = externalServerKeyShares != null ? externalServerKeyShares : updatedWalletProperties.externalServerKeyShares;
|
|
448
421
|
const { derivedPrivateKey } = await this.exportKey({
|
|
449
422
|
accountAddress,
|
|
450
423
|
chainName: this.chainName,
|
|
451
424
|
password,
|
|
452
|
-
externalServerKeyShares
|
|
453
|
-
bitcoinConfig
|
|
425
|
+
externalServerKeyShares,
|
|
426
|
+
bitcoinConfig,
|
|
427
|
+
walletMetadata
|
|
454
428
|
});
|
|
455
429
|
if (!derivedPrivateKey) {
|
|
456
430
|
throw new Error('Derived private key is undefined');
|
|
@@ -486,10 +460,10 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
486
460
|
* @param thresholdSignatureScheme - The threshold signature scheme to use for the wallet
|
|
487
461
|
* @param password - The password to use for the wallet
|
|
488
462
|
* @param onError - The function to call if an error occurs
|
|
489
|
-
* @param
|
|
463
|
+
* @param backUpToDynamic - Whether to back up the external server key shares to the client share service. By default, it is false.
|
|
490
464
|
* @param bitcoinConfig - Bitcoin configuration (addressType, network)
|
|
491
465
|
* @returns The account address, public key, raw public key, external server key shares
|
|
492
|
-
*/ async importPrivateKey({ privateKey, chainName, thresholdSignatureScheme, password
|
|
466
|
+
*/ async importPrivateKey({ privateKey, chainName, thresholdSignatureScheme, password, backUpToDynamic = false, onError, bitcoinConfig }) {
|
|
493
467
|
try {
|
|
494
468
|
const { addressType, network = BitcoinNetwork.MAINNET } = bitcoinConfig;
|
|
495
469
|
if (!addressType) {
|
|
@@ -498,6 +472,7 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
498
472
|
if (addressType !== BitcoinAddressType.NATIVE_SEGWIT && addressType !== BitcoinAddressType.TAPROOT) {
|
|
499
473
|
throw new Error(`Invalid addressType: ${addressType}. Must be one of: ${BitcoinAddressType.NATIVE_SEGWIT}, ${BitcoinAddressType.TAPROOT}`);
|
|
500
474
|
}
|
|
475
|
+
let resolvedWalletId;
|
|
501
476
|
let ceremonyCeremonyCompleteResolver;
|
|
502
477
|
let ceremonyAccountAddress;
|
|
503
478
|
const ceremonyCompletePromise = new Promise((resolve)=>{
|
|
@@ -517,33 +492,22 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
517
492
|
privateKey: formattedPrivateKey,
|
|
518
493
|
thresholdSignatureScheme,
|
|
519
494
|
bitcoinConfig,
|
|
495
|
+
password,
|
|
496
|
+
backUpToDynamic,
|
|
520
497
|
onError,
|
|
521
498
|
onCeremonyComplete: (accountAddress, walletId)=>{
|
|
522
|
-
// Store the ceremony account address to ensure consistency
|
|
523
499
|
ceremonyAccountAddress = accountAddress;
|
|
500
|
+
resolvedWalletId = walletId;
|
|
524
501
|
// Verify address matches
|
|
525
502
|
if (accountAddress !== expectedAddress) {
|
|
526
503
|
throw new Error(`Public address mismatch: derived address ${accountAddress} !== expected address ${expectedAddress}`);
|
|
527
504
|
}
|
|
528
|
-
// update wallet map
|
|
529
|
-
const chainConfig = getMPCChainConfig(this.chainName, bitcoinConfig);
|
|
530
|
-
this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
|
|
531
|
-
accountAddress,
|
|
532
|
-
walletId,
|
|
533
|
-
chainName: this.chainName,
|
|
534
|
-
thresholdSignatureScheme,
|
|
535
|
-
derivationPath: JSON.stringify(Object.fromEntries(chainConfig.derivationPath.map((value, index)=>[
|
|
536
|
-
index,
|
|
537
|
-
value
|
|
538
|
-
]))),
|
|
539
|
-
externalServerKeySharesBackupInfo: getExternalServerKeyShareBackupInfo()
|
|
540
|
-
});
|
|
541
505
|
ceremonyCeremonyCompleteResolver(undefined);
|
|
542
506
|
}
|
|
543
507
|
});
|
|
544
508
|
// Wait for the ceremony to complete before proceeding
|
|
545
509
|
await ceremonyCompletePromise;
|
|
546
|
-
if (!rawPublicKey || !externalServerKeyShares) {
|
|
510
|
+
if (!rawPublicKey || !externalServerKeyShares || !resolvedWalletId) {
|
|
547
511
|
throw new Error('Error creating wallet account');
|
|
548
512
|
}
|
|
549
513
|
// Use the ceremony account address if available, otherwise derive it from raw public key
|
|
@@ -555,19 +519,28 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
555
519
|
if (accountAddress !== expectedAddress) {
|
|
556
520
|
throw new Error(`Public address mismatch: derived address ${accountAddress} !== expected address ${expectedAddress}`);
|
|
557
521
|
}
|
|
558
|
-
const
|
|
522
|
+
const walletMetadata = this.buildWalletMetadata({
|
|
523
|
+
walletId: resolvedWalletId,
|
|
524
|
+
accountAddress,
|
|
525
|
+
thresholdSignatureScheme,
|
|
526
|
+
addressType,
|
|
527
|
+
bitcoinConfig
|
|
528
|
+
});
|
|
529
|
+
const { keySharesWithBackupStatus, backupInfo } = await this.storeEncryptedBackupByWalletWithRetry({
|
|
559
530
|
accountAddress,
|
|
560
531
|
externalServerKeyShares,
|
|
561
532
|
password,
|
|
562
|
-
|
|
533
|
+
backUpToDynamic,
|
|
534
|
+
walletMetadata
|
|
563
535
|
});
|
|
536
|
+
walletMetadata.externalServerKeySharesBackupInfo = backupInfo;
|
|
564
537
|
const publicKeyHex = extractPublicKeyHex(rawPublicKey);
|
|
565
538
|
return {
|
|
566
|
-
|
|
539
|
+
walletMetadata,
|
|
567
540
|
rawPublicKey,
|
|
568
541
|
publicKeyHex,
|
|
569
542
|
externalServerKeyShares,
|
|
570
|
-
externalKeySharesWithBackupStatus
|
|
543
|
+
externalKeySharesWithBackupStatus: keySharesWithBackupStatus
|
|
571
544
|
};
|
|
572
545
|
} catch (error) {
|
|
573
546
|
logError({
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dynamic-labs-wallet/node-btc",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "1.0.0-beta",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@dynamic-labs-wallet/core": "0.0
|
|
8
|
-
"@dynamic-labs-wallet/node": "0.0
|
|
9
|
-
"@dynamic-labs-wallet/btc-utils": "0.0
|
|
7
|
+
"@dynamic-labs-wallet/core": "1.0.0-beta",
|
|
8
|
+
"@dynamic-labs-wallet/node": "1.0.0-beta",
|
|
9
|
+
"@dynamic-labs-wallet/btc-utils": "1.0.0-beta",
|
|
10
10
|
"@dynamic-labs/sdk-api-core": "^0.0.984",
|
|
11
11
|
"bitcoinjs-lib": "^7.0.0",
|
|
12
12
|
"tiny-secp256k1": "^2.2.3"
|
package/src/client/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DynamicWalletClient, type DynamicWalletClientProps, type ServerKeyShare, type ThresholdSignatureScheme, type EcdsaPublicKey, type BIP340KeygenResult, type EcdsaKeygenResult, type WalletProperties } from '@dynamic-labs-wallet/node';
|
|
1
|
+
import { DynamicWalletClient, type DynamicWalletClientProps, type ServerKeyShare, type ThresholdSignatureScheme, type EcdsaPublicKey, type BIP340KeygenResult, type EcdsaKeygenResult, type WalletMetadata, type WalletProperties } from '@dynamic-labs-wallet/node';
|
|
2
2
|
import type { SignMessageContext } from '@dynamic-labs/sdk-api-core';
|
|
3
3
|
import { BitcoinAddressType, BitcoinNetwork, type BitcoinConfig } from '@dynamic-labs-wallet/core';
|
|
4
4
|
export declare class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
@@ -22,11 +22,12 @@ export declare class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
22
22
|
accountAddress: string;
|
|
23
23
|
};
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
26
|
-
* @param
|
|
27
|
-
* @returns The
|
|
25
|
+
* Extracts derivation path and address type from walletMetadata.
|
|
26
|
+
* @param walletMetadata - The wallet metadata
|
|
27
|
+
* @returns The derivation path and derived address type
|
|
28
28
|
*/
|
|
29
|
-
private
|
|
29
|
+
private getDerivationInfoFromMetadata;
|
|
30
|
+
private buildWalletMetadata;
|
|
30
31
|
/**
|
|
31
32
|
* Verifies that the derived address matches the expected address
|
|
32
33
|
* @param rawPublicKey - The raw public key
|
|
@@ -40,21 +41,20 @@ export declare class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
40
41
|
* @param thresholdSignatureScheme - The threshold signature scheme to use for the wallet.
|
|
41
42
|
* @param password - The password to use for the wallet.
|
|
42
43
|
* @param onError - The function to call if an error occurs.
|
|
43
|
-
* @param
|
|
44
|
+
* @param backUpToDynamic - Whether to back up the external server key shares to the client share service. By default, it is false.
|
|
44
45
|
* @param bitcoinConfig - Bitcoin configuration (addressType, network)
|
|
45
46
|
* @returns The account address, public key, raw public key, external server key shares, and wallet id.
|
|
46
47
|
*/
|
|
47
|
-
createWalletAccount({ thresholdSignatureScheme, password, onError,
|
|
48
|
+
createWalletAccount({ thresholdSignatureScheme, password, onError, backUpToDynamic, bitcoinConfig, }: {
|
|
48
49
|
thresholdSignatureScheme: ThresholdSignatureScheme;
|
|
49
50
|
password?: string;
|
|
50
51
|
onError?: (error: Error) => void;
|
|
51
|
-
|
|
52
|
+
backUpToDynamic?: boolean;
|
|
52
53
|
bitcoinConfig?: BitcoinConfig;
|
|
53
54
|
}): Promise<{
|
|
54
|
-
|
|
55
|
+
walletMetadata: WalletMetadata;
|
|
55
56
|
publicKeyHex: string;
|
|
56
57
|
rawPublicKey: EcdsaPublicKey | Uint8Array | string | undefined;
|
|
57
|
-
/** @deprecated Use externalKeySharesWithBackupStatus instead */
|
|
58
58
|
externalServerKeyShares: ServerKeyShare[];
|
|
59
59
|
externalKeySharesWithBackupStatus: Array<{
|
|
60
60
|
share: ServerKeyShare;
|
|
@@ -77,9 +77,9 @@ export declare class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
77
77
|
* @returns Promise resolving to the BIP-322 signature as a base64 string
|
|
78
78
|
* @throws Error if required parameters are missing, derivation path is invalid, or signing fails
|
|
79
79
|
*/
|
|
80
|
-
signMessage({ message,
|
|
80
|
+
signMessage({ message, walletMetadata, network, password, externalServerKeyShares, context, onError, }: {
|
|
81
81
|
message: string;
|
|
82
|
-
|
|
82
|
+
walletMetadata: WalletMetadata;
|
|
83
83
|
network: BitcoinNetwork;
|
|
84
84
|
password?: string;
|
|
85
85
|
externalServerKeyShares?: ServerKeyShare[];
|
|
@@ -90,22 +90,22 @@ export declare class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
90
90
|
* Signs a Bitcoin transaction (PSBT)
|
|
91
91
|
*
|
|
92
92
|
* The address type is automatically derived from the wallet's derivation path.
|
|
93
|
-
* Only inputs belonging to the
|
|
93
|
+
* Only inputs belonging to the account address are signed. Supports both TAPROOT
|
|
94
94
|
* (BIP-341) and Native SegWit (BIP-143) signing methods.
|
|
95
95
|
*
|
|
96
96
|
* @param transaction - The PSBT to sign as a base64 string
|
|
97
|
-
* @param
|
|
97
|
+
* @param accountAddress - The account address (must match inputs to be signed)
|
|
98
98
|
* @param network - The Bitcoin network (MAINNET or TESTNET)
|
|
99
99
|
* @param password - Optional password for encrypted backup shares
|
|
100
100
|
* @param externalServerKeyShares - Optional external server key shares
|
|
101
101
|
* @param context - Optional. Sign message context for API tracking
|
|
102
102
|
* @param onError - Optional. Error callback function
|
|
103
103
|
* @returns Promise resolving to the signed PSBT as a base64 string
|
|
104
|
-
* @throws Error if required parameters are missing, no inputs belong to
|
|
104
|
+
* @throws Error if required parameters are missing, no inputs belong to account address, or signing fails
|
|
105
105
|
*/
|
|
106
|
-
signTransaction({ transaction,
|
|
106
|
+
signTransaction({ transaction, walletMetadata, network, password, externalServerKeyShares, context, onError, }: {
|
|
107
107
|
transaction: string;
|
|
108
|
-
|
|
108
|
+
walletMetadata: WalletMetadata;
|
|
109
109
|
network: BitcoinNetwork;
|
|
110
110
|
password?: string;
|
|
111
111
|
externalServerKeyShares?: ServerKeyShare[];
|
|
@@ -119,8 +119,8 @@ export declare class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
119
119
|
* @param externalServerKeyShares - Optional external server key shares
|
|
120
120
|
* @returns The private key in WIF format
|
|
121
121
|
*/
|
|
122
|
-
exportPrivateKey({
|
|
123
|
-
|
|
122
|
+
exportPrivateKey({ walletMetadata, password, externalServerKeyShares, }: {
|
|
123
|
+
walletMetadata: WalletMetadata;
|
|
124
124
|
password?: string;
|
|
125
125
|
externalServerKeyShares?: ServerKeyShare[];
|
|
126
126
|
}): Promise<string>;
|
|
@@ -143,23 +143,22 @@ export declare class DynamicBtcWalletClient extends DynamicWalletClient {
|
|
|
143
143
|
* @param thresholdSignatureScheme - The threshold signature scheme to use for the wallet
|
|
144
144
|
* @param password - The password to use for the wallet
|
|
145
145
|
* @param onError - The function to call if an error occurs
|
|
146
|
-
* @param
|
|
146
|
+
* @param backUpToDynamic - Whether to back up the external server key shares to the client share service. By default, it is false.
|
|
147
147
|
* @param bitcoinConfig - Bitcoin configuration (addressType, network)
|
|
148
148
|
* @returns The account address, public key, raw public key, external server key shares
|
|
149
149
|
*/
|
|
150
|
-
importPrivateKey({ privateKey, chainName, thresholdSignatureScheme, password,
|
|
150
|
+
importPrivateKey({ privateKey, chainName, thresholdSignatureScheme, password, backUpToDynamic, onError, bitcoinConfig, }: {
|
|
151
151
|
privateKey: string;
|
|
152
152
|
chainName: string;
|
|
153
153
|
thresholdSignatureScheme: ThresholdSignatureScheme;
|
|
154
154
|
password?: string;
|
|
155
|
-
|
|
155
|
+
backUpToDynamic?: boolean;
|
|
156
156
|
onError?: (error: Error) => void;
|
|
157
157
|
bitcoinConfig: BitcoinConfig;
|
|
158
158
|
}): Promise<{
|
|
159
|
-
|
|
159
|
+
walletMetadata: WalletMetadata;
|
|
160
160
|
publicKeyHex: string;
|
|
161
161
|
rawPublicKey: EcdsaPublicKey | Uint8Array | string | undefined;
|
|
162
|
-
/** @deprecated Use externalKeySharesWithBackupStatus instead */
|
|
163
162
|
externalServerKeyShares: ServerKeyShare[];
|
|
164
163
|
externalKeySharesWithBackupStatus: Array<{
|
|
165
164
|
share: ServerKeyShare;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACnB,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EAEnB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"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"}
|