Skip to main content

Three-Tier Rule System

PolicyKit organizes rules into three tiers based on where and how they are evaluated. This tiered approach balances security, cost, and capability.

Overview

Rules are evaluated sequentially: Tier 1 first, then Tier 2, then Tier 3. If any rule fails at any tier, the transaction is rejected immediately.

Tier 1: Stateless On-Chain Rules

Stateless rules are the simplest and cheapest. They only look at the current transaction parameters — no storage reads needed.

ALLOW_TARGETS

Whitelist specific contract addresses that the account can interact with.
policy.allowTargets([
  "0xUniswapV3Router",
  "0xAaveLendingPool",
  "0xCompoundCToken",
]);
Transactions to any address not in the list are rejected.

DENY_TARGETS

Blacklist specific contract addresses.
policy.denyTargets([
  "0xKnownScamContract",
  "0xSanctionedAddress",
]);
Transactions to any address in the list are rejected. All others are allowed.
If both ALLOW_TARGETS and DENY_TARGETS are set, ALLOW_TARGETS is evaluated first. A transaction must be in the allow list AND not in the deny list.

ALLOW_SELECTORS

Whitelist specific function selectors (first 4 bytes of calldata).
policy.allowSelectors([
  "0x38ed1739", // swapExactTokensForTokens
  "0x7ff36ab5", // swapExactETHForTokens
]);

DENY_SELECTORS

Blacklist specific function selectors.
policy.denySelectors([
  "0x095ea7b3", // approve (prevent unlimited approvals)
]);

MAX_VALUE

Set a maximum ETH value per transaction.
policy.maxValue(parseEther("10")); // Max 10 ETH per tx

Tier 2: Stateful On-Chain Rules

Stateful rules use on-chain storage to track state across transactions. They cost more gas but enable time-based and cumulative constraints.

SPEND_LIMIT

Limit how much of a specific token can be spent within a rolling time window.
policy.spendLimit(
  "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
  parseUnits("50000", 6), // 50,000 USDC
  86400 // per 24 hours
);
The on-chain contract tracks cumulative spending and resets the counter when the time window expires.

COOLDOWN

Enforce a minimum time between transactions.
policy.cooldown(300); // 5 minutes between transactions
This is useful for preventing rapid-fire transactions from compromised agents or scripts.

Tier 3: Off-Chain Rules (Lit Protocol)

Off-chain rules are evaluated by the Lit Protocol network. They can access external data, perform simulations, and run arbitrary logic that would be impractical on-chain.

MAX_SLIPPAGE_BPS

Check that a swap transaction doesn’t exceed a maximum slippage tolerance.
policy.maxSlippageBps(50); // 0.5% max slippage
The Lit Action decodes the transaction calldata, compares input/output amounts, and checks against current market prices.

REQUIRE_SIMULATION

Require that the transaction succeeds when simulated.
policy.requireSimulation(true);
The Lit Action simulates the transaction using an RPC endpoint and rejects it if the simulation reverts.

CUSTOM

Define custom rule logic hosted on IPFS.
policy.customRule({
  name: "check-oracle-price",
  description: "Verify price is within oracle bounds",
  cid: "QmCustomRuleLogicCID...",
  params: {
    oracle: "0xChainlinkPriceFeed",
    maxDeviation: 500, // 5%
  },
});
Custom rules let you implement any evaluation logic. The code is fetched from IPFS and executed in the Lit Action’s secure environment.

Choosing the Right Tier

ConsiderationTier 1Tier 2Tier 3
Gas costLowestMediumNone (off-chain)
Trust modelTrustlessTrustlessDecentralized TEE
LatencyInstantInstant~1-3 seconds
External dataNoNoYes
State trackingNoYesYes
Custom logicNoNoYes
Guidelines:
  • Use Tier 1 for simple access control (targets, selectors, value limits)
  • Use Tier 2 when you need time-based or cumulative constraints
  • Use Tier 3 when you need external data, simulation, or custom logic