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