kawasekit 0.1.0-alpha.1 → 0.1.0-beta.2

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/README.md CHANGED
@@ -167,13 +167,41 @@ Client (any `fetch` becomes x402-aware):
167
167
  import { createX402PaymentSigner, wrapFetch } from "kawasekit";
168
168
  import { privateKeyToAccount } from "viem/accounts";
169
169
 
170
- const signer = createX402PaymentSigner({ account: privateKeyToAccount("0x...") });
171
- const fetch402 = wrapFetch({ signer });
170
+ const signer = createX402PaymentSigner({
171
+ network: "testnet",
172
+ account: privateKeyToAccount("0x..."),
173
+ // Pin to the JPYC v2 EIP-712 domain at construction. The wire-format
174
+ // extra.name / extra.version are ignored — Threat 1.4 mitigation.
175
+ asset: { kind: "known", id: "jpyc-v2" },
176
+ });
177
+
178
+ // onPayment is *required* at the type level — kawasekit refuses to default
179
+ // to "always pay" silently. The callback is your budget guard.
180
+ let spent = 0n;
181
+ const MAX_SPEND = 100_000n; // 100 JPYC (6 decimals)
182
+ const fetch402 = wrapFetch({
183
+ signer,
184
+ onPayment: (req) => {
185
+ const next = spent + BigInt(req.amount);
186
+ if (next > MAX_SPEND) return false; // budget exhausted → 402 returned
187
+ spent = next;
188
+ return true;
189
+ },
190
+ });
172
191
 
173
192
  const res = await fetch402("https://api.example.com/weather/Tokyo");
174
- // → 402 → signed retry → 200 with JPYC settled on-chain
193
+ // → 402 → onPayment guard → signed retry → 200 with JPYC settled on-chain
175
194
  ```
176
195
 
196
+ > **⚠️ Call-level idempotency only.** kawasekit guarantees that a single
197
+ > `fetch402(...)` call settles **at most once** (EIP-3009 nonce + viem
198
+ > `nonceManager`). It does **not** prevent your agent from invoking
199
+ > `fetch402(...)` twice for the same reasoning step — retries, regeneration,
200
+ > pause-resume, and multi-agent fan-out can each cause duplicate charges.
201
+ > **Step-level idempotency is your responsibility**: track an
202
+ > `Idempotency-Key` per reasoning step at the agent framework layer.
203
+ > See [`docs/THREAT_MODEL.md` §6.1](./docs/THREAT_MODEL.md#61-reasoning-step-idempotency-gap) for the threat boundary.
204
+
177
205
  ### Session-key lifecycle (M3-2)
178
206
 
179
207
  ```typescript
@@ -1,4 +1,4 @@
1
- import { getJpycAddress, jpycAbi } from './chunk-LNXYCHRY.js';
1
+ import { getJpycAddress, jpycAbi } from './chunk-ZY6RT2DB.js';
2
2
  import { isSupportedChainId } from './chunk-SA7LMQFG.js';
3
3
  import { isAddress, encodeFunctionData } from 'viem';
4
4
  import { toCallPolicy, ParamCondition, CallPolicyVersion, toRateLimitPolicy } from '@zerodev/permissions/policies';
@@ -77,5 +77,5 @@ function createJpycDailyLimitPolicies(params) {
77
77
  }
78
78
 
79
79
  export { ONE_DAY_SECONDS, TransferJpycInputError, createJpycDailyLimitPolicies, transferJpyc };
