Overview
Policies are rule-based security controls that evaluate every transaction before execution. They can allow , deny , or require manual approval for transactions based on configurable criteria.
Policy Evaluation Flow
Every spend-capable transaction passes through policy evaluation:
Creating Policies
npm run cli -- policy create \
--wallet-id < walletI d > \
--name "Trading Limits" \
--rules '[
{
"type": "spending_limit",
"maxLamportsPerTx": 5000000,
"maxLamportsPerDay": 50000000,
"requireApprovalAboveLamports": 10000000
},
{
"type": "protocol_allowlist",
"protocols": ["system-program", "jupiter", "marinade"]
}
]' \
--active true
curl -X POST http://localhost:3000/api/v1/policies \
-H "Content-Type: application/json" \
-H "x-api-key: dev-api-key" \
-d '{
"walletId": "<walletId>",
"name": "Trading Limits",
"active": true,
"rules": [
{
"type": "spending_limit",
"maxLamportsPerTx": 5000000,
"maxLamportsPerDay": 50000000,
"requireApprovalAboveLamports": 10000000
},
{
"type": "protocol_allowlist",
"protocols": ["system-program", "jupiter", "marinade"]
}
]
}'
const policy = await client . policy . create ({
walletId: walletId ,
name: 'Trading Limits' ,
active: true ,
rules: [
{
type: 'spending_limit' ,
maxLamportsPerTx: 5_000_000 ,
maxLamportsPerDay: 50_000_000 ,
requireApprovalAboveLamports: 10_000_000
},
{
type: 'protocol_allowlist' ,
protocols: [ 'system-program' , 'jupiter' , 'marinade' ]
}
]
});
console . log ( `Policy created: ${ policy . id } ` );
Policy Rule Types
Spending Limit
Control transaction amounts and require approval above thresholds:
{
"type" : "spending_limit" ,
"maxLamportsPerTx" : 1000000 ,
"maxLamportsPerDay" : 10000000 ,
"requireApprovalAboveLamports" : 500000
}
Field Description maxLamportsPerTxMaximum lamports per transaction (deny above) maxLamportsPerDayMaximum lamports per 24-hour period (deny above) requireApprovalAboveLamportsTrigger approval gate for amounts above this
All fields are optional. Omit a field to skip that check.
Protocol Allowlist
Restrict which protocols can be used:
{
"type" : "protocol_allowlist" ,
"protocols" : [ "system-program" , "jupiter" , "spl-token" ]
}
Denies any transaction using protocols not in the list.
Address Allowlist
Only allow transactions to specific addresses:
{
"type" : "address_allowlist" ,
"addresses" : [
"8xKzZ..." ,
"9yNmP..."
]
}
Address Blocklist
Block transactions to specific addresses:
{
"type" : "address_blocklist" ,
"addresses" : [
"BadAddr1..." ,
"BadAddr2..."
]
}
Program Allowlist
Restrict which Solana programs can be invoked:
{
"type" : "program_allowlist" ,
"programIds" : [
"11111111111111111111111111111111" ,
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
]
}
Token Allowlist
Only allow specific SPL token mints:
{
"type" : "token_allowlist" ,
"mints" : [
"So11111111111111111111111111111111111111112" ,
"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
]
}
Rate Limit
Limit transaction frequency:
{
"type" : "rate_limit" ,
"maxTx" : 10 ,
"windowSeconds" : 3600
}
Allows maximum of 10 transactions per hour.
Time Window
Only allow transactions during specific hours:
{
"type" : "time_window" ,
"startHourUtc" : 9 ,
"endHourUtc" : 17
}
Allows transactions only between 9 AM and 5 PM UTC.
Max Slippage
Limit slippage tolerance for swaps:
{
"type" : "max_slippage" ,
"maxBps" : 100
}
Denies swaps with slippage above 1% (100 basis points).
Protocol Risk
Advanced controls for specific protocols:
{
"type" : "protocol_risk" ,
"protocol" : "jupiter" ,
"maxSlippageBps" : 50 ,
"maxPoolConcentrationBps" : 5000 ,
"allowedPools" : [ "pool1..." , "pool2..." ],
"allowedPrograms" : [ "prog1..." , "prog2..." ],
"oracleDeviationBps" : 200
}
Portfolio Risk
Portfolio-level risk controls:
{
"type" : "portfolio_risk" ,
"maxDrawdownLamports" : 100000000 ,
"maxDailyLossLamports" : 50000000 ,
"maxExposureBpsPerToken" : 2000 ,
"maxExposureBpsPerProtocol" : 3000
}
Field Description maxDrawdownLamportsMaximum portfolio drawdown allowed maxDailyLossLamportsMaximum daily loss allowed maxExposureBpsPerTokenMax 20% exposure per token (2000 bps) maxExposureBpsPerProtocolMax 30% exposure per protocol (3000 bps)
Policy Evaluation
Test how a transaction would be evaluated without executing it:
npm run cli -- policy evaluate \
--wallet-id < walletI d > \
--type transfer_sol \
--protocol system-program \
--destination < pubke y > \
--amount-lamports 1000000
Response:
{
"decision" : "allow" ,
"reasons" : [
"Spending limit check passed" ,
"Protocol allowlist check passed"
],
"riskTier" : "low"
}
Possible decisions:
allow - Transaction proceeds automatically
deny - Transaction blocked
require_approval - Transaction pauses at approval gate
Approval Gate Workflow
When a policy requires approval:
Transaction Pauses
Transaction status becomes approval_gate and waits for operator action.
List Pending Approvals
npm run cli -- tx pending --wallet-id < walletI d >
Or via API: curl -H "x-api-key: dev-api-key" \
http://localhost:3000/api/v1/wallets/ < walletI d > /pending-approvals
Review Transaction Details
npm run cli -- tx get < txI d >
Check the intent, amount, destination, and policy reasons.
Approve or Reject
npm run cli -- tx approve < txI d >
Transaction Continues
After approval, transaction proceeds to signing and submission.
Policy Versioning
Policies support versioning for safe updates:
List Policy Versions
npm run cli -- policy versions < policyI d >
Get Specific Version
npm run cli -- policy version < policyI d > --number 2
Migrate Policy
npm run cli -- policy migrate < policyI d > --target-version 3 --mode safe
Migration modes:
safe - Only migrate if compatible
force - Migrate regardless of compatibility warnings
Check Compatibility
Validate rules before creating or updating:
npm run cli -- policy compatibility-check \
--rules '[{"type":"spending_limit","maxLamportsPerTx":1000000}]'
Managing Policies
List Wallet Policies
npm run cli -- policy list --wallet-id < walletI d >
Update Policy
const updated = await client . policy . update ( policyId , {
active: false , // Disable policy
rules: [ /* updated rules */ ]
});
Updating a policy creates a new version. Old transactions may reference previous versions.
Real-World Examples
Conservative Trading Bot
{
"name" : "Conservative Trader" ,
"rules" : [
{
"type" : "spending_limit" ,
"maxLamportsPerTx" : 10000000 ,
"maxLamportsPerDay" : 100000000
},
{
"type" : "protocol_allowlist" ,
"protocols" : [ "jupiter" ]
},
{
"type" : "max_slippage" ,
"maxBps" : 50
},
{
"type" : "rate_limit" ,
"maxTx" : 20 ,
"windowSeconds" : 3600
}
]
}
High-Security Treasury
{
"name" : "Treasury Security" ,
"rules" : [
{
"type" : "spending_limit" ,
"requireApprovalAboveLamports" : 5000000
},
{
"type" : "address_allowlist" ,
"addresses" : [ "TrustedAddr1..." , "TrustedAddr2..." ]
},
{
"type" : "time_window" ,
"startHourUtc" : 9 ,
"endHourUtc" : 17
},
{
"type" : "rate_limit" ,
"maxTx" : 5 ,
"windowSeconds" : 86400
}
]
}
DeFi Yield Farmer
{
"name" : "Yield Strategy" ,
"rules" : [
{
"type" : "protocol_allowlist" ,
"protocols" : [ "marinade" , "solend" , "jupiter" ]
},
{
"type" : "max_slippage" ,
"maxBps" : 100
},
{
"type" : "portfolio_risk" ,
"maxExposureBpsPerProtocol" : 3000 ,
"maxDailyLossLamports" : 50000000
}
]
}
Policy Best Practices
Security Recommendations:
Always set maxLamportsPerTx and maxLamportsPerDay for production wallets
Use requireApprovalAboveLamports for high-value thresholds
Combine multiple rule types for defense-in-depth
Test policies with policy evaluate before activating
Enable time_window rules for business hours-only operation
Use rate_limit to prevent runaway execution
Next Steps
Managing Agents Create autonomous agents with policy-gated capabilities
Protocol Interactions Execute DeFi operations with policy protection