@nevermined-io/core-kit 1.6.0 → 1.8.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.
@@ -1,6 +1,7 @@
1
1
  import { signerToEcdsaValidator } from '@zerodev/ecdsa-validator';
2
2
  import { KernelAccountClient } from '@zerodev/sdk';
3
- import { Address, type Abi, type AbiEvent, type AbiFunction, type Account, type PublicClient, type TransactionReceipt } from 'viem';
3
+ import { KERNEL_V3_1, KERNEL_V3_3 } from '@zerodev/sdk/constants';
4
+ import { Address, type Abi, type AbiEvent, type AbiFunction, type Account, type PublicClient, type SignAuthorizationReturnType, type TransactionReceipt } from 'viem';
4
5
  import { SmartAccount } from 'viem/account-abstraction';
5
6
  import { Instantiable, InstantiableConfig, Web3Clients } from '../../Instantiable.abstract.js';
6
7
  import { Signer } from '@zerodev/sdk/types';
@@ -34,15 +35,15 @@ export declare function getTransactionReceipt({ txHash, publicClient, }: {
34
35
  */
35
36
  export declare function getContractInstance(contractAddress: string, abi: Abi, client: Web3Clients): Promise<{
36
37
  read: {
37
- [x: string]: (...parameters: [options?: import("viem").Prettify<import("viem").UnionOmit<import("viem").ReadContractParameters<Abi, string, readonly unknown[]>, "address" | "abi" | "args" | "functionName">> | undefined] | [args: readonly unknown[], options?: import("viem").Prettify<import("viem").UnionOmit<import("viem").ReadContractParameters<Abi, string, readonly unknown[]>, "address" | "abi" | "args" | "functionName">> | undefined]) => Promise<import("viem").ReadContractReturnType>;
38
+ [x: string]: (...parameters: [options?: import("viem").Prettify<import("viem").UnionOmit<import("viem").ReadContractParameters<Abi, string, readonly unknown[]>, "address" | "abi" | "functionName" | "args">> | undefined] | [args: readonly unknown[], options?: import("viem").Prettify<import("viem").UnionOmit<import("viem").ReadContractParameters<Abi, string, readonly unknown[]>, "address" | "abi" | "functionName" | "args">> | undefined]) => Promise<import("viem").ReadContractReturnType>;
38
39
  };
39
40
  estimateGas: {
40
- [x: string]: (...parameters: [options: import("viem").Prettify<import("viem").UnionOmit<import("viem").EstimateContractGasParameters<Abi, string, readonly unknown[], import("viem").Chain | undefined>, "address" | "abi" | "args" | "functionName">>] | [args: readonly unknown[], options: import("viem").Prettify<import("viem").UnionOmit<import("viem").EstimateContractGasParameters<Abi, string, readonly unknown[], import("viem").Chain | undefined>, "address" | "abi" | "args" | "functionName">>]) => Promise<import("viem").EstimateContractGasReturnType>;
41
+ [x: string]: (...parameters: [options: import("viem").Prettify<import("viem").UnionOmit<import("viem").EstimateContractGasParameters<Abi, string, readonly unknown[], import("viem").Chain | undefined>, "address" | "abi" | "functionName" | "args">>] | [args: readonly unknown[], options: import("viem").Prettify<import("viem").UnionOmit<import("viem").EstimateContractGasParameters<Abi, string, readonly unknown[], import("viem").Chain | undefined>, "address" | "abi" | "functionName" | "args">>]) => Promise<import("viem").EstimateContractGasReturnType>;
41
42
  } & {
42
- [x: string]: (...parameters: [options: import("viem").Prettify<import("viem").UnionOmit<import("viem").EstimateContractGasParameters<Abi, string, readonly unknown[], import("viem").Chain | undefined>, "address" | "abi" | "args" | "functionName">>] | [args: readonly unknown[], options: import("viem").Prettify<import("viem").UnionOmit<import("viem").EstimateContractGasParameters<Abi, string, readonly unknown[], import("viem").Chain | undefined>, "address" | "abi" | "args" | "functionName">>]) => Promise<import("viem").EstimateContractGasReturnType>;
43
+ [x: string]: (...parameters: [options: import("viem").Prettify<import("viem").UnionOmit<import("viem").EstimateContractGasParameters<Abi, string, readonly unknown[], import("viem").Chain | undefined>, "address" | "abi" | "functionName" | "args">>] | [args: readonly unknown[], options: import("viem").Prettify<import("viem").UnionOmit<import("viem").EstimateContractGasParameters<Abi, string, readonly unknown[], import("viem").Chain | undefined>, "address" | "abi" | "functionName" | "args">>]) => Promise<import("viem").EstimateContractGasReturnType>;
43
44
  };
44
45
  simulate: {
45
- [x: string]: <chainOverride extends import("viem").Chain | undefined = undefined, accountOverride extends Account | Address | undefined = undefined>(...parameters: [options?: Omit<import("viem").SimulateContractParameters<Abi, string, readonly unknown[], import("viem").Chain | undefined, chainOverride, accountOverride>, "address" | "abi" | "args" | "functionName"> | undefined] | [args: readonly unknown[], options?: Omit<import("viem").SimulateContractParameters<Abi, string, readonly unknown[], import("viem").Chain | undefined, chainOverride, accountOverride>, "address" | "abi" | "args" | "functionName"> | undefined]) => Promise<import("viem").SimulateContractReturnType>;
46
+ [x: string]: <chainOverride extends import("viem").Chain | undefined = undefined, accountOverride extends Account | Address | undefined = undefined>(...parameters: [options?: Omit<import("viem").SimulateContractParameters<Abi, string, readonly unknown[], import("viem").Chain | undefined, chainOverride, accountOverride>, "address" | "abi" | "functionName" | "args"> | undefined] | [args: readonly unknown[], options?: Omit<import("viem").SimulateContractParameters<Abi, string, readonly unknown[], import("viem").Chain | undefined, chainOverride, accountOverride>, "address" | "abi" | "functionName" | "args"> | undefined]) => Promise<import("viem").SimulateContractReturnType>;
46
47
  };
47
48
  createEventFilter: {
48
49
  [x: string]: <strict extends boolean | undefined = undefined>(...parameters: [options?: ({
@@ -68,10 +69,10 @@ export declare function getContractInstance(contractAddress: string, abi: Abi, c
68
69
  };
69
70
  getEvents: {
70
71
  [x: string]: (...parameters: [options?: {
72
+ blockHash?: `0x${string}` | undefined;
71
73
  strict?: boolean | undefined;
72
74
  fromBlock?: bigint | import("viem").BlockTag | undefined;
73
75
  toBlock?: bigint | import("viem").BlockTag | undefined;
74
- blockHash?: `0x${string}` | undefined;
75
76
  } | undefined] | [args?: readonly unknown[] | {
76
77
  [x: string]: unknown;
77
78
  address?: undefined;
@@ -86,10 +87,10 @@ export declare function getContractInstance(contractAddress: string, abi: Abi, c
86
87
  batch?: undefined;
87
88
  pollingInterval?: undefined;
88
89
  } | undefined, options?: {
90
+ blockHash?: `0x${string}` | undefined;
89
91
  strict?: boolean | undefined;
90
92
  fromBlock?: bigint | import("viem").BlockTag | undefined;
91
93
  toBlock?: bigint | import("viem").BlockTag | undefined;
92
- blockHash?: `0x${string}` | undefined;
93
94
  } | undefined]) => Promise<import("viem").GetContractEventsReturnType<Abi, string>>;
94
95
  };
95
96
  watchEvent: {
@@ -125,7 +126,7 @@ export declare function getContractInstance(contractAddress: string, abi: Abi, c
125
126
  } | undefined]) => import("viem").WatchContractEventReturnType;
126
127
  };
127
128
  write: {
128
- [x: string]: <chainOverride extends import("viem").Chain | undefined, options extends import("viem").UnionOmit<import("viem").WriteContractParameters<Abi, string, readonly unknown[], import("viem").Chain | undefined, Account | undefined, chainOverride>, "address" | "abi" | "args" | "functionName"> extends infer T ? { [K in keyof T]: T[K]; } : never, Rest extends unknown[] = [options: options]>(...parameters: Rest | [args: readonly unknown[], ...parameters: Rest]) => Promise<import("viem").WriteContractReturnType>;
129
+ [x: string]: <chainOverride extends import("viem").Chain | undefined, options extends import("viem").UnionOmit<import("viem").WriteContractParameters<Abi, string, readonly unknown[], import("viem").Chain | undefined, Account | undefined, chainOverride>, "address" | "abi" | "functionName" | "args"> extends infer T ? { [K in keyof T]: T[K]; } : never, Rest extends unknown[] = [options: options]>(...parameters: Rest | [args: readonly unknown[], ...parameters: Rest]) => Promise<import("viem").WriteContractReturnType>;
129
130
  };
130
131
  address: `0x${string}`;
131
132
  abi: Abi;
@@ -285,6 +286,17 @@ export declare function estimateUserOperationFees(bundlerClient: any, _publicCli
285
286
  maxFeePerGas: bigint;
286
287
  maxPriorityFeePerGas: bigint;
287
288
  }>;
289
+ /**
290
+ * Floors `verificationGasLimit` on Tempo networks before the UserOp is handed to
291
+ * the ZeroDev paymaster, so `zd_sponsorUserOperation` has headroom and does not
292
+ * revert AA26. No-op on every other network. Shared by both paymaster sponsor
293
+ * call sites. Generic so the caller's UserOp type is preserved; typing
294
+ * `verificationGasLimit?: bigint` also turns a plain-number literal (a `bigint`
295
+ * missing its `n`) into a compile error instead of a silent floor-to-30M.
296
+ */
297
+ export declare function applyTempoVerificationGasFloor<T extends {
298
+ verificationGasLimit?: bigint;
299
+ }>(userOperation: T, chainId: number): T;
288
300
  /**
289
301
  * It creates a ZeroDev Kernel client.
290
302
  * @param signer the signer account
@@ -304,6 +316,13 @@ export type EcdsaValidator = Awaited<ReturnType<typeof signerToEcdsaValidator>>;
304
316
  * (e.g. the webapp's localStorage) should stamp this and invalidate on change.
305
317
  */
306
318
  export declare const SCA_DERIVATION_VERSION: string;
319
+ export declare const ACCOUNT_CACHE_MAX_ENTRIES = 5000;
320
+ /** Current entry count of the Kernel account-resolution memo (#2206). */
321
+ export declare function getAccountResolutionCacheStats(): {
322
+ size: number;
323
+ };
324
+ /** Clear the account-resolution memo (test isolation / kernel-upgrade invalidation). */
325
+ export declare function clearAccountResolutionCache(): void;
307
326
  /**
308
327
  * Build the ECDSA sudo validator for a signer. Both `createKernelSmartAccount`
309
328
  * and `createSessionKey` need this validator and each derives it via a ZeroDev
@@ -319,8 +338,48 @@ export declare function createEcdsaValidator(signer: Signer, publicClient: Publi
319
338
  export declare function createKernelSmartAccount(signer: Signer, publicClient: PublicClient, ecdsaValidator?: EcdsaValidator): Promise<SmartAccount>;
320
339
  export declare function getApproval(signer: Signer, publicClient: any, policies: any[]): Promise<string>;
321
340
  export declare function useSessionKey(approval: string, signer: Signer, publicClient: any): Promise<import("@zerodev/sdk").CreateKernelAccountReturnType<"0.7">>;
322
- export declare function createSessionKey(signer: Signer, publicClient: any, policies: any[], ecdsaValidator?: EcdsaValidator): Promise<string>;
323
- export declare function getSessionKey(serializedSessionKey: string, publicClient: any): Promise<import("@zerodev/sdk").CreateKernelAccountReturnType<"0.7">>;
341
+ export declare function createSessionKey(signer: Signer, publicClient: any, policies: any[], ecdsaValidator?: EcdsaValidator, sessionPrivateKey?: `0x${string}`): Promise<string>;
342
+ /**
343
+ * Multi-network session keys (#1929). Generates ONE session private key and
344
+ * serializes the permission account once per network — each serialization
345
+ * carries that network's chain-bound enable signature. The SAME session key
346
+ * works on every supported chain (the smart-account address + init code are
347
+ * identical via CREATE2 parity); only the enable signature differs per chain.
348
+ *
349
+ * Use the returned map (chainId → serialized session key) to build a single
350
+ * multi-network API key: the backend selects the entry for the operation's
351
+ * network. Avoids the `EnableNotApproved` revert when an API key minted on one
352
+ * chain is used on another.
353
+ *
354
+ * @param signer the smart-account owner (e.g. the Privy EOA) — signs each
355
+ * network's enable signature
356
+ * @param publicClientByChainId map of chainId → a PublicClient for that chain
357
+ * @param policies the permission policies (same on every chain)
358
+ */
359
+ export declare function createSessionKeysForNetworks(signer: Signer, publicClientByChainId: Record<number, any>, policies: any[], requiredChainId?: number): Promise<Record<number, string>>;
360
+ /**
361
+ * The canonical, CREATE2-deterministic Kernel v3.3 implementation that an EOA
362
+ * delegates to under EIP-7702 (same address on Base mainnet + Base Sepolia).
363
+ * This is the `contract`/`address` passed to Privy `sign7702Authorization` and
364
+ * carried in the type-4 authorization. See #2148.
365
+ */
366
+ export declare const KERNEL_7702_IMPL_ADDRESS = "0xd6CEDDe84be40893d153Be9d467CD6aD37875b28";
367
+ export { KERNEL_V3_1, KERNEL_V3_3 };
368
+ export type KernelVersion = typeof KERNEL_V3_1 | typeof KERNEL_V3_3;
369
+ /**
370
+ * Resolves a user's EIP-7702 account: the Privy EOA delegated to Kernel v3.3.
371
+ * The resulting account's address **equals the EOA** (no counterfactual SCA),
372
+ * so it both signs EIP-3009 as a plain EOA (Router) and acts as a 4337 smart
373
+ * account (credits/session-keys). `eip7702Auth` is the signed type-4
374
+ * authorization (from Privy `sign7702Authorization`); omit it once the account
375
+ * is already delegated on-chain.
376
+ *
377
+ * ponytail: on-chain correctness (delegation designator, UserOp submission)
378
+ * is validated on Base Sepolia in Phase 0 (#2153); this wrapper only pins the
379
+ * SDK call shape.
380
+ */
381
+ export declare function createKernel7702Account(signer: Signer, publicClient: PublicClient, eip7702Auth?: SignAuthorizationReturnType): Promise<SmartAccount>;
382
+ export declare function getSessionKey(serializedSessionKey: string, publicClient: any, kernelVersion?: KernelVersion): Promise<import("@zerodev/sdk").CreateKernelAccountReturnType<"0.7">>;
324
383
  /**
325
384
  * Creates a delegated session key for an existing kernel account.
326
385
  * The resulting serialized session key can be deserialized into a SmartAccount
@@ -331,7 +390,7 @@ export declare function getSessionKey(serializedSessionKey: string, publicClient
331
390
  * @param policies Array of policies to enforce for this session key
332
391
  * @returns Serialized session key string
333
392
  */
334
- export declare function createDelegatedSessionKeyFromKernel(kernelAccount: SmartAccount, publicClient: PublicClient, policies: any[]): Promise<string>;
393
+ export declare function createDelegatedSessionKeyFromKernel(kernelAccount: SmartAccount, publicClient: PublicClient, policies: any[], kernelVersion?: KernelVersion): Promise<string>;
335
394
  export declare const WalletUtils: {
336
395
  makeWallet: typeof makeWallet;
337
396
  makeWallets: typeof makeWallets;
@@ -1 +1 @@
1
- {"version":3,"file":"BlockchainViemUtils.d.ts","sourceRoot":"","sources":["../../../src/nevermined/utils/BlockchainViemUtils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"BlockchainViemUtils.d.ts","sourceRoot":"","sources":["../../../src/nevermined/utils/BlockchainViemUtils.ts"],"names":[],"mappings":"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"}
@@ -2,12 +2,12 @@ import { signerToEcdsaValidator } from '@zerodev/ecdsa-validator';
2
2
  import { deserializePermissionAccount, serializePermissionAccount, toPermissionValidator } from '@zerodev/permissions';
3
3
  import { toECDSASigner } from '@zerodev/permissions/signers';
4
4
  import { addressToEmptyAccount, createKernelAccount, createKernelAccountClient, createZeroDevPaymasterClient, getUserOperationGasPrice } from '@zerodev/sdk';
5
- import { KERNEL_V3_1, getEntryPoint } from '@zerodev/sdk/constants';
5
+ import { KERNEL_V3_1, KERNEL_V3_3, KERNEL_7702_DELEGATION_ADDRESS, getEntryPoint } from '@zerodev/sdk/constants';
6
6
  import { encodeAbiParameters, getAbiItem, getAddress, getContract, http, isAddress, pad, stringToBytes, stringToHex, toBytes, keccak256 as viemKeccak256 } from 'viem';
7
7
  import { english, generateMnemonic, generatePrivateKey, mnemonicToAccount, privateKeyToAccount } from 'viem/accounts';
8
8
  import { Instantiable } from '../../Instantiable.abstract.js';
9
9
  import { ContractsError } from '../../errors/NeverminedErrors.js';
10
- import { getChain } from '../../utils/Network.js';
10
+ import { getChain, isTempoNetwork } from '../../utils/Network.js';
11
11
  const ENTRY_POINT_VERSION = '0.7';
12
12
  /**
13
13
  * Utility class with methods that allow the interaction with the blockchain.
@@ -244,10 +244,13 @@ const TRANSACTION_RECEIPT_POLLING_INTERVAL_MS = 1_500;
244
244
  * `BUNDLER_RPC_URL_OVERRIDE` is set.
245
245
  */ export function getBundlerRpcUrl(zeroDevProjectId, chainId, useUltraRelay = false) {
246
246
  const base = `https://rpc.zerodev.app/api/v3/${zeroDevProjectId}/chain/${chainId}`;
247
- // `||` (not `??`) because Vite replaces missing browser env vars with the
248
- // empty string at build time; an empty override is equivalent to "no
249
- // override" for our purposes.
250
- return process.env.BUNDLER_RPC_URL_OVERRIDE || (useUltraRelay ? `${base}?provider=ULTRA_RELAY` : base);
247
+ // Per-chain override wins, then the global override, then the canonical URL.
248
+ // The per-chain form (`BUNDLER_RPC_URL_OVERRIDE_<chainId>`) lets a single
249
+ // process route UserOps for different networks to different local bundlers —
250
+ // e.g. a dual-fork dev stack (base-sepolia bundler :4337 + tempo bundler
251
+ // :4338). `||` (not `??`) because Vite replaces missing browser env vars with
252
+ // the empty string at build time; an empty override is equivalent to none.
253
+ return process.env[`BUNDLER_RPC_URL_OVERRIDE_${chainId}`] || process.env.BUNDLER_RPC_URL_OVERRIDE || (useUltraRelay ? `${base}?provider=ULTRA_RELAY` : base);
251
254
  }
252
255
  /**
253
256
  * Returns the paymaster RPC URL (ZeroDev-only; the local fork stack uses
@@ -280,6 +283,32 @@ const TRANSACTION_RECEIPT_POLLING_INTERVAL_MS = 1_500;
280
283
  }
281
284
  return getUserOperationGasPrice(bundlerClient);
282
285
  }
286
+ // Tempo undersizes the ZeroDev bundler's `verificationGasLimit` estimate (cold
287
+ // SCA deploy + session-key enable under TIP-20 gas), so `zd_sponsorUserOperation`
288
+ // re-simulates with that too-low ceiling and reverts `AA26 over
289
+ // verificationGasLimit` (see #1929, staging createPlan on tempo-moderato). We give
290
+ // the sponsor an explicit floor so it stops undersizing. A multiplier is useless
291
+ // here — viem calls getPaymasterData with verificationGasLimit still 0/undefined,
292
+ // so `x * n` is 0. An absolute floor covers both the 0 and the too-low cases.
293
+ // NOTE(#1929): fixed floor — bump if a Tempo op still AA26s (env-tunable if it ever needs per-deploy calibration).
294
+ // needs per-deploy calibration).
295
+ const TEMPO_MIN_VERIFICATION_GAS = 30_000_000n;
296
+ /**
297
+ * Floors `verificationGasLimit` on Tempo networks before the UserOp is handed to
298
+ * the ZeroDev paymaster, so `zd_sponsorUserOperation` has headroom and does not
299
+ * revert AA26. No-op on every other network. Shared by both paymaster sponsor
300
+ * call sites. Generic so the caller's UserOp type is preserved; typing
301
+ * `verificationGasLimit?: bigint` also turns a plain-number literal (a `bigint`
302
+ * missing its `n`) into a compile error instead of a silent floor-to-30M.
303
+ */ export function applyTempoVerificationGasFloor(userOperation, chainId) {
304
+ if (!isTempoNetwork(chainId)) return userOperation;
305
+ const current = typeof userOperation.verificationGasLimit === 'bigint' ? userOperation.verificationGasLimit : 0n;
306
+ const floored = current > TEMPO_MIN_VERIFICATION_GAS ? current : TEMPO_MIN_VERIFICATION_GAS;
307
+ return {
308
+ ...userOperation,
309
+ verificationGasLimit: floored
310
+ };
311
+ }
283
312
  /**
284
313
  * It creates a ZeroDev Kernel client.
285
314
  * @param signer the signer account
@@ -305,7 +334,7 @@ const TRANSACTION_RECEIPT_POLLING_INTERVAL_MS = 1_500;
305
334
  transport: http(paymasterRpc)
306
335
  });
307
336
  return zerodevPaymaster.sponsorUserOperation({
308
- userOperation
337
+ userOperation: applyTempoVerificationGasFloor(userOperation, chainId)
309
338
  });
310
339
  }
311
340
  }
@@ -323,6 +352,71 @@ const TRANSACTION_RECEIPT_POLLING_INTERVAL_MS = 1_500;
323
352
  * bump here means the same EOA derives a different SCA. Persisted SCA caches
324
353
  * (e.g. the webapp's localStorage) should stamp this and invalidate on change.
325
354
  */ export const SCA_DERIVATION_VERSION = `${ENTRY_POINT_VERSION}:${KERNEL_V3_1}`;
355
+ // ponytail: in-process memo for ZeroDev Kernel account resolution. Every
356
+ // deserializePermissionAccount / createKernelAccount reads the EIP-1967 impl
357
+ // slot (eth_getStorageAt) of a deployed account — ~56% of backend Infura RPC
358
+ // volume, and the same session key/owner is re-resolved per request and twice
359
+ // per x402 payment (verify + settle). See #2206. Safe to reuse the resolved
360
+ // account: the Kernel account fetches its nonce fresh at send time, so a cached
361
+ // account never signs against a stale nonce. Keyed by the deterministic inputs
362
+ // (serialized key / owner + kernel version + chainId); short TTL bounds
363
+ // staleness across a kernel upgrade. Single-process only — cross-pod dedup is
364
+ // out of scope (#2206 notes). Upgrade path: swap the Map for a shared store.
365
+ const ACCOUNT_CACHE_TTL_MS = 60_000;
366
+ // Bound the cache: `getSessionKey` runs behind `getAccountAttributes` on every
367
+ // authenticated request, keyed per-API-key, so an entry never re-requested
368
+ // would otherwise sit past its TTL for the life of the (long-lived) apps/api
369
+ // process — a slow leak. Cardinality ≈ distinct API keys ever seen; cap + sweep
370
+ // keep it bounded (matches BlockchainCacheService's MAX_ENTRIES + cleanup()).
371
+ export const ACCOUNT_CACHE_MAX_ENTRIES = 5_000;
372
+ const accountResolutionCache = new Map();
373
+ function memoResolveAccount(key, resolver) {
374
+ const now = Date.now();
375
+ const cached = accountResolutionCache.get(key);
376
+ if (cached && cached.expiresAt > now) {
377
+ return cached.value;
378
+ }
379
+ // Sweep expired entries + bound size so keys never re-requested don't
380
+ // accumulate for the life of the process (Map keeps insertion order → FIFO).
381
+ for (const [k, e] of accountResolutionCache){
382
+ if (e.expiresAt <= now) accountResolutionCache.delete(k);
383
+ }
384
+ if (accountResolutionCache.size >= ACCOUNT_CACHE_MAX_ENTRIES) {
385
+ accountResolutionCache.delete(accountResolutionCache.keys().next().value);
386
+ }
387
+ const entry = {
388
+ value: undefined,
389
+ expiresAt: now + ACCOUNT_CACHE_TTL_MS
390
+ };
391
+ // Coalesce concurrent identical resolutions; evict on rejection so a transient
392
+ // RPC failure isn't cached — but only if this exact entry is still current, so
393
+ // a resolver that hangs past its TTL and then rejects can't drop a newer one.
394
+ entry.value = resolver().catch((err)=>{
395
+ if (accountResolutionCache.get(key) === entry) accountResolutionCache.delete(key);
396
+ throw err;
397
+ });
398
+ accountResolutionCache.set(key, entry);
399
+ return entry.value;
400
+ }
401
+ /** Current entry count of the Kernel account-resolution memo (#2206). */ export function getAccountResolutionCacheStats() {
402
+ return {
403
+ size: accountResolutionCache.size
404
+ };
405
+ }
406
+ /** Clear the account-resolution memo (test isolation / kernel-upgrade invalidation). */ export function clearAccountResolutionCache() {
407
+ accountResolutionCache.clear();
408
+ }
409
+ function chainIdOf(publicClient) {
410
+ const id = publicClient?.chain?.id;
411
+ // chainId is the ONLY discriminator in the sca:/7702:/sk: keys, and SCA /
412
+ // session-key addresses are identical across chains by CREATE2 design — so an
413
+ // id-less client must fail closed rather than alias two networks under one
414
+ // bucket and serve a chain-A account to a chain-B request (latent until #1933).
415
+ if (id == null) {
416
+ throw new Error('account-resolution cache: publicClient.chain.id is required for keying');
417
+ }
418
+ return id;
419
+ }
326
420
  /**
327
421
  * Build the ECDSA sudo validator for a signer. Both `createKernelSmartAccount`
328
422
  * and `createSessionKey` need this validator and each derives it via a ZeroDev
@@ -341,14 +435,21 @@ const TRANSACTION_RECEIPT_POLLING_INTERVAL_MS = 1_500;
341
435
  });
342
436
  }
343
437
  export async function createKernelSmartAccount(signer, publicClient, ecdsaValidator) {
344
- const validator = ecdsaValidator ?? await createEcdsaValidator(signer, publicClient);
345
- return await createKernelAccount(publicClient, {
346
- plugins: {
347
- sudo: validator
348
- },
349
- entryPoint: getEntryPoint(ENTRY_POINT_VERSION),
350
- kernelVersion: KERNEL_V3_1
351
- });
438
+ const build = async ()=>{
439
+ const validator = ecdsaValidator ?? await createEcdsaValidator(signer, publicClient);
440
+ return createKernelAccount(publicClient, {
441
+ plugins: {
442
+ sudo: validator
443
+ },
444
+ entryPoint: getEntryPoint(ENTRY_POINT_VERSION),
445
+ kernelVersion: KERNEL_V3_1
446
+ });
447
+ };
448
+ // A caller-supplied validator isn't part of the key — bypass the memo (like
449
+ // createKernel7702Account does for eip7702Auth) rather than let a cache entry
450
+ // built by a different call silently ignore it (the mismatch createEcdsaValidator warns about).
451
+ if (ecdsaValidator) return build();
452
+ return memoResolveAccount(`sca:${chainIdOf(publicClient)}:${SCA_DERIVATION_VERSION}:${signer.address}`, build);
352
453
  }
353
454
  export async function getApproval(signer, publicClient, policies) {
354
455
  const ecdsaValidator = await signerToEcdsaValidator(publicClient, {
@@ -383,9 +484,8 @@ export async function useSessionKey(approval, signer, publicClient) {
383
484
  const sessionKeyAccount = await deserializePermissionAccount(publicClient, getEntryPoint(ENTRY_POINT_VERSION), KERNEL_V3_1, approval, sessionKeySigner);
384
485
  return sessionKeyAccount;
385
486
  }
386
- export async function createSessionKey(signer, publicClient, policies, ecdsaValidator) {
487
+ export async function createSessionKey(signer, publicClient, policies, ecdsaValidator, sessionPrivateKey = generatePrivateKey()) {
387
488
  const validator = ecdsaValidator ?? await createEcdsaValidator(signer, publicClient);
388
- const sessionPrivateKey = generatePrivateKey();
389
489
  const masterAccount = privateKeyToAccount(sessionPrivateKey);
390
490
  const sessionKeySigner = await toECDSASigner({
391
491
  signer: masterAccount
@@ -404,11 +504,86 @@ export async function createSessionKey(signer, publicClient, policies, ecdsaVali
404
504
  },
405
505
  kernelVersion: KERNEL_V3_1
406
506
  });
507
+ // serializePermissionAccount embeds the ENABLE signature for `publicClient`'s
508
+ // chain (signed by the sudo/owner). That signature is chain-bound, which is
509
+ // why one serialization only validates on the chain it was made for. #1929
407
510
  return serializePermissionAccount(sessionKeyAccount, sessionPrivateKey);
408
511
  }
409
- export async function getSessionKey(serializedSessionKey, publicClient) {
410
- const sessionKeyAccount = await deserializePermissionAccount(publicClient, getEntryPoint(ENTRY_POINT_VERSION), KERNEL_V3_1, serializedSessionKey);
411
- return sessionKeyAccount;
512
+ /**
513
+ * Multi-network session keys (#1929). Generates ONE session private key and
514
+ * serializes the permission account once per network — each serialization
515
+ * carries that network's chain-bound enable signature. The SAME session key
516
+ * works on every supported chain (the smart-account address + init code are
517
+ * identical via CREATE2 parity); only the enable signature differs per chain.
518
+ *
519
+ * Use the returned map (chainId → serialized session key) to build a single
520
+ * multi-network API key: the backend selects the entry for the operation's
521
+ * network. Avoids the `EnableNotApproved` revert when an API key minted on one
522
+ * chain is used on another.
523
+ *
524
+ * @param signer the smart-account owner (e.g. the Privy EOA) — signs each
525
+ * network's enable signature
526
+ * @param publicClientByChainId map of chainId → a PublicClient for that chain
527
+ * @param policies the permission policies (same on every chain)
528
+ */ export async function createSessionKeysForNetworks(signer, publicClientByChainId, policies, requiredChainId) {
529
+ const sessionPrivateKey = generatePrivateKey();
530
+ const out = {};
531
+ for (const [chainIdStr, publicClient] of Object.entries(publicClientByChainId)){
532
+ const chainId = Number(chainIdStr);
533
+ try {
534
+ out[chainId] = await createSessionKey(signer, publicClient, policies, undefined, sessionPrivateKey);
535
+ } catch (err) {
536
+ // Best-effort: a secondary network whose RPC is unreachable must not break
537
+ // key generation (e.g. login). `requiredChainId` (the primary) still throws.
538
+ if (requiredChainId != null && chainId === Number(requiredChainId)) throw err;
539
+ console.warn(`[createSessionKeysForNetworks] skipping network ${chainId}: ${err instanceof Error ? err.message : String(err)}`);
540
+ }
541
+ }
542
+ // Enforce the `requiredChainId` contract even when it is ABSENT from the input
543
+ // map (the loop above only throws when it is present AND fails). Without this,
544
+ // callers read `out[primary]` → undefined → an API key with no primary session
545
+ // key, which fails opaquely downstream.
546
+ if (requiredChainId != null && out[requiredChainId] == null) {
547
+ throw new Error(`createSessionKeysForNetworks: required network ${requiredChainId} was not in the public-client map`);
548
+ }
549
+ return out;
550
+ }
551
+ /**
552
+ * The canonical, CREATE2-deterministic Kernel v3.3 implementation that an EOA
553
+ * delegates to under EIP-7702 (same address on Base mainnet + Base Sepolia).
554
+ * This is the `contract`/`address` passed to Privy `sign7702Authorization` and
555
+ * carried in the type-4 authorization. See #2148.
556
+ */ export const KERNEL_7702_IMPL_ADDRESS = KERNEL_7702_DELEGATION_ADDRESS;
557
+ // The two Kernel versions the platform runs: v3.1 for the legacy counterfactual
558
+ // SCA, v3.3 for the EIP-7702-delegated EOA account. Re-exported so the API
559
+ // layer can pick the right version for (de)serializing session keys.
560
+ export { KERNEL_V3_1, KERNEL_V3_3 };
561
+ /**
562
+ * Resolves a user's EIP-7702 account: the Privy EOA delegated to Kernel v3.3.
563
+ * The resulting account's address **equals the EOA** (no counterfactual SCA),
564
+ * so it both signs EIP-3009 as a plain EOA (Router) and acts as a 4337 smart
565
+ * account (credits/session-keys). `eip7702Auth` is the signed type-4
566
+ * authorization (from Privy `sign7702Authorization`); omit it once the account
567
+ * is already delegated on-chain.
568
+ *
569
+ * ponytail: on-chain correctness (delegation designator, UserOp submission)
570
+ * is validated on Base Sepolia in Phase 0 (#2153); this wrapper only pins the
571
+ * SDK call shape.
572
+ */ export async function createKernel7702Account(signer, publicClient, eip7702Auth) {
573
+ const build = ()=>createKernelAccount(publicClient, {
574
+ eip7702Account: signer,
575
+ ...eip7702Auth ? {
576
+ eip7702Auth
577
+ } : {},
578
+ entryPoint: getEntryPoint(ENTRY_POINT_VERSION),
579
+ kernelVersion: KERNEL_V3_3
580
+ });
581
+ // The install path (auth attached) is a one-time mutating op — never cache it.
582
+ if (eip7702Auth) return build();
583
+ return memoResolveAccount(`7702:${chainIdOf(publicClient)}:${signer.address}`, build);
584
+ }
585
+ export async function getSessionKey(serializedSessionKey, publicClient, kernelVersion = KERNEL_V3_1) {
586
+ return memoResolveAccount(`sk:${chainIdOf(publicClient)}:${kernelVersion}:${serializedSessionKey}`, ()=>deserializePermissionAccount(publicClient, getEntryPoint(ENTRY_POINT_VERSION), kernelVersion, serializedSessionKey));
412
587
  }
413
588
  /**
414
589
  * Creates a delegated session key for an existing kernel account.
@@ -419,7 +594,7 @@ export async function getSessionKey(serializedSessionKey, publicClient) {
419
594
  * @param publicClient Viem PublicClient instance
420
595
  * @param policies Array of policies to enforce for this session key
421
596
  * @returns Serialized session key string
422
- */ export async function createDelegatedSessionKeyFromKernel(kernelAccount, publicClient, policies) {
597
+ */ export async function createDelegatedSessionKeyFromKernel(kernelAccount, publicClient, policies, kernelVersion = KERNEL_V3_1) {
423
598
  // 1) Generate ephemeral session private key (used only for the permission plugin)
424
599
  const sessionPrivateKey = generatePrivateKey();
425
600
  const sessionAccount = privateKeyToAccount(sessionPrivateKey);
@@ -427,12 +602,14 @@ export async function getSessionKey(serializedSessionKey, publicClient) {
427
602
  const sessionKeySigner = await toECDSASigner({
428
603
  signer: sessionAccount
429
604
  });
430
- // 3) Create the permission validator plugin
605
+ // 3) Create the permission validator plugin — MUST match the parent kernel's
606
+ // version (v3.3 for a 7702 account, v3.1 for the legacy SCA), otherwise the
607
+ // serialized blob deserializes/validates against the wrong kernel.
431
608
  const permissionValidator = await toPermissionValidator(publicClient, {
432
609
  entryPoint: getEntryPoint(ENTRY_POINT_VERSION),
433
610
  signer: sessionKeySigner,
434
611
  policies,
435
- kernelVersion: KERNEL_V3_1
612
+ kernelVersion
436
613
  });
437
614
  // 4) Extract the sudo validator from the existing kernel account
438
615
  const kernelAccountTyped = kernelAccount;
@@ -440,14 +617,18 @@ export async function getSessionKey(serializedSessionKey, publicClient) {
440
617
  if (!sudoValidator) {
441
618
  throw new Error('Kernel account does not have a sudo validator');
442
619
  }
443
- // 5) Create a new kernel account with both sudo (from original) and permission validator
620
+ // 5) Create a new kernel account with both sudo (from original) and permission
621
+ // validator, at the same address as the parent kernel. For a 7702 account
622
+ // that address is the EOA; pinning `address` keeps the session-key account
623
+ // on the same account rather than a fresh counterfactual one.
444
624
  const sessionKeyAccount = await createKernelAccount(publicClient, {
445
625
  entryPoint: getEntryPoint(ENTRY_POINT_VERSION),
626
+ address: kernelAccountTyped.address,
446
627
  plugins: {
447
628
  sudo: sudoValidator,
448
629
  regular: permissionValidator
449
630
  },
450
- kernelVersion: KERNEL_V3_1
631
+ kernelVersion
451
632
  });
452
633
  // 6) Serialize the session key account with the ephemeral private key
453
634
  const serialized = await serializePermissionAccount(sessionKeyAccount, sessionPrivateKey);