Implement temporary permissions for dApps using session keys
import { toECDSASigner } from "@zerodev/permissions/signers";
import { toPermissionValidator } from "@zerodev/permissions";
import { toCallPolicy, toSudoPolicy } from "@zerodev/permissions/policies";
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
async function createSessionKey(
kernelClient: any,
permissions: {
target?: string;
functionSelector?: string;
valueLimit?: bigint;
validAfter?: number;
validUntil?: number;
}
) {
const sessionPrivateKey = generatePrivateKey();
const sessionKeySigner = privateKeyToAccount(sessionPrivateKey);
console.log("Session Key Address:", sessionKeySigner.address);
const ecdsaSigner = toECDSASigner({ signer: sessionKeySigner });
const policies = [];
if (permissions.target) {
policies.push(
toCallPolicy({
target: permissions.target,
selector: permissions.functionSelector,
valueLimit: permissions.valueLimit || 0n
})
);
}
const permissionPlugin = await toPermissionValidator(kernelClient.publicClient, {
signer: ecdsaSigner,
policies,
validAfter: permissions.validAfter || Math.floor(Date.now() / 1000),
validUntil: permissions.validUntil || Math.floor(Date.now() / 1000) + 86400
});
const userOpHash = await kernelClient.installPlugin({
plugin: permissionPlugin
});
await kernelClient.waitForUserOperationReceipt({ hash: userOpHash });
console.log("Session key created!");
return {
sessionKey: sessionPrivateKey,
sessionKeySigner,
permissionPlugin
};
}
import { createKernelAccountClient } from "@zerodev/sdk";
import { toECDSASigner } from "@zerodev/permissions/signers";
import { privateKeyToAccount } from "viem/accounts";
async function useSessionKey(
sessionPrivateKey: string,
account: any,
bundlerUrl: string,
publicClient: any
) {
const sessionKeySigner = privateKeyToAccount(sessionPrivateKey);
const ecdsaSigner = toECDSASigner({ signer: sessionKeySigner });
const sessionKeyClient = createKernelAccountClient({
account,
chain: account.client.chain,
bundlerTransport: http(bundlerUrl),
client: publicClient,
middleware: {
sponsorUserOperation: async (args) => {
console.log("Using session key for:", args);
return args;
}
}
});
console.log("Session key client ready");
console.log("Using session key:", sessionKeySigner.address);
return sessionKeyClient;
}
import { toCallPolicy, toGasPolicy, toRateLimitPolicy } from "@zerodev/permissions/policies";
import { encodeFunctionData, parseAbi } from "viem";
async function createScopedSessionKey(
kernelClient: any,
config: {
erc20Token: string;
spendLimit: bigint;
recipient: string;
rateLimit: number;
}
) {
const erc20Abi = parseAbi([
"function transfer(address to, uint256 amount) returns (bool)"
]);
const policies = [
toCallPolicy({
target: config.erc20Token,
selector: "0xa9059cbb",
valueLimit: 0n,
constraints: [
{
condition: "EQUAL",
offset: 0,
value: config.recipient
},
{
condition: "LESS_THAN_OR_EQUAL",
offset: 32,
value: config.spendLimit
}
]
}),
toGasPolicy({
allowed: parseEther("0.01")
}),
toRateLimitPolicy({
count: config.rateLimit,
interval: 86400
})
];
const sessionPrivateKey = generatePrivateKey();
const sessionKeySigner = privateKeyToAccount(sessionPrivateKey);
const ecdsaSigner = toECDSASigner({ signer: sessionKeySigner });
const permissionPlugin = await toPermissionValidator(kernelClient.publicClient, {
signer: ecdsaSigner,
policies,
validUntil: Math.floor(Date.now() / 1000) + 86400
});
const userOpHash = await kernelClient.installPlugin({
plugin: permissionPlugin
});
await kernelClient.waitForUserOperationReceipt({ hash: userOpHash });
console.log("Scoped session key created");
console.log("- Token:", config.erc20Token);
console.log("- Recipient:", config.recipient);
console.log("- Spend Limit:", formatEther(config.spendLimit));
console.log("- Rate Limit:", config.rateLimit, "per day");
return {
sessionKey: sessionPrivateKey,
sessionKeySigner,
permissionPlugin
};
}
async function revokeSessionKey(
kernelClient: any,
permissionPlugin: any
) {
try {
const userOpHash = await kernelClient.uninstallPlugin({
plugin: permissionPlugin
});
console.log("Revoking session key...");
const receipt = await kernelClient.waitForUserOperationReceipt({
hash: userOpHash
});
console.log("Session key revoked:", receipt.receipt.transactionHash);
return receipt;
} catch (error) {
console.error("Failed to revoke session key:", error);
throw error;
}
}