Smart Sessions allow accounts to delegate specific permissions to other signers with fine-grained control over what actions they can perform.
toSmartSessionsModule
Create a Smart Sessions validator module.
import { toSmartSessionsModule } from "@biconomy/abstractjs";
const sessionsModule = toSmartSessionsModule(options);
Parameters
| Parameter | Type | Required | Description |
|---|
signer | Account | Yes | The session signer |
Example
import { toSmartSessionsModule } from "@biconomy/abstractjs";
import { privateKeyToAccount } from "viem/accounts";
const sessionSigner = privateKeyToAccount("0x...");
const sessionsModule = toSmartSessionsModule({
signer: sessionSigner
});
meeSessionActions
Extend the MEE client with session-related methods.
import { meeSessionActions } from "@biconomy/abstractjs";
const sessionClient = meeClient.extend(meeSessionActions);
Added Methods
prepareForPermissions
grantPermissionTypedDataSign
grantPermissionPersonalSign
usePermission
isPermissionEnabled
checkEnabledPermissions
prepareForPermissions
Deploy accounts and install Smart Sessions module.
const payload = await sessionClient.prepareForPermissions(options);
Parameters
| Parameter | Type | Required | Description |
|---|
smartSessionsValidator | SessionsModule | Yes | Sessions module |
feeToken | FeeTokenInfo | Yes | Gas payment token |
trigger | Trigger | No | Funding trigger |
Example
const payload = await sessionClient.prepareForPermissions({
smartSessionsValidator: sessionsModule,
feeToken: { address: USDC, chainId: 8453 },
trigger: {
tokenAddress: USDC,
chainId: 8453,
amount: parseUnits("10", 6)
}
});
if (payload) {
await meeClient.waitForSupertransactionReceipt({ hash: payload.hash });
}
grantPermissionTypedDataSign
Grant permissions using EIP-712 typed data signature.
const sessionDetails = await sessionClient.grantPermissionTypedDataSign(options);
Parameters
| Parameter | Type | Required | Description |
|---|
redeemer | Address | Yes | Session signer address |
feeToken | FeeTokenInfo | Yes | Gas payment token |
actions | ActionConfig[] | Yes | Allowed actions |
maxPaymentAmount | bigint | No | Max gas payment |
ActionConfig
| Property | Type | Description |
|---|
chainId | number | Chain where permission applies |
actionTarget | Address | Contract address |
actionTargetSelector | Hex | Function selector |
actionPolicies | Policy[] | Policies to apply |
Example
import { toFunctionSelector, getAbiItem } from "viem";
const sessionDetails = await sessionClient.grantPermissionTypedDataSign({
redeemer: sessionSigner.address,
feeToken: { address: USDC, chainId: 8453 },
actions: [
{
chainId: 8453,
actionTarget: CounterContract,
actionTargetSelector: toFunctionSelector(
getAbiItem({ abi: CounterAbi, name: "increment" })
),
actionPolicies: [getSudoPolicy()]
}
],
maxPaymentAmount: parseUnits("2", 6)
});
usePermission
Execute instructions using granted permissions.
const result = await sessionClient.usePermission(options);
Parameters
| Parameter | Type | Required | Description |
|---|
sessionDetails | SessionDetails | Yes | From grantPermission |
mode | "ENABLE_AND_USE" | "USE" | Yes | Execution mode |
feeToken | FeeTokenInfo | Yes | Gas payment token |
instructions | Instruction[] | Yes | Instructions to execute |
sponsorship | boolean | No | Enable sponsorship |
verificationGasLimit | bigint | No | Custom gas limit |
Example
const result = await sessionClient.usePermission({
sessionDetails,
mode: "ENABLE_AND_USE",
feeToken: { address: USDC, chainId: 8453 },
instructions: [
{
chainId: 8453,
calls: [{ to: CounterContract, data: "0x..." }]
}
]
});
await meeClient.waitForSupertransactionReceipt({ hash: result.hash });
Policies
getSudoPolicy
Grants unlimited permissions for specified functions.
import { getSudoPolicy } from "@biconomy/abstractjs";
actionPolicies: [getSudoPolicy()]
Use with caution—provides highest level of access.
getUniversalActionPolicy
Fine-grained parameter-level control.
import { getUniversalActionPolicy, ParamCondition } from "@biconomy/abstractjs";
const policy = getUniversalActionPolicy({
valueLimitPerUse: maxUint256,
paramRules: {
length: 2n,
rules: [
{
condition: ParamCondition.EQUAL,
isLimited: false,
offset: 0n,
ref: pad(recipientAddress),
usage: { limit: 0n, used: 0n }
},
{
condition: ParamCondition.LESS_THAN_OR_EQUAL,
isLimited: true,
offset: 32n,
ref: pad(toHex(parseUnits("100", 6))),
usage: { limit: parseUnits("1000", 6), used: 0n }
}
]
}
});
ParamCondition
| Value | Description |
|---|
EQUAL | Exact match |
GREATER_THAN | Value > reference |
LESS_THAN | Value < reference |
GREATER_THAN_OR_EQUAL | Value ≥ reference |
LESS_THAN_OR_EQUAL | Value ≤ reference |
NOT_EQUAL | Value ≠ reference |
Time-Based Permissions
const sessionDetails = await sessionClient.grantPermissionTypedDataSign({
redeemer: sessionSigner.address,
feeToken,
sessionValidAfter: Math.floor(Date.now() / 1000),
sessionValidUntil: Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60, // 7 days
actions: [...]
});
Check Permission Status
isPermissionEnabled
const isEnabled = await sessionClient.isPermissionEnabled({
permissionId: permission.permissionId,
chainId: 8453
});
checkEnabledPermissions
const enabledMap = await sessionClient.checkEnabledPermissions(sessionDetails);
// Returns: { [permissionId]: { [chainId]: boolean } }
Complete Flow
// 1. Setup
const sessionSigner = privateKeyToAccount("0x...");
const sessionsModule = toSmartSessionsModule({ signer: sessionSigner });
const sessionClient = meeClient.extend(meeSessionActions);
// 2. Prepare (deploy + install module)
await sessionClient.prepareForPermissions({
smartSessionsValidator: sessionsModule,
feeToken,
trigger
});
// 3. Grant permissions
const sessionDetails = await sessionClient.grantPermissionTypedDataSign({
redeemer: sessionSigner.address,
feeToken,
actions: [{ chainId: 8453, actionTarget: contract, actionTargetSelector, actionPolicies: [getSudoPolicy()] }]
});
// 4. Use permissions (from session signer)
const result = await dappSessionClient.usePermission({
sessionDetails,
mode: "ENABLE_AND_USE",
feeToken,
instructions: [...]
});