Skip to content

Rate Limit Policy

The rate limit policy specifies the frequency at which the signer is allowed to send UserOps.

We have two types of rate limit policies:

  • Rate limits with no reset: send one UserOp per interval, for up to count times.
  • Rate limits with reset: send count UserOps within an interval, for an indefinite number of intervals.

Rate limit with no reset

Send one UserOp per interval, for up to count times. Each UserOp call must have at least an interval of time between it and the next call.

API

import { toRateLimitPolicy } from "@zerodev/permissions/policies"
 
// In this example, the signer can send one UserOp per month
const rateLimitPolicy = toRateLimitPolicy({
  count: 1,
  interval: 60 * 60 * 24 * 30,  // one month in seconds
})
 
const validator = toPermissionValidator(publicClient, {
  entryPoint,
  kernelVersion,
  signer: someSigner,
  policies: [
    rateLimitPolicy,
    // ...other policies
  ],
})

Arguments to toRateLimitPolicy:

  • count: the number of intervals.
  • (optional) interval: the length of an interval.
  • (optional) startAt: the starting UNIX timestamp for when the rate limit should take effect. Before that, the signer cannot send any UserOps.

Rate limit with reset

Send count UserOps within an interval, for an indefinite number of intervals.

The Rate Limit Policy with reset allows you to define a recurring allowance of UserOps that refreshes after each interval period. This is useful for creating recurring permissions that automatically renew, such as monthly subscription payments or regular administrative actions.

API

Unlike the standard Rate Limit Policy which counts down a total number of allowed operations, the reset version gives the signer a fresh allocation of operations after each interval passes.

import { toRateLimitPolicy, RATE_LIMIT_POLICY_WITH_RESET_CONTRACT } from "@zerodev/permissions/policies"
 
// In this example, the signer can send one UserOp per month
const rateLimitPolicy = toRateLimitPolicy({
  count: 1,
  interval: 60 * 60 * 24 * 30,  // one month in seconds
})
 
// only difference from non-reset is using RATE_LIMIT_POLICY_WITH_RESET_CONTRACT for policyAddress
const validator = toPermissionValidator(publicClient, {
  policyAddress : RATE_LIMIT_POLICY_WITH_RESET_CONTRACT,
  entryPoint,
  kernelVersion,
  signer: someSigner,
  policies: [
    rateLimitPolicy,
    // ...other policies
  ],
})

Examples

If you want to do a monthly payment for 2 years (no reset after two years), the parameters will be:

  count : 24,
  interval : 60 * 60 * 24 * 30 // 30 days for month
  startAt : <Current timestamp in UNIX timestamp format>

If you want to do a monthly payment indefinitely, the parameters will be:

  policyAddress : RATE_LIMIT_POLICY_WITH_RESET_CONTRACT,
  count : 1,
  interval : 60 * 60 * 24 * 30 // 30 days for month
  startAt : 0 or undefined

Notes

  • We are aware that the semantics of count and interval changes completely between the no reset version and the reset version and it's very confusing; this is technical debt we intend to clean up.
  • The reset version technically violates ERC-4337 storage rules since it needs to access block.timestamp, so it won't work with all bundler, but it's known to work with UltraRelay and Pimlico.