80
- //# sourceMappingURL=chunk-7DWIT6D4.js.map
81
- //# sourceMappingURL=chunk-7DWIT6D4.js.map
80
+ //# sourceMappingURL=chunk-DLH2O4MU.js.map
81
+ //# sourceMappingURL=chunk-DLH2O4MU.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client/transfer-jpyc.ts","../src/policy/daily-limit.ts"],"names":[],"mappings":";;;;;AA6DO,IAAM,sBAAA,GAAN,cAAqC,KAAA,CAAM;AAAA,EACjD,YAAY,OAAA,EAAiB;AAC5B,IAAA,KAAA,CAAM,CAAA,cAAA,EAAiB,OAAO,CAAA,CAAE,CAAA;AAChC,IAAA,IAAA,CAAK,IAAA,GAAO,wBAAA;AAAA,EACb;AACD;AAgBA,eAAsB,YAAA,CACrB,cACA,MAAA,EAC8B;AAC9B,EAAA,IAAI,CAAC,UAAU,MAAA,CAAO,EAAA,EAAI,EAAE,MAAA,EAAQ,KAAA,EAAO,CAAA,EAAG;AAC7C,IAAA,MAAM,IAAI,sBAAA,CAAuB,CAAA,+BAAA,EAAkC,MAAA,CAAO,EAAE,CAAA,CAAE,CAAA;AAAA,EAC/E;AACA,EAAA,IAAI,MAAA,CAAO,UAAU,EAAA,EAAI;AACxB,IAAA,MAAM,IAAI,sBAAA,CAAuB,CAAA,iCAAA,EAAoC,MAAA,CAAO,MAAM,CAAA,CAAA,CAAG,CAAA;AAAA,EACtF;AAEA,EAAA,MAAM,OAAA,GAAU,aAAa,KAAA,CAAM,EAAA;AACnC,EAAA,IAAI,CAAC,kBAAA,CAAmB,OAAO,CAAA,EAAG;AACjC,IAAA,MAAM,IAAI,sBAAA,CAAuB,CAAA,SAAA,EAAY,OAAO,CAAA,oCAAA,CAAsC,CAAA;AAAA,EAC3F;AACA,EAAA,MAAM,WAAA,GAAc,eAAe,OAAkC,CAAA;AAErE,EAAA,MAAM,OAAO,kBAAA,CAAmB;AAAA,IAC/B,GAAA,EAAK,OAAA;AAAA,IACL,YAAA,EAAc,UAAA;AAAA,IACd,IAAA,EAAM,CAAC,MAAA,CAAO,EAAA,EAAI,OAAO,MAAM;AAAA,GAC/B,CAAA;AAED,EAAA,MAAM,QAAA,GAAW,MAAM,YAAA,CAAa,OAAA,CAAQ,WAAA,CAAY,CAAC,EAAE,EAAA,EAAI,WAAA,EAAa,KAAA,EAAO,EAAA,EAAI,IAAA,EAAM,CAAC,CAAA;AAE9F,EAAA,MAAM,aAAa,MAAM,YAAA,CAAa,iBAAA,CAAkB,EAAE,UAAU,CAAA;AAEpE,EAAA,IAAI,MAAA,CAAO,mBAAmB,KAAA,EAAO;AACpC,IAAA,OAAO,EAAE,UAAA,EAAY,eAAA,EAAiB,IAAA,EAAM,SAAS,IAAA,EAAK;AAAA,EAC3D;AAEA,EAAA,MAAM,UAAU,MAAM,YAAA,CAAa,4BAA4B,EAAE,IAAA,EAAM,YAAY,CAAA;AACnF,EAAA,OAAO;AAAA,IACN,UAAA;AAAA,IACA,eAAA,EAAiB,QAAQ,OAAA,CAAQ,eAAA;AAAA,IACjC,SAAS,OAAA,CAAQ;AAAA,GAClB;AACD;AC3FO,IAAM,eAAA,GAAkB;AAyCxB,SAAS,6BACf,MAAA,EAC4B;AAC5B,EAAA,IAAI,MAAA,CAAO,kBAAkB,EAAA,EAAI;AAChC,IAAA,MAAM,IAAI,KAAA;AAAA,MACT,CAAA,mEAAA,EAAsE,OAAO,cAAc,CAAA,CAAA;AAAA,KAC5F;AAAA,EACD;AACA,EAAA,IAAI,CAAC,OAAO,SAAA,CAAU,MAAA,CAAO,kBAAkB,CAAA,IAAK,MAAA,CAAO,qBAAqB,CAAA,EAAG;AAClF,IAAA,MAAM,IAAI,KAAA;AAAA,MACT,CAAA,iFAAA,EAAoF,OAAO,kBAAkB,CAAA,CAAA;AAAA,KAC9G;AAAA,EACD;AAEA,EAAA,MAAM,aAAa,YAAA,CAAa;AAAA,IAC/B,aAAA,EAAe,MAAA,CAAO,iBAAA,IAAqB,iBAAA,CAAkB,MAAA;AAAA,IAC7D,WAAA,EAAa;AAAA,MACZ;AAAA,QACC,QAAQ,MAAA,CAAO,WAAA;AAAA,QACf,GAAA,EAAK,OAAA;AAAA,QACL,YAAA,EAAc,UAAA;AAAA,QACd,IAAA,EAAM;AAAA;AAAA,UAEL,IAAA;AAAA;AAAA,UAEA;AAAA,YACC,WAAW,cAAA,CAAe,kBAAA;AAAA,YAC1B,OAAO,MAAA,CAAO;AAAA;AACf;AACD;AACD;AACD,GACA,CAAA;AAED,EAAA,MAAM,kBAAkB,iBAAA,CAAkB;AAAA,IACzC,QAAA,EAAU,eAAA;AAAA,IACV,OAAO,MAAA,CAAO;AAAA,GACd,CAAA;AAED,EAAA,OAAO,CAAC,YAAY,eAAe,CAAA;AACpC","file":"chunk-7DWIT6D4.js","sourcesContent":["/**\n * High-level helper: transfer JPYC from a Kernel smart account via a sponsored\n * UserOp.\n *\n * This is the canonical \"agent payment\" path for M2. The flow:\n * 1. Resolve the JPYC contract address for `kernelClient.chain`.\n * 2. Encode `JPYC.transfer(to, amount)` calldata.\n * 3. Wrap it as a Kernel call and submit via `sendUserOperation`.\n * 4. Wait for the bundler receipt and return both hashes.\n *\n * EIP-3009 `transferWithAuthorization` cannot be used here: JPYC's signature\n * verification is pure `ecrecover`, so a smart account cannot be `from`. See\n * `src/tokens/eip3009.ts` for the EOA-payer path.\n *\n * @packageDocumentation\n */\n\nimport type { KernelAccountClient } from \"@zerodev/sdk\";\nimport type { Address, Chain, Hex, Transport } from \"viem\";\nimport { encodeFunctionData, isAddress } from \"viem\";\nimport type { SmartAccount } from \"viem/account-abstraction\";\nimport { isSupportedChainId, type SupportedChainId } from \"../chains\";\nimport { getJpycAddress, jpycAbi } from \"../tokens/jpyc\";\n\n/** A {@link KernelAccountClient} that is fully configured (chain + account). */\nexport type ConfiguredKernelClient = KernelAccountClient<Transport, Chain, SmartAccount>;\n\n/** Parameters for {@link transferJpyc}. */\nexport interface TransferJpycParams {\n\t/** Recipient address. */\n\treadonly to: Address;\n\t/**\n\t * Raw token amount in the token's smallest unit (JPYC has 18 decimals).\n\t *\n\t * @example\n\t * ```ts\n\t * import { parseUnits } from \"viem\";\n\t * import { JPYC_DECIMALS } from \"kawasekit\";\n\t *\n\t * parseUnits(\"100\", JPYC_DECIMALS); // 100 JPYC\n\t * ```\n\t */\n\treadonly amount: bigint;\n\t/**\n\t * Optional. Defaults to waiting for the bundler receipt before returning.\n\t * Set to `false` to return after the UserOp is submitted but before it\n\t * lands on chain — useful when the caller wants to do its own polling.\n\t */\n\treadonly waitForReceipt?: boolean;\n}\n\n/** Result of a {@link transferJpyc} call. */\nexport interface TransferJpycResult {\n\treadonly userOpHash: Hex;\n\t/** `null` when `waitForReceipt: false` was requested. */\n\treadonly transactionHash: Hex | null;\n\t/** `true` if the bundler receipt reported success; `null` if not awaited. */\n\treadonly success: boolean | null;\n}\n\n/** Thrown when {@link transferJpyc} is called with invalid arguments. */\nexport class TransferJpycInputError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(`transferJpyc: ${message}`);\n\t\tthis.name = \"TransferJpycInputError\";\n\t}\n}\n\n/**\n * Transfer JPYC from the Kernel smart account to `to` via a sponsored UserOp.\n *\n * @example\n * ```ts\n * import { parseUnits } from \"viem\";\n * import { JPYC_DECIMALS, transferJpyc } from \"kawasekit\";\n *\n * const { userOpHash, transactionHash } = await transferJpyc(kernelClient, {\n * to: \"0xBeef0000000000000000000000000000DEADBEEF\",\n * amount: parseUnits(\"100\", JPYC_DECIMALS),\n * });\n * ```\n */\nexport async function transferJpyc(\n\tkernelClient: ConfiguredKernelClient,\n\tparams: TransferJpycParams,\n): Promise<TransferJpycResult> {\n\tif (!isAddress(params.to, { strict: false })) {\n\t\tthrow new TransferJpycInputError(`\\`to\\` is not a valid address: ${params.to}`);\n\t}\n\tif (params.amount <= 0n) {\n\t\tthrow new TransferJpycInputError(`\\`amount\\` must be positive, got ${params.amount}.`);\n\t}\n\n\tconst chainId = kernelClient.chain.id;\n\tif (!isSupportedChainId(chainId)) {\n\t\tthrow new TransferJpycInputError(`Chain ID ${chainId} is not a kawasekit-supported chain.`);\n\t}\n\tconst jpycAddress = getJpycAddress(chainId satisfies SupportedChainId);\n\n\tconst data = encodeFunctionData({\n\t\tabi: jpycAbi,\n\t\tfunctionName: \"transfer\",\n\t\targs: [params.to, params.amount],\n\t});\n\n\tconst callData = await kernelClient.account.encodeCalls([{ to: jpycAddress, value: 0n, data }]);\n\n\tconst userOpHash = await kernelClient.sendUserOperation({ callData });\n\n\tif (params.waitForReceipt === false) {\n\t\treturn { userOpHash, transactionHash: null, success: null };\n\t}\n\n\tconst receipt = await kernelClient.waitForUserOperationReceipt({ hash: userOpHash });\n\treturn {\n\t\tuserOpHash,\n\t\ttransactionHash: receipt.receipt.transactionHash,\n\t\tsuccess: receipt.success,\n\t};\n}\n","/**\n * Daily-limit spending policy for JPYC, built on ZeroDev's Permission System.\n *\n * Composes two ZeroDev policies:\n * 1. **callPolicy** — locks the session key to `JPYC.transfer(to, value)`\n * with `value ≤ maxPerTransfer`. Recipient is unrestricted in M2;\n * add allowlisting in M3 when use cases firm up.\n * 2. **rateLimitPolicy** — caps userOp count to `maxTransfersPerDay` in any\n * 24-hour rolling window.\n *\n * Effective daily cap = `maxPerTransfer × maxTransfersPerDay`. This is not a\n * cumulative-amount tracker (ZeroDev doesn't ship one), but the agent cannot\n * exceed either dimension, so the spirit of \"daily limit\" holds.\n *\n * @packageDocumentation\n */\n\nimport type { Policy } from \"@zerodev/permissions\";\nimport {\n\tCallPolicyVersion,\n\tParamCondition,\n\ttoCallPolicy,\n\ttoRateLimitPolicy,\n} from \"@zerodev/permissions/policies\";\nimport type { Address } from \"viem\";\nimport { jpycAbi } from \"../tokens/jpyc\";\n\n/** One day in seconds — the period for {@link createJpycDailyLimitPolicies}. */\nexport const ONE_DAY_SECONDS = 86_400;\n\n/** Parameters for {@link createJpycDailyLimitPolicies}. */\nexport interface CreateJpycDailyLimitPoliciesParams {\n\t/** JPYC contract address on the target chain. */\n\treadonly jpycAddress: Address;\n\t/** Maximum JPYC (in raw units) the session key may move in one transfer. */\n\treadonly maxPerTransfer: bigint;\n\t/** Maximum number of transfer userOps the session key may submit per day. */\n\treadonly maxTransfersPerDay: number;\n\t/**\n\t * ZeroDev callPolicy on-chain version. Defaults to V0_0_4 (latest at the\n\t * time of writing). Bump only after auditing the new version's semantics.\n\t */\n\treadonly callPolicyVersion?: CallPolicyVersion;\n}\n\n/**\n * Builds the ZeroDev policy bundle that enforces a JPYC daily spend limit.\n *\n * Plug the returned policies into `toPermissionValidator({ policies, … })`\n * — see {@link createAgentSmartAccount} for the common wiring.\n *\n * @example\n * ```ts\n * import { parseUnits } from \"viem\";\n * import {\n * createJpycDailyLimitPolicies,\n * getJpycAddress,\n * JPYC_DECIMALS,\n * polygonAmoy,\n * } from \"kawasekit\";\n *\n * const policies = createJpycDailyLimitPolicies({\n * jpycAddress: getJpycAddress(polygonAmoy.id),\n * maxPerTransfer: parseUnits(\"100\", JPYC_DECIMALS), // 100 JPYC / tx\n * maxTransfersPerDay: 10, // 10 tx / day\n * // effective daily cap = 1000 JPYC\n * });\n * ```\n */\nexport function createJpycDailyLimitPolicies(\n\tparams: CreateJpycDailyLimitPoliciesParams,\n): readonly [Policy, Policy] {\n\tif (params.maxPerTransfer <= 0n) {\n\t\tthrow new Error(\n\t\t\t`createJpycDailyLimitPolicies: maxPerTransfer must be positive, got ${params.maxPerTransfer}.`,\n\t\t);\n\t}\n\tif (!Number.isInteger(params.maxTransfersPerDay) || params.maxTransfersPerDay < 1) {\n\t\tthrow new Error(\n\t\t\t`createJpycDailyLimitPolicies: maxTransfersPerDay must be a positive integer, got ${params.maxTransfersPerDay}.`,\n\t\t);\n\t}\n\n\tconst callPolicy = toCallPolicy({\n\t\tpolicyVersion: params.callPolicyVersion ?? CallPolicyVersion.V0_0_4,\n\t\tpermissions: [\n\t\t\t{\n\t\t\t\ttarget: params.jpycAddress,\n\t\t\t\tabi: jpycAbi,\n\t\t\t\tfunctionName: \"transfer\",\n\t\t\t\targs: [\n\t\t\t\t\t// Recipient: any address allowed (no allowlist in M2).\n\t\t\t\t\tnull,\n\t\t\t\t\t// value: must be ≤ maxPerTransfer.\n\t\t\t\t\t{\n\t\t\t\t\t\tcondition: ParamCondition.LESS_THAN_OR_EQUAL,\n\t\t\t\t\t\tvalue: params.maxPerTransfer,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t});\n\n\tconst rateLimitPolicy = toRateLimitPolicy({\n\t\tinterval: ONE_DAY_SECONDS,\n\t\tcount: params.maxTransfersPerDay,\n\t});\n\n\treturn [callPolicy, rateLimitPolicy] as const;\n}\n"]}
1
+ {"version":3,"sources":["../src/client/transfer-jpyc.ts","../src/policy/daily-limit.ts"],"names":[],"mappings":"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","file":"chunk-DLH2O4MU.js","sourcesContent":["/**\n * High-level helper: transfer JPYC from a Kernel smart account via a sponsored\n * UserOp.\n *\n * This is the canonical \"agent payment\" path for M2. The flow:\n * 1. Resolve the JPYC contract address for `kernelClient.chain`.\n * 2. Encode `JPYC.transfer(to, amount)` calldata.\n * 3. Wrap it as a Kernel call and submit via `sendUserOperation`.\n * 4. Wait for the bundler receipt and return both hashes.\n *\n * EIP-3009 `transferWithAuthorization` cannot be used here: JPYC's signature\n * verification is pure `ecrecover`, so a smart account cannot be `from`. See\n * `src/tokens/eip3009.ts` for the EOA-payer path.\n *\n * @packageDocumentation\n */\n\nimport type { KernelAccountClient } from \"@zerodev/sdk\";\nimport type { Address, Chain, Hex, Transport } from \"viem\";\nimport { encodeFunctionData, isAddress } from \"viem\";\nimport type { SmartAccount } from \"viem/account-abstraction\";\nimport { isSupportedChainId, type SupportedChainId } from \"../chains\";\nimport { getJpycAddress, jpycAbi } from \"../tokens/jpyc\";\n\n/** A {@link KernelAccountClient} that is fully configured (chain + account). */\nexport type ConfiguredKernelClient = KernelAccountClient<Transport, Chain, SmartAccount>;\n\n/** Parameters for {@link transferJpyc}. */\nexport interface TransferJpycParams {\n\t/** Recipient address. */\n\treadonly to: Address;\n\t/**\n\t * Raw token amount in the token's smallest unit (JPYC has 18 decimals).\n\t *\n\t * @example\n\t * ```ts\n\t * import { parseUnits } from \"viem\";\n\t * import { JPYC_DECIMALS } from \"kawasekit\";\n\t *\n\t * parseUnits(\"100\", JPYC_DECIMALS); // 100 JPYC\n\t * ```\n\t */\n\treadonly amount: bigint;\n\t/**\n\t * Optional. Defaults to waiting for the bundler receipt before returning.\n\t * Set to `false` to return after the UserOp is submitted but before it\n\t * lands on chain — useful when the caller wants to do its own polling.\n\t */\n\treadonly waitForReceipt?: boolean;\n}\n\n/** Result of a {@link transferJpyc} call. */\nexport interface TransferJpycResult {\n\treadonly userOpHash: Hex;\n\t/** `null` when `waitForReceipt: false` was requested. */\n\treadonly transactionHash: Hex | null;\n\t/** `true` if the bundler receipt reported success; `null` if not awaited. */\n\treadonly success: boolean | null;\n}\n\n/** Thrown when {@link transferJpyc} is called with invalid arguments. */\nexport class TransferJpycInputError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(`transferJpyc: ${message}`);\n\t\tthis.name = \"TransferJpycInputError\";\n\t}\n}\n\n/**\n * Transfer JPYC from the Kernel smart account to `to` via a sponsored UserOp.\n *\n * @example\n * ```ts\n * import { parseUnits } from \"viem\";\n * import { JPYC_DECIMALS, transferJpyc } from \"kawasekit\";\n *\n * const { userOpHash, transactionHash } = await transferJpyc(kernelClient, {\n * to: \"0xBeef0000000000000000000000000000DEADBEEF\",\n * amount: parseUnits(\"100\", JPYC_DECIMALS),\n * });\n * ```\n */\nexport async function transferJpyc(\n\tkernelClient: ConfiguredKernelClient,\n\tparams: TransferJpycParams,\n): Promise<TransferJpycResult> {\n\tif (!isAddress(params.to, { strict: false })) {\n\t\tthrow new TransferJpycInputError(`\\`to\\` is not a valid address: ${params.to}`);\n\t}\n\tif (params.amount <= 0n) {\n\t\tthrow new TransferJpycInputError(`\\`amount\\` must be positive, got ${params.amount}.`);\n\t}\n\n\tconst chainId = kernelClient.chain.id;\n\tif (!isSupportedChainId(chainId)) {\n\t\tthrow new TransferJpycInputError(`Chain ID ${chainId} is not a kawasekit-supported chain.`);\n\t}\n\tconst jpycAddress = getJpycAddress(chainId satisfies SupportedChainId);\n\n\tconst data = encodeFunctionData({\n\t\tabi: jpycAbi,\n\t\tfunctionName: \"transfer\",\n\t\targs: [params.to, params.amount],\n\t});\n\n\tconst callData = await kernelClient.account.encodeCalls([{ to: jpycAddress, value: 0n, data }]);\n\n\tconst userOpHash = await kernelClient.sendUserOperation({ callData });\n\n\tif (params.waitForReceipt === false) {\n\t\treturn { userOpHash, transactionHash: null, success: null };\n\t}\n\n\tconst receipt = await kernelClient.waitForUserOperationReceipt({ hash: userOpHash });\n\treturn {\n\t\tuserOpHash,\n\t\ttransactionHash: receipt.receipt.transactionHash,\n\t\tsuccess: receipt.success,\n\t};\n}\n","/**\n * Daily-limit spending policy for JPYC, built on ZeroDev's Permission System.\n *\n * Composes two ZeroDev policies:\n * 1. **callPolicy** — locks the session key to `JPYC.transfer(to, value)`\n * with `value ≤ maxPerTransfer`. Recipient is unrestricted in M2;\n * add allowlisting in M3 when use cases firm up.\n * 2. **rateLimitPolicy** — caps userOp count to `maxTransfersPerDay` in any\n * 24-hour rolling window.\n *\n * Effective daily cap = `maxPerTransfer × maxTransfersPerDay`. This is not a\n * cumulative-amount tracker (ZeroDev doesn't ship one), but the agent cannot\n * exceed either dimension, so the spirit of \"daily limit\" holds.\n *\n * @packageDocumentation\n */\n\nimport type { Policy } from \"@zerodev/permissions\";\nimport {\n\tCallPolicyVersion,\n\tParamCondition,\n\ttoCallPolicy,\n\ttoRateLimitPolicy,\n} from \"@zerodev/permissions/policies\";\nimport type { Address } from \"viem\";\nimport { jpycAbi } from \"../tokens/jpyc\";\n\n/** One day in seconds — the period for {@link createJpycDailyLimitPolicies}. */\nexport const ONE_DAY_SECONDS = 86_400;\n\n/** Parameters for {@link createJpycDailyLimitPolicies}. */\nexport interface CreateJpycDailyLimitPoliciesParams {\n\t/** JPYC contract address on the target chain. */\n\treadonly jpycAddress: Address;\n\t/** Maximum JPYC (in raw units) the session key may move in one transfer. */\n\treadonly maxPerTransfer: bigint;\n\t/** Maximum number of transfer userOps the session key may submit per day. */\n\treadonly maxTransfersPerDay: number;\n\t/**\n\t * ZeroDev callPolicy on-chain version. Defaults to V0_0_4 (latest at the\n\t * time of writing). Bump only after auditing the new version's semantics.\n\t */\n\treadonly callPolicyVersion?: CallPolicyVersion;\n}\n\n/**\n * Builds the ZeroDev policy bundle that enforces a JPYC daily spend limit.\n *\n * Plug the returned policies into `toPermissionValidator({ policies, … })`\n * — see {@link createAgentSmartAccount} for the common wiring.\n *\n * @example\n * ```ts\n * import { parseUnits } from \"viem\";\n * import {\n * createJpycDailyLimitPolicies,\n * getJpycAddress,\n * JPYC_DECIMALS,\n * polygonAmoy,\n * } from \"kawasekit\";\n *\n * const policies = createJpycDailyLimitPolicies({\n * jpycAddress: getJpycAddress(polygonAmoy.id),\n * maxPerTransfer: parseUnits(\"100\", JPYC_DECIMALS), // 100 JPYC / tx\n * maxTransfersPerDay: 10, // 10 tx / day\n * // effective daily cap = 1000 JPYC\n * });\n * ```\n */\nexport function createJpycDailyLimitPolicies(\n\tparams: CreateJpycDailyLimitPoliciesParams,\n): readonly [Policy, Policy] {\n\tif (params.maxPerTransfer <= 0n) {\n\t\tthrow new Error(\n\t\t\t`createJpycDailyLimitPolicies: maxPerTransfer must be positive, got ${params.maxPerTransfer}.`,\n\t\t);\n\t}\n\tif (!Number.isInteger(params.maxTransfersPerDay) || params.maxTransfersPerDay < 1) {\n\t\tthrow new Error(\n\t\t\t`createJpycDailyLimitPolicies: maxTransfersPerDay must be a positive integer, got ${params.maxTransfersPerDay}.`,\n\t\t);\n\t}\n\n\tconst callPolicy = toCallPolicy({\n\t\tpolicyVersion: params.callPolicyVersion ?? CallPolicyVersion.V0_0_4,\n\t\tpermissions: [\n\t\t\t{\n\t\t\t\ttarget: params.jpycAddress,\n\t\t\t\tabi: jpycAbi,\n\t\t\t\tfunctionName: \"transfer\",\n\t\t\t\targs: [\n\t\t\t\t\t// Recipient: any address allowed (no allowlist in M2).\n\t\t\t\t\tnull,\n\t\t\t\t\t// value: must be ≤ maxPerTransfer.\n\t\t\t\t\t{\n\t\t\t\t\t\tcondition: ParamCondition.LESS_THAN_OR_EQUAL,\n\t\t\t\t\t\tvalue: params.maxPerTransfer,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t});\n\n\tconst rateLimitPolicy = toRateLimitPolicy({\n\t\tinterval: ONE_DAY_SECONDS,\n\t\tcount: params.maxTransfersPerDay,\n\t});\n\n\treturn [callPolicy, rateLimitPolicy] as const;\n}\n"]}
@@ -248,7 +248,7 @@ async function revokeSessionKey(params) {
248
248
  const { ownerKernelClient, envelope, sessionKeySigner, policies } = params;
249
249
  if (params.invalidateInFlightNonces === true) {
250
250
  throw new Error(
251
- "revokeSessionKey: `invalidateInFlightNonces` is not implemented yet \u2014 the helper signature accepts the option to lock in the API shape, but in-flight nonce invalidation lands in M4. Hard revoke via uninstallPlugin is what runs today."
251
+ "revokeSessionKey: `invalidateInFlightNonces` is not implemented yet \u2014 the helper signature accepts the option to lock in the API shape, but in-flight nonce invalidation lands in M5. Hard revoke via uninstallPlugin is what runs today; see docs/recipes/revoke-race-mitigation.md for the four-layer operator playbook to use until then."
252
252
  );
253
253
  }
254
254
  if (getAddress(sessionKeySigner.address) !== getAddress(envelope.sessionKeyAddress)) {
@@ -300,5 +300,5 @@ async function rotateSessionKey(params) {
300
300
  }
301
301
 
302
302
  export { KAWASEKIT_SESSION_ENVELOPE_VERSION, SessionEnvelopeChainMismatchError, SessionEnvelopeParseError, SessionEnvelopeSignerMismatchError, SessionEnvelopeVersionError, createAgentSmartAccount, issueSessionKey, parseSessionEnvelope, restoreSessionAccount, revokeSessionKey, rotateSessionKey, serializeSessionEnvelope };
303
- //# sourceMappingURL=chunk-V5PUKFPL.js.map
304
- //# sourceMappingURL=chunk-V5PUKFPL.js.map
303
+ //# sourceMappingURL=chunk-KWCPYGFE.js.map
304
+ //# sourceMappingURL=chunk-KWCPYGFE.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/account/session-key.ts","../src/session/errors.ts","../src/session/envelope.ts","../src/session/issue.ts","../src/session/restore.ts","../src/session/revoke.ts","../src/session/rotate.ts"],"names":["getEntryPoint","KERNEL_V3_1","toECDSASigner","getAddress","toPermissionValidator"],"mappings":"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","file":"chunk-V5PUKFPL.js","sourcesContent":["/**\n * Agent smart account = Kernel v3.1 + ECDSA sudo validator + session-key\n * permission validator.\n *\n * The owner EOA keeps full control (sudo) and can revoke / rotate the session\n * key at any time. The session key is the day-to-day signer the AI agent\n * holds; whatever policies you attach (see {@link createJpycDailyLimitPolicies})\n * are enforced at the ERC-4337 validation phase by ZeroDev's\n * `PermissionValidator`. Violating userOps revert before execution — they\n * never spend any of the smart account's funds, and a sponsored bundler\n * cannot be tricked into paying for them either.\n *\n * @packageDocumentation\n */\n\nimport { signerToEcdsaValidator } from \"@zerodev/ecdsa-validator\";\nimport type { Policy } from \"@zerodev/permissions\";\nimport { toPermissionValidator } from \"@zerodev/permissions\";\nimport { toECDSASigner } from \"@zerodev/permissions/signers\";\nimport type { CreateKernelAccountReturnType } from \"@zerodev/sdk\";\nimport { createKernelAccount } from \"@zerodev/sdk\";\nimport { getEntryPoint, KERNEL_V3_1 } from \"@zerodev/sdk/constants\";\nimport type { EntryPointType, GetKernelVersion } from \"@zerodev/sdk/types\";\nimport type { Chain, LocalAccount, PublicClient, Transport } from \"viem\";\n\n/** Parameters for {@link createAgentSmartAccount}. */\nexport interface CreateAgentSmartAccountParams {\n\t/**\n\t * viem `PublicClient` used to read on-chain state during account derivation.\n\t */\n\treadonly publicClient: PublicClient<Transport, Chain | undefined>;\n\t/**\n\t * The owner EOA. Retains sudo authority — can install new plugins,\n\t * revoke / rotate the session key, and bypass any policy.\n\t */\n\treadonly ownerSigner: LocalAccount;\n\t/**\n\t * The day-to-day signer the agent holds. Authority is limited to whatever\n\t * `policies` allow — by default it can do nothing.\n\t */\n\treadonly sessionKeySigner: LocalAccount;\n\t/**\n\t * ZeroDev policies (e.g. {@link createJpycDailyLimitPolicies}) the session\n\t * key must satisfy at userOp validation time.\n\t */\n\treadonly policies: readonly Policy[];\n\t/**\n\t * EntryPoint version + address. Defaults to v0.7 at the canonical\n\t * ERC-4337 entry-point address.\n\t */\n\treadonly entryPoint?: EntryPointType<\"0.7\">;\n\t/** Kernel version. Defaults to {@link KERNEL_V3_1}. */\n\treadonly kernelVersion?: GetKernelVersion<\"0.7\">;\n}\n\n/**\n * Builds a Kernel v3.1 smart account with sudo (owner) + regular (session key)\n * validators wired up.\n *\n * @example\n * ```ts\n * import { parseUnits } from \"viem\";\n * import { privateKeyToAccount } from \"viem/accounts\";\n * import {\n * createAgentSmartAccount,\n * createJpycDailyLimitPolicies,\n * getJpycAddress,\n * JPYC_DECIMALS,\n * polygonAmoy,\n * } from \"kawasekit\";\n *\n * const owner = privateKeyToAccount(process.env.OWNER_PRIVATE_KEY as `0x${string}`);\n * const sessionKey = privateKeyToAccount(process.env.SESSION_KEY_PRIVATE_KEY as `0x${string}`);\n *\n * const account = await createAgentSmartAccount({\n * publicClient,\n * ownerSigner: owner,\n * sessionKeySigner: sessionKey,\n * policies: createJpycDailyLimitPolicies({\n * jpycAddress: getJpycAddress(polygonAmoy.id),\n * maxPerTransfer: parseUnits(\"100\", JPYC_DECIMALS),\n * maxTransfersPerDay: 10,\n * }),\n * });\n * ```\n */\nexport async function createAgentSmartAccount(\n\tparams: CreateAgentSmartAccountParams,\n): Promise<CreateKernelAccountReturnType<\"0.7\">> {\n\tconst entryPoint = params.entryPoint ?? getEntryPoint(\"0.7\");\n\tconst kernelVersion = params.kernelVersion ?? KERNEL_V3_1;\n\n\tconst sudoValidator = await signerToEcdsaValidator(params.publicClient, {\n\t\tsigner: params.ownerSigner,\n\t\tentryPoint,\n\t\tkernelVersion,\n\t});\n\n\tconst modularSessionSigner = await toECDSASigner({ signer: params.sessionKeySigner });\n\n\tconst permissionValidator = await toPermissionValidator(params.publicClient, {\n\t\tsigner: modularSessionSigner,\n\t\tpolicies: [...params.policies],\n\t\tentryPoint,\n\t\tkernelVersion,\n\t});\n\n\treturn createKernelAccount(params.publicClient, {\n\t\tplugins: {\n\t\t\tsudo: sudoValidator,\n\t\t\tregular: permissionValidator,\n\t\t},\n\t\tentryPoint,\n\t\tkernelVersion,\n\t});\n}\n","/**\n * Typed errors thrown by the `kawasekit/session` modules.\n *\n * Centralised so consumers can `instanceof`-discriminate without importing\n * deep paths.\n *\n * @packageDocumentation\n */\n\nimport type { Address } from \"viem\";\n\n/**\n * Thrown when {@link parseSessionEnvelope} encounters an envelope whose\n * `kawasekitVersion` does not match the current\n * {@link KAWASEKIT_SESSION_ENVELOPE_VERSION}.\n *\n * The version field is intentionally a string (\"1\") so that future migrations\n * can introduce non-numeric variants (e.g. \"1-jwe\") without breaking the\n * parser ordering.\n */\nexport class SessionEnvelopeVersionError extends Error {\n\treadonly expected: string;\n\treadonly received: unknown;\n\n\tconstructor(expected: string, received: unknown) {\n\t\tsuper(\n\t\t\t`Session envelope version mismatch: expected ${JSON.stringify(expected)}, got ${JSON.stringify(received)}.`,\n\t\t);\n\t\tthis.name = \"SessionEnvelopeVersionError\";\n\t\tthis.expected = expected;\n\t\tthis.received = received;\n\t}\n}\n\n/**\n * Thrown by `restoreSessionAccount()` when an envelope's `chainId` differs\n * from the chain the consumer is restoring on. Catches the common mistake of\n * issuing on Polygon Amoy and trying to restore on Polygon mainnet.\n */\nexport class SessionEnvelopeChainMismatchError extends Error {\n\treadonly envelopeChainId: number;\n\treadonly clientChainId: number;\n\n\tconstructor(envelopeChainId: number, clientChainId: number) {\n\t\tsuper(\n\t\t\t`Session envelope is for chain ${envelopeChainId} but the restore client is on chain ${clientChainId}.`,\n\t\t);\n\t\tthis.name = \"SessionEnvelopeChainMismatchError\";\n\t\tthis.envelopeChainId = envelopeChainId;\n\t\tthis.clientChainId = clientChainId;\n\t}\n}\n\n/**\n * Thrown by `restoreSessionAccount()` when the session-key signer the consumer\n * passes does not match the `sessionKeyAddress` recorded in the envelope.\n *\n * Defence against accidentally restoring with the wrong private key — which\n * would otherwise succeed locally and only fail at UserOp validation time.\n */\nexport class SessionEnvelopeSignerMismatchError extends Error {\n\treadonly envelopeSignerAddress: Address;\n\treadonly providedSignerAddress: Address;\n\n\tconstructor(envelopeSignerAddress: Address, providedSignerAddress: Address) {\n\t\tsuper(\n\t\t\t`Session envelope was issued for signer ${envelopeSignerAddress}, but the provided session-key signer is ${providedSignerAddress}.`,\n\t\t);\n\t\tthis.name = \"SessionEnvelopeSignerMismatchError\";\n\t\tthis.envelopeSignerAddress = envelopeSignerAddress;\n\t\tthis.providedSignerAddress = providedSignerAddress;\n\t}\n}\n\n/**\n * Thrown when {@link parseSessionEnvelope} cannot decode the input as a\n * structurally valid envelope (malformed JSON, missing fields, bad types).\n */\nexport class SessionEnvelopeParseError extends Error {\n\treadonly reason: string;\n\n\tconstructor(reason: string, options?: { cause?: unknown }) {\n\t\tsuper(`Failed to parse session envelope: ${reason}`, options);\n\t\tthis.name = \"SessionEnvelopeParseError\";\n\t\tthis.reason = reason;\n\t}\n}\n","/**\n * `KawasekitSessionEnvelope` — kawasekit's typed wrapper around ZeroDev's\n * opaque `serializePermissionAccount` blob.\n *\n * Why wrap ZeroDev's blob rather than use it directly?\n *\n * - **Fail-fast on restore**: chainId / version / signer mismatches surface as\n * typed errors instead of confusing UserOp-time reverts.\n * - **Host-UI affordances**: `expiresAt` and `policySummary` are advisory\n * fields a wallet can render (\"this session expires in 2 hours, max 100\n * JPYC/day\") before handing the blob to {@link restoreSessionAccount}.\n * - **Version pin**: when ZeroDev changes their serialization format we bump\n * {@link KAWASEKIT_SESSION_ENVELOPE_VERSION} and provide a migration; the\n * inner `serialized` field stays opaque.\n *\n * Wire format: a single JSON string. Bigint fields (`expiresAt`,\n * `policySummary.maxPerTransfer`) round-trip via decimal-string encoding so\n * the JSON itself is portable through any transport (env var, HTTP header,\n * file).\n *\n * @packageDocumentation\n */\n\nimport { type Address, isAddress } from \"viem\";\nimport { isSupportedChainId, type SupportedChainId } from \"../chains\";\nimport { SessionEnvelopeParseError, SessionEnvelopeVersionError } from \"./errors\";\n\n/**\n * Current envelope format version. Bumped when the envelope schema changes\n * in a way that breaks backward compatibility.\n */\nexport const KAWASEKIT_SESSION_ENVELOPE_VERSION = \"1\" as const;\n\n/** Type of {@link KAWASEKIT_SESSION_ENVELOPE_VERSION}. */\nexport type KawasekitSessionEnvelopeVersion = typeof KAWASEKIT_SESSION_ENVELOPE_VERSION;\n\n/**\n * Advisory summary of the spending policy attached to a session key. Useful\n * for host UI; **not** consulted at validation time (the on-chain validator\n * is the source of truth).\n */\nexport interface KawasekitSessionPolicySummary {\n\treadonly jpycAddress: Address;\n\treadonly maxPerTransfer: bigint;\n\treadonly maxTransfersPerDay: number;\n}\n\n/** kawasekit's typed envelope around a ZeroDev session-key serialization. */\nexport interface KawasekitSessionEnvelope {\n\treadonly kawasekitVersion: KawasekitSessionEnvelopeVersion;\n\treadonly chainId: SupportedChainId;\n\treadonly smartAccountAddress: Address;\n\treadonly sessionKeyAddress: Address;\n\t/** Optional unix-seconds expiry. Advisory + ideally enforced by a `TimestampPolicy`. */\n\treadonly expiresAt?: bigint;\n\treadonly policySummary?: KawasekitSessionPolicySummary;\n\t/** Opaque ZeroDev `serializePermissionAccount` output. */\n\treadonly serialized: string;\n}\n\n// ---------------------------------------------------------------------------\n// Wire (JSON) shape\n// ---------------------------------------------------------------------------\n\n/**\n * Internal: the JSON shape we (de)serialize to/from. Bigint fields are stored\n * as decimal strings. Kept separate from {@link KawasekitSessionEnvelope} so\n * the public type stays bigint-friendly while the wire stays string-only.\n */\ninterface SessionEnvelopeJson {\n\treadonly kawasekitVersion: string;\n\treadonly chainId: number;\n\treadonly smartAccountAddress: string;\n\treadonly sessionKeyAddress: string;\n\treadonly expiresAt?: string;\n\treadonly policySummary?: {\n\t\treadonly jpycAddress: string;\n\t\treadonly maxPerTransfer: string;\n\t\treadonly maxTransfersPerDay: number;\n\t};\n\treadonly serialized: string;\n}\n\n// ---------------------------------------------------------------------------\n// Validation helpers\n// ---------------------------------------------------------------------------\n\nconst UINT_DECIMAL = /^(0|[1-9][0-9]*)$/;\n\nfunction assertAddress(value: unknown, field: string): Address {\n\tif (typeof value !== \"string\" || !isAddress(value, { strict: false })) {\n\t\tthrow new SessionEnvelopeParseError(`\\`${field}\\` is not a valid address: ${String(value)}`);\n\t}\n\treturn value as Address;\n}\n\nfunction assertString(value: unknown, field: string): string {\n\tif (typeof value !== \"string\" || value === \"\") {\n\t\tthrow new SessionEnvelopeParseError(`\\`${field}\\` must be a non-empty string`);\n\t}\n\treturn value;\n}\n\nfunction assertNumber(value: unknown, field: string): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) {\n\t\tthrow new SessionEnvelopeParseError(`\\`${field}\\` must be a finite number`);\n\t}\n\treturn value;\n}\n\nfunction parseBigIntString(value: unknown, field: string): bigint {\n\tif (typeof value !== \"string\" || !UINT_DECIMAL.test(value)) {\n\t\tthrow new SessionEnvelopeParseError(\n\t\t\t`\\`${field}\\` must be a non-negative decimal string: ${String(value)}`,\n\t\t);\n\t}\n\treturn BigInt(value);\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Serialises a {@link KawasekitSessionEnvelope} to a transportable JSON string.\n *\n * The output is plain UTF-8 JSON (no base64). Callers who need\n * URL-/header-safe transport can base64-encode the result themselves.\n *\n * @example\n * ```ts\n * import { serializeSessionEnvelope } from \"kawasekit\";\n *\n * const blob = serializeSessionEnvelope(envelope);\n * fs.writeFileSync(\"agent.session\", blob);\n * ```\n */\nexport function serializeSessionEnvelope(envelope: KawasekitSessionEnvelope): string {\n\tconst json: SessionEnvelopeJson = {\n\t\tkawasekitVersion: envelope.kawasekitVersion,\n\t\tchainId: envelope.chainId,\n\t\tsmartAccountAddress: envelope.smartAccountAddress,\n\t\tsessionKeyAddress: envelope.sessionKeyAddress,\n\t\tserialized: envelope.serialized,\n\t\t...(envelope.expiresAt !== undefined ? { expiresAt: envelope.expiresAt.toString() } : {}),\n\t\t...(envelope.policySummary !== undefined\n\t\t\t? {\n\t\t\t\t\tpolicySummary: {\n\t\t\t\t\t\tjpycAddress: envelope.policySummary.jpycAddress,\n\t\t\t\t\t\tmaxPerTransfer: envelope.policySummary.maxPerTransfer.toString(),\n\t\t\t\t\t\tmaxTransfersPerDay: envelope.policySummary.maxTransfersPerDay,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {}),\n\t};\n\treturn JSON.stringify(json);\n}\n\n/**\n * Parses a JSON string back into a {@link KawasekitSessionEnvelope}, asserting\n * shape and version invariants.\n *\n * @throws {SessionEnvelopeParseError} On malformed JSON or structural errors.\n * @throws {SessionEnvelopeVersionError} On `kawasekitVersion` mismatch.\n *\n * @example\n * ```ts\n * import { parseSessionEnvelope } from \"kawasekit\";\n *\n * const envelope = parseSessionEnvelope(fs.readFileSync(\"agent.session\", \"utf8\"));\n * ```\n */\nexport function parseSessionEnvelope(input: string): KawasekitSessionEnvelope {\n\tlet raw: unknown;\n\ttry {\n\t\traw = JSON.parse(input);\n\t} catch (cause) {\n\t\tthrow new SessionEnvelopeParseError(\"input is not valid JSON\", { cause });\n\t}\n\tif (raw === null || typeof raw !== \"object\" || Array.isArray(raw)) {\n\t\tthrow new SessionEnvelopeParseError(\"input is not a JSON object\");\n\t}\n\tconst obj = raw as {\n\t\tkawasekitVersion?: unknown;\n\t\tchainId?: unknown;\n\t\tsmartAccountAddress?: unknown;\n\t\tsessionKeyAddress?: unknown;\n\t\tserialized?: unknown;\n\t\texpiresAt?: unknown;\n\t\tpolicySummary?: unknown;\n\t};\n\n\tif (obj.kawasekitVersion !== KAWASEKIT_SESSION_ENVELOPE_VERSION) {\n\t\tthrow new SessionEnvelopeVersionError(KAWASEKIT_SESSION_ENVELOPE_VERSION, obj.kawasekitVersion);\n\t}\n\tconst chainIdNum = assertNumber(obj.chainId, \"chainId\");\n\tif (!isSupportedChainId(chainIdNum)) {\n\t\tthrow new SessionEnvelopeParseError(`chainId ${chainIdNum} is not a kawasekit-supported chain`);\n\t}\n\tconst chainId: SupportedChainId = chainIdNum;\n\tconst smartAccountAddress = assertAddress(obj.smartAccountAddress, \"smartAccountAddress\");\n\tconst sessionKeyAddress = assertAddress(obj.sessionKeyAddress, \"sessionKeyAddress\");\n\tconst serialized = assertString(obj.serialized, \"serialized\");\n\n\tconst expiresAt =\n\t\tobj.expiresAt !== undefined ? parseBigIntString(obj.expiresAt, \"expiresAt\") : undefined;\n\n\tlet policySummary: KawasekitSessionPolicySummary | undefined;\n\tif (obj.policySummary !== undefined) {\n\t\tif (\n\t\t\tobj.policySummary === null ||\n\t\t\ttypeof obj.policySummary !== \"object\" ||\n\t\t\tArray.isArray(obj.policySummary)\n\t\t) {\n\t\t\tthrow new SessionEnvelopeParseError(\"`policySummary` must be a JSON object\");\n\t\t}\n\t\tconst ps = obj.policySummary as {\n\t\t\tjpycAddress?: unknown;\n\t\t\tmaxPerTransfer?: unknown;\n\t\t\tmaxTransfersPerDay?: unknown;\n\t\t};\n\t\tpolicySummary = {\n\t\t\tjpycAddress: assertAddress(ps.jpycAddress, \"policySummary.jpycAddress\"),\n\t\t\tmaxPerTransfer: parseBigIntString(ps.maxPerTransfer, \"policySummary.maxPerTransfer\"),\n\t\t\tmaxTransfersPerDay: assertNumber(ps.maxTransfersPerDay, \"policySummary.maxTransfersPerDay\"),\n\t\t};\n\t}\n\n\tconst base = {\n\t\tkawasekitVersion: KAWASEKIT_SESSION_ENVELOPE_VERSION,\n\t\tchainId,\n\t\tsmartAccountAddress,\n\t\tsessionKeyAddress,\n\t\tserialized,\n\t} as const;\n\tif (expiresAt !== undefined && policySummary !== undefined) {\n\t\treturn { ...base, expiresAt, policySummary };\n\t}\n\tif (expiresAt !== undefined) {\n\t\treturn { ...base, expiresAt };\n\t}\n\tif (policySummary !== undefined) {\n\t\treturn { ...base, policySummary };\n\t}\n\treturn base;\n}\n","/**\n * `issueSessionKey()` — owner-side primitive that builds a Kernel agent\n * account and wraps ZeroDev's `serializePermissionAccount` output in a\n * {@link KawasekitSessionEnvelope}.\n *\n * The envelope is portable: callers can hand it to an agent on a different\n * machine, the agent passes it to {@link restoreSessionAccount} along with the\n * session-key private key, and it ends up holding a `KernelAccountClient`\n * scoped to the policies installed at issue time.\n *\n * The owner retains sudo authority on-chain and can revoke at any time via\n * `revokeSessionKey()` (task 2.5).\n *\n * @packageDocumentation\n */\n\nimport type { Policy } from \"@zerodev/permissions\";\nimport { serializePermissionAccount } from \"@zerodev/permissions\";\nimport { getEntryPoint, KERNEL_V3_1 } from \"@zerodev/sdk/constants\";\nimport type { EntryPointType, GetKernelVersion } from \"@zerodev/sdk/types\";\nimport type { Chain, LocalAccount, PublicClient, Transport } from \"viem\";\nimport { createAgentSmartAccount } from \"../account/session-key\";\nimport { isSupportedChainId, type SupportedChainId } from \"../chains\";\nimport {\n\tKAWASEKIT_SESSION_ENVELOPE_VERSION,\n\ttype KawasekitSessionEnvelope,\n\ttype KawasekitSessionPolicySummary,\n} from \"./envelope\";\n\n/** Parameters for {@link issueSessionKey}. */\nexport interface IssueSessionKeyParams {\n\t/**\n\t * viem `PublicClient` on the chain the smart account will live on. Its\n\t * `chain.id` MUST be a {@link SupportedChainId} and is recorded in the\n\t * envelope so restore-time mismatches fail fast.\n\t */\n\treadonly publicClient: PublicClient<Transport, Chain>;\n\t/** Owner EOA — retains sudo authority. */\n\treadonly ownerSigner: LocalAccount;\n\t/** Session-key EOA — the day-to-day signer the agent will hold. */\n\treadonly sessionKeySigner: LocalAccount;\n\t/**\n\t * Policies the session key must satisfy at userOp validation time\n\t * (e.g. {@link createJpycDailyLimitPolicies}).\n\t */\n\treadonly policies: readonly Policy[];\n\t/** Optional advisory expiry (unix seconds). Recorded in the envelope. */\n\treadonly expiresAt?: bigint;\n\t/** Optional advisory policy summary for host UI. */\n\treadonly policySummary?: KawasekitSessionPolicySummary;\n\t/** EntryPoint override. Defaults to v0.7. */\n\treadonly entryPoint?: EntryPointType<\"0.7\">;\n\t/** Kernel version override. Defaults to {@link KERNEL_V3_1}. */\n\treadonly kernelVersion?: GetKernelVersion<\"0.7\">;\n}\n\n/**\n * Issues a fresh session key for an agent smart account.\n *\n * Notes:\n * - The session-key **private key is not embedded** in the returned envelope.\n * The agent must receive the private key out-of-band; the envelope alone is\n * not enough to spend.\n * - The smart account is **not deployed** by this call. It will be deployed\n * on first userOp from `restoreSessionAccount`.\n *\n * @example\n * ```ts\n * import { parseUnits } from \"viem\";\n * import { privateKeyToAccount } from \"viem/accounts\";\n * import {\n * createJpycDailyLimitPolicies,\n * getJpycAddress,\n * issueSessionKey,\n * JPYC_DECIMALS,\n * polygonAmoy,\n * serializeSessionEnvelope,\n * } from \"kawasekit\";\n *\n * const owner = privateKeyToAccount(process.env.OWNER_PRIVATE_KEY as `0x${string}`);\n * const sessionKey = privateKeyToAccount(process.env.SESSION_KEY_PRIVATE_KEY as `0x${string}`);\n *\n * const envelope = await issueSessionKey({\n * publicClient,\n * ownerSigner: owner,\n * sessionKeySigner: sessionKey,\n * policies: createJpycDailyLimitPolicies({\n * jpycAddress: getJpycAddress(polygonAmoy.id),\n * maxPerTransfer: parseUnits(\"100\", JPYC_DECIMALS),\n * maxTransfersPerDay: 10,\n * }),\n * policySummary: {\n * jpycAddress: getJpycAddress(polygonAmoy.id),\n * maxPerTransfer: parseUnits(\"100\", JPYC_DECIMALS),\n * maxTransfersPerDay: 10,\n * },\n * });\n *\n * fs.writeFileSync(\"agent.session\", serializeSessionEnvelope(envelope));\n * ```\n */\nexport async function issueSessionKey(\n\tparams: IssueSessionKeyParams,\n): Promise<KawasekitSessionEnvelope> {\n\tconst chainId = params.publicClient.chain.id;\n\tif (!isSupportedChainId(chainId)) {\n\t\tthrow new Error(\n\t\t\t`issueSessionKey: publicClient.chain.id ${chainId} is not a kawasekit-supported chain`,\n\t\t);\n\t}\n\tconst supportedChainId: SupportedChainId = chainId;\n\tconst entryPoint = params.entryPoint ?? getEntryPoint(\"0.7\");\n\tconst kernelVersion = params.kernelVersion ?? KERNEL_V3_1;\n\n\tconst account = await createAgentSmartAccount({\n\t\tpublicClient: params.publicClient,\n\t\townerSigner: params.ownerSigner,\n\t\tsessionKeySigner: params.sessionKeySigner,\n\t\tpolicies: params.policies,\n\t\tentryPoint,\n\t\tkernelVersion,\n\t});\n\n\tconst serialized = await serializePermissionAccount(account);\n\n\tconst base = {\n\t\tkawasekitVersion: KAWASEKIT_SESSION_ENVELOPE_VERSION,\n\t\tchainId: supportedChainId,\n\t\tsmartAccountAddress: account.address,\n\t\tsessionKeyAddress: params.sessionKeySigner.address,\n\t\tserialized,\n\t} as const;\n\tif (params.expiresAt !== undefined && params.policySummary !== undefined) {\n\t\treturn {\n\t\t\t...base,\n\t\t\texpiresAt: params.expiresAt,\n\t\t\tpolicySummary: params.policySummary,\n\t\t};\n\t}\n\tif (params.expiresAt !== undefined) {\n\t\treturn { ...base, expiresAt: params.expiresAt };\n\t}\n\tif (params.policySummary !== undefined) {\n\t\treturn { ...base, policySummary: params.policySummary };\n\t}\n\treturn base;\n}\n","/**\n * `restoreSessionAccount()` — agent-side primitive that unwraps a\n * {@link KawasekitSessionEnvelope} back into a usable Kernel account scoped\n * to the policies installed at issue time.\n *\n * Three invariants are checked **before** touching ZeroDev's deserialization\n * so that misconfiguration manifests as a typed error here, not a confusing\n * UserOp-time revert:\n *\n * 1. `envelope.kawasekitVersion` matches the current envelope version\n * (already enforced by {@link parseSessionEnvelope}; re-checked here for\n * callers who construct the envelope object directly).\n * 2. `envelope.chainId === publicClient.chain.id`.\n * 3. `envelope.sessionKeyAddress` matches the provided `sessionKeySigner`.\n *\n * @packageDocumentation\n */\n\nimport { deserializePermissionAccount } from \"@zerodev/permissions\";\nimport { toECDSASigner } from \"@zerodev/permissions/signers\";\nimport type { CreateKernelAccountReturnType } from \"@zerodev/sdk\";\nimport { getEntryPoint, KERNEL_V3_1 } from \"@zerodev/sdk/constants\";\nimport type { EntryPointType, GetKernelVersion } from \"@zerodev/sdk/types\";\nimport { type Chain, getAddress, type LocalAccount, type PublicClient, type Transport } from \"viem\";\nimport { KAWASEKIT_SESSION_ENVELOPE_VERSION, type KawasekitSessionEnvelope } from \"./envelope\";\nimport {\n\tSessionEnvelopeChainMismatchError,\n\tSessionEnvelopeSignerMismatchError,\n\tSessionEnvelopeVersionError,\n} from \"./errors\";\n\n/** Parameters for {@link restoreSessionAccount}. */\nexport interface RestoreSessionAccountParams {\n\t/** Must be on the same chain the envelope was issued for. */\n\treadonly publicClient: PublicClient<Transport, Chain>;\n\t/** Envelope produced by {@link issueSessionKey} (or parsed via {@link parseSessionEnvelope}). */\n\treadonly envelope: KawasekitSessionEnvelope;\n\t/**\n\t * The session-key signer the agent holds. Its address MUST equal\n\t * `envelope.sessionKeyAddress` — otherwise the restored account would\n\t * sign userOps that the on-chain permission validator rejects.\n\t */\n\treadonly sessionKeySigner: LocalAccount;\n\t/** EntryPoint override. Defaults to v0.7. */\n\treadonly entryPoint?: EntryPointType<\"0.7\">;\n\t/** Kernel version override. Defaults to {@link KERNEL_V3_1}. */\n\treadonly kernelVersion?: GetKernelVersion<\"0.7\">;\n}\n\n/**\n * Rebuilds the Kernel account from an envelope + the session-key signer.\n *\n * @throws {SessionEnvelopeVersionError} If `envelope.kawasekitVersion` does\n * not match the current envelope version.\n * @throws {SessionEnvelopeChainMismatchError} If `envelope.chainId !==\n * publicClient.chain.id`.\n * @throws {SessionEnvelopeSignerMismatchError} If `sessionKeySigner.address !==\n * envelope.sessionKeyAddress`.\n *\n * @example\n * ```ts\n * import { createPublicClient, http } from \"viem\";\n * import { privateKeyToAccount } from \"viem/accounts\";\n * import {\n * parseSessionEnvelope,\n * polygonAmoy,\n * restoreSessionAccount,\n * } from \"kawasekit\";\n *\n * const publicClient = createPublicClient({\n * chain: polygonAmoy,\n * transport: http(),\n * });\n * const envelope = parseSessionEnvelope(fs.readFileSync(\"agent.session\", \"utf8\"));\n * const sessionKey = privateKeyToAccount(process.env.SESSION_KEY_PRIVATE_KEY as `0x${string}`);\n *\n * const account = await restoreSessionAccount({\n * publicClient,\n * envelope,\n * sessionKeySigner: sessionKey,\n * });\n * ```\n */\nexport async function restoreSessionAccount(\n\tparams: RestoreSessionAccountParams,\n): Promise<CreateKernelAccountReturnType<\"0.7\">> {\n\tconst { publicClient, envelope, sessionKeySigner } = params;\n\n\tif (envelope.kawasekitVersion !== KAWASEKIT_SESSION_ENVELOPE_VERSION) {\n\t\tthrow new SessionEnvelopeVersionError(\n\t\t\tKAWASEKIT_SESSION_ENVELOPE_VERSION,\n\t\t\tenvelope.kawasekitVersion,\n\t\t);\n\t}\n\tif (publicClient.chain.id !== envelope.chainId) {\n\t\tthrow new SessionEnvelopeChainMismatchError(envelope.chainId, publicClient.chain.id);\n\t}\n\tif (getAddress(sessionKeySigner.address) !== getAddress(envelope.sessionKeyAddress)) {\n\t\tthrow new SessionEnvelopeSignerMismatchError(\n\t\t\tenvelope.sessionKeyAddress,\n\t\t\tsessionKeySigner.address,\n\t\t);\n\t}\n\n\tconst entryPoint = params.entryPoint ?? getEntryPoint(\"0.7\");\n\tconst kernelVersion = params.kernelVersion ?? KERNEL_V3_1;\n\tconst modularSigner = await toECDSASigner({ signer: sessionKeySigner });\n\n\treturn deserializePermissionAccount(\n\t\tpublicClient,\n\t\tentryPoint,\n\t\tkernelVersion,\n\t\tenvelope.serialized,\n\t\tmodularSigner,\n\t);\n}\n","/**\n * `revokeSessionKey()` — owner-side primitive that uninstalls a session-key\n * permission validator from the agent's smart account.\n *\n * Implementation strategy (per plan §risk #3): ZeroDev does not expose a\n * dedicated revoke helper, so we re-derive the `PermissionPlugin` from the\n * envelope's `sessionKeyAddress` + the same policies that were installed at\n * issue time, then submit a sudo UserOp via `@zerodev/sdk`'s\n * {@link uninstallPlugin} action. After the receipt, the session key can no\n * longer sign UserOps the validator would accept.\n *\n * In-flight UserOps already submitted to the bundler but not yet mined can\n * still settle before the uninstall transaction lands. A future \"soft revoke\"\n * via `invalidateNonce` on the session-key validator's nonce key will close\n * that race; tracked for M4 (the helper signature accepts an\n * `invalidateInFlightNonces` option today and throws `\"not implemented\"` to\n * lock in the API shape).\n *\n * @packageDocumentation\n */\n\nimport type { Policy } from \"@zerodev/permissions\";\nimport { toPermissionValidator } from \"@zerodev/permissions\";\nimport { toECDSASigner } from \"@zerodev/permissions/signers\";\nimport { uninstallPlugin } from \"@zerodev/sdk\";\nimport { getEntryPoint, KERNEL_V3_1 } from \"@zerodev/sdk/constants\";\nimport type { EntryPointType, GetKernelVersion } from \"@zerodev/sdk/types\";\nimport { getAddress, type Hash, type LocalAccount } from \"viem\";\nimport type { ConfiguredKernelClient } from \"../client/transfer-jpyc\";\nimport type { KawasekitSessionEnvelope } from \"./envelope\";\nimport { SessionEnvelopeSignerMismatchError } from \"./errors\";\n\n/** Parameters for {@link revokeSessionKey}. */\nexport interface RevokeSessionKeyParams {\n\t/**\n\t * The owner's sudo Kernel client — the only entity that can call\n\t * `uninstallValidation` on the agent account.\n\t *\n\t * **CRITICAL: must be a SUDO-ONLY kernel account** (i.e.\n\t * `createKernelAccount(publicClient, { plugins: { sudo: ecdsaValidator } })`\n\t * — no `regular` plugin). If you pass a client whose account also has the\n\t * session-key permission validator wired as `regular`, ZeroDev signs\n\t * userOps with that validator by default and the spending policy will\n\t * reject `uninstallValidation` at the validation phase (`AA23 reverted`).\n\t *\n\t * The counterfactual smart-account address only depends on the sudo\n\t * validator in Kernel v3.1, so a sudo-only client points at the SAME\n\t * account as one built with both sudo + regular.\n\t *\n\t * Its `account.address` MUST equal `envelope.smartAccountAddress`.\n\t */\n\treadonly ownerKernelClient: ConfiguredKernelClient;\n\t/** The envelope of the session being revoked. */\n\treadonly envelope: KawasekitSessionEnvelope;\n\t/**\n\t * A LocalAccount whose address equals `envelope.sessionKeyAddress`. Used\n\t * to reconstruct the validator's on-chain identifier; no signing is\n\t * actually performed with this account during revoke.\n\t */\n\treadonly sessionKeySigner: LocalAccount;\n\t/**\n\t * The policies that were installed at issue time. ZeroDev does not store\n\t * these on-chain in a retrievable form, so the caller MUST re-supply\n\t * them. Mismatches surface as an `uninstallValidation` revert at userOp\n\t * validation time.\n\t */\n\treadonly policies: readonly Policy[];\n\t/**\n\t * Future option: also invalidate the session-key validator's nonce key\n\t * to kill in-flight UserOps. Not implemented in M3 — passing `true`\n\t * throws.\n\t */\n\treadonly invalidateInFlightNonces?: boolean;\n\t/** EntryPoint override. Defaults to v0.7. */\n\treadonly entryPoint?: EntryPointType<\"0.7\">;\n\t/** Kernel version override. Defaults to {@link KERNEL_V3_1}. */\n\treadonly kernelVersion?: GetKernelVersion<\"0.7\">;\n\t/**\n\t * If `false`, return after submitting the UserOp without waiting for the\n\t * bundler receipt. Default `true` (wait).\n\t */\n\treadonly waitForReceipt?: boolean;\n}\n\n/** Result of {@link revokeSessionKey}. */\nexport interface RevokeSessionKeyResult {\n\t/** Hash of the uninstall UserOp. */\n\treadonly userOpHash: Hash;\n\t/** Bundler transaction hash, present when `waitForReceipt` (default true). */\n\treadonly transactionHash: Hash | null;\n\t/** `true` if the bundler reported success, `null` if not awaited. */\n\treadonly success: boolean | null;\n}\n\n/**\n * Uninstalls a session-key permission validator from the agent's smart\n * account. After the returned UserOp lands, the session key can no longer\n * authorise actions.\n *\n * @throws {SessionEnvelopeSignerMismatchError} If `sessionKeySigner.address`\n * does not match `envelope.sessionKeyAddress`.\n * @throws {Error} If `invalidateInFlightNonces` is `true` (M4).\n *\n * @example\n * ```ts\n * import { signerToEcdsaValidator } from \"@zerodev/ecdsa-validator\";\n * import { createKernelAccount, createKernelAccountClient } from \"@zerodev/sdk\";\n * import { getEntryPoint, KERNEL_V3_1 } from \"@zerodev/sdk/constants\";\n * import { revokeSessionKey } from \"kawasekit\";\n *\n * // Build a SUDO-ONLY kernel account for the owner — see param JSDoc.\n * const sudoValidator = await signerToEcdsaValidator(publicClient, {\n * signer: owner,\n * entryPoint: getEntryPoint(\"0.7\"),\n * kernelVersion: KERNEL_V3_1,\n * });\n * const ownerSudoAccount = await createKernelAccount(publicClient, {\n * plugins: { sudo: sudoValidator },\n * entryPoint: getEntryPoint(\"0.7\"),\n * kernelVersion: KERNEL_V3_1,\n * });\n * const ownerKernelClient = createKernelAccountClient({\n * account: ownerSudoAccount,\n * chain,\n * client: publicClient,\n * bundlerTransport,\n * paymaster,\n * });\n *\n * await revokeSessionKey({\n * ownerKernelClient,\n * envelope,\n * sessionKeySigner,\n * policies: createJpycDailyLimitPolicies({ ... }),\n * });\n * ```\n */\nexport async function revokeSessionKey(\n\tparams: RevokeSessionKeyParams,\n): Promise<RevokeSessionKeyResult> {\n\tconst { ownerKernelClient, envelope, sessionKeySigner, policies } = params;\n\n\tif (params.invalidateInFlightNonces === true) {\n\t\tthrow new Error(\n\t\t\t\"revokeSessionKey: `invalidateInFlightNonces` is not implemented yet — the helper signature accepts the option to lock in the API shape, but in-flight nonce invalidation lands in M4. Hard revoke via uninstallPlugin is what runs today.\",\n\t\t);\n\t}\n\n\tif (getAddress(sessionKeySigner.address) !== getAddress(envelope.sessionKeyAddress)) {\n\t\tthrow new SessionEnvelopeSignerMismatchError(\n\t\t\tenvelope.sessionKeyAddress,\n\t\t\tsessionKeySigner.address,\n\t\t);\n\t}\n\n\tif (getAddress(ownerKernelClient.account.address) !== getAddress(envelope.smartAccountAddress)) {\n\t\tthrow new Error(\n\t\t\t`revokeSessionKey: ownerKernelClient is bound to ${ownerKernelClient.account.address}, but envelope is for ${envelope.smartAccountAddress}.`,\n\t\t);\n\t}\n\n\tconst entryPoint = params.entryPoint ?? getEntryPoint(\"0.7\");\n\tconst kernelVersion = params.kernelVersion ?? KERNEL_V3_1;\n\n\tif (ownerKernelClient.client === undefined) {\n\t\tthrow new Error(\n\t\t\t\"revokeSessionKey: ownerKernelClient.client is undefined — pass `client: publicClient` when constructing the Kernel client so the validator can be reconstructed.\",\n\t\t);\n\t}\n\n\tconst modularSigner = await toECDSASigner({ signer: sessionKeySigner });\n\tconst permissionPlugin = await toPermissionValidator(ownerKernelClient.client, {\n\t\tsigner: modularSigner,\n\t\tpolicies: [...policies],\n\t\tentryPoint,\n\t\tkernelVersion,\n\t});\n\n\tconst userOpHash = await uninstallPlugin(ownerKernelClient, {\n\t\tplugin: permissionPlugin,\n\t});\n\n\tif (params.waitForReceipt === false) {\n\t\treturn { userOpHash, transactionHash: null, success: null };\n\t}\n\n\tconst receipt = await ownerKernelClient.waitForUserOperationReceipt({\n\t\thash: userOpHash,\n\t});\n\treturn {\n\t\tuserOpHash,\n\t\ttransactionHash: receipt.receipt.transactionHash,\n\t\tsuccess: receipt.success,\n\t};\n}\n","/**\n * `rotateSessionKey()` — a thin compositional helper that revokes the\n * current session key and issues a new one in sequence.\n *\n * Compose-don't-conflate: rotate is just `revoke` followed by `issue`. Both\n * primitives are exposed individually so callers who need finer control\n * (e.g. revoke now, issue tomorrow with different policies) can chain them\n * themselves.\n *\n * @packageDocumentation\n */\n\nimport type { KawasekitSessionEnvelope } from \"./envelope\";\nimport { type IssueSessionKeyParams, issueSessionKey } from \"./issue\";\nimport {\n\ttype RevokeSessionKeyParams,\n\ttype RevokeSessionKeyResult,\n\trevokeSessionKey,\n} from \"./revoke\";\n\n/** Parameters for {@link rotateSessionKey}. */\nexport interface RotateSessionKeyParams {\n\t/** Inputs for revoking the current session. `waitForReceipt` is forced `true`. */\n\treadonly revoke: Omit<RevokeSessionKeyParams, \"waitForReceipt\">;\n\t/** Inputs for issuing the replacement session. */\n\treadonly issue: IssueSessionKeyParams;\n}\n\n/** Result of {@link rotateSessionKey}. */\nexport interface RotateSessionKeyResult {\n\t/** Outcome of the revoke step. */\n\treadonly revoke: RevokeSessionKeyResult;\n\t/** The freshly issued replacement envelope. */\n\treadonly envelope: KawasekitSessionEnvelope;\n}\n\n/**\n * Atomically rotate the agent's session key: revoke the old, issue the new.\n *\n * The revoke is always awaited to the bundler receipt — issuing a replacement\n * before the old key is actually disarmed would leave two valid signers at\n * once, defeating the point.\n *\n * @example\n * ```ts\n * import { rotateSessionKey } from \"kawasekit\";\n *\n * const { revoke, envelope } = await rotateSessionKey({\n * revoke: {\n * ownerKernelClient,\n * envelope: oldEnvelope,\n * sessionKeySigner: oldSessionKeySigner,\n * policies: oldPolicies,\n * },\n * issue: {\n * publicClient,\n * ownerSigner,\n * sessionKeySigner: newSessionKeySigner,\n * policies: newPolicies,\n * },\n * });\n * ```\n */\nexport async function rotateSessionKey(\n\tparams: RotateSessionKeyParams,\n): Promise<RotateSessionKeyResult> {\n\tconst revoke = await revokeSessionKey({ ...params.revoke, waitForReceipt: true });\n\tconst envelope = await issueSessionKey(params.issue);\n\treturn { revoke, envelope };\n}\n"]}
1
+ {"version":3,"sources":["../src/account/session-key.ts","../src/session/errors.ts","../src/session/envelope.ts","../src/session/issue.ts","../src/session/restore.ts","../src/session/revoke.ts","../src/session/rotate.ts"],"names":["getEntryPoint","KERNEL_V3_1","toECDSASigner","getAddress","toPermissionValidator"],"mappings":"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","file":"chunk-KWCPYGFE.js","sourcesContent":["/**\n * Agent smart account = Kernel v3.1 + ECDSA sudo validator + session-key\n * permission validator.\n *\n * The owner EOA keeps full control (sudo) and can revoke / rotate the session\n * key at any time. The session key is the day-to-day signer the AI agent\n * holds; whatever policies you attach (see {@link createJpycDailyLimitPolicies})\n * are enforced at the ERC-4337 validation phase by ZeroDev's\n * `PermissionValidator`. Violating userOps revert before execution — they\n * never spend any of the smart account's funds, and a sponsored bundler\n * cannot be tricked into paying for them either.\n *\n * @packageDocumentation\n */\n\nimport { signerToEcdsaValidator } from \"@zerodev/ecdsa-validator\";\nimport type { Policy } from \"@zerodev/permissions\";\nimport { toPermissionValidator } from \"@zerodev/permissions\";\nimport { toECDSASigner } from \"@zerodev/permissions/signers\";\nimport type { CreateKernelAccountReturnType } from \"@zerodev/sdk\";\nimport { createKernelAccount } from \"@zerodev/sdk\";\nimport { getEntryPoint, KERNEL_V3_1 } from \"@zerodev/sdk/constants\";\nimport type { EntryPointType, GetKernelVersion } from \"@zerodev/sdk/types\";\nimport type { Chain, LocalAccount, PublicClient, Transport } from \"viem\";\n\n/** Parameters for {@link createAgentSmartAccount}. */\nexport interface CreateAgentSmartAccountParams {\n\t/**\n\t * viem `PublicClient` used to read on-chain state during account derivation.\n\t */\n\treadonly publicClient: PublicClient<Transport, Chain | undefined>;\n\t/**\n\t * The owner EOA. Retains sudo authority — can install new plugins,\n\t * revoke / rotate the session key, and bypass any policy.\n\t */\n\treadonly ownerSigner: LocalAccount;\n\t/**\n\t * The day-to-day signer the agent holds. Authority is limited to whatever\n\t * `policies` allow — by default it can do nothing.\n\t */\n\treadonly sessionKeySigner: LocalAccount;\n\t/**\n\t * ZeroDev policies (e.g. {@link createJpycDailyLimitPolicies}) the session\n\t * key must satisfy at userOp validation time.\n\t */\n\treadonly policies: readonly Policy[];\n\t/**\n\t * EntryPoint version + address. Defaults to v0.7 at the canonical\n\t * ERC-4337 entry-point address.\n\t */\n\treadonly entryPoint?: EntryPointType<\"0.7\">;\n\t/** Kernel version. Defaults to {@link KERNEL_V3_1}. */\n\treadonly kernelVersion?: GetKernelVersion<\"0.7\">;\n}\n\n/**\n * Builds a Kernel v3.1 smart account with sudo (owner) + regular (session key)\n * validators wired up.\n *\n * @example\n * ```ts\n * import { parseUnits } from \"viem\";\n * import { privateKeyToAccount } from \"viem/accounts\";\n * import {\n * createAgentSmartAccount,\n * createJpycDailyLimitPolicies,\n * getJpycAddress,\n * JPYC_DECIMALS,\n * polygonAmoy,\n * } from \"kawasekit\";\n *\n * const owner = privateKeyToAccount(process.env.OWNER_PRIVATE_KEY as `0x${string}`);\n * const sessionKey = privateKeyToAccount(process.env.SESSION_KEY_PRIVATE_KEY as `0x${string}`);\n *\n * const account = await createAgentSmartAccount({\n * publicClient,\n * ownerSigner: owner,\n * sessionKeySigner: sessionKey,\n * policies: createJpycDailyLimitPolicies({\n * jpycAddress: getJpycAddress(polygonAmoy.id),\n * maxPerTransfer: parseUnits(\"100\", JPYC_DECIMALS),\n * maxTransfersPerDay: 10,\n * }),\n * });\n * ```\n */\nexport async function createAgentSmartAccount(\n\tparams: CreateAgentSmartAccountParams,\n): Promise<CreateKernelAccountReturnType<\"0.7\">> {\n\tconst entryPoint = params.entryPoint ?? getEntryPoint(\"0.7\");\n\tconst kernelVersion = params.kernelVersion ?? KERNEL_V3_1;\n\n\tconst sudoValidator = await signerToEcdsaValidator(params.publicClient, {\n\t\tsigner: params.ownerSigner,\n\t\tentryPoint,\n\t\tkernelVersion,\n\t});\n\n\tconst modularSessionSigner = await toECDSASigner({ signer: params.sessionKeySigner });\n\n\tconst permissionValidator = await toPermissionValidator(params.publicClient, {\n\t\tsigner: modularSessionSigner,\n\t\tpolicies: [...params.policies],\n\t\tentryPoint,\n\t\tkernelVersion,\n\t});\n\n\treturn createKernelAccount(params.publicClient, {\n\t\tplugins: {\n\t\t\tsudo: sudoValidator,\n\t\t\tregular: permissionValidator,\n\t\t},\n\t\tentryPoint,\n\t\tkernelVersion,\n\t});\n}\n","/**\n * Typed errors thrown by the `kawasekit/session` modules.\n *\n * Centralised so consumers can `instanceof`-discriminate without importing\n * deep paths.\n *\n * @packageDocumentation\n */\n\nimport type { Address } from \"viem\";\n\n/**\n * Thrown when {@link parseSessionEnvelope} encounters an envelope whose\n * `kawasekitVersion` does not match the current\n * {@link KAWASEKIT_SESSION_ENVELOPE_VERSION}.\n *\n * The version field is intentionally a string (\"1\") so that future migrations\n * can introduce non-numeric variants (e.g. \"1-jwe\") without breaking the\n * parser ordering.\n */\nexport class SessionEnvelopeVersionError extends Error {\n\treadonly expected: string;\n\treadonly received: unknown;\n\n\tconstructor(expected: string, received: unknown) {\n\t\tsuper(\n\t\t\t`Session envelope version mismatch: expected ${JSON.stringify(expected)}, got ${JSON.stringify(received)}.`,\n\t\t);\n\t\tthis.name = \"SessionEnvelopeVersionError\";\n\t\tthis.expected = expected;\n\t\tthis.received = received;\n\t}\n}\n\n/**\n * Thrown by `restoreSessionAccount()` when an envelope's `chainId` differs\n * from the chain the consumer is restoring on. Catches the common mistake of\n * issuing on Polygon Amoy and trying to restore on Polygon mainnet.\n */\nexport class SessionEnvelopeChainMismatchError extends Error {\n\treadonly envelopeChainId: number;\n\treadonly clientChainId: number;\n\n\tconstructor(envelopeChainId: number, clientChainId: number) {\n\t\tsuper(\n\t\t\t`Session envelope is for chain ${envelopeChainId} but the restore client is on chain ${clientChainId}.`,\n\t\t);\n\t\tthis.name = \"SessionEnvelopeChainMismatchError\";\n\t\tthis.envelopeChainId = envelopeChainId;\n\t\tthis.clientChainId = clientChainId;\n\t}\n}\n\n/**\n * Thrown by `restoreSessionAccount()` when the session-key signer the consumer\n * passes does not match the `sessionKeyAddress` recorded in the envelope.\n *\n * Defence against accidentally restoring with the wrong private key — which\n * would otherwise succeed locally and only fail at UserOp validation time.\n */\nexport class SessionEnvelopeSignerMismatchError extends Error {\n\treadonly envelopeSignerAddress: Address;\n\treadonly providedSignerAddress: Address;\n\n\tconstructor(envelopeSignerAddress: Address, providedSignerAddress: Address) {\n\t\tsuper(\n\t\t\t`Session envelope was issued for signer ${envelopeSignerAddress}, but the provided session-key signer is ${providedSignerAddress}.`,\n\t\t);\n\t\tthis.name = \"SessionEnvelopeSignerMismatchError\";\n\t\tthis.envelopeSignerAddress = envelopeSignerAddress;\n\t\tthis.providedSignerAddress = providedSignerAddress;\n\t}\n}\n\n/**\n * Thrown when {@link parseSessionEnvelope} cannot decode the input as a\n * structurally valid envelope (malformed JSON, missing fields, bad types).\n */\nexport class SessionEnvelopeParseError extends Error {\n\treadonly reason: string;\n\n\tconstructor(reason: string, options?: { cause?: unknown }) {\n\t\tsuper(`Failed to parse session envelope: ${reason}`, options);\n\t\tthis.name = \"SessionEnvelopeParseError\";\n\t\tthis.reason = reason;\n\t}\n}\n","/**\n * `KawasekitSessionEnvelope` — kawasekit's typed wrapper around ZeroDev's\n * opaque `serializePermissionAccount` blob.\n *\n * Why wrap ZeroDev's blob rather than use it directly?\n *\n * - **Fail-fast on restore**: chainId / version / signer mismatches surface as\n * typed errors instead of confusing UserOp-time reverts.\n * - **Host-UI affordances**: `expiresAt` and `policySummary` are advisory\n * fields a wallet can render (\"this session expires in 2 hours, max 100\n * JPYC/day\") before handing the blob to {@link restoreSessionAccount}.\n * - **Version pin**: when ZeroDev changes their serialization format we bump\n * {@link KAWASEKIT_SESSION_ENVELOPE_VERSION} and provide a migration; the\n * inner `serialized` field stays opaque.\n *\n * Wire format: a single JSON string. Bigint fields (`expiresAt`,\n * `policySummary.maxPerTransfer`) round-trip via decimal-string encoding so\n * the JSON itself is portable through any transport (env var, HTTP header,\n * file).\n *\n * @packageDocumentation\n */\n\nimport { type Address, isAddress } from \"viem\";\nimport { isSupportedChainId, type SupportedChainId } from \"../chains\";\nimport { SessionEnvelopeParseError, SessionEnvelopeVersionError } from \"./errors\";\n\n/**\n * Current envelope format version. Bumped when the envelope schema changes\n * in a way that breaks backward compatibility.\n */\nexport const KAWASEKIT_SESSION_ENVELOPE_VERSION = \"1\" as const;\n\n/** Type of {@link KAWASEKIT_SESSION_ENVELOPE_VERSION}. */\nexport type KawasekitSessionEnvelopeVersion = typeof KAWASEKIT_SESSION_ENVELOPE_VERSION;\n\n/**\n * Advisory summary of the spending policy attached to a session key. Useful\n * for host UI; **not** consulted at validation time (the on-chain validator\n * is the source of truth).\n */\nexport interface KawasekitSessionPolicySummary {\n\treadonly jpycAddress: Address;\n\treadonly maxPerTransfer: bigint;\n\treadonly maxTransfersPerDay: number;\n}\n\n/** kawasekit's typed envelope around a ZeroDev session-key serialization. */\nexport interface KawasekitSessionEnvelope {\n\treadonly kawasekitVersion: KawasekitSessionEnvelopeVersion;\n\treadonly chainId: SupportedChainId;\n\treadonly smartAccountAddress: Address;\n\treadonly sessionKeyAddress: Address;\n\t/** Optional unix-seconds expiry. Advisory + ideally enforced by a `TimestampPolicy`. */\n\treadonly expiresAt?: bigint;\n\treadonly policySummary?: KawasekitSessionPolicySummary;\n\t/** Opaque ZeroDev `serializePermissionAccount` output. */\n\treadonly serialized: string;\n}\n\n// ---------------------------------------------------------------------------\n// Wire (JSON) shape\n// ---------------------------------------------------------------------------\n\n/**\n * Internal: the JSON shape we (de)serialize to/from. Bigint fields are stored\n * as decimal strings. Kept separate from {@link KawasekitSessionEnvelope} so\n * the public type stays bigint-friendly while the wire stays string-only.\n */\ninterface SessionEnvelopeJson {\n\treadonly kawasekitVersion: string;\n\treadonly chainId: number;\n\treadonly smartAccountAddress: string;\n\treadonly sessionKeyAddress: string;\n\treadonly expiresAt?: string;\n\treadonly policySummary?: {\n\t\treadonly jpycAddress: string;\n\t\treadonly maxPerTransfer: string;\n\t\treadonly maxTransfersPerDay: number;\n\t};\n\treadonly serialized: string;\n}\n\n// ---------------------------------------------------------------------------\n// Validation helpers\n// ---------------------------------------------------------------------------\n\nconst UINT_DECIMAL = /^(0|[1-9][0-9]*)$/;\n\nfunction assertAddress(value: unknown, field: string): Address {\n\tif (typeof value !== \"string\" || !isAddress(value, { strict: false })) {\n\t\tthrow new SessionEnvelopeParseError(`\\`${field}\\` is not a valid address: ${String(value)}`);\n\t}\n\treturn value as Address;\n}\n\nfunction assertString(value: unknown, field: string): string {\n\tif (typeof value !== \"string\" || value === \"\") {\n\t\tthrow new SessionEnvelopeParseError(`\\`${field}\\` must be a non-empty string`);\n\t}\n\treturn value;\n}\n\nfunction assertNumber(value: unknown, field: string): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) {\n\t\tthrow new SessionEnvelopeParseError(`\\`${field}\\` must be a finite number`);\n\t}\n\treturn value;\n}\n\nfunction parseBigIntString(value: unknown, field: string): bigint {\n\tif (typeof value !== \"string\" || !UINT_DECIMAL.test(value)) {\n\t\tthrow new SessionEnvelopeParseError(\n\t\t\t`\\`${field}\\` must be a non-negative decimal string: ${String(value)}`,\n\t\t);\n\t}\n\treturn BigInt(value);\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Serialises a {@link KawasekitSessionEnvelope} to a transportable JSON string.\n *\n * The output is plain UTF-8 JSON (no base64). Callers who need\n * URL-/header-safe transport can base64-encode the result themselves.\n *\n * @example\n * ```ts\n * import { serializeSessionEnvelope } from \"kawasekit\";\n *\n * const blob = serializeSessionEnvelope(envelope);\n * fs.writeFileSync(\"agent.session\", blob);\n * ```\n */\nexport function serializeSessionEnvelope(envelope: KawasekitSessionEnvelope): string {\n\tconst json: SessionEnvelopeJson = {\n\t\tkawasekitVersion: envelope.kawasekitVersion,\n\t\tchainId: envelope.chainId,\n\t\tsmartAccountAddress: envelope.smartAccountAddress,\n\t\tsessionKeyAddress: envelope.sessionKeyAddress,\n\t\tserialized: envelope.serialized,\n\t\t...(envelope.expiresAt !== undefined ? { expiresAt: envelope.expiresAt.toString() } : {}),\n\t\t...(envelope.policySummary !== undefined\n\t\t\t? {\n\t\t\t\t\tpolicySummary: {\n\t\t\t\t\t\tjpycAddress: envelope.policySummary.jpycAddress,\n\t\t\t\t\t\tmaxPerTransfer: envelope.policySummary.maxPerTransfer.toString(),\n\t\t\t\t\t\tmaxTransfersPerDay: envelope.policySummary.maxTransfersPerDay,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {}),\n\t};\n\treturn JSON.stringify(json);\n}\n\n/**\n * Parses a JSON string back into a {@link KawasekitSessionEnvelope}, asserting\n * shape and version invariants.\n *\n * @throws {SessionEnvelopeParseError} On malformed JSON or structural errors.\n * @throws {SessionEnvelopeVersionError} On `kawasekitVersion` mismatch.\n *\n * @example\n * ```ts\n * import { parseSessionEnvelope } from \"kawasekit\";\n *\n * const envelope = parseSessionEnvelope(fs.readFileSync(\"agent.session\", \"utf8\"));\n * ```\n */\nexport function parseSessionEnvelope(input: string): KawasekitSessionEnvelope {\n\tlet raw: unknown;\n\ttry {\n\t\traw = JSON.parse(input);\n\t} catch (cause) {\n\t\tthrow new SessionEnvelopeParseError(\"input is not valid JSON\", { cause });\n\t}\n\tif (raw === null || typeof raw !== \"object\" || Array.isArray(raw)) {\n\t\tthrow new SessionEnvelopeParseError(\"input is not a JSON object\");\n\t}\n\tconst obj = raw as {\n\t\tkawasekitVersion?: unknown;\n\t\tchainId?: unknown;\n\t\tsmartAccountAddress?: unknown;\n\t\tsessionKeyAddress?: unknown;\n\t\tserialized?: unknown;\n\t\texpiresAt?: unknown;\n\t\tpolicySummary?: unknown;\n\t};\n\n\tif (obj.kawasekitVersion !== KAWASEKIT_SESSION_ENVELOPE_VERSION) {\n\t\tthrow new SessionEnvelopeVersionError(KAWASEKIT_SESSION_ENVELOPE_VERSION, obj.kawasekitVersion);\n\t}\n\tconst chainIdNum = assertNumber(obj.chainId, \"chainId\");\n\tif (!isSupportedChainId(chainIdNum)) {\n\t\tthrow new SessionEnvelopeParseError(`chainId ${chainIdNum} is not a kawasekit-supported chain`);\n\t}\n\tconst chainId: SupportedChainId = chainIdNum;\n\tconst smartAccountAddress = assertAddress(obj.smartAccountAddress, \"smartAccountAddress\");\n\tconst sessionKeyAddress = assertAddress(obj.sessionKeyAddress, \"sessionKeyAddress\");\n\tconst serialized = assertString(obj.serialized, \"serialized\");\n\n\tconst expiresAt =\n\t\tobj.expiresAt !== undefined ? parseBigIntString(obj.expiresAt, \"expiresAt\") : undefined;\n\n\tlet policySummary: KawasekitSessionPolicySummary | undefined;\n\tif (obj.policySummary !== undefined) {\n\t\tif (\n\t\t\tobj.policySummary === null ||\n\t\t\ttypeof obj.policySummary !== \"object\" ||\n\t\t\tArray.isArray(obj.policySummary)\n\t\t) {\n\t\t\tthrow new SessionEnvelopeParseError(\"`policySummary` must be a JSON object\");\n\t\t}\n\t\tconst ps = obj.policySummary as {\n\t\t\tjpycAddress?: unknown;\n\t\t\tmaxPerTransfer?: unknown;\n\t\t\tmaxTransfersPerDay?: unknown;\n\t\t};\n\t\tpolicySummary = {\n\t\t\tjpycAddress: assertAddress(ps.jpycAddress, \"policySummary.jpycAddress\"),\n\t\t\tmaxPerTransfer: parseBigIntString(ps.maxPerTransfer, \"policySummary.maxPerTransfer\"),\n\t\t\tmaxTransfersPerDay: assertNumber(ps.maxTransfersPerDay, \"policySummary.maxTransfersPerDay\"),\n\t\t};\n\t}\n\n\tconst base = {\n\t\tkawasekitVersion: KAWASEKIT_SESSION_ENVELOPE_VERSION,\n\t\tchainId,\n\t\tsmartAccountAddress,\n\t\tsessionKeyAddress,\n\t\tserialized,\n\t} as const;\n\tif (expiresAt !== undefined && policySummary !== undefined) {\n\t\treturn { ...base, expiresAt, policySummary };\n\t}\n\tif (expiresAt !== undefined) {\n\t\treturn { ...base, expiresAt };\n\t}\n\tif (policySummary !== undefined) {\n\t\treturn { ...base, policySummary };\n\t}\n\treturn base;\n}\n","/**\n * `issueSessionKey()` — owner-side primitive that builds a Kernel agent\n * account and wraps ZeroDev's `serializePermissionAccount` output in a\n * {@link KawasekitSessionEnvelope}.\n *\n * The envelope is portable: callers can hand it to an agent on a different\n * machine, the agent passes it to {@link restoreSessionAccount} along with the\n * session-key private key, and it ends up holding a `KernelAccountClient`\n * scoped to the policies installed at issue time.\n *\n * The owner retains sudo authority on-chain and can revoke at any time via\n * `revokeSessionKey()` (task 2.5).\n *\n * @packageDocumentation\n */\n\nimport type { Policy } from \"@zerodev/permissions\";\nimport { serializePermissionAccount } from \"@zerodev/permissions\";\nimport { getEntryPoint, KERNEL_V3_1 } from \"@zerodev/sdk/constants\";\nimport type { EntryPointType, GetKernelVersion } from \"@zerodev/sdk/types\";\nimport type { Chain, LocalAccount, PublicClient, Transport } from \"viem\";\nimport { createAgentSmartAccount } from \"../account/session-key\";\nimport { isSupportedChainId, type SupportedChainId } from \"../chains\";\nimport {\n\tKAWASEKIT_SESSION_ENVELOPE_VERSION,\n\ttype KawasekitSessionEnvelope,\n\ttype KawasekitSessionPolicySummary,\n} from \"./envelope\";\n\n/** Parameters for {@link issueSessionKey}. */\nexport interface IssueSessionKeyParams {\n\t/**\n\t * viem `PublicClient` on the chain the smart account will live on. Its\n\t * `chain.id` MUST be a {@link SupportedChainId} and is recorded in the\n\t * envelope so restore-time mismatches fail fast.\n\t */\n\treadonly publicClient: PublicClient<Transport, Chain>;\n\t/** Owner EOA — retains sudo authority. */\n\treadonly ownerSigner: LocalAccount;\n\t/** Session-key EOA — the day-to-day signer the agent will hold. */\n\treadonly sessionKeySigner: LocalAccount;\n\t/**\n\t * Policies the session key must satisfy at userOp validation time\n\t * (e.g. {@link createJpycDailyLimitPolicies}).\n\t */\n\treadonly policies: readonly Policy[];\n\t/** Optional advisory expiry (unix seconds). Recorded in the envelope. */\n\treadonly expiresAt?: bigint;\n\t/** Optional advisory policy summary for host UI. */\n\treadonly policySummary?: KawasekitSessionPolicySummary;\n\t/** EntryPoint override. Defaults to v0.7. */\n\treadonly entryPoint?: EntryPointType<\"0.7\">;\n\t/** Kernel version override. Defaults to {@link KERNEL_V3_1}. */\n\treadonly kernelVersion?: GetKernelVersion<\"0.7\">;\n}\n\n/**\n * Issues a fresh session key for an agent smart account.\n *\n * Notes:\n * - The session-key **private key is not embedded** in the returned envelope.\n * The agent must receive the private key out-of-band; the envelope alone is\n * not enough to spend.\n * - The smart account is **not deployed** by this call. It will be deployed\n * on first userOp from `restoreSessionAccount`.\n *\n * @example\n * ```ts\n * import { parseUnits } from \"viem\";\n * import { privateKeyToAccount } from \"viem/accounts\";\n * import {\n * createJpycDailyLimitPolicies,\n * getJpycAddress,\n * issueSessionKey,\n * JPYC_DECIMALS,\n * polygonAmoy,\n * serializeSessionEnvelope,\n * } from \"kawasekit\";\n *\n * const owner = privateKeyToAccount(process.env.OWNER_PRIVATE_KEY as `0x${string}`);\n * const sessionKey = privateKeyToAccount(process.env.SESSION_KEY_PRIVATE_KEY as `0x${string}`);\n *\n * const envelope = await issueSessionKey({\n * publicClient,\n * ownerSigner: owner,\n * sessionKeySigner: sessionKey,\n * policies: createJpycDailyLimitPolicies({\n * jpycAddress: getJpycAddress(polygonAmoy.id),\n * maxPerTransfer: parseUnits(\"100\", JPYC_DECIMALS),\n * maxTransfersPerDay: 10,\n * }),\n * policySummary: {\n * jpycAddress: getJpycAddress(polygonAmoy.id),\n * maxPerTransfer: parseUnits(\"100\", JPYC_DECIMALS),\n * maxTransfersPerDay: 10,\n * },\n * });\n *\n * fs.writeFileSync(\"agent.session\", serializeSessionEnvelope(envelope));\n * ```\n */\nexport async function issueSessionKey(\n\tparams: IssueSessionKeyParams,\n): Promise<KawasekitSessionEnvelope> {\n\tconst chainId = params.publicClient.chain.id;\n\tif (!isSupportedChainId(chainId)) {\n\t\tthrow new Error(\n\t\t\t`issueSessionKey: publicClient.chain.id ${chainId} is not a kawasekit-supported chain`,\n\t\t);\n\t}\n\tconst supportedChainId: SupportedChainId = chainId;\n\tconst entryPoint = params.entryPoint ?? getEntryPoint(\"0.7\");\n\tconst kernelVersion = params.kernelVersion ?? KERNEL_V3_1;\n\n\tconst account = await createAgentSmartAccount({\n\t\tpublicClient: params.publicClient,\n\t\townerSigner: params.ownerSigner,\n\t\tsessionKeySigner: params.sessionKeySigner,\n\t\tpolicies: params.policies,\n\t\tentryPoint,\n\t\tkernelVersion,\n\t});\n\n\tconst serialized = await serializePermissionAccount(account);\n\n\tconst base = {\n\t\tkawasekitVersion: KAWASEKIT_SESSION_ENVELOPE_VERSION,\n\t\tchainId: supportedChainId,\n\t\tsmartAccountAddress: account.address,\n\t\tsessionKeyAddress: params.sessionKeySigner.address,\n\t\tserialized,\n\t} as const;\n\tif (params.expiresAt !== undefined && params.policySummary !== undefined) {\n\t\treturn {\n\t\t\t...base,\n\t\t\texpiresAt: params.expiresAt,\n\t\t\tpolicySummary: params.policySummary,\n\t\t};\n\t}\n\tif (params.expiresAt !== undefined) {\n\t\treturn { ...base, expiresAt: params.expiresAt };\n\t}\n\tif (params.policySummary !== undefined) {\n\t\treturn { ...base, policySummary: params.policySummary };\n\t}\n\treturn base;\n}\n","/**\n * `restoreSessionAccount()` — agent-side primitive that unwraps a\n * {@link KawasekitSessionEnvelope} back into a usable Kernel account scoped\n * to the policies installed at issue time.\n *\n * Three invariants are checked **before** touching ZeroDev's deserialization\n * so that misconfiguration manifests as a typed error here, not a confusing\n * UserOp-time revert:\n *\n * 1. `envelope.kawasekitVersion` matches the current envelope version\n * (already enforced by {@link parseSessionEnvelope}; re-checked here for\n * callers who construct the envelope object directly).\n * 2. `envelope.chainId === publicClient.chain.id`.\n * 3. `envelope.sessionKeyAddress` matches the provided `sessionKeySigner`.\n *\n * @packageDocumentation\n */\n\nimport { deserializePermissionAccount } from \"@zerodev/permissions\";\nimport { toECDSASigner } from \"@zerodev/permissions/signers\";\nimport type { CreateKernelAccountReturnType } from \"@zerodev/sdk\";\nimport { getEntryPoint, KERNEL_V3_1 } from \"@zerodev/sdk/constants\";\nimport type { EntryPointType, GetKernelVersion } from \"@zerodev/sdk/types\";\nimport { type Chain, getAddress, type LocalAccount, type PublicClient, type Transport } from \"viem\";\nimport { KAWASEKIT_SESSION_ENVELOPE_VERSION, type KawasekitSessionEnvelope } from \"./envelope\";\nimport {\n\tSessionEnvelopeChainMismatchError,\n\tSessionEnvelopeSignerMismatchError,\n\tSessionEnvelopeVersionError,\n} from \"./errors\";\n\n/** Parameters for {@link restoreSessionAccount}. */\nexport interface RestoreSessionAccountParams {\n\t/** Must be on the same chain the envelope was issued for. */\n\treadonly publicClient: PublicClient<Transport, Chain>;\n\t/** Envelope produced by {@link issueSessionKey} (or parsed via {@link parseSessionEnvelope}). */\n\treadonly envelope: KawasekitSessionEnvelope;\n\t/**\n\t * The session-key signer the agent holds. Its address MUST equal\n\t * `envelope.sessionKeyAddress` — otherwise the restored account would\n\t * sign userOps that the on-chain permission validator rejects.\n\t */\n\treadonly sessionKeySigner: LocalAccount;\n\t/** EntryPoint override. Defaults to v0.7. */\n\treadonly entryPoint?: EntryPointType<\"0.7\">;\n\t/** Kernel version override. Defaults to {@link KERNEL_V3_1}. */\n\treadonly kernelVersion?: GetKernelVersion<\"0.7\">;\n}\n\n/**\n * Rebuilds the Kernel account from an envelope + the session-key signer.\n *\n * @throws {SessionEnvelopeVersionError} If `envelope.kawasekitVersion` does\n * not match the current envelope version.\n * @throws {SessionEnvelopeChainMismatchError} If `envelope.chainId !==\n * publicClient.chain.id`.\n * @throws {SessionEnvelopeSignerMismatchError} If `sessionKeySigner.address !==\n * envelope.sessionKeyAddress`.\n *\n * @example\n * ```ts\n * import { createPublicClient, http } from \"viem\";\n * import { privateKeyToAccount } from \"viem/accounts\";\n * import {\n * parseSessionEnvelope,\n * polygonAmoy,\n * restoreSessionAccount,\n * } from \"kawasekit\";\n *\n * const publicClient = createPublicClient({\n * chain: polygonAmoy,\n * transport: http(),\n * });\n * const envelope = parseSessionEnvelope(fs.readFileSync(\"agent.session\", \"utf8\"));\n * const sessionKey = privateKeyToAccount(process.env.SESSION_KEY_PRIVATE_KEY as `0x${string}`);\n *\n * const account = await restoreSessionAccount({\n * publicClient,\n * envelope,\n * sessionKeySigner: sessionKey,\n * });\n * ```\n */\nexport async function restoreSessionAccount(\n\tparams: RestoreSessionAccountParams,\n): Promise<CreateKernelAccountReturnType<\"0.7\">> {\n\tconst { publicClient, envelope, sessionKeySigner } = params;\n\n\tif (envelope.kawasekitVersion !== KAWASEKIT_SESSION_ENVELOPE_VERSION) {\n\t\tthrow new SessionEnvelopeVersionError(\n\t\t\tKAWASEKIT_SESSION_ENVELOPE_VERSION,\n\t\t\tenvelope.kawasekitVersion,\n\t\t);\n\t}\n\tif (publicClient.chain.id !== envelope.chainId) {\n\t\tthrow new SessionEnvelopeChainMismatchError(envelope.chainId, publicClient.chain.id);\n\t}\n\tif (getAddress(sessionKeySigner.address) !== getAddress(envelope.sessionKeyAddress)) {\n\t\tthrow new SessionEnvelopeSignerMismatchError(\n\t\t\tenvelope.sessionKeyAddress,\n\t\t\tsessionKeySigner.address,\n\t\t);\n\t}\n\n\tconst entryPoint = params.entryPoint ?? getEntryPoint(\"0.7\");\n\tconst kernelVersion = params.kernelVersion ?? KERNEL_V3_1;\n\tconst modularSigner = await toECDSASigner({ signer: sessionKeySigner });\n\n\treturn deserializePermissionAccount(\n\t\tpublicClient,\n\t\tentryPoint,\n\t\tkernelVersion,\n\t\tenvelope.serialized,\n\t\tmodularSigner,\n\t);\n}\n","/**\n * `revokeSessionKey()` — owner-side primitive that uninstalls a session-key\n * permission validator from the agent's smart account.\n *\n * Implementation strategy (per plan §risk #3): ZeroDev does not expose a\n * dedicated revoke helper, so we re-derive the `PermissionPlugin` from the\n * envelope's `sessionKeyAddress` + the same policies that were installed at\n * issue time, then submit a sudo UserOp via `@zerodev/sdk`'s\n * {@link uninstallPlugin} action. After the receipt, the session key can no\n * longer sign UserOps the validator would accept.\n *\n * In-flight UserOps already submitted to the bundler but not yet mined can\n * still settle before the uninstall transaction lands. A future \"soft revoke\"\n * via `invalidateNonce` on the session-key validator's nonce key will close\n * that race; tracked for M5 (the helper signature accepts an\n * `invalidateInFlightNonces` option today and throws `\"not implemented\"` to\n * lock in the API shape). Until M5 lands, see\n * `docs/recipes/revoke-race-mitigation.md` for the four-layer operator\n * playbook (SDK call → merchant kill-switch → paymaster sponsorship\n * freeze → bundler mempool monitoring).\n *\n * @packageDocumentation\n */\n\nimport type { Policy } from \"@zerodev/permissions\";\nimport { toPermissionValidator } from \"@zerodev/permissions\";\nimport { toECDSASigner } from \"@zerodev/permissions/signers\";\nimport { uninstallPlugin } from \"@zerodev/sdk\";\nimport { getEntryPoint, KERNEL_V3_1 } from \"@zerodev/sdk/constants\";\nimport type { EntryPointType, GetKernelVersion } from \"@zerodev/sdk/types\";\nimport { getAddress, type Hash, type LocalAccount } from \"viem\";\nimport type { ConfiguredKernelClient } from \"../client/transfer-jpyc\";\nimport type { KawasekitSessionEnvelope } from \"./envelope\";\nimport { SessionEnvelopeSignerMismatchError } from \"./errors\";\n\n/** Parameters for {@link revokeSessionKey}. */\nexport interface RevokeSessionKeyParams {\n\t/**\n\t * The owner's sudo Kernel client — the only entity that can call\n\t * `uninstallValidation` on the agent account.\n\t *\n\t * **CRITICAL: must be a SUDO-ONLY kernel account** (i.e.\n\t * `createKernelAccount(publicClient, { plugins: { sudo: ecdsaValidator } })`\n\t * — no `regular` plugin). If you pass a client whose account also has the\n\t * session-key permission validator wired as `regular`, ZeroDev signs\n\t * userOps with that validator by default and the spending policy will\n\t * reject `uninstallValidation` at the validation phase (`AA23 reverted`).\n\t *\n\t * The counterfactual smart-account address only depends on the sudo\n\t * validator in Kernel v3.1, so a sudo-only client points at the SAME\n\t * account as one built with both sudo + regular.\n\t *\n\t * Its `account.address` MUST equal `envelope.smartAccountAddress`.\n\t */\n\treadonly ownerKernelClient: ConfiguredKernelClient;\n\t/** The envelope of the session being revoked. */\n\treadonly envelope: KawasekitSessionEnvelope;\n\t/**\n\t * A LocalAccount whose address equals `envelope.sessionKeyAddress`. Used\n\t * to reconstruct the validator's on-chain identifier; no signing is\n\t * actually performed with this account during revoke.\n\t */\n\treadonly sessionKeySigner: LocalAccount;\n\t/**\n\t * The policies that were installed at issue time. ZeroDev does not store\n\t * these on-chain in a retrievable form, so the caller MUST re-supply\n\t * them. Mismatches surface as an `uninstallValidation` revert at userOp\n\t * validation time.\n\t */\n\treadonly policies: readonly Policy[];\n\t/**\n\t * Future option: also invalidate the session-key validator's nonce key\n\t * to kill in-flight UserOps. Not implemented today — passing `true`\n\t * throws. Tracked for M5; see `docs/THREAT_MODEL.md` §6.3 and\n\t * `docs/recipes/revoke-race-mitigation.md` for the operator playbook to\n\t * use until then.\n\t */\n\treadonly invalidateInFlightNonces?: boolean;\n\t/** EntryPoint override. Defaults to v0.7. */\n\treadonly entryPoint?: EntryPointType<\"0.7\">;\n\t/** Kernel version override. Defaults to {@link KERNEL_V3_1}. */\n\treadonly kernelVersion?: GetKernelVersion<\"0.7\">;\n\t/**\n\t * If `false`, return after submitting the UserOp without waiting for the\n\t * bundler receipt. Default `true` (wait).\n\t */\n\treadonly waitForReceipt?: boolean;\n}\n\n/** Result of {@link revokeSessionKey}. */\nexport interface RevokeSessionKeyResult {\n\t/** Hash of the uninstall UserOp. */\n\treadonly userOpHash: Hash;\n\t/** Bundler transaction hash, present when `waitForReceipt` (default true). */\n\treadonly transactionHash: Hash | null;\n\t/** `true` if the bundler reported success, `null` if not awaited. */\n\treadonly success: boolean | null;\n}\n\n/**\n * Uninstalls a session-key permission validator from the agent's smart\n * account. After the returned UserOp lands, the session key can no longer\n * authorise actions.\n *\n * @throws {SessionEnvelopeSignerMismatchError} If `sessionKeySigner.address`\n * does not match `envelope.sessionKeyAddress`.\n * @throws {Error} If `invalidateInFlightNonces` is `true` (planned for M5;\n * see `docs/THREAT_MODEL.md` §6.3 and\n * `docs/recipes/revoke-race-mitigation.md` for the four-layer\n * operator playbook to use until then).\n *\n * @example\n * ```ts\n * import { signerToEcdsaValidator } from \"@zerodev/ecdsa-validator\";\n * import { createKernelAccount, createKernelAccountClient } from \"@zerodev/sdk\";\n * import { getEntryPoint, KERNEL_V3_1 } from \"@zerodev/sdk/constants\";\n * import { revokeSessionKey } from \"kawasekit\";\n *\n * // Build a SUDO-ONLY kernel account for the owner — see param JSDoc.\n * const sudoValidator = await signerToEcdsaValidator(publicClient, {\n * signer: owner,\n * entryPoint: getEntryPoint(\"0.7\"),\n * kernelVersion: KERNEL_V3_1,\n * });\n * const ownerSudoAccount = await createKernelAccount(publicClient, {\n * plugins: { sudo: sudoValidator },\n * entryPoint: getEntryPoint(\"0.7\"),\n * kernelVersion: KERNEL_V3_1,\n * });\n * const ownerKernelClient = createKernelAccountClient({\n * account: ownerSudoAccount,\n * chain,\n * client: publicClient,\n * bundlerTransport,\n * paymaster,\n * });\n *\n * await revokeSessionKey({\n * ownerKernelClient,\n * envelope,\n * sessionKeySigner,\n * policies: createJpycDailyLimitPolicies({ ... }),\n * });\n * ```\n */\nexport async function revokeSessionKey(\n\tparams: RevokeSessionKeyParams,\n): Promise<RevokeSessionKeyResult> {\n\tconst { ownerKernelClient, envelope, sessionKeySigner, policies } = params;\n\n\tif (params.invalidateInFlightNonces === true) {\n\t\tthrow new Error(\n\t\t\t\"revokeSessionKey: `invalidateInFlightNonces` is not implemented yet — the helper signature accepts the option to lock in the API shape, but in-flight nonce invalidation lands in M5. Hard revoke via uninstallPlugin is what runs today; see docs/recipes/revoke-race-mitigation.md for the four-layer operator playbook to use until then.\",\n\t\t);\n\t}\n\n\tif (getAddress(sessionKeySigner.address) !== getAddress(envelope.sessionKeyAddress)) {\n\t\tthrow new SessionEnvelopeSignerMismatchError(\n\t\t\tenvelope.sessionKeyAddress,\n\t\t\tsessionKeySigner.address,\n\t\t);\n\t}\n\n\tif (getAddress(ownerKernelClient.account.address) !== getAddress(envelope.smartAccountAddress)) {\n\t\tthrow new Error(\n\t\t\t`revokeSessionKey: ownerKernelClient is bound to ${ownerKernelClient.account.address}, but envelope is for ${envelope.smartAccountAddress}.`,\n\t\t);\n\t}\n\n\tconst entryPoint = params.entryPoint ?? getEntryPoint(\"0.7\");\n\tconst kernelVersion = params.kernelVersion ?? KERNEL_V3_1;\n\n\tif (ownerKernelClient.client === undefined) {\n\t\tthrow new Error(\n\t\t\t\"revokeSessionKey: ownerKernelClient.client is undefined — pass `client: publicClient` when constructing the Kernel client so the validator can be reconstructed.\",\n\t\t);\n\t}\n\n\tconst modularSigner = await toECDSASigner({ signer: sessionKeySigner });\n\tconst permissionPlugin = await toPermissionValidator(ownerKernelClient.client, {\n\t\tsigner: modularSigner,\n\t\tpolicies: [...policies],\n\t\tentryPoint,\n\t\tkernelVersion,\n\t});\n\n\tconst userOpHash = await uninstallPlugin(ownerKernelClient, {\n\t\tplugin: permissionPlugin,\n\t});\n\n\tif (params.waitForReceipt === false) {\n\t\treturn { userOpHash, transactionHash: null, success: null };\n\t}\n\n\tconst receipt = await ownerKernelClient.waitForUserOperationReceipt({\n\t\thash: userOpHash,\n\t});\n\treturn {\n\t\tuserOpHash,\n\t\ttransactionHash: receipt.receipt.transactionHash,\n\t\tsuccess: receipt.success,\n\t};\n}\n","/**\n * `rotateSessionKey()` — a thin compositional helper that revokes the\n * current session key and issues a new one in sequence.\n *\n * Compose-don't-conflate: rotate is just `revoke` followed by `issue`. Both\n * primitives are exposed individually so callers who need finer control\n * (e.g. revoke now, issue tomorrow with different policies) can chain them\n * themselves.\n *\n * @packageDocumentation\n */\n\nimport type { KawasekitSessionEnvelope } from \"./envelope\";\nimport { type IssueSessionKeyParams, issueSessionKey } from \"./issue\";\nimport {\n\ttype RevokeSessionKeyParams,\n\ttype RevokeSessionKeyResult,\n\trevokeSessionKey,\n} from \"./revoke\";\n\n/** Parameters for {@link rotateSessionKey}. */\nexport interface RotateSessionKeyParams {\n\t/** Inputs for revoking the current session. `waitForReceipt` is forced `true`. */\n\treadonly revoke: Omit<RevokeSessionKeyParams, \"waitForReceipt\">;\n\t/** Inputs for issuing the replacement session. */\n\treadonly issue: IssueSessionKeyParams;\n}\n\n/** Result of {@link rotateSessionKey}. */\nexport interface RotateSessionKeyResult {\n\t/** Outcome of the revoke step. */\n\treadonly revoke: RevokeSessionKeyResult;\n\t/** The freshly issued replacement envelope. */\n\treadonly envelope: KawasekitSessionEnvelope;\n}\n\n/**\n * Atomically rotate the agent's session key: revoke the old, issue the new.\n *\n * The revoke is always awaited to the bundler receipt — issuing a replacement\n * before the old key is actually disarmed would leave two valid signers at\n * once, defeating the point.\n *\n * @example\n * ```ts\n * import { rotateSessionKey } from \"kawasekit\";\n *\n * const { revoke, envelope } = await rotateSessionKey({\n * revoke: {\n * ownerKernelClient,\n * envelope: oldEnvelope,\n * sessionKeySigner: oldSessionKeySigner,\n * policies: oldPolicies,\n * },\n * issue: {\n * publicClient,\n * ownerSigner,\n * sessionKeySigner: newSessionKeySigner,\n * policies: newPolicies,\n * },\n * });\n * ```\n */\nexport async function rotateSessionKey(\n\tparams: RotateSessionKeyParams,\n): Promise<RotateSessionKeyResult> {\n\tconst revoke = await revokeSessionKey({ ...params.revoke, waitForReceipt: true });\n\tconst envelope = await issueSessionKey(params.issue);\n\treturn { revoke, envelope };\n}\n"]}
@@ -1,7 +1,7 @@
1
- import { X402InvalidPayloadError, X402_VERSION, chainIdToX402Network, X402_HEADER_PAYMENT_SIGNATURE, encodePaymentSignatureHeader, X402_HEADER_PAYMENT_RESPONSE, decodePaymentResponseHeader, x402NetworkToChainId, JPYC_V2_ADDRESS, JPYC_EIP712_DOMAIN_HINT, X402_HEADER_PAYMENT_REQUIRED, decodePaymentRequiredHeader, jpycAbi } from './chunk-LNXYCHRY.js';
1
+ import { JPYC_EIP712_DOMAIN_HINT, JPYC_V2_ADDRESS, X402InvalidPayloadError, X402_VERSION, chainIdToX402Network, X402_HEADER_PAYMENT_SIGNATURE, encodePaymentSignatureHeader, X402_HEADER_PAYMENT_RESPONSE, decodePaymentResponseHeader, X402InvalidConfigError, x402NetworkToChainId, X402_HEADER_PAYMENT_REQUIRED, decodePaymentRequiredHeader, jpycAbi } from './chunk-ZY6RT2DB.js';
2
2
  import { getChain, isSupportedChainId } from './chunk-SA7LMQFG.js';
3
3
  import { invokeHookSafely } from './chunk-LEHWRDVS.js';
4
- import { parseSignature, getAddress, recoverTypedDataAddress, isAddress } from 'viem';
4
+ import { getAddress, parseSignature, isAddress, recoverTypedDataAddress } from 'viem';
5
5
 
6
6
  var transferWithAuthorizationTypes = {
7
7
  TransferWithAuthorization: [
@@ -98,6 +98,20 @@ function splitAuthorization(signature, domain, message) {
98
98
  message
99
99
  };
100
100
  }
101
+ var KNOWN_ASSETS = [
102
+ {
103
+ id: "jpyc-v2",
104
+ name: JPYC_EIP712_DOMAIN_HINT.name,
105
+ version: JPYC_EIP712_DOMAIN_HINT.version,
106
+ verifyingContract: getAddress(JPYC_V2_ADDRESS)
107
+ }
108
+ ];
109
+ function getKnownAssetDomain(id) {
110
+ return KNOWN_ASSETS.find((entry) => entry.id === id);
111
+ }
112
+ function listKnownAssetIds() {
113
+ return KNOWN_ASSETS.map((entry) => entry.id);
114
+ }
101
115
  var X402_DEFAULT_AUTHORIZATION_LIFETIME_SECONDS = 300;
102
116
  var UINT256_MAX = (1n << 256n) - 1n;
103
117
  var UINT256_DECIMAL = /^(0|[1-9][0-9]*)$/;
@@ -126,20 +140,51 @@ function assertAddress(value, field) {
126
140
  }
127
141
  return value;
128
142
  }
129
- function resolveDomain(requirements, override) {
130
- if (override) {
131
- return override;
132
- }
133
- const extra = requirements.extra;
134
- if (typeof extra.name === "string" && typeof extra.version === "string") {
135
- return { name: extra.name, version: extra.version };
143
+ function resolveAssetParam(asset) {
144
+ if (asset.kind === "known") {
145
+ const entry = getKnownAssetDomain(asset.id);
146
+ if (entry === void 0) {
147
+ throw new X402InvalidConfigError(
148
+ "asset.id",
149
+ `unknown asset id ${JSON.stringify(asset.id)}. Supported: ${listKnownAssetIds().map((id) => JSON.stringify(id)).join(", ")}.`
150
+ );
151
+ }
152
+ return {
153
+ name: entry.name,
154
+ version: entry.version,
155
+ verifyingContract: entry.verifyingContract
156
+ };
136
157
  }
137
- if (getAddress(requirements.asset) === getAddress(JPYC_V2_ADDRESS)) {
138
- return JPYC_EIP712_DOMAIN_HINT;
158
+ if (asset.kind === "unsafeOverride") {
159
+ const { domain } = asset;
160
+ if (typeof domain.name !== "string" || domain.name === "") {
161
+ throw new X402InvalidConfigError(
162
+ "asset.domain.name",
163
+ "`unsafeOverride.domain.name` must be a non-empty string"
164
+ );
165
+ }
166
+ if (typeof domain.version !== "string" || domain.version === "") {
167
+ throw new X402InvalidConfigError(
168
+ "asset.domain.version",
169
+ "`unsafeOverride.domain.version` must be a non-empty string"
170
+ );
171
+ }
172
+ if (!isAddress(domain.verifyingContract, { strict: false })) {
173
+ throw new X402InvalidConfigError(
174
+ "asset.domain.verifyingContract",
175
+ `\`unsafeOverride.domain.verifyingContract\` must be a valid address, got ${JSON.stringify(domain.verifyingContract)}`
176
+ );
177
+ }
178
+ return {
179
+ name: domain.name,
180
+ version: domain.version,
181
+ verifyingContract: getAddress(domain.verifyingContract)
182
+ };
139
183
  }
140
- throw new X402InvalidPayloadError(
141
- "PaymentRequirements",
142
- "`extra.name` and `extra.version` are required for exact-EVM signing on a non-JPYC asset"
184
+ const exhaustive = asset;
185
+ throw new X402InvalidConfigError(
186
+ "asset.kind",
187
+ `unsupported kind ${JSON.stringify(exhaustive.kind)}. Expected "known" or "unsafeOverride".`
143
188
  );
144
189
  }
145
190
  function validateRequirements(requirements) {
@@ -179,7 +224,7 @@ function createX402PaymentSigner(params) {
179
224
  `\`defaultLifetimeSeconds\` must be positive, got ${defaultLifetimeSeconds}`
180
225
  );
181
226
  }
182
- const domainOverride = params.domainOverride;
227
+ const pinnedDomain = resolveAssetParam(params.asset);
183
228
  return {
184
229
  address: account.address,
185
230
  async sign(signParams) {
@@ -198,7 +243,12 @@ function createX402PaymentSigner(params) {
198
243
  `signer was configured for network="testnet" but requirements.network="${paymentRequirements.network}" (chainId ${chainId}) is a mainnet \u2014 refusing to sign payment for real funds`
199
244
  );
200
245
  }
201
- const domain = resolveDomain(paymentRequirements, domainOverride);
246
+ if (getAddress(asset) !== pinnedDomain.verifyingContract) {
247
+ throw new X402InvalidPayloadError(
248
+ "PaymentRequirements",
249
+ `requirements.asset (${getAddress(asset)}) does not match the signer's pinned verifyingContract (${pinnedDomain.verifyingContract}) \u2014 refusing to sign for an asset the signer was not configured to handle`
250
+ );
251
+ }
202
252
  const lifetime = Math.min(defaultLifetimeSeconds, paymentRequirements.maxTimeoutSeconds);
203
253
  const validAfter = signParams.validAfter ?? 0n;
204
254
  const validBefore = signParams.validBefore ?? authorizationDeadlineFromNow(lifetime);
@@ -211,7 +261,12 @@ function createX402PaymentSigner(params) {
211
261
  const nonce = generateAuthorizationNonce();
212
262
  const signed = await signTransferWithAuthorization(
213
263
  account,
214
- { name: domain.name, version: domain.version, chainId, verifyingContract: asset },
264
+ {
265
+ name: pinnedDomain.name,
266
+ version: pinnedDomain.version,
267
+ chainId,
268
+ verifyingContract: pinnedDomain.verifyingContract
269
+ },
215
270
  {
216
271
  from: account.address,
217
272
  to: payTo,
@@ -302,7 +357,7 @@ var TRANSFER_AUTHORIZATION_TYPES = {
302
357
  { name: "nonce", type: "bytes32" }
303
358
  ]
304
359
  };
305
- function resolveDomain2(requirements) {
360
+ function resolveDomain(requirements) {
306
361
  const extra = requirements.extra;
307
362
  if (typeof extra.name === "string" && typeof extra.version === "string") {
308
363
  return { name: extra.name, version: extra.version };
@@ -509,7 +564,7 @@ function createSelfFacilitator(params) {
509
564
  }
510
565
  let recovered;
511
566
  try {
512
- const domain = resolveDomain2(req.paymentRequirements);
567
+ const domain = resolveDomain(req.paymentRequirements);
513
568
  recovered = await recoverTypedDataAddress({
514
569
  domain: {
515
570
  name: domain.name,
@@ -811,12 +866,10 @@ function wrapFetch(params) {
811
866
  emitFailure("no_acceptable_requirement", 402);
812
867
  return initialResponse;
813
868
  }
814
- if (onPayment) {
815
- const proceed = await onPayment(chosen, paymentRequired);
816
- if (proceed === false) {
817
- emitFailure("onPayment_declined", 402);
818
- return initialResponse;
819
- }
869
+ const proceed = await onPayment(chosen, paymentRequired);
870
+ if (proceed === false) {
871
+ emitFailure("onPayment_declined", 402);
872
+ return initialResponse;
820
873
  }
821
874
  const paymentPayload = await params.signer.sign({
822
875
  paymentRequirements: chosen,
@@ -859,6 +912,6 @@ function wrapFetch(params) {
859
912
  };
860
913
  }
861
914
 
862
- export { X402_DEFAULT_AUTHORIZATION_LIFETIME_SECONDS, X402_FACILITATOR_ERROR_CODES, authorizationDeadlineFromNow, createCoinbaseFacilitator, createHttpFacilitator, createSelfFacilitator, createX402PaymentSigner, generateAuthorizationNonce, signCancelAuthorization, signReceiveWithAuthorization, signTransferWithAuthorization, wrapFetch };
863
- //# sourceMappingURL=chunk-2QYCWRYR.js.map
864
- //# sourceMappingURL=chunk-2QYCWRYR.js.map
915
+ export { X402_DEFAULT_AUTHORIZATION_LIFETIME_SECONDS, X402_FACILITATOR_ERROR_CODES, authorizationDeadlineFromNow, createCoinbaseFacilitator, createHttpFacilitator, createSelfFacilitator, createX402PaymentSigner, generateAuthorizationNonce, getKnownAssetDomain, listKnownAssetIds, signCancelAuthorization, signReceiveWithAuthorization, signTransferWithAuthorization, wrapFetch };
916
+ //# sourceMappingURL=chunk-ZES4UYIQ.js.map
917
+ //# sourceMappingURL=chunk-ZES4UYIQ.js.map