@dynamic-labs-wallet/node-evm 0.0.0-preview.114.4 → 0.0.1-paolo-1

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.js CHANGED
@@ -1,8 +1,21 @@
1
1
  'use strict';
2
2
 
3
+ var accounts = require('viem/accounts');
3
4
  var node = require('@dynamic-labs-wallet/node');
4
5
  var viem = require('viem');
6
+ var utils = require('viem/utils');
7
+ var logger$1 = require('@dynamic-labs/logger');
8
+ var axios = require('axios');
9
+ var core = require('@dynamic-labs-wallet/core');
5
10
  var chains = require('viem/chains');
11
+ var client = require('@dynamic-labs-sdk/client');
12
+ var core$1 = require('@dynamic-labs-sdk/client/core');
13
+ var viem$1 = require('@dynamic-labs-sdk/evm/viem');
14
+ var waas = require('@dynamic-labs-sdk/evm/waas');
15
+ var zerodev = require('@dynamic-labs-sdk/zerodev');
16
+ var core$2 = require('@dynamic-labs-sdk/zerodev/core');
17
+ var ecdsaValidator = require('@zerodev/ecdsa-validator');
18
+ var sdk = require('@zerodev/sdk');
6
19
 
7
20
  function _extends() {
8
21
  _extends = Object.assign || function assign(target) {
@@ -20,11 +33,24 @@ const EVM_SIGN_MESSAGE_PREFIX = `\x19Ethereum Signed Message:\n`;
20
33
  const ERROR_KEYGEN_FAILED = 'Error with keygen';
21
34
  const ERROR_CREATE_WALLET_ACCOUNT = 'Error creating evm wallet account';
22
35
  const ERROR_SIGN_MESSAGE = 'Error signing message';
36
+ const ERROR_SIGN_TYPED_DATA = 'Error signing typed data';
23
37
  const ERROR_ACCOUNT_ADDRESS_REQUIRED = 'Account address is required';
24
38
  const ERROR_VERIFY_MESSAGE_SIGNATURE = 'Error verifying message signature';
25
39
 
26
- const formatEVMMessage = (message)=>{
27
- return `${EVM_SIGN_MESSAGE_PREFIX}${message.length}${message}`;
40
+ const formatEVMMessage = (message_)=>{
41
+ const message = (()=>{
42
+ if (typeof message_ === 'string') return viem.stringToHex(message_);
43
+ if (typeof message_.raw === 'string') return message_.raw;
44
+ return viem.bytesToHex(message_.raw);
45
+ })();
46
+ const prefix = viem.stringToHex(`${EVM_SIGN_MESSAGE_PREFIX}${viem.size(message)}`);
47
+ return viem.concat([
48
+ prefix,
49
+ message
50
+ ]);
51
+ };
52
+ const formatTypedData = (typedData)=>{
53
+ return viem.hashTypedData(typedData).slice(2);
28
54
  };
29
55
  const serializeECDSASignature = (signature)=>{
30
56
  return viem.serializeSignature({
@@ -46,32 +72,373 @@ const deriveAccountAddress = ({ rawPublicKey })=>{
46
72
  };
47
73
  };
48
74
 
75
+ const logger = new logger$1.Logger('DynamicWaasWalletClient');
76
+ const logError = ({ message, error, context })=>{
77
+ if (error instanceof axios.AxiosError) {
78
+ core.handleAxiosError(error, message, context, logger);
79
+ }
80
+ logger.error('[DynamicWaasWalletClient] Error in node-evm client', {
81
+ error: error instanceof Error ? error.message : String(error),
82
+ context
83
+ });
84
+ };
85
+
86
+ /**
87
+ * Creates a delegated EVM wallet client for functional operations
88
+ */ const createDelegatedEvmWalletClient = ({ environmentId, baseApiUrl, baseMPCRelayApiUrl, apiKey, debug = false })=>{
89
+ const baseClient = node.createDelegatedWalletClient({
90
+ environmentId,
91
+ baseApiUrl,
92
+ baseMPCRelayApiUrl,
93
+ apiKey,
94
+ debug
95
+ });
96
+ const evmClient = _extends({}, baseClient, {
97
+ chainName: 'EVM'
98
+ });
99
+ return evmClient;
100
+ };
101
+ /**
102
+ * Signs a message using delegated signing for EVM
103
+ */ const delegatedSignMessage = async (client, { walletId, walletApiKey, keyShare, message, context, onError })=>{
104
+ try {
105
+ if (!keyShare || !walletId || !walletApiKey) {
106
+ throw new Error('Delegated key share, wallet ID, and wallet API key are required to sign a message');
107
+ }
108
+ const formattedMessage = formatEVMMessage(message);
109
+ const resolvedContext = context != null ? context : {
110
+ evmMessage: message
111
+ };
112
+ const signatureEcdsa = await node.delegatedSignMessage(client, {
113
+ walletId,
114
+ walletApiKey,
115
+ keyShare,
116
+ message: formattedMessage,
117
+ chainName: client.chainName,
118
+ context: resolvedContext,
119
+ onError
120
+ });
121
+ const serializedSignature = serializeECDSASignature(signatureEcdsa);
122
+ return serializedSignature;
123
+ } catch (error) {
124
+ logError({
125
+ message: 'Error in delegatedSignMessage',
126
+ error: error,
127
+ context: {
128
+ walletId
129
+ }
130
+ });
131
+ throw error;
132
+ }
133
+ };
134
+ /**
135
+ * Signs a transaction using delegated signing for EVM
136
+ */ const delegatedSignTransaction = async (client, { walletId, walletApiKey, keyShare, transaction })=>{
137
+ try {
138
+ // Serialize the transaction
139
+ const serializedTx = viem.serializeTransaction(transaction);
140
+ const serializedTxBytes = Uint8Array.from(Buffer.from(serializedTx.slice(2), 'hex'));
141
+ if (!(serializedTxBytes instanceof Uint8Array)) {
142
+ throw new Error('Invalid serializedTxBytes');
143
+ }
144
+ // Use the delegated sign message function from node package
145
+ const signatureEcdsa = await node.delegatedSignMessage(client, {
146
+ walletId,
147
+ walletApiKey,
148
+ keyShare,
149
+ message: serializedTxBytes,
150
+ chainName: client.chainName
151
+ });
152
+ if (!('r' in signatureEcdsa && 's' in signatureEcdsa && 'v' in signatureEcdsa)) {
153
+ throw new Error('Invalid signature format returned from MPC signing');
154
+ }
155
+ // Construct the signed transaction
156
+ const r = `0x${Buffer.from(signatureEcdsa.r).toString('hex')}`;
157
+ const s = `0x${Buffer.from(signatureEcdsa.s).toString('hex')}`;
158
+ const v = BigInt(signatureEcdsa.v);
159
+ const signedTx = _extends({}, transaction, {
160
+ r: r,
161
+ s: s,
162
+ v: v
163
+ });
164
+ const serializedSignedTx = viem.serializeTransaction(signedTx);
165
+ return serializedSignedTx;
166
+ } catch (error) {
167
+ logError({
168
+ message: 'Error in delegatedSignTransaction',
169
+ error: error,
170
+ context: {
171
+ walletId
172
+ }
173
+ });
174
+ throw error;
175
+ }
176
+ };
177
+ /**
178
+ * Signs typed data using delegated signing for EVM
179
+ */ const delegatedSignTypedData = async (client, { walletId, walletApiKey, keyShare, typedData })=>{
180
+ try {
181
+ if (!keyShare || !walletId || !walletApiKey) {
182
+ throw new Error('Delegated key share, wallet ID, and wallet API key are required to sign typed data');
183
+ }
184
+ const formattedTypedData = formatTypedData(typedData);
185
+ const signatureEcdsa = await node.delegatedSignMessage(client, {
186
+ walletId,
187
+ walletApiKey,
188
+ keyShare,
189
+ message: formattedTypedData,
190
+ chainName: client.chainName,
191
+ isFormatted: true,
192
+ context: {
193
+ evmTypedData: typedData
194
+ }
195
+ });
196
+ const serializedSignature = serializeECDSASignature(signatureEcdsa);
197
+ return serializedSignature;
198
+ } catch (error) {
199
+ logError({
200
+ message: 'Error in delegatedSignTypedData',
201
+ error: error,
202
+ context: {
203
+ walletId
204
+ }
205
+ });
206
+ throw error;
207
+ }
208
+ };
209
+ /**
210
+ * Signs EIP-7702 authorization using delegated signing for EVM
211
+ */ const delegatedSignAuthorization = async (client, { walletId, walletApiKey, keyShare, authorization })=>{
212
+ try {
213
+ if (!keyShare || !walletId || !walletApiKey) {
214
+ throw new Error('Delegated key share, wallet ID, and wallet API key are required to sign authorization');
215
+ }
216
+ const digest = utils.hashAuthorization(authorization);
217
+ const prehashed = digest.startsWith('0x') ? digest.slice(2) : digest;
218
+ const signatureEcdsa = await node.delegatedSignMessage(client, {
219
+ walletId,
220
+ walletApiKey,
221
+ keyShare,
222
+ message: prehashed,
223
+ chainName: client.chainName,
224
+ isFormatted: true,
225
+ context: {
226
+ eip7702Auth: authorization
227
+ }
228
+ });
229
+ const serializedSignature = serializeECDSASignature(signatureEcdsa);
230
+ const signature = viem.parseSignature(serializedSignature);
231
+ return signature;
232
+ } catch (error) {
233
+ logError({
234
+ message: 'Error in delegatedSignAuthorization',
235
+ error: error,
236
+ context: {
237
+ walletId
238
+ }
239
+ });
240
+ throw error;
241
+ }
242
+ };
243
+ /**
244
+ * Revoke delegation - delegates to the node package
245
+ */ const revokeDelegation = async (client, params)=>{
246
+ return node.revokeDelegation(client, params);
247
+ };
248
+
249
+ const createAccountAdapter = ({ evmClient, accountAddress, password, externalServerKeyShares, delegated })=>{
250
+ return accounts.toAccount({
251
+ address: accountAddress,
252
+ signMessage: async ({ message })=>{
253
+ if (delegated) {
254
+ return delegatedSignMessage(delegated.delegatedClient, {
255
+ walletId: delegated.walletId,
256
+ walletApiKey: delegated.walletApiKey,
257
+ keyShare: delegated.keyShare,
258
+ message: message
259
+ });
260
+ }
261
+ const signature = await evmClient.signMessage({
262
+ message: message,
263
+ accountAddress,
264
+ password,
265
+ externalServerKeyShares
266
+ });
267
+ return signature;
268
+ },
269
+ signTypedData: async (typedData)=>{
270
+ if (delegated) {
271
+ return delegatedSignTypedData(delegated.delegatedClient, {
272
+ walletId: delegated.walletId,
273
+ walletApiKey: delegated.walletApiKey,
274
+ keyShare: delegated.keyShare,
275
+ typedData: typedData
276
+ });
277
+ }
278
+ return evmClient.signTypedData({
279
+ accountAddress,
280
+ typedData: typedData,
281
+ password: password,
282
+ externalServerKeyShares
283
+ });
284
+ },
285
+ signTransaction: async (transaction)=>{
286
+ if (delegated) {
287
+ return delegatedSignTransaction(delegated.delegatedClient, {
288
+ walletId: delegated.walletId,
289
+ walletApiKey: delegated.walletApiKey,
290
+ keyShare: delegated.keyShare,
291
+ transaction
292
+ });
293
+ }
294
+ const signedTx = await evmClient.signTransaction({
295
+ senderAddress: accountAddress,
296
+ transaction,
297
+ password,
298
+ externalServerKeyShares
299
+ });
300
+ return signedTx;
301
+ },
302
+ signAuthorization: async (authorization)=>{
303
+ if (delegated) {
304
+ const signature = await delegatedSignAuthorization(delegated.delegatedClient, {
305
+ walletId: delegated.walletId,
306
+ walletApiKey: delegated.walletApiKey,
307
+ keyShare: delegated.keyShare,
308
+ authorization
309
+ });
310
+ var _authorization_address;
311
+ const signedAuthorization = {
312
+ address: (_authorization_address = authorization.address) != null ? _authorization_address : authorization.contractAddress,
313
+ chainId: authorization.chainId,
314
+ nonce: authorization.nonce,
315
+ r: signature.r,
316
+ s: signature.s,
317
+ v: signature.v,
318
+ yParity: signature.yParity
319
+ };
320
+ return signedAuthorization;
321
+ }
322
+ const signature = await evmClient.signAuthorization({
323
+ authorization,
324
+ accountAddress,
325
+ password,
326
+ externalServerKeyShares
327
+ });
328
+ var _authorization_address1;
329
+ const signedAuthorization = {
330
+ address: (_authorization_address1 = authorization.address) != null ? _authorization_address1 : authorization.contractAddress,
331
+ chainId: authorization.chainId,
332
+ nonce: authorization.nonce,
333
+ r: signature.r,
334
+ s: signature.s,
335
+ v: signature.v,
336
+ yParity: signature.yParity
337
+ };
338
+ return signedAuthorization;
339
+ }
340
+ });
341
+ };
342
+
49
343
  class DynamicEvmWalletClient extends node.DynamicWalletClient {
344
+ get jwtAuthToken() {
345
+ return this.baseJWTAuthToken;
346
+ }
347
+ get apiUrl() {
348
+ var _this_baseApiUrl;
349
+ return (_this_baseApiUrl = this.baseApiUrl) != null ? _this_baseApiUrl : 'https://app.dynamicauth.com';
350
+ }
50
351
  createViemPublicClient({ chain, rpcUrl }) {
51
352
  return viem.createPublicClient({
52
353
  chain,
53
354
  transport: viem.http(rpcUrl)
54
355
  });
55
356
  }
56
- async createWalletAccount({ thresholdSignatureScheme, password = undefined, onError }) {
357
+ async getWalletClient({ accountAddress, password, externalServerKeyShares, chain, chainId, rpcUrl }) {
358
+ const account = createAccountAdapter({
359
+ evmClient: this,
360
+ accountAddress: accountAddress,
361
+ password,
362
+ externalServerKeyShares
363
+ });
364
+ let viemChain;
365
+ if (chain) {
366
+ viemChain = chain;
367
+ } else if (chainId) {
368
+ if (!rpcUrl) {
369
+ throw new Error('rpcUrl is required when providing chainId. Please provide a valid RPC URL for the chain.');
370
+ }
371
+ viemChain = viem.defineChain({
372
+ id: chainId,
373
+ name: `Chain ${chainId}`,
374
+ nativeCurrency: {
375
+ name: 'Ether',
376
+ symbol: 'ETH',
377
+ decimals: 18
378
+ },
379
+ rpcUrls: {
380
+ default: {
381
+ http: [
382
+ rpcUrl
383
+ ]
384
+ }
385
+ }
386
+ });
387
+ } else {
388
+ viemChain = chains.mainnet;
389
+ }
390
+ return viem.createWalletClient({
391
+ account,
392
+ chain: viemChain,
393
+ transport: viem.http(rpcUrl)
394
+ });
395
+ }
396
+ /**
397
+ * Creates a new wallet account and stores the key shares in the wallet map.
398
+ * @param thresholdSignatureScheme - The threshold signature scheme to use for the wallet.
399
+ * @param password - The password to use for the wallet.
400
+ * @param onError - The function to call if an error occurs.
401
+ * @param backUpToClientShareService - Whether to back up the external server key shares to the client share service. By default, it is false.
402
+ * @returns The account address, public key, raw public key, external server key shares, and wallet id.
403
+ */ async createWalletAccount({ thresholdSignatureScheme, password = undefined, onError, backUpToClientShareService = false }) {
57
404
  try {
405
+ let ceremonyCeremonyCompleteResolver;
406
+ const ceremonyCompletePromise = new Promise((resolve)=>{
407
+ ceremonyCeremonyCompleteResolver = resolve;
408
+ });
58
409
  // Generate key shares for given threshold signature scheme (TSS)
59
410
  const { rawPublicKey, externalServerKeyShares } = await this.keyGen({
60
411
  chainName: this.chainName,
61
412
  thresholdSignatureScheme,
413
+ skipLock: true,
62
414
  onError,
63
415
  onCeremonyComplete: (accountAddress, walletId)=>{
64
416
  // update wallet map
65
417
  const checksumAddress = viem.getAddress(accountAddress);
418
+ const chainConfig = node.getMPCChainConfig(this.chainName);
66
419
  this.walletMap[checksumAddress] = _extends({}, this.walletMap[checksumAddress] || {}, {
67
420
  accountAddress: checksumAddress,
68
421
  walletId,
69
422
  chainName: this.chainName,
70
423
  thresholdSignatureScheme,
424
+ derivationPath: JSON.stringify(Object.fromEntries(chainConfig.derivationPath.map((value, index)=>[
425
+ index,
426
+ value
427
+ ]))),
71
428
  externalServerKeySharesBackupInfo: node.getExternalServerKeyShareBackupInfo()
72
429
  });
430
+ this.logger.debug('walletMap updated for wallet', {
431
+ context: {
432
+ accountAddress,
433
+ walletId,
434
+ walletMap: this.walletMap
435
+ }
436
+ });
437
+ ceremonyCeremonyCompleteResolver(undefined);
73
438
  }
74
439
  });
440
+ // Wait for the ceremony to complete before proceeding
441
+ await ceremonyCompletePromise;
75
442
  if (!rawPublicKey || !externalServerKeyShares) {
76
443
  throw new Error(ERROR_KEYGEN_FAILED);
77
444
  }
@@ -79,53 +446,152 @@ class DynamicEvmWalletClient extends node.DynamicWalletClient {
79
446
  const { accountAddress, publicKeyHex } = deriveAccountAddress({
80
447
  rawPublicKey: rawPublicKey
81
448
  });
82
- void this.storeEncryptedBackupByWalletWithRetry({
449
+ await this.storeEncryptedBackupByWalletWithRetry({
83
450
  accountAddress,
84
451
  externalServerKeyShares,
85
- password
452
+ password,
453
+ backUpToClientShareService
86
454
  });
87
455
  return {
456
+ walletId: this.walletMap[accountAddress].walletId,
88
457
  accountAddress,
89
458
  rawPublicKey,
90
459
  publicKeyHex,
91
460
  externalServerKeyShares
92
461
  };
93
462
  } catch (error) {
94
- // this.logger.error(ERROR_CREATE_WALLET_ACCOUNT, error);
463
+ logError({
464
+ message: ERROR_CREATE_WALLET_ACCOUNT,
465
+ error: error,
466
+ context: {}
467
+ });
95
468
  throw new Error(ERROR_CREATE_WALLET_ACCOUNT);
96
469
  }
97
470
  }
98
- async signMessage({ message, accountAddress, password = undefined }) {
99
- await this.verifyPassword({
100
- accountAddress,
101
- password,
102
- walletOperation: node.WalletOperation.SIGN_MESSAGE
103
- });
104
- await this.getWallet({
105
- accountAddress,
106
- walletOperation: node.WalletOperation.SIGN_MESSAGE
107
- });
471
+ async signMessage({ message, accountAddress, password = undefined, externalServerKeyShares, context, onError }) {
108
472
  try {
109
473
  if (!accountAddress) {
110
474
  throw new Error(ERROR_ACCOUNT_ADDRESS_REQUIRED);
111
475
  }
112
476
  // Format the message for EVM signing
113
477
  const formattedMessage = formatEVMMessage(message);
114
- // Sign the message using MPC
478
+ const resolvedContext = context != null ? context : {
479
+ evmMessage: message
480
+ };
481
+ // Attempt to recover key shares from backup if not provided
482
+ await this.ensureKeySharesRecovered({
483
+ accountAddress,
484
+ password,
485
+ walletOperation: node.WalletOperation.SIGN_MESSAGE,
486
+ externalServerKeyShares,
487
+ errorMessage: 'External server key shares are required to sign a message. No backup shares available for recovery.'
488
+ });
115
489
  const signatureEcdsa = await this.sign({
116
490
  message: formattedMessage,
117
491
  accountAddress: accountAddress,
118
492
  chainName: this.chainName,
119
- password
493
+ password,
494
+ externalServerKeyShares,
495
+ context: resolvedContext,
496
+ onError
120
497
  });
121
498
  // Serialize the signature
122
499
  const serializedSignature = serializeECDSASignature(signatureEcdsa);
123
500
  return serializedSignature;
124
501
  } catch (error) {
125
- this.logger.error(ERROR_SIGN_MESSAGE, error);
502
+ logError({
503
+ message: ERROR_SIGN_MESSAGE,
504
+ error: error,
505
+ context: {
506
+ accountAddress
507
+ }
508
+ });
509
+ throw new Error(ERROR_SIGN_MESSAGE);
510
+ }
511
+ }
512
+ isSignAuthorizationSupported() {
513
+ return true;
514
+ }
515
+ async signAuthorization({ authorization, accountAddress, password = undefined, externalServerKeyShares, onError }) {
516
+ try {
517
+ if (!accountAddress) {
518
+ throw new Error(ERROR_ACCOUNT_ADDRESS_REQUIRED);
519
+ }
520
+ const digest = utils.hashAuthorization(authorization);
521
+ const prehashed = digest.startsWith('0x') ? digest.slice(2) : digest;
522
+ // Attempt to recover key shares from backup if not provided
523
+ await this.ensureKeySharesRecovered({
524
+ accountAddress,
525
+ password,
526
+ walletOperation: node.WalletOperation.SIGN_MESSAGE,
527
+ externalServerKeyShares,
528
+ errorMessage: 'External server key shares are required to sign authorization. No backup shares available for recovery.'
529
+ });
530
+ const signatureEcdsa = await this.sign({
531
+ message: prehashed,
532
+ accountAddress: accountAddress,
533
+ chainName: this.chainName,
534
+ password,
535
+ externalServerKeyShares,
536
+ isFormatted: true,
537
+ context: {
538
+ eip7702Auth: authorization
539
+ },
540
+ onError
541
+ });
542
+ const serializedSignature = serializeECDSASignature(signatureEcdsa);
543
+ const signature = viem.parseSignature(serializedSignature);
544
+ return signature;
545
+ } catch (error) {
546
+ logError({
547
+ message: ERROR_SIGN_MESSAGE,
548
+ error: error,
549
+ context: {
550
+ accountAddress
551
+ }
552
+ });
126
553
  throw new Error(ERROR_SIGN_MESSAGE);
127
554
  }
128
555
  }
556
+ async signTypedData({ accountAddress, typedData, password = undefined, externalServerKeyShares, onError }) {
557
+ try {
558
+ if (!accountAddress) {
559
+ throw new Error(ERROR_ACCOUNT_ADDRESS_REQUIRED);
560
+ }
561
+ const formattedTypedData = formatTypedData(typedData);
562
+ // Attempt to recover key shares from backup if not provided
563
+ await this.ensureKeySharesRecovered({
564
+ accountAddress,
565
+ password,
566
+ walletOperation: node.WalletOperation.SIGN_MESSAGE,
567
+ externalServerKeyShares,
568
+ errorMessage: 'External server key shares are required to sign typed data. No backup shares available for recovery.'
569
+ });
570
+ const signatureEcdsa = await this.sign({
571
+ message: formattedTypedData,
572
+ accountAddress: accountAddress,
573
+ chainName: this.chainName,
574
+ password,
575
+ externalServerKeyShares,
576
+ isFormatted: true,
577
+ context: {
578
+ evmTypedData: typedData
579
+ },
580
+ onError
581
+ });
582
+ const serializedSignature = serializeECDSASignature(signatureEcdsa);
583
+ return serializedSignature;
584
+ } catch (error) {
585
+ logError({
586
+ message: ERROR_SIGN_TYPED_DATA,
587
+ error: error,
588
+ context: {
589
+ accountAddress
590
+ }
591
+ });
592
+ throw new Error(ERROR_SIGN_TYPED_DATA);
593
+ }
594
+ }
129
595
  async verifyMessageSignature({ accountAddress, message, signature }) {
130
596
  try {
131
597
  // Verify the signature using the public client
@@ -139,16 +605,30 @@ class DynamicEvmWalletClient extends node.DynamicWalletClient {
139
605
  });
140
606
  return verified;
141
607
  } catch (error) {
142
- this.logger.error(ERROR_VERIFY_MESSAGE_SIGNATURE, error);
608
+ logError({
609
+ message: ERROR_VERIFY_MESSAGE_SIGNATURE,
610
+ error: error,
611
+ context: {
612
+ accountAddress
613
+ }
614
+ });
143
615
  throw new Error(ERROR_VERIFY_MESSAGE_SIGNATURE);
144
616
  }
145
617
  }
146
- async signTransaction({ senderAddress, transaction, password = undefined }) {
618
+ async signTransaction({ senderAddress, transaction, password = undefined, externalServerKeyShares }) {
147
619
  await this.verifyPassword({
148
620
  accountAddress: senderAddress,
149
621
  password,
150
622
  walletOperation: node.WalletOperation.SIGN_TRANSACTION
151
623
  });
624
+ // Attempt to recover key shares from backup if not provided
625
+ await this.ensureKeySharesRecovered({
626
+ accountAddress: senderAddress,
627
+ password,
628
+ walletOperation: node.WalletOperation.SIGN_TRANSACTION,
629
+ externalServerKeyShares,
630
+ errorMessage: 'External server key shares are required to sign transaction. No backup shares available for recovery.'
631
+ });
152
632
  const serializedTx = viem.serializeTransaction(transaction);
153
633
  const serializedTxBytes = Uint8Array.from(Buffer.from(serializedTx.slice(2), 'hex'));
154
634
  if (!(serializedTxBytes instanceof Uint8Array)) {
@@ -159,7 +639,8 @@ class DynamicEvmWalletClient extends node.DynamicWalletClient {
159
639
  message: serializedTxBytes,
160
640
  accountAddress: senderAddress,
161
641
  chainName: this.chainName,
162
- password
642
+ password,
643
+ externalServerKeyShares
163
644
  });
164
645
  if (!('r' in signatureEcdsa && 's' in signatureEcdsa && 'v' in signatureEcdsa)) {
165
646
  throw new Error('Invalid signature format returned from MPC signing');
@@ -176,20 +657,35 @@ class DynamicEvmWalletClient extends node.DynamicWalletClient {
176
657
  const serializedSignedTx = viem.serializeTransaction(signedTx);
177
658
  return serializedSignedTx;
178
659
  } catch (error) {
179
- this.logger.error('Error signing transaction:', error);
660
+ logError({
661
+ message: 'Error signing transaction:',
662
+ error: error,
663
+ context: {
664
+ senderAddress
665
+ }
666
+ });
180
667
  throw error;
181
668
  }
182
669
  }
183
- async exportPrivateKey({ accountAddress, password = undefined }) {
670
+ async exportPrivateKey({ accountAddress, password = undefined, externalServerKeyShares }) {
184
671
  await this.verifyPassword({
185
672
  accountAddress,
186
673
  password,
187
674
  walletOperation: node.WalletOperation.EXPORT_PRIVATE_KEY
188
675
  });
676
+ // Attempt to recover key shares from backup if not provided
677
+ await this.ensureKeySharesRecovered({
678
+ accountAddress,
679
+ password,
680
+ walletOperation: node.WalletOperation.EXPORT_PRIVATE_KEY,
681
+ externalServerKeyShares,
682
+ errorMessage: 'External server key shares are required to export private key. No backup shares available for recovery.'
683
+ });
189
684
  const { derivedPrivateKey } = await this.exportKey({
190
685
  accountAddress,
191
686
  chainName: this.chainName,
192
- password
687
+ password,
688
+ externalServerKeyShares
193
689
  });
194
690
  return {
195
691
  derivedPrivateKey
@@ -205,35 +701,64 @@ class DynamicEvmWalletClient extends node.DynamicWalletClient {
205
701
  derivedPrivateKey
206
702
  };
207
703
  }
208
- async importPrivateKey({ privateKey, chainName, thresholdSignatureScheme, password = undefined, onError }) {
704
+ /**
705
+ * Imports a private key and stores the key shares in the wallet map.
706
+ * @param privateKey - The private key to import.
707
+ * @param chainName - The chain name to use for the wallet.
708
+ * @param thresholdSignatureScheme - The threshold signature scheme to use for the wallet.
709
+ * @param password - The password to use for the wallet.
710
+ * @param onError - The function to call if an error occurs.
711
+ * @param backUpToClientShareService - Whether to back up the external server key shares to the client share service. By default, it is false.
712
+ * @returns The account address, public key, raw public key, external server key shares.
713
+ */ async importPrivateKey({ privateKey, chainName, thresholdSignatureScheme, password = undefined, backUpToClientShareService = false, onError }) {
714
+ let ceremonyCeremonyCompleteResolver;
715
+ const ceremonyCompletePromise = new Promise((resolve)=>{
716
+ ceremonyCeremonyCompleteResolver = resolve;
717
+ });
209
718
  // TODO: validate private key for EVM
210
719
  const { rawPublicKey, externalServerKeyShares } = await this.importRawPrivateKey({
211
720
  chainName,
212
721
  privateKey,
213
722
  thresholdSignatureScheme,
214
- onError,
215
723
  onCeremonyComplete: (accountAddress, walletId)=>{
216
724
  // update wallet map
217
725
  const checksumAddress = viem.getAddress(accountAddress);
726
+ const chainConfig = node.getMPCChainConfig(this.chainName);
218
727
  this.walletMap[checksumAddress] = _extends({}, this.walletMap[checksumAddress] || {}, {
219
728
  accountAddress: checksumAddress,
220
729
  walletId,
221
730
  chainName: this.chainName,
222
731
  thresholdSignatureScheme,
732
+ derivationPath: JSON.stringify(Object.fromEntries(chainConfig.derivationPath.map((value, index)=>[
733
+ index,
734
+ value
735
+ ]))),
223
736
  externalServerKeySharesBackupInfo: node.getExternalServerKeyShareBackupInfo()
224
737
  });
738
+ ceremonyCeremonyCompleteResolver(undefined);
739
+ },
740
+ onError: (e)=>{
741
+ logError({
742
+ message: 'importPrivateKey: onError',
743
+ error: e,
744
+ context: {}
745
+ });
746
+ onError == null ? void 0 : onError(e);
225
747
  }
226
748
  });
749
+ // Wait for the ceremony to complete before proceeding
750
+ await ceremonyCompletePromise;
227
751
  if (!rawPublicKey || !externalServerKeyShares) {
228
752
  throw new Error('Error creating wallet account');
229
753
  }
230
754
  const { accountAddress, publicKeyHex } = deriveAccountAddress({
231
755
  rawPublicKey: rawPublicKey
232
756
  });
233
- void this.storeEncryptedBackupByWalletWithRetry({
757
+ await this.storeEncryptedBackupByWalletWithRetry({
234
758
  accountAddress,
235
759
  externalServerKeyShares,
236
- password
760
+ password,
761
+ backUpToClientShareService
237
762
  });
238
763
  return {
239
764
  accountAddress,
@@ -247,14 +772,217 @@ class DynamicEvmWalletClient extends node.DynamicWalletClient {
247
772
  const evmWallets = wallets.filter((wallet)=>wallet.chainName === 'eip155');
248
773
  return evmWallets;
249
774
  }
250
- constructor({ environmentId, baseApiUrl, baseMPCRelayApiUrl, debug }){
775
+ constructor({ environmentId, baseApiUrl, baseMPCRelayApiUrl, debug, enableMPCAccelerator }){
251
776
  super({
252
777
  environmentId,
253
778
  baseApiUrl,
254
779
  baseMPCRelayApiUrl,
255
- debug
780
+ debug,
781
+ enableMPCAccelerator
256
782
  }), this.chainName = 'EVM';
257
783
  }
258
784
  }
259
785
 
786
+ const getJwtExpiration = (jwt)=>{
787
+ if (!jwt) {
788
+ return 0;
789
+ }
790
+ return JSON.parse(Buffer.from(jwt.split('.')[1], 'base64').toString()).exp * 1000;
791
+ };
792
+ class MemoryStorageAdapter {
793
+ async getItem(key) {
794
+ if (key.includes('session')) {
795
+ // This is a workaround so we can pass the JWT that the authenticate the node SDK to
796
+ // the vanilla client, once set we can refresh the user and populate the user data, wallets and etc.
797
+ return JSON.stringify({
798
+ value: {
799
+ token: this.jwt,
800
+ sessionExpiration: getJwtExpiration(this.jwt),
801
+ legacyToken: null,
802
+ mfaToken: null,
803
+ captchaToken: null,
804
+ sessionKeys: null
805
+ }
806
+ });
807
+ }
808
+ var _this_store_get;
809
+ return (_this_store_get = this.store.get(key)) != null ? _this_store_get : null;
810
+ }
811
+ async setItem(key, value) {
812
+ this.store.set(key, value);
813
+ }
814
+ async removeItem(key) {
815
+ this.store.delete(key);
816
+ }
817
+ clear() {
818
+ this.store.clear();
819
+ }
820
+ get size() {
821
+ return this.store.size;
822
+ }
823
+ constructor(jwt){
824
+ this.store = new Map();
825
+ this.jwt = jwt;
826
+ }
827
+ }
828
+ const createMemoryStorageAdapter = (jwt)=>{
829
+ return new MemoryStorageAdapter(jwt);
830
+ };
831
+
832
+ class DynamicEvmZeroDevClient {
833
+ async initialize() {
834
+ await client.initializeClient(this.dynamicClient);
835
+ if ('jwtAuthToken' in this.evmClient) {
836
+ // Fetch user data to populate wallet accounts
837
+ await client.refreshUser(this.dynamicClient);
838
+ }
839
+ }
840
+ /**
841
+ * Get network data by networkId from project configuration
842
+ */ getNetworkData(networkId) {
843
+ const networksData = client.getNetworksData(this.dynamicClient);
844
+ const networkData = networksData.find((n)=>n.networkId === networkId);
845
+ core$1.assertDefined(networkData, `No network found with networkId: ${networkId}. Available networks: ${networksData.map((n)=>n.networkId).join(', ')}`);
846
+ return networkData;
847
+ }
848
+ async createKernelClientForAddress(options) {
849
+ const viemSigner = createAccountAdapter({
850
+ evmClient: this.evmClient,
851
+ accountAddress: options.address,
852
+ password: options.password,
853
+ externalServerKeyShares: options.externalServerKeyShares,
854
+ delegated: options.delegated
855
+ });
856
+ const activeNetworkData = this.getNetworkData(options.networkId);
857
+ const viemChain = viem$1.mapNetworkDataToViemChain(activeNetworkData);
858
+ var _options_bundlerRpc;
859
+ const bundlerRpc = (_options_bundlerRpc = options.bundlerRpc) != null ? _options_bundlerRpc : core$2.getZerodevRpc({
860
+ bundlerProvider: options.bundlerProvider,
861
+ networkId: activeNetworkData.networkId,
862
+ rpcType: 'bundler'
863
+ }, this.dynamicClient);
864
+ const bundlerTransport = viem.http(bundlerRpc);
865
+ const publicClient = viem.createPublicClient({
866
+ chain: viemChain,
867
+ transport: bundlerTransport
868
+ });
869
+ const account = await this.createKernelAccountWithCustomSigner({
870
+ publicClient,
871
+ signer: viemSigner
872
+ });
873
+ var _options_paymasterRpc;
874
+ const paymasterRpc = (_options_paymasterRpc = options.paymasterRpc) != null ? _options_paymasterRpc : core$2.getZerodevRpc({
875
+ bundlerProvider: options.bundlerProvider,
876
+ networkId: activeNetworkData.networkId,
877
+ rpcType: 'paymaster'
878
+ }, this.dynamicClient);
879
+ var _options_withSponsorship;
880
+ const paymasterConfig = ((_options_withSponsorship = options.withSponsorship) != null ? _options_withSponsorship : true) ? core$2.getPaymasterConfig({
881
+ chain: viemChain,
882
+ gasTokenAddress: options.gasTokenAddress,
883
+ paymasterRpc
884
+ }) : {};
885
+ const kernelClient = sdk.createKernelAccountClient(_extends({
886
+ account,
887
+ bundlerTransport,
888
+ chain: viemChain,
889
+ client: publicClient,
890
+ userOperation: {
891
+ estimateFeesPerGas: async ({ bundlerClient })=>sdk.getUserOperationGasPrice(bundlerClient)
892
+ }
893
+ }, paymasterConfig));
894
+ return kernelClient;
895
+ }
896
+ async createKernelAccountWithCustomSigner({ publicClient, signer }) {
897
+ const zerodevProvider = core$2.getZerodevProviderFromSettings(this.dynamicClient);
898
+ core$1.assertDefined(zerodevProvider, 'Zerodev provider is not enabled in project settings');
899
+ const useEIP7702 = zerodevProvider.enableEIP7702;
900
+ const entryPointVersion = zerodevProvider.entryPointVersion;
901
+ const entryPoint = core$2.getEntryPoint(entryPointVersion);
902
+ if (useEIP7702) {
903
+ return sdk.createKernelAccount(publicClient, {
904
+ eip7702Account: signer,
905
+ entryPoint,
906
+ kernelVersion: sdk.constants.KERNEL_V3_3
907
+ });
908
+ }
909
+ const kernelVersionValue = zerodevProvider.kernelVersion;
910
+ const kernelVersion = core$2.getKernelVersion({
911
+ entryPoint,
912
+ kernelVersion: kernelVersionValue
913
+ });
914
+ var _zerodevProvider_enableKernelV3Migration;
915
+ const kernelV3MigrationEnabled = (_zerodevProvider_enableKernelV3Migration = zerodevProvider.enableKernelV3Migration) != null ? _zerodevProvider_enableKernelV3Migration : false;
916
+ if (kernelV3MigrationEnabled) {
917
+ const apiKernelVersion = core$2.getKernelVersion({
918
+ entryPoint,
919
+ kernelVersion: zerodevProvider.kernelVersion
920
+ });
921
+ return ecdsaValidator.createEcdsaKernelMigrationAccount(publicClient, {
922
+ entryPoint,
923
+ migrationVersion: {
924
+ from: kernelVersion,
925
+ to: apiKernelVersion
926
+ },
927
+ signer
928
+ });
929
+ }
930
+ const validator = await core$2.getEcdsaValidator({
931
+ ecdsaProviderType: zerodevProvider.ecdsaProviderType,
932
+ entryPoint,
933
+ kernelVersion,
934
+ publicClient,
935
+ signer
936
+ });
937
+ return sdk.createKernelAccount(publicClient, {
938
+ entryPoint,
939
+ kernelVersion,
940
+ plugins: {
941
+ sudo: validator
942
+ }
943
+ });
944
+ }
945
+ constructor(evmClient){
946
+ this.evmClient = evmClient;
947
+ var _evmClient_jwtAuthToken;
948
+ const authToken = 'jwtAuthToken' in evmClient ? (_evmClient_jwtAuthToken = evmClient.jwtAuthToken) != null ? _evmClient_jwtAuthToken : null : null;
949
+ const storageAdapter = createMemoryStorageAdapter(authToken);
950
+ this.dynamicClient = client.createDynamicClient({
951
+ environmentId: evmClient.environmentId,
952
+ autoInitialize: false,
953
+ coreConfig: {
954
+ storageAdapter,
955
+ fetch: fetch,
956
+ apiBaseUrl: `${evmClient.apiUrl}/api/v0`
957
+ }
958
+ });
959
+ zerodev.addZerodevExtension(this.dynamicClient);
960
+ waas.addWaasEvmExtension(this.dynamicClient);
961
+ }
962
+ }
963
+ const createZerodevClient = async (evmClient)=>{
964
+ const client = new DynamicEvmZeroDevClient(evmClient);
965
+ await client.initialize();
966
+ return client;
967
+ };
968
+
260
969
  exports.DynamicEvmWalletClient = DynamicEvmWalletClient;
970
+ exports.ERROR_ACCOUNT_ADDRESS_REQUIRED = ERROR_ACCOUNT_ADDRESS_REQUIRED;
971
+ exports.ERROR_CREATE_WALLET_ACCOUNT = ERROR_CREATE_WALLET_ACCOUNT;
972
+ exports.ERROR_KEYGEN_FAILED = ERROR_KEYGEN_FAILED;
973
+ exports.ERROR_SIGN_MESSAGE = ERROR_SIGN_MESSAGE;
974
+ exports.ERROR_SIGN_TYPED_DATA = ERROR_SIGN_TYPED_DATA;
975
+ exports.ERROR_VERIFY_MESSAGE_SIGNATURE = ERROR_VERIFY_MESSAGE_SIGNATURE;
976
+ exports.EVM_SIGN_MESSAGE_PREFIX = EVM_SIGN_MESSAGE_PREFIX;
977
+ exports.createAccountAdapter = createAccountAdapter;
978
+ exports.createDelegatedEvmWalletClient = createDelegatedEvmWalletClient;
979
+ exports.createZerodevClient = createZerodevClient;
980
+ exports.delegatedSignAuthorization = delegatedSignAuthorization;
981
+ exports.delegatedSignMessage = delegatedSignMessage;
982
+ exports.delegatedSignTransaction = delegatedSignTransaction;
983
+ exports.delegatedSignTypedData = delegatedSignTypedData;
984
+ exports.deriveAccountAddress = deriveAccountAddress;
985
+ exports.formatEVMMessage = formatEVMMessage;
986
+ exports.formatTypedData = formatTypedData;
987
+ exports.revokeDelegation = revokeDelegation;
988
+ exports.serializeECDSASignature = serializeECDSASignature;