Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.startale.com/llms.txt

Use this file to discover all available pages before exploring further.

Smart sessions let your dapp act on the user’s behalf within an explicit policy: a set of allowed contracts, function selectors, and an expiry. The user signs once to grant the session; afterwards every UserOperation that fits inside the policy can be executed by a session signer without prompting the user again. Smart sessions are implemented as an ERC-7579 validator module. The Startale AA SDK ships first-party helpers around the Rhinestone Smart Sessions module so you can install it and grant permissions through the same StartaleAccountClient you already use.
Source: StartaleGroup/scs-aa-sdk. The flow below mirrors the production integration in the Startale super-app.

How it fits together

Two artefacts come out of the granting step:
  • A permission id that identifies the policy onchain.
  • A session key keypair. The public key is committed to the policy; the private key is used by your backend or browser to sign UserOperations within scope.

1. Check whether the module is installed

getSmartSessionsValidator builds the validator descriptor. The module is keyed by its onchain address, so you can call isModuleInstalled on the account client to check status before installing.
import {
  getSmartSessionsValidator,
  type StartaleAccountClient,
} from "@startale-scs/aa-sdk"

const SMART_SESSIONS_MODULE = "0x00000000008bDABA73cD9815d79069c247Eb4bDA" as const

async function isSmartSessionsInstalled(client: StartaleAccountClient) {
  const sessionModule = getSmartSessionsValidator({})
  sessionModule.address = SMART_SESSIONS_MODULE
  sessionModule.module = SMART_SESSIONS_MODULE
  return client.isModuleInstalled({ module: sessionModule })
}
SymbolSourceRole
getSmartSessionsValidator@startale-scs/aa-sdkReturns a validator descriptor pre-wired for the Smart Sessions module.
isModuleInstalledStartaleAccountClient (ERC-7579 actions)Reads the account’s installed validators onchain.

2. Install the module (one-time per account)

If the module is not installed, install it once. Installation is itself a UserOperation, so it goes through your bundler and (optionally) your paymaster.
async function installSmartSessions(client: StartaleAccountClient) {
  const sessionModule = getSmartSessionsValidator({})
  sessionModule.address = SMART_SESSIONS_MODULE
  sessionModule.module = SMART_SESSIONS_MODULE

  const userOpHash = await client.installModule({ module: sessionModule })
  return client.waitForUserOperationReceipt({ hash: userOpHash })
}
SymbolSourceRole
installModuleStartaleAccountClient (ERC-7579 actions)Sends a UserOperation that installs the module on the account.
waitForUserOperationReceiptStartaleAccountClientPolls the bundler for the receipt.

3. Define the permission scope

A session scope is a list of CreateSessionDataParams. Each entry binds the session key to a contract and a function selector, with optional onchain policies.
import type { CreateSessionDataParams } from "@startale-scs/aa-sdk"
import type { Address } from "viem"

function buildSessionScope(sessionPublicKey: Address): CreateSessionDataParams[] {
  return [
    {
      sessionPublicKey,
      actionPoliciesInfo: [
        {
          contractAddress: "0x...USDC...",
          functionSelector: "0x095ea7b3", // approve(address,uint256)
          sudo: true,
        },
        {
          contractAddress: "0x...Router...",
          functionSelector: "0xa3443faa", // your target selector
          sudo: true,
        },
      ],
    },
  ]
}
FieldTypeNotes
sessionPublicKeyAddressThe public key of the session signer. The corresponding private key signs UserOperations within scope.
actionPoliciesInfo[].contractAddressAddressContract the session is allowed to call.
actionPoliciesInfo[].functionSelectorHexThe 4-byte selector the session is allowed to call on that contract.
actionPoliciesInfo[].sudobooleanWhen true, allows any arguments. Set to false and add granular policies (spending caps, allowlists) for tighter control.
Generate the session key with viem’s generatePrivateKey() + privateKeyToAccount() and store the private key wherever you intend to sign from (typically a backend service or a sealed browser store).

4. Grant the permission

Granting the permission is also a UserOperation, signed once by the account owner. Use smartSessionCreateActions to extend the account client with the granting action, then call grantPermission.
import {
  smartSessionCreateActions,
  toSmartSessionsValidator,
  type Signer,
} from "@startale-scs/aa-sdk"
import type { Address, Hex } from "viem"

async function grantSession(
  client: StartaleAccountClient,
  sessionPublicKey: Address,
) {
  const sessionData = buildSessionScope(sessionPublicKey)

  const sessionSigner = toSmartSessionsValidator({
    account: client.account,
    signer: {
      address: sessionPublicKey,
      // Backend or remote signer holds the private key; the frontend uses a noop.
      signMessage: () => Promise.resolve("0x" as Hex),
      signTransaction: () => Promise.resolve("0x" as Hex),
      signTypedData: () => Promise.resolve("0x" as Hex),
      publicKey: "0x" as Hex,
      source: "",
      type: "local",
    } as Signer,
  })

  const response = await client
    .extend(smartSessionCreateActions(sessionSigner))
    .grantPermission({ sessionRequestedInfo: sessionData })

  return {
    permissionIds: response.permissionIds,
    userOpHash: response.userOpHash,
  }
}
SymbolSourceRole
toSmartSessionsValidator@startale-scs/aa-sdkBuilds the per-session validator object bound to the account and the session signer.
smartSessionCreateActions@startale-scs/aa-sdkExtends StartaleAccountClient with grantPermission.
grantPermissionextended client actionSends a UserOperation that registers the policy and returns one permission id per sessionRequestedInfo entry.

5. Execute UserOperations under the session

Once granted, build a separate StartaleAccountClient whose signer is the session key. UserOperations from this client are validated by the Smart Sessions module instead of the account’s default validator.
import { http } from "viem"
import { privateKeyToAccount } from "viem/accounts"
import { soneiumMinato } from "viem/chains"
import {
  createSmartAccountClient,
  toStartaleSmartAccount,
} from "@startale-scs/aa-sdk"

const sessionSigner = privateKeyToAccount(SESSION_PRIVATE_KEY)

const sessionAccount = await toStartaleSmartAccount({
  signer: sessionSigner,
  chain: soneiumMinato,
  transport: http(),
  accountAddress: ownerAccountAddress, // same smart account, different signer
})

const sessionClient = createSmartAccountClient({
  account: sessionAccount,
  transport: http(process.env.BUNDLER_URL!),
  client: publicClient,
})

const hash = await sessionClient.sendUserOperation({
  calls: [{ to: routerAddress, data: callData, value: 0n }],
})
The user is not prompted; the session key signs locally, and the Smart Sessions module decides onchain whether the call is in scope.

Operational guidance

Treat session private keys like any other production secret. Keep them on a backend or in a sealed enclave, never in plain localStorage. Set the shortest expiry that still produces a good UX, and rotate keys on a schedule.
ConcernRecommendation
StorageBackend KMS, secure enclave, or sealed browser storage.
RotationIssue short sessions (minutes-to-hours for high-risk flows, days for low-risk).
RevocationRevoke a permission id by calling the module’s revocation flow when a session is compromised.
AuditingPersist permission ids alongside userOpHash so you can correlate signed sessions with onchain activity.

Next steps

Social recovery

Combine sessions with a guardian-based recovery module.

Sponsored paymaster

Sponsor every session UserOperation through the SCS paymaster.

Parallel transactions

Run independent session UserOperations concurrently.

Smart account setup

Refresh the underlying account and client setup.