The Sudo Policy grants unrestricted access to specified contract functions. It’s the simplest policy—and the most powerful.
When to Use Sudo
Target contract is audited and trusted (Uniswap, Aave, Morpho)
No user funds at direct risk (game actions, governance votes)
You need simplicity over granular control
Combined with time limits or usage limits
When NOT to Use Sudo
Agent handles significant user funds without other limits
Target contract has dangerous functions (e.g., approve for arbitrary spenders)
You need spending caps or parameter validation
Indefinite access without time bounds
Basic Usage
import { getSudoPolicy } from "@biconomy/abstractjs";
const sessionDetails = await sessionClient.grantPermissionTypedDataSign({
redeemer: agentSigner.address,
feeToken: { address: USDC, chainId: base.id },
actions: [{
chainId: base.id,
actionTarget: MORPHO_VAULT,
actionTargetSelector: toFunctionSelector("deposit(uint256,address)"),
actionPolicies: [getSudoPolicy()]
}]
});
Agent Examples
Yield Optimizer Agent
Trust deposits/withdrawals on vetted protocols:
const TRUSTED_PROTOCOLS = {
morpho: "0xA2Cac0023a4797b4729Db94783405189a4203AFc",
aave: "0x...",
};
const sessionDetails = await sessionClient.grantPermissionTypedDataSign({
redeemer: agentSigner.address,
feeToken: { address: USDC, chainId: base.id },
// Always add time limits with Sudo
sessionValidUntil: Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60,
// Cap gas spend
maxPaymentAmount: parseUnits("50", 6),
actions: [
// Morpho deposit
{
chainId: base.id,
actionTarget: TRUSTED_PROTOCOLS.morpho,
actionTargetSelector: toFunctionSelector("deposit(uint256,address)"),
actionPolicies: [getSudoPolicy()]
},
// Morpho withdraw
{
chainId: base.id,
actionTarget: TRUSTED_PROTOCOLS.morpho,
actionTargetSelector: toFunctionSelector("withdraw(uint256,address,address)"),
actionPolicies: [getSudoPolicy()]
},
// Aave supply
{
chainId: base.id,
actionTarget: TRUSTED_PROTOCOLS.aave,
actionTargetSelector: toFunctionSelector("supply(address,uint256,address,uint16)"),
actionPolicies: [getSudoPolicy()]
},
// Aave withdraw
{
chainId: base.id,
actionTarget: TRUSTED_PROTOCOLS.aave,
actionTargetSelector: toFunctionSelector("withdraw(address,uint256,address)"),
actionPolicies: [getSudoPolicy()]
}
]
});
Gaming Agent
Full access to game contract with usage limits:
const GAME_CONTRACT = "0x...";
const sessionDetails = await sessionClient.grantPermissionTypedDataSign({
redeemer: agentSigner.address,
feeToken: { address: USDC, chainId: base.id },
// 7-day session
sessionValidUntil: Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60,
actions: [
{
chainId: base.id,
actionTarget: GAME_CONTRACT,
actionTargetSelector: toFunctionSelector("claimRewards()"),
usageLimit: 100n, // Max 100 claims
actionPolicies: [getSudoPolicy()]
},
{
chainId: base.id,
actionTarget: GAME_CONTRACT,
actionTargetSelector: toFunctionSelector("performAction(uint256)"),
usageLimit: 1000n, // Max 1000 actions
actionPolicies: [getSudoPolicy()]
}
]
});
Governance Agent
Vote on proposals automatically:
const GOVERNOR = "0x...";
const sessionDetails = await sessionClient.grantPermissionTypedDataSign({
redeemer: agentSigner.address,
feeToken: { address: USDC, chainId: base.id },
// 1 year for governance
sessionValidUntil: Math.floor(Date.now() / 1000) + 365 * 24 * 60 * 60,
actions: [{
chainId: base.id,
actionTarget: GOVERNOR,
actionTargetSelector: toFunctionSelector("castVote(uint256,uint8)"),
actionPolicies: [getSudoPolicy()]
}]
});
Sudo + Time Range
Always combine Sudo with time limits:
const sessionDetails = await sessionClient.grantPermissionTypedDataSign({
redeemer: agentSigner.address,
feeToken,
// Session-level time bounds
sessionValidAfter: Math.floor(Date.now() / 1000),
sessionValidUntil: Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60,
actions: [{
chainId: base.id,
actionTarget: CONTRACT,
actionTargetSelector: selector,
// Action-level time bounds (can be narrower)
validAfter: Math.floor(Date.now() / 1000),
validUntil: Math.floor(Date.now() / 1000) + 24 * 60 * 60, // Just 1 day
actionPolicies: [getSudoPolicy()]
}]
});
Sudo + Usage Limit
Cap total number of actions:
actions: [{
chainId: base.id,
actionTarget: CONTRACT,
actionTargetSelector: selector,
usageLimit: 50n, // Max 50 uses ever
actionPolicies: [getSudoPolicy()]
}]
Security Checklist
Time limit set (sessionValidUntil)
Only specific functions allowed (not entire contract)
Target contract is audited
Usage limit considered for high-risk actions
Gas spend capped (maxPaymentAmount)
Common Mistakes
Granting Sudo to approve() functionThis lets the agent approve arbitrary spenders. Never do this:// ❌ DANGEROUS
actionTargetSelector: toFunctionSelector("approve(address,uint256)")
No time limitWithout sessionValidUntil, the permission never expires:// ❌ BAD - no time limit
const sessionDetails = await sessionClient.grantPermissionTypedDataSign({
actions: [{ actionPolicies: [getSudoPolicy()] }]
});
// ✅ GOOD - expires in 30 days
const sessionDetails = await sessionClient.grantPermissionTypedDataSign({
sessionValidUntil: Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60,
actions: [{ actionPolicies: [getSudoPolicy()] }]
});
When to Upgrade to Universal Action
Switch to Universal Action when you need:
- Spending limits (per-action or total)
- Recipient whitelisting
- Parameter validation
- Cumulative caps
See Universal Action Policy for details.