@dynamic-labs/ethereum-aa 4.10.2 → 4.10.4-preview.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.
@@ -0,0 +1,502 @@
1
+ 'use client'
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, '__esModule', { value: true });
5
+
6
+ var _tslib = require('../_virtual/_tslib.cjs');
7
+ var viem = require('viem');
8
+ var zksync = require('viem/zksync');
9
+ var passkey = require('zksync-sso/client/passkey');
10
+ var utils$1 = require('zksync-sso/utils');
11
+ var ethereumCore = require('@dynamic-labs/ethereum-core');
12
+ var utils = require('@dynamic-labs/utils');
13
+ var AccountAbstractionConnector = require('./AccountAbstractionConnector.cjs');
14
+ var abi = require('./utils/abi.cjs');
15
+ var client = require('./ZKsync/client.cjs');
16
+ var walletActions = require('./ZKsync/walletActions.cjs');
17
+
18
+ class ZKsyncConnector extends AccountAbstractionConnector.AccountAbstractionConnector {
19
+ constructor(props) {
20
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
21
+ super(props);
22
+ // Core wallet properties
23
+ this.ChainWallet = ethereumCore.EthereumWallet;
24
+ this.name = 'ZKsync';
25
+ this.overrideKey = 'zksync';
26
+ // Chain configuration
27
+ this.connectedChain = 'EVM';
28
+ this.evmNetworks = [];
29
+ this.supportedChains = ['ETH', 'EVM'];
30
+ this._isSmartAccountDeployed = false;
31
+ this.enablePasskeys = true;
32
+ this.enableEIP7702Mode = false;
33
+ this.walletFallback = {
34
+ brand: {
35
+ alt: 'Smart Wallet',
36
+ spriteId: 'smartwallet',
37
+ },
38
+ name: 'ZKsync',
39
+ };
40
+ this._walletUiUtils = props.walletUiUtils;
41
+ this.providersConfig = (_a = props.providersConfig) !== null && _a !== void 0 ? _a : {};
42
+ this.chainId = (_b = props.apiProviders.zksync) === null || _b === void 0 ? void 0 : _b.defaultChainId;
43
+ this.evmNetworks = utils.parseEvmNetworks(props.evmNetworks).filter((network) => network.chainId === this.chainId);
44
+ this.factoryAddress = ((_d = (_c = props.apiProviders.zksync) === null || _c === void 0 ? void 0 : _c.factoryAddress) !== null && _d !== void 0 ? _d : '0xa980E4B20354d4944de93F2a51f0a14c6E8e481d'); // Fallback if not provided
45
+ this.paymasterAddress = ((_f = (_e = props.apiProviders.zksync) === null || _e === void 0 ? void 0 : _e.paymasterAddress) !== null && _f !== void 0 ? _f : '0xD681ef8eD603F8F3b1CF9c1ef93548e698F60F0a'); // Fallback if not provided
46
+ this.passkeyAddress = ((_h = (_g = props.apiProviders.zksync) === null || _g === void 0 ? void 0 : _g.passkeyAddress) !== null && _h !== void 0 ? _h : '0x271546A4a3d8050610367e68040d41ee56E4BB31'); // Fallback if not provided
47
+ this.sessionKeyAddress = ((_k = (_j = props.apiProviders.zksync) === null || _j === void 0 ? void 0 : _j.sessionAddress) !== null && _k !== void 0 ? _k : '0xA8CC0A6bD462B44A8830bBbfB54Ce19F32815Fb7'); // Fallback if not provided
48
+ this.enablePasskeys =
49
+ (_m = (_l = props.settings.sdk.accountAbstraction) === null || _l === void 0 ? void 0 : _l.enablePasskeys) !== null && _m !== void 0 ? _m : false;
50
+ }
51
+ getEnabledNetworks() {
52
+ return this.evmNetworks;
53
+ }
54
+ getConnectedAccounts() {
55
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
56
+ var _a;
57
+ yield ((_a = this.initializedDeferredPromise) === null || _a === void 0 ? void 0 : _a.promise);
58
+ if (!this.smartAccountAddress) {
59
+ throw new Error('Smart account address is not initialized');
60
+ }
61
+ return [this.smartAccountAddress];
62
+ });
63
+ }
64
+ getNetwork() {
65
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
66
+ var _a;
67
+ yield ((_a = this.initializedDeferredPromise) === null || _a === void 0 ? void 0 : _a.promise);
68
+ if (!this.smartAccountAddress) {
69
+ throw new Error('Smart account address is not initialized');
70
+ }
71
+ return this.chainId;
72
+ });
73
+ }
74
+ getPublicClient() {
75
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
76
+ return viem.createPublicClient({
77
+ chain: ethereumCore.getOrMapViemChain(this.evmNetworks[0]),
78
+ transport: viem.http(),
79
+ });
80
+ });
81
+ }
82
+ canSponsorTransactionGas() {
83
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
84
+ return false;
85
+ });
86
+ }
87
+ getAccountAbstractionProvider() {
88
+ return this.smartAccount;
89
+ }
90
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
91
+ getWalletClient() {
92
+ if (!this.smartAccount) {
93
+ return undefined;
94
+ }
95
+ return this.smartAccount;
96
+ }
97
+ getTransport(provider) {
98
+ const transport = ethereumCore.confirmationTransport({
99
+ getAccounts: () => _tslib.__awaiter(this, void 0, void 0, function* () { return [provider.account.address]; }),
100
+ onPersonalSign: (_a) => _tslib.__awaiter(this, [_a], void 0, function* ({ message }) {
101
+ this._walletUiUtils.disabledConfirmationOnce();
102
+ if (!this._isSmartAccountDeployed) {
103
+ yield this.deploySmartAccountWithPaymaster();
104
+ }
105
+ this._walletUiUtils.disabledConfirmationOnce();
106
+ return provider.signMessage({
107
+ message,
108
+ });
109
+ }),
110
+ onSignTypedData: (_b) => _tslib.__awaiter(this, [_b], void 0, function* ({ message }) {
111
+ this._walletUiUtils.disabledConfirmationOnce();
112
+ const signTypedData = JSON.parse(message);
113
+ if (!this._isSmartAccountDeployed) {
114
+ yield this.deploySmartAccountWithPaymaster();
115
+ }
116
+ this._walletUiUtils.disabledConfirmationOnce();
117
+ return provider.signTypedData({
118
+ domain: signTypedData.domain,
119
+ message: signTypedData.message,
120
+ primaryType: signTypedData.primaryType,
121
+ types: signTypedData.types,
122
+ });
123
+ }),
124
+ provider: provider.extend(viem.publicActions),
125
+ transport: viem.custom(provider, this.providersConfig.httpTransportConfig),
126
+ // TODO: remove this. We should not be passing references to wallet connectors
127
+ walletConnector: this,
128
+ walletUiUtils: this._walletUiUtils,
129
+ });
130
+ return transport;
131
+ }
132
+ getSigner() {
133
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
134
+ return this.getWalletClient();
135
+ });
136
+ }
137
+ createEcdsaClient(eoaConnector) {
138
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
139
+ const eoaSigner = yield (eoaConnector === null || eoaConnector === void 0 ? void 0 : eoaConnector.getSigner());
140
+ if (!eoaSigner) {
141
+ throw new Error('EOA wallet client not found');
142
+ }
143
+ const transport = this.getTransport(eoaSigner);
144
+ const ownerWithTransport = viem.createWalletClient(Object.assign(Object.assign({}, eoaSigner), { transport }));
145
+ const walletClient = yield client.createZksyncEcdsaClient({
146
+ address: this.smartAccountAddress,
147
+ chain: ethereumCore.getOrMapViemChain(this.evmNetworks[0]),
148
+ contracts: {
149
+ accountFactory: this.factoryAddress,
150
+ session: this.sessionKeyAddress,
151
+ },
152
+ owner: ownerWithTransport,
153
+ transport: viem.http(),
154
+ });
155
+ return walletClient;
156
+ });
157
+ }
158
+ /**
159
+ * Implementation of the interface method required by IAccountAbstractionWalletConnector
160
+ * @param eoaConnector - The EOA connector to use for signing transactions
161
+ * @param smartAccountAddress - The address of the smart account
162
+ */
163
+ initializeZksyncConnector(_a) {
164
+ return _tslib.__awaiter(this, arguments, void 0, function* ({ eoaConnector, smartAccountAddress, }) {
165
+ this.initializedDeferredPromise = this.initializedDeferredPromise
166
+ ? this.initializedDeferredPromise
167
+ : new utils.DeferredPromise();
168
+ this.eoaConnector = eoaConnector;
169
+ this.eoaAddress = yield eoaConnector.getAddress();
170
+ this.smartAccountAddress = smartAccountAddress;
171
+ this.smartAccount = (yield this.createEcdsaClient(eoaConnector));
172
+ yield this.checkIsDeployed();
173
+ this.initializedDeferredPromise.resolve();
174
+ });
175
+ }
176
+ /**
177
+ * Creates a passkey client for ZKsync authentication
178
+ *
179
+ * This method initializes a passkey client using stored credentials and
180
+ * configures it with the necessary contract addresses and chain information.
181
+ *
182
+ */
183
+ createPasskeyClient() {
184
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
185
+ if (!this.smartAccountAddress) {
186
+ throw new Error('Smart account address is not initialized');
187
+ }
188
+ const storedCredentialPublicKey = utils.StorageService.getItem('credentialPublicKey');
189
+ if (!storedCredentialPublicKey) {
190
+ throw new Error('Credential public key not found');
191
+ }
192
+ const credentialPublicKey = new Uint8Array(Object.values(storedCredentialPublicKey));
193
+ const publicClient = yield this.getTypedPublicClient();
194
+ const { chain } = publicClient;
195
+ if (!chain) {
196
+ throw new Error('Chain information not available');
197
+ }
198
+ const contractAddresses = {
199
+ accountFactory: this.factoryAddress,
200
+ passkey: this.passkeyAddress,
201
+ session: this.sessionKeyAddress,
202
+ };
203
+ this.passkeyClient = passkey.createZksyncPasskeyClient({
204
+ address: this.smartAccountAddress,
205
+ chain,
206
+ contracts: contractAddresses,
207
+ credentialPublicKey,
208
+ transport: viem.http(),
209
+ userDisplayName: this.smartAccountAddress,
210
+ userName: this.smartAccountAddress,
211
+ });
212
+ });
213
+ }
214
+ registerPasskeyAndDeploy() {
215
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
216
+ const { credentialPublicKey, credentialId } = yield passkey.registerNewPasskey({
217
+ attestationType: 'none',
218
+ authenticatorSelection: {
219
+ authenticatorAttachment: 'platform',
220
+ requireResidentKey: false,
221
+ userVerification: 'required',
222
+ },
223
+ userDisplayName: this.smartAccountAddress,
224
+ userName: this.smartAccountAddress,
225
+ });
226
+ utils.StorageService.setItem('credentialPublicKey', credentialPublicKey);
227
+ utils.StorageService.setItem('credentialId', credentialId);
228
+ yield this.deploySmartAccount({
229
+ withPaymaster: true,
230
+ });
231
+ });
232
+ }
233
+ deploySmartAccount(_a) {
234
+ return _tslib.__awaiter(this, arguments, void 0, function* ({ withPaymaster, }) {
235
+ if (withPaymaster) {
236
+ yield this.deploySmartAccountWithPaymaster();
237
+ }
238
+ else {
239
+ yield this.deploySmartAccountWithoutPaymaster();
240
+ }
241
+ });
242
+ }
243
+ deploySmartAccountWithPaymaster() {
244
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
245
+ const paymaster = this.paymasterAddress;
246
+ const publicClient = yield this.getTypedPublicClient();
247
+ const walletClient = yield this.getTypedWalletClient();
248
+ const deploymentParams = yield this.getDeploymentParameters();
249
+ const { request } = yield this.simulateAccountDeployment(publicClient, walletClient, deploymentParams, false);
250
+ const paymasterInput = zksync.getGeneralPaymasterInput({
251
+ innerInput: new Uint8Array(),
252
+ });
253
+ const requestWithPaymaster = Object.assign(Object.assign({}, request), { paymaster,
254
+ paymasterInput });
255
+ yield this.executeAccountDeployment(walletClient, requestWithPaymaster);
256
+ });
257
+ }
258
+ /**
259
+ * Deploys a new smart account contract
260
+ * @throws {ZkSyncConnectorError} If deployment fails
261
+ * @testable This method can be mocked in tests
262
+ */
263
+ deploySmartAccountWithoutPaymaster() {
264
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
265
+ if (!this.eoaConnector) {
266
+ throw new Error('EOA connector is not initialized');
267
+ }
268
+ const walletClient = yield this.getTypedWalletClient();
269
+ const publicClient = yield this.getTypedPublicClient();
270
+ const deploymentParams = yield this.getDeploymentParameters();
271
+ // Simulate the contract deployment first
272
+ const { request } = yield this.simulateAccountDeployment(publicClient, walletClient, deploymentParams, false);
273
+ // Execute the deployment transaction
274
+ yield this.executeAccountDeployment(walletClient, request);
275
+ });
276
+ }
277
+ /**
278
+ * Gets typed public client from EOA connector
279
+ * @throws {ZkSyncConnectorError} If public client cannot be obtained
280
+ * @testable This method can be mocked in tests
281
+ */
282
+ getTypedPublicClient() {
283
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
284
+ if (!this.eoaConnector) {
285
+ throw new Error('EOA connector is not initialized');
286
+ }
287
+ const publicClient = yield this.eoaConnector.getPublicClient();
288
+ if (!publicClient) {
289
+ throw new Error('Failed to get public client from EOA connector');
290
+ }
291
+ return publicClient;
292
+ });
293
+ }
294
+ /**
295
+ * Gets typed wallet client from EOA connector
296
+ * @throws {ZkSyncConnectorError} If wallet client cannot be obtained
297
+ * @testable This method can be mocked in tests
298
+ */
299
+ getTypedWalletClient() {
300
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
301
+ if (!this.eoaConnector) {
302
+ throw new Error('EOA connector is not initialized');
303
+ }
304
+ const walletClient = yield this.eoaConnector.getWalletClient();
305
+ if (!walletClient) {
306
+ throw new Error('Failed to get wallet client from EOA connector');
307
+ }
308
+ return walletClient
309
+ .extend(viem.publicActions)
310
+ .extend(viem.walletActions)
311
+ .extend(zksync.eip712WalletActions())
312
+ .extend(walletActions.zksyncSsoEcdsaWalletActions);
313
+ });
314
+ }
315
+ /**
316
+ * Returns the parameters needed for deploying the smart account
317
+ * @returns Deployment parameters object
318
+ * @testable This method can be overridden in tests
319
+ */
320
+ getDeploymentParameters() {
321
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
322
+ const salt = `0x${Buffer.from(viem.toBytes('DynamicLabs', { size: 32 })).toString('hex')}`;
323
+ const initialValidators = [];
324
+ const initialK1Owners = [this.eoaAddress];
325
+ if (this.enablePasskeys) {
326
+ const encodedPasskeyModuleData = yield this.getEncodedPasskeyModuleData();
327
+ initialValidators.push(encodedPasskeyModuleData);
328
+ }
329
+ return {
330
+ initialK1Owners,
331
+ initialValidators,
332
+ salt,
333
+ };
334
+ });
335
+ }
336
+ /**
337
+ * Retrieves and encodes passkey module data for smart account deployment
338
+ * @returns Encoded passkey module data as a hex string
339
+ * @throws {Error} If credential public key or ID is not found
340
+ * @private
341
+ */
342
+ getEncodedPasskeyModuleData() {
343
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
344
+ const storedCredentialPublicKey = utils.StorageService.getItem('credentialPublicKey');
345
+ if (!storedCredentialPublicKey) {
346
+ throw new Error('Credential public key not found');
347
+ }
348
+ const credentialPublicKey = new Uint8Array(Object.values(storedCredentialPublicKey));
349
+ const credentialId = utils.StorageService.getItem('credentialId');
350
+ if (!credentialId) {
351
+ throw new Error('Credential ID not found');
352
+ }
353
+ const passkeyPublicKey = utils$1.getPublicKeyBytesFromPasskeySignature(credentialPublicKey);
354
+ const encodedPasskeyParameters = utils$1.encodePasskeyModuleParameters({
355
+ credentialId: credentialId,
356
+ expectedOrigin: window.location.origin, // TODO: how is this going to be set?
357
+ passkeyPublicKey,
358
+ });
359
+ return utils$1.encodeModuleData({
360
+ address: this.passkeyAddress,
361
+ parameters: encodedPasskeyParameters,
362
+ });
363
+ });
364
+ }
365
+ /**
366
+ * Simulates the smart account deployment
367
+ * @param publicClient - The public client to use for simulation
368
+ * @param walletClient - The wallet client to use for account information
369
+ * @param params - The deployment parameters
370
+ * @returns The simulation result
371
+ * @throws {ZkSyncConnectorError} If simulation fails
372
+ * @testable This method can be mocked in tests
373
+ */
374
+ simulateAccountDeployment(publicClient_1, walletClient_1, params_1) {
375
+ return _tslib.__awaiter(this, arguments, void 0, function* (publicClient, walletClient, params, checkBalance = true) {
376
+ var _a, _b, _c;
377
+ // this is to keep the same salt as calculated on zksync sso package
378
+ const salt = viem.keccak256(viem.toHex(params.salt));
379
+ const gasEstimate = yield publicClient.estimateContractGas({
380
+ abi: abi.AAFactoryABI,
381
+ account: (_a = walletClient.account) === null || _a === void 0 ? void 0 : _a.address,
382
+ address: this.factoryAddress,
383
+ args: [salt, params.initialValidators, params.initialK1Owners],
384
+ functionName: 'deployProxySsoAccount',
385
+ });
386
+ if (checkBalance) {
387
+ const balance = yield publicClient.getBalance({
388
+ address: (_b = walletClient.account) === null || _b === void 0 ? void 0 : _b.address,
389
+ });
390
+ if (balance < gasEstimate) {
391
+ throw new Error('Insufficient balance to deploy account');
392
+ }
393
+ }
394
+ // Simulate the contract call
395
+ return publicClient.simulateContract({
396
+ abi: abi.AAFactoryABI,
397
+ account: (_c = walletClient.account) === null || _c === void 0 ? void 0 : _c.address,
398
+ address: this.factoryAddress,
399
+ args: [salt, params.initialValidators, params.initialK1Owners],
400
+ functionName: 'deployProxySsoAccount',
401
+ });
402
+ });
403
+ }
404
+ /**
405
+ * Executes the smart account deployment transaction
406
+ * @param walletClient - The wallet client to use for transaction execution
407
+ * @param request - The deployment request object containing transaction parameters
408
+ * @returns Promise that resolves when the deployment transaction is confirmed
409
+ * @throws {DynamicError} If the smart account address is not initialized
410
+ * @throws {Error} If transaction execution or confirmation fails
411
+ */
412
+ executeAccountDeployment(walletClient, request) {
413
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
414
+ if (!this.smartAccountAddress) {
415
+ throw new Error('Smart account address is not initialized');
416
+ }
417
+ const tx = yield walletClient.writeContract(request);
418
+ const publicClient = yield this.getPublicClient();
419
+ yield publicClient.waitForTransactionReceipt({ hash: tx });
420
+ this._isSmartAccountDeployed = true;
421
+ });
422
+ }
423
+ signMessage(message) {
424
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
425
+ const walletClient = this.getWalletClient();
426
+ if (!walletClient) {
427
+ throw new Error('Wallet client not found');
428
+ }
429
+ return yield walletClient.signMessage({
430
+ account: walletClient.account,
431
+ message,
432
+ });
433
+ });
434
+ }
435
+ /**
436
+ * Checks if a smart account is deployed
437
+ * @throws {ZkSyncConnectorError} If the check fails
438
+ * @returns Promise that resolves when the check is complete
439
+ */
440
+ checkIsDeployed() {
441
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
442
+ const client = yield this.getPublicClient();
443
+ if (!client) {
444
+ throw new Error('Failed to get public client from EOA connector');
445
+ }
446
+ const code = yield client.getCode({
447
+ address: this.smartAccountAddress,
448
+ });
449
+ const isDeployed = Boolean(code);
450
+ this._isSmartAccountDeployed = isDeployed;
451
+ });
452
+ }
453
+ getAddress() {
454
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
455
+ var _a;
456
+ yield ((_a = this.initializedDeferredPromise) === null || _a === void 0 ? void 0 : _a.promise);
457
+ if (!this.smartAccount) {
458
+ throw new Error('Smart account is not initialized');
459
+ }
460
+ return this.smartAccountAddress;
461
+ });
462
+ }
463
+ validateActiveWallet(expectedAddress) {
464
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
465
+ const currentAddress = yield this.getAddress();
466
+ if (currentAddress !== expectedAddress) {
467
+ throw new utils.DynamicError('Invalid active wallet');
468
+ }
469
+ return;
470
+ });
471
+ }
472
+ createUiTransaction(from) {
473
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
474
+ yield this.validateActiveWallet(from);
475
+ const walletClient = this.getWalletClient();
476
+ const publicClient = yield this.getPublicClient();
477
+ if (!publicClient || !walletClient) {
478
+ throw new utils.DynamicError('No public client available');
479
+ }
480
+ return ethereumCore.createViemUiTransaction({
481
+ from: from,
482
+ publicClient: publicClient,
483
+ walletClient: walletClient,
484
+ });
485
+ });
486
+ }
487
+ isSmartAccountDeployed() {
488
+ return _tslib.__awaiter(this, arguments, void 0, function* (refetch = false) {
489
+ if (refetch) {
490
+ yield this.checkIsDeployed();
491
+ }
492
+ return this._isSmartAccountDeployed;
493
+ });
494
+ }
495
+ registerEoa(_a) {
496
+ return _tslib.__awaiter(this, arguments, void 0, function* ({ smartWalletAddress, eoaAddress, eoaConnector, shouldSetEoaConnector, }) {
497
+ throw new Error('Not implemented');
498
+ });
499
+ }
500
+ }
501
+
502
+ exports.ZKsyncConnector = ZKsyncConnector;