What Are Spending Policies?
Spending policies let wallet owners set dollar-denominated caps on what a session key can spend. The CHIPI wallet contract enforces these limits automatically during transaction execution — no backend or middleware needed. Limits are enforced on ERC-20 operations:transfer, approve, increase_allowance.
Spending policies require CHIPI v33 wallets. v29 wallets do not have these entrypoints. See Wallet Upgrades to upgrade.
When to Use Spending Policies
How It Works
Configuration
A spending policy has three parameters:
The contract also tracks:
If no policy is set (maxPerWindow is 0), the session has no spending limits. All ERC-20 operations are allowed without caps.
TypeScript Backend
React / Next.js
TheuseChipiSession hook includes spending policy actions:
The React hook automatically injects the current session’s
sessionPublicKey. You only need to pass token, maxPerCall, maxPerWindow, and windowSeconds.Python
aset_spending_policy, aget_spending_policy, aremove_spending_policy.
Validation Rules
The SDK validates before submitting to the contract:On-Chain Enforcement
The contract enforces spending limits during__execute__() for session-signed transactions:
- Tracked selectors:
transfer,approve,increase_allowance,increaseAllowance - Per-call check: If
amount > maxPerCall, transaction reverts with “Spending: exceeds per-call” - Window check: If
spentInWindow + amount > maxPerWindow, transaction reverts with “Spending: exceeds window limit” - Auto-reset: When
now >= windowStart + windowSeconds, the window resets to zero
Security notes
For anyone giving a session key to an agent:- The whitelist is not scoped to a contract.
allowedEntrypointsis matched by selector, and a selector is allowed on every contract."transfer"lets the session calltransferon any token the wallet holds. Set a spending policy for every token the wallet can hold, not only the one the agent is meant to use. - Only ERC-20 transfers and approvals are metered. Policies cap
transfer,approveand allowance increases (see On-Chain Enforcement). Any other whitelisted entrypoint that moves value is uncapped. In particular, don’t whitelist a vault’swithdraw/redeemfor a session: ERC-4626 versions take areceiver, so the session could send the assets to any address. Route vault exits through a contract whose functions return funds to the caller. maxPerWindow: 0means no cap. It disables the policy for that token; it does not block spending. Always set a positive window cap.maxPerCall: 0with a positive window blocks every metered spend of that token.- A refused call can still report success. Sent through Chipi’s paymaster, a session call the wallet refuses (over a cap, not whitelisted, revoked session) comes back
success: truewith nothing moved. Check the receipt’s events: aTransfer(orApproval) from your wallet is the proof, not the status. - Register the caps with the session.
registerSession({ ..., spendingPolicies })inuseChipiSession, orbuildSessionSetupCalls, puts the session and its policies in one owner-signed transaction, so the session never exists on-chain without its limits. See Agent with a session key and a passkey.
