diff --git a/docs/docs.json b/docs/docs.json
index fa5be3419..8d04f3bc2 100644
--- a/docs/docs.json
+++ b/docs/docs.json
@@ -153,6 +153,7 @@
{
"group": "Guides",
"pages": [
+ "guides/v7-to-v8-migration",
"guides/lit-action-sign-as-action",
"guides/server-sessions"
]
@@ -246,4 +247,4 @@
"discord": "https://litgateway.com/discord"
}
}
-}
\ No newline at end of file
+}
diff --git a/docs/guides/v7-to-v8-migration.mdx b/docs/guides/v7-to-v8-migration.mdx
new file mode 100644
index 000000000..9b05e56a3
--- /dev/null
+++ b/docs/guides/v7-to-v8-migration.mdx
@@ -0,0 +1,562 @@
+---
+title: "Migrating from Lit SDK v7 (Datil) to v8 (Naga)"
+description: "Complete migration guide covering package renames, authContext, Lit Actions runtime changes, PKP signing, encryption, wrapped keys, and the new payment system."
+---
+
+# Overview
+
+Lit SDK v8 (“Naga”) is a major release over v7 (“Datil”). The public API is more modular, uses `viem` for chain interactions, introduces the `AuthManager`/`authContext` model, and replaces Capacity Credits with Ledger‑based payments.
+
+This guide is written for teams upgrading existing v7 integrations. It focuses on **breaking changes** and **exact replacements**.
+
+# Upgrade checklist
+
+1. Replace v7 packages/imports with v8 packages (see tables below).
+2. Swap `LitNodeClient`/`connect()` for `createLitClient()`.
+3. Replace `sessionSigs` and most `authSig` usage with `authContext` from `AuthManager` (`authSig` remains optional only for `decrypt` overrides).
+4. Update Lit Actions to read inputs from `jsParams.*` (no longer global).
+5. Update PKP signing to `litClient.chain.*.pkpSign`.
+6. Replace v7 encryption helpers with `litClient.encrypt` / `litClient.decrypt`.
+7. If you use Wrapped Keys, keep using `pkpSessionSigs` but mint them via `AuthManager`.
+8. On paid networks, migrate Capacity Credits flows to the new `PaymentManager`.
+
+# Quick reference: v7 → v8 mapping
+
+Use this section as a **searchable symbol map**. Find the v7 name you used and jump to the v8 equivalent.
+
+## Packages and modules
+
+| v7 | v8 | Notes |
+| --- | --- | --- |
+| `@lit-protocol/lit-node-client` | `@lit-protocol/lit-client` | Core client package renamed/re‑architected. |
+| `@lit-protocol/lit-node-client-nodejs` | **Removed** | v8 is isomorphic; use `@lit-protocol/lit-client` in Node and browser. |
+| `@lit-protocol/lit-auth-client` | `@lit-protocol/auth` (+ optional `@lit-protocol/auth-services`) | Providers replaced by authenticators + AuthManager; hosted infra moved to auth-services. |
+| `@lit-protocol/pkp-*` (ethers/cosmos/sui/walletconnect/…) | **Removed** | Use `litClient.getPkpViemAccount()` or `litClient.chain.*.pkpSign`. |
+| `@lit-protocol/encryption` | **Removed from core flow** | Use `litClient.encrypt` / `litClient.decrypt`. |
+| `@lit-protocol/contracts-sdk` | `@lit-protocol/contracts` | Contract helpers updated for Naga networks. |
+| `LIT_NETWORK.*` constants | network modules from `@lit-protocol/networks` | Example: `nagaDev`, `nagaTest`. |
+
+## Client + network setup
+
+| v7 | v8 | Notes |
+| --- | --- | --- |
+| `new LitNodeClient({ litNetwork, debug, ... })` | `await createLitClient({ network })` | Handshake happens during creation. |
+| `litNodeClient.connect()` | **Removed** | No explicit connect step in v8. |
+| `litNodeClient.disconnect()` | `litClient.disconnect()` | Stops state manager/handshake polling. |
+| `litNodeClient.getLatestBlockhash()` | `const { latestBlockhash } = await litClient.getContext()` | Mostly internal now; AuthManager handles nonces. |
+| `litNodeClient.signSessionKey()` | **Don’t call directly** | Still exists as a low‑level endpoint; AuthManager uses it. |
+| `rpcUrl / bootstrapUrls` in client config | `network.withOverrides({ rpcUrl })` | Overrides are applied on the network module. |
+
+## Networks
+
+| v7 network | v8 network module | Notes |
+| --- | --- | --- |
+| `datil-dev` / `LIT_NETWORK.DatilDev` | `nagaDev` | Free dev network. |
+| `datil-test` / `LIT_NETWORK.DatilTest` | `nagaTest` | Paid testnet with Ledger. |
+| `datil` / `LIT_NETWORK.Datil` | `naga` | Mainnet module (still rolling out). |
+
+## Authentication and session material
+
+| v7 | v8 | Notes |
+| --- | --- | --- |
+| `authSig` required params on core APIs | **Removed** (optional on `decrypt`) | Core APIs accept `authContext`; `decrypt` also allows an optional `authSig` override. |
+| `sessionSigs` params on core APIs | **Removed** | Session sigs minted internally from authContext. |
+| `litNodeClient.getSessionSigs(...)` | `authManager.createEoaAuthContext(...)` | No `authNeededCallback` required. |
+| `litNodeClient.getPkpSessionSigs(...)` | `authManager.createPkpAuthContext(...)` (core) or `authManager.createPkpSessionSigs(...)` (wrapped‑keys) | Wrapped‑keys still needs exported sigs. |
+| `litNodeClient.getLitActionSessionSigs(...)` | `authManager.createCustomAuthContext(...)` or `createEoaAuthContext` with `lit-action-execution` | Depends on whether a Lit Action is your auth method. |
+| `resourceAbilityRequests: [{ resource, ability }]` | `resources: [[litAbility, "*"]]` | Example: `[['lit-action-execution','*']]`. |
+| `generateSessionCapabilityObjectWithWildcards(...)` on client | `generateSessionCapabilityObjectWithWildcards(...)` from `@lit-protocol/auth-helpers` | Same helper, now standalone. |
+
+## Core APIs
+
+| v7 call | v8 call | Notes |
+| --- | --- | --- |
+| `litNodeClient.executeJs({ sessionSigs, code/ipfsId, jsParams })` | `litClient.executeJs({ authContext, code/ipfsId, jsParams })` | `jsParams` is nested in actions (see below). |
+| `litNodeClient.pkpSign({ sessionSigs, pubKey, toSign })` | `litClient.chain.ethereum.pkpSign({ authContext, pubKey, toSign })` | Use `chain.bitcoin` or `chain.raw` for other schemes. |
+| `encryptString(...)` / `encryptUint8Array(...)` (`@lit-protocol/encryption`) | `litClient.encrypt({ dataToEncrypt, unifiedAccessControlConditions, chain })` | Encryption does **not** require authContext. |
+| `decryptToString(...)` / `decryptToUint8Array(...)` (`@lit-protocol/encryption`) | `litClient.decrypt({ data, unifiedAccessControlConditions, authContext, chain })` | Decryption **requires** authContext. |
+| `getHashedAccessControlConditions(...)` on client | `getHashedAccessControlConditions(...)` from `@lit-protocol/access-control-conditions` | Same name, standalone. |
+| `getFormattedAccessControlConditions(...)` on client | `getFormattedAccessControlConditions(...)` from `@lit-protocol/access-control-conditions` | Same name, standalone. |
+| `litNodeClient.getSignedToken(...)` (JWT) | **Not yet ported / undocumented** | No v8 public helper at time of writing. |
+
+## Lit Actions runtime
+
+| v7 Lit Action | v8 Lit Action | Notes |
+| --- | --- | --- |
+| Globals injected from `jsParams` | Access via `jsParams.*` | Example: `magicNumber` → `jsParams.magicNumber`. |
+| `LitActions.*` | `Lit.Actions.*` | New canonical namespace. |
+
+## PKP management & permissions
+
+| v7 | v8 | Notes |
+| --- | --- | --- |
+| `new LitContracts(...)` (`@lit-protocol/contracts-sdk`) | `litClient.mintWithEoa` / `litClient.mintWithAuth` | PKP minting moved onto litClient. |
+| `contractsClient.addPermittedAction(...)` | `pkpPermissionsManager.addPermittedAction(...)` | Obtain manager via `litClient.getPKPPermissionsManager`. |
+| `contractsClient.addPermittedAddress(...)` | `pkpPermissionsManager.addPermittedAddress(...)` | Same method name, new object. |
+| `contractsClient.addPermittedAuthMethod(...)` | `pkpPermissionsManager.addPermittedAuthMethod(...)` | Same name, new object. |
+| `contractsClient.getPermittedActions/Addresses/AuthMethods` | `pkpPermissionsManager.getPermittedActions/Addresses/AuthMethods` | Same names. |
+| `provider.fetchPKPs(...)` / `provider.getPKPsForAuthMethod(authMethod)` (`@lit-protocol/lit-auth-client`) | `litClient.viewPKPsByAddress({ ownerAddress })` / `litClient.viewPKPsByAuthData({ authData })` | PKP discovery moved onto litClient. |
+
+## Wrapped Keys
+
+| v7 | v8 | Notes |
+| --- | --- | --- |
+| `wrappedKeysApi.*({ pkpSessionSigs, litNodeClient })` | `wrappedKeysApi.*({ pkpSessionSigs, litClient })` | Only the client param changes. |
+| `litNodeClient.getPkpSessionSigs` for WK | `authManager.createPkpSessionSigs` | Generate via AuthManager + delegation auth sig. |
+
+## Payments
+
+| v7 | v8 | Notes |
+| --- | --- | --- |
+| Capacity Credits NFTs | **Removed** | Paid networks use Ledger balance per request. |
+| `createCapacityDelegationAuthSig` | `paymentManager.delegatePaymentsBatch` | Sponsoring users now uses payment delegation. |
+| Capacity “request per kilosecond” limits | `paymentManager.setRestriction` | Same concept, new API. |
+
+# Package and import changes
+
+## Core client + networks
+
+| v7 | v8 |
+| --- | --- |
+| `@lit-protocol/lit-node-client` | `@lit-protocol/lit-client` |
+| `@lit-protocol/lit-node-client-nodejs` | **Removed** (use `@lit-protocol/lit-client` everywhere) |
+| `LIT_NETWORK.*` from `@lit-protocol/constants` | network modules from `@lit-protocol/networks` |
+| `@lit-protocol/encryption` helpers | **Removed from core flow** → use `litClient.encrypt` / `litClient.decrypt` |
+
+Install:
+
+```bash
+npm i @lit-protocol/lit-client @lit-protocol/networks viem
+```
+
+`viem` is a peer dependency in v8; your app must install it.
+
+## Authentication
+
+| v7 | v8 |
+| --- | --- |
+| `litNodeClient.getSessionSigs()` | `authManager.createEoaAuthContext()` |
+| `litNodeClient.getPkpSessionSigs()` | `authManager.createPkpSessionSigs()` (for wrapped-keys) or `authManager.createPkpAuthContext()` (for core APIs) |
+| `@lit-protocol/lit-auth-client` providers (e.g. `EthWalletProvider`) | `@lit-protocol/auth` authenticators + `AuthManager` |
+| Hosted login/mint infra via v7 clients | `@lit-protocol/auth-services` (optional infra) |
+
+Install:
+
+```bash
+npm i @lit-protocol/auth viem
+```
+
+## PKP wallets / chain libs
+
+| v7 | v8 |
+| --- | --- |
+| `@lit-protocol/pkp-ethers`, `PKPEthersWallet`, etc. | **Removed** → use `litClient.getPkpViemAccount()` or `litClient.chain.*.pkpSign` |
+| `ethers`-first examples | `viem`-first examples |
+
+## Contracts
+
+| v7 | v8 |
+| --- | --- |
+| `@lit-protocol/contracts-sdk` | `@lit-protocol/contracts` |
+
+# Networks and client setup
+
+## v7
+
+```ts
+import { LitNodeClient } from "@lit-protocol/lit-node-client";
+import { LIT_NETWORK } from "@lit-protocol/constants";
+
+const litNodeClient = new LitNodeClient({
+ litNetwork: LIT_NETWORK.DatilDev,
+ debug: false,
+});
+await litNodeClient.connect();
+```
+
+## v8
+
+```ts
+import { createLitClient } from "@lit-protocol/lit-client";
+import { nagaDev } from "@lit-protocol/networks";
+
+const litClient = await createLitClient({ network: nagaDev });
+// optional when shutting down:
+litClient.disconnect();
+```
+
+
+ If you previously used `litNodeClient.getLatestBlockhash()` (for SIWE nonces),
+ you can access it via `const { latestBlockhash } = await litClient.getContext();`.
+
+
+### Network name mapping
+
+| v7 network | v8 network |
+| --- | --- |
+| `datil-dev` / `LIT_NETWORK.DatilDev` | `naga-dev` / `nagaDev` |
+| `datil-test` / `LIT_NETWORK.DatilTest` | `naga-test` / `nagaTest` |
+| `datil` / `LIT_NETWORK.Datil` | `naga` / `naga` (mainnet coming soon) |
+
+### Custom RPC / bootstrap overrides
+
+v7 typically passed `rpcUrl` or custom bootstrap URLs into the client config.
+v8 does this on the **network module**:
+
+```ts
+import { nagaTest } from "@lit-protocol/networks";
+
+const network = nagaTest.withOverrides({
+ rpcUrl: "https://my-private-rpc.example.com",
+});
+
+const litClient = await createLitClient({ network });
+```
+
+# Authentication and sessions
+
+v8 removes `sessionSigs` from core APIs and no longer requires `authSig` (except as an optional override on `decrypt`). Instead, you create an `authContext` once and pass it to any method that needs authorization.
+
+## EOA session (replaces `getSessionSigs`)
+
+### v7
+
+```ts
+const sessionSigs = await litNodeClient.getSessionSigs({
+ chain: "ethereum",
+ expiration: new Date(Date.now() + 10 * 60 * 1000).toISOString(),
+ resourceAbilityRequests: [
+ { resource: new LitActionResource("*"), ability: LIT_ABILITY.LitActionExecution },
+ ],
+ authNeededCallback: async ({ uri, expiration, resourceAbilityRequests }) => {
+ const toSign = await createSiweMessage({
+ uri,
+ expiration,
+ resources: resourceAbilityRequests,
+ walletAddress: await ethersWallet.getAddress(),
+ nonce: await litNodeClient.getLatestBlockhash(),
+ litNodeClient,
+ });
+ return generateAuthSig({ signer: ethersWallet, toSign });
+ },
+});
+```
+
+### v8
+
+```ts
+import { createAuthManager, storagePlugins } from "@lit-protocol/auth";
+
+const authManager = createAuthManager({
+ storage: storagePlugins.localStorage({
+ appName: "my-app",
+ networkName: "naga-dev",
+ }),
+});
+
+const eoaAuthContext = await authManager.createEoaAuthContext({
+ config: { account: myViemAccount },
+ authConfig: {
+ domain: "example.com",
+ statement: "Authorize Lit session",
+ resources: [
+ ["lit-action-execution", "*"],
+ ["access-control-condition-decryption", "*"],
+ ["pkp-signing", "*"],
+ ],
+ expiration: new Date(Date.now() + 15 * 60 * 1000).toISOString(),
+ },
+ litClient,
+});
+```
+
+You no longer build SIWE messages or fetch nonces manually; the AuthManager handles that through its authenticators.
+
+
+ v7 helpers like `checkAndSignAuthMessage` / `signAndSaveAuthMessage` are no longer needed.
+ AuthManager persists session materials automatically using the storage plugin you configure.
+
+
+## PKP session (core APIs)
+
+### v7
+
+You typically generated `pkpSessionSigs` and passed them into `executeJs` / `pkpSign`.
+
+### v8
+
+Create a PKP auth context and pass it to core APIs:
+
+```ts
+import { ViemAccountAuthenticator } from "@lit-protocol/auth";
+
+const authData = await ViemAccountAuthenticator.authenticate(myViemAccount);
+
+const pkpAuthContext = await authManager.createPkpAuthContext({
+ authData,
+ pkpPublicKey: myPkp.pubkey,
+ authConfig: {
+ resources: [
+ ["pkp-signing", "*"],
+ ["lit-action-execution", "*"],
+ ],
+ expiration: new Date(Date.now() + 30 * 60 * 1000).toISOString(),
+ },
+ litClient,
+});
+```
+
+## PKP session signatures (wrapped-keys only)
+
+Wrapped-keys APIs still expect a `pkpSessionSigs` bundle for v7 compatibility.
+Generate them in v8 like this:
+
+```ts
+import { generateSessionKeyPair } from "@lit-protocol/auth";
+
+const sessionKeyPair = generateSessionKeyPair();
+
+const delegationAuthSig = await authManager.generatePkpDelegationAuthSig({
+ pkpPublicKey: myPkp.pubkey,
+ authData,
+ sessionKeyPair,
+ authConfig: {
+ resources: [
+ ["pkp-signing", "*"],
+ ["lit-action-execution", "*"],
+ ["access-control-condition-decryption", "*"],
+ ],
+ expiration: new Date(Date.now() + 15 * 60 * 1000).toISOString(),
+ },
+ litClient,
+});
+
+const pkpSessionSigs = await authManager.createPkpSessionSigs({
+ sessionKeyPair,
+ pkpPublicKey: myPkp.pubkey,
+ delegationAuthSig,
+ litClient,
+});
+```
+
+# Core API method changes
+
+## `executeJs`
+
+### v7
+
+```ts
+const res = await litNodeClient.executeJs({
+ sessionSigs,
+ code,
+ jsParams: { magicNumber: 43 },
+});
+```
+
+### v8
+
+```ts
+const res = await litClient.executeJs({
+ code,
+ authContext: eoaAuthContext,
+ jsParams: { magicNumber: 43 },
+});
+```
+
+## Lit Actions runtime: **`jsParams` is now nested**
+
+This is the biggest Lit Actions breaking change.
+
+| v7 Lit Action | v8 Lit Action |
+| --- | --- |
+| `if (magicNumber >= 42) { ... }` | `if (jsParams.magicNumber >= 42) { ... }` |
+
+In v7, keys in `jsParams` were injected as globals.
+In v8, all custom inputs live under the global `jsParams` object.
+
+Also prefer `Lit.Actions.*` over `LitActions.*` in new actions.
+
+## `pkpSign`
+
+### v7
+
+```ts
+const sig = await litNodeClient.pkpSign({
+ pubKey: pkpPubKey,
+ toSign,
+ sessionSigs,
+});
+```
+
+### v8
+
+```ts
+const sig = await litClient.chain.ethereum.pkpSign({
+ pubKey: pkpPubKey,
+ toSign,
+ authContext: pkpAuthContext,
+ // bypassAutoHashing: true, // if you already hashed data (e.g. EIP-712 digest)
+});
+```
+
+Notes:
+
+- PKP signing is now grouped by chain (`litClient.chain.ethereum`, `litClient.chain.bitcoin`, or `litClient.chain.raw`).
+- Core APIs always require `authContext`; they mint session signatures internally.
+
+## Encryption / decryption
+
+### v7 (typical)
+
+```ts
+import { encryptString, decryptToString } from "@lit-protocol/encryption";
+
+const encrypted = await encryptString(
+ {
+ accessControlConditions,
+ dataToEncrypt: "secret",
+ chain: "ethereum",
+ },
+ litNodeClient
+);
+
+const plaintext = await decryptToString(
+ {
+ accessControlConditions,
+ ciphertext: encrypted.ciphertext,
+ dataToEncryptHash: encrypted.dataToEncryptHash,
+ chain: "ethereum",
+ sessionSigs,
+ },
+ litNodeClient
+);
+```
+
+### v8
+
+```ts
+const encrypted = await litClient.encrypt({
+ dataToEncrypt: "secret",
+ unifiedAccessControlConditions,
+ chain: "ethereum",
+});
+
+const plaintext = await litClient.decrypt({
+ data: encrypted,
+ unifiedAccessControlConditions,
+ authContext: eoaAuthContext,
+ chain: "ethereum",
+});
+```
+
+v8 still accepts `accessControlConditions`, `evmContractConditions`, or `solRpcConditions`, but the unified builder (`createAccBuilder`) plus `unifiedAccessControlConditions` is the recommended path.
+
+# Wrapped Keys migration
+
+Only two changes for most users:
+
+1. Pass `litClient` instead of `litNodeClient`.
+2. Generate `pkpSessionSigs` via `AuthManager` (section above).
+
+```ts
+import { api as wrappedKeysApi } from "@lit-protocol/wrapped-keys";
+
+const { id } = await wrappedKeysApi.generatePrivateKey({
+ pkpSessionSigs,
+ litClient,
+ network: "evm",
+});
+```
+
+# Payments: Capacity Credits → Ledger + PaymentManager
+
+v7 Capacity Credits NFTs and `createCapacityDelegationAuthSig` flows are deprecated in v8.
+
+In v8:
+
+- Paid networks (`naga-test`, `naga`) charge per request.
+- Users (or your app) fund a Ledger balance.
+- Apps can sponsor users by delegating payments.
+
+## Minimal self‑funded setup
+
+```ts
+const paymentManager = await litClient.getPaymentManager({
+ account: myViemAccount,
+});
+
+await paymentManager.deposit({ amountInEth: "0.1" });
+```
+
+Then call core APIs as usual.
+Use `userMaxPrice` to cap spend per request:
+
+```ts
+await litClient.executeJs({
+ code,
+ authContext,
+ jsParams,
+ userMaxPrice: 1_000_000_000_000_000n,
+});
+```
+
+## Sponsoring users (replaces Capacity Delegation)
+
+```ts
+await paymentManager.setRestriction({
+ totalMaxPrice: "1000000000000000000", // wei
+ requestsPerPeriod: "100",
+ periodSeconds: "3600",
+});
+
+await paymentManager.delegatePaymentsBatch({
+ userAddresses: ["0xAlice...", "0xBob..."],
+});
+```
+
+See [Payment Manager Setup](/sdk/getting-started/payment-manager-setup) for full details.
+
+# If you used `pkp-ethers`
+
+The ethers PKP wallets were removed. Two common replacements:
+
+1. **Use viem account integration**
+
+```ts
+const pkpAccount = await litClient.getPkpViemAccount({
+ pkpPublicKey: myPkp.pubkey,
+ authContext: pkpAuthContext,
+ chainConfig: myViemChain,
+});
+```
+
+2. **Call `pkpSign` directly** via `litClient.chain.*.pkpSign` and assemble transactions yourself.
+
+# Other notable removals / moves
+
+- `lit-auth-client` and its auth providers are replaced by `@lit-protocol/auth` + optional `@lit-protocol/auth-services`.
+- Node‑only vs browser‑only split packages are consolidated; v8 is isomorphic by default.
+- Low‑level helpers from v7 still exist in subpackages where applicable, but most apps can migrate to the higher‑level `litClient`/`authManager` APIs shown here.
+
+# Troubleshooting after upgrade
+
+## “`magicNumber` is not defined” inside Lit Actions
+
+Update Lit Action code to read `jsParams.magicNumber` (see runtime section).
+
+## “Missing peer dependency `viem`”
+
+Install `viem` and ensure your bundler doesn’t dedupe it away.
+
+## “Insufficient ledger balance / payment required”
+
+Deposit funds with `PaymentManager.deposit` or delegate a payer (paid networks only).
+
+## Wrapped keys failing with “missing pkpSessionSigs”
+
+Core APIs no longer need session sigs, but wrapped‑keys still do. Generate them via `authManager.createPkpSessionSigs`.
+
+# Next steps
+
+- Browse the v8 SDK docs starting at [Lit Client Setup](/sdk/getting-started/lit-client).
+- For serverless reuse patterns, see [Server Sessions](/guides/server-sessions).
diff --git a/packages/networks/src/networks/vNaga/shared/factories/BaseModuleFactory.ts b/packages/networks/src/networks/vNaga/shared/factories/BaseModuleFactory.ts
index a7fc55500..d9813b4cf 100644
--- a/packages/networks/src/networks/vNaga/shared/factories/BaseModuleFactory.ts
+++ b/packages/networks/src/networks/vNaga/shared/factories/BaseModuleFactory.ts
@@ -907,6 +907,10 @@ export function createBaseModule(config: BaseModuleConfig) {
accessToken: requestBody.authData.accessToken,
} as AuthMethod;
+ const maxPriceHex = `0x${getUserMaxPrice({
+ product: 'SIGN_SESSION_KEY',
+ }).toString(16)}`;
+
const requests: RequestItem<
z.infer
>[] = [];
@@ -921,9 +925,7 @@ export function createBaseModule(config: BaseModuleConfig) {
curveType: 'BLS' as const,
epoch: requestBody.epoch,
nodeSet: requestBody.nodeSet,
- maxPrice: getUserMaxPrice({
- product: 'SIGN_SESSION_KEY',
- }).toString(),
+ maxPrice: maxPriceHex,
};
const encryptedPayload = E2EERequestManager.encryptRequestData(
@@ -1031,6 +1033,28 @@ export function createBaseModule(config: BaseModuleConfig) {
(node) => `${httpProtocol}${node.socketAddress}`
);
+ const encodedCode = requestBody.litActionCode
+ ? Buffer.from(requestBody.litActionCode, 'utf-8').toString('base64')
+ : undefined;
+
+ const maxPriceHex = `0x${getUserMaxPrice({
+ product: 'SIGN_SESSION_KEY',
+ }).toString(16)}`;
+
+ // `requestBody.jsParams` can arrive in either shape:
+ // - raw: ``
+ // - nested (AuthManager): `{ jsParams: }` via
+ // `params.customAuthParams.jsParams = { jsParams: params.customAuthParams.jsParams };`
+ // in `packages/auth/src/lib/AuthManager/auth-manager.ts`
+ //
+ // Example:
+ // - user passes: `{ foo: 1 }`
+ // - AuthManager wraps: `{ jsParams: { foo: 1 } }`
+ // - normalized here: `rawJsParams = { foo: 1 }`
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const rawJsParams =
+ (requestBody.jsParams as any)?.jsParams ?? requestBody.jsParams;
+
const requests: RequestItem<
z.infer
>[] = [];
@@ -1045,12 +1069,20 @@ export function createBaseModule(config: BaseModuleConfig) {
curveType: 'BLS' as const,
epoch: requestBody.epoch,
nodeSet: requestBody.nodeSet,
- litActionCode: requestBody.litActionCode,
- litActionIpfsId: requestBody.litActionIpfsId,
- jsParams: requestBody.jsParams,
- maxPrice: getUserMaxPrice({
- product: 'SIGN_SESSION_KEY',
- }).toString(),
+ ...(encodedCode && { code: encodedCode }),
+ ...(requestBody.litActionIpfsId && {
+ litActionIpfsId: requestBody.litActionIpfsId,
+ }),
+ ...(rawJsParams && {
+ // Expose both raw + nested `jsParams` for compatibility:
+ // - Lit Action can read `jsParams.foo`
+ // - or `jsParams.jsParams.foo`
+ jsParams: {
+ ...rawJsParams,
+ jsParams: rawJsParams,
+ },
+ }),
+ maxPrice: maxPriceHex,
};
const encryptedPayload = E2EERequestManager.encryptRequestData(
diff --git a/packages/wrapped-keys-lit-actions/src/lib/internal/solana/signMessage.ts b/packages/wrapped-keys-lit-actions/src/lib/internal/solana/signMessage.ts
index ffc9cdc8c..8680abcd9 100644
--- a/packages/wrapped-keys-lit-actions/src/lib/internal/solana/signMessage.ts
+++ b/packages/wrapped-keys-lit-actions/src/lib/internal/solana/signMessage.ts
@@ -39,10 +39,11 @@ function verifyMessageSignature({
messageToSign,
}: VerifyMessageSignatureParams): boolean {
try {
+ const messageBytes = new TextEncoder().encode(messageToSign);
const isValid = nacl.sign.detached.verify(
- Buffer.from(messageToSign),
+ messageBytes,
signature,
- solanaKeyPair.publicKey.toBuffer()
+ solanaKeyPair.publicKey.toBytes()
);
return isValid;
@@ -62,7 +63,8 @@ export async function signMessageSolanaKey({
messageToSign: string;
privateKey: string;
}): Promise {
- const solanaKeyPair = Keypair.fromSecretKey(Buffer.from(privateKey, 'hex'));
+ const privateKeyBytes = Uint8Array.from(Buffer.from(privateKey, 'hex'));
+ const solanaKeyPair = Keypair.fromSecretKey(privateKeyBytes);
const { signature } = signMessage({
messageToSign,
diff --git a/packages/wrapped-keys-lit-actions/src/lib/internal/solana/signTransaction.ts b/packages/wrapped-keys-lit-actions/src/lib/internal/solana/signTransaction.ts
index a9aba72e7..3bf69e842 100644
--- a/packages/wrapped-keys-lit-actions/src/lib/internal/solana/signTransaction.ts
+++ b/packages/wrapped-keys-lit-actions/src/lib/internal/solana/signTransaction.ts
@@ -98,21 +98,22 @@ export async function signTransactionSolanaKey({
}) {
// Be sure you call validateUnsignedTransaction(unsignedTransaction); before calling this method!
- const solanaKeyPair = Keypair.fromSecretKey(Buffer.from(privateKey, 'hex'));
+ const privateKeyBytes = Uint8Array.from(Buffer.from(privateKey, 'hex'));
+ const solanaKeyPair = Keypair.fromSecretKey(privateKeyBytes);
let transaction;
let signature;
if (versionedTransaction) {
- const swapTransactionBuf = Buffer.from(
- unsignedTransaction.serializedTransaction,
- 'base64'
+ const serializedTxBytes = Uint8Array.from(
+ Buffer.from(unsignedTransaction.serializedTransaction, 'base64')
);
- transaction = VersionedTransaction.deserialize(swapTransactionBuf);
+ transaction = VersionedTransaction.deserialize(serializedTxBytes);
signature = signVersionedTransaction({ transaction, solanaKeyPair });
} else {
- transaction = Transaction.from(
+ const serializedTxBytes = Uint8Array.from(
Buffer.from(unsignedTransaction.serializedTransaction, 'base64')
);
+ transaction = Transaction.from(serializedTxBytes);
signature = signLegacyTransaction({ transaction, solanaKeyPair });
}