Skip to main content

What you will learn

  • How the PolicyEngine evaluates TxIntents against configurable rules
  • Available policy fields and their effects
  • How to configure policies for different risk profiles
  • How risk scoring interacts with policy decisions

Overview

The PolicyEngine is the gatekeeper of Domain B. Every TxIntent must pass policy evaluation before it can be built, simulated, or signed. The engine evaluates a fixed set of rules in order and produces one of three decisions:
DecisionMeaning
allowTransaction proceeds without human confirmation
require_approvalTransaction is paused for human confirmation
denyTransaction is rejected. No signing occurs.

Evaluation order

Rules are evaluated in this order. The first deny stops evaluation:
#RuleChecksDecision on Failure
1Chain restrictionchainId in allowedChainsdeny
2Token allowlistToken address in tokenAllowlistdeny
3Contract allowlistRouter/spender in contractAllowlistdeny
4Value limitValue <= maxValueWeideny
5Approval amountAmount <= maxApprovalAmountdeny
6Recipient allowlistRecipient in recipientAllowlistdeny
7Risk scoreScore <= maxRiskScorerequire_approval
8Rate limitCount < maxTxPerHourdeny

PolicyConfig Fields

FieldTypeDefaultDescription
version"1""1"Schema version
maxValueWeistring"0"Maximum transaction value in wei. "0" = deny all
maxApprovalAmountstring"0"Maximum ERC-20 approval amount. "0" = deny all
contractAllowliststring[][]Allowed contracts for swaps/approvals. Empty = allow all
tokenAllowliststring[][]Allowed tokens for transfers/swaps. Empty = allow all
allowedChainsnumber[][1, 10, 42161, 8453]Allowed chain IDs
recipientAllowliststring[][]Allowed transfer recipients. Empty = allow all
maxRiskScoreinteger50Risk score ceiling (0-100)
requireApprovalAboveobject{"valueWei":"0"}Value threshold for mandatory approval
maxTxPerHourinteger10Per-wallet rate limit (rolling hour)
The default policy has maxValueWei: "0", which denies ALL value-bearing transactions. This is fail-closed by design — you must explicitly configure limits.

Allowlist behavior

Empty allowlists ([]) are permissive — they allow all values:
"tokenAllowlist": []        // All tokens allowed
"tokenAllowlist": ["0x..."] // Only this specific token allowed
This applies to contractAllowlist, tokenAllowlist, and recipientAllowlist.

Value extraction per action type

The policy engine extracts different fields depending on the action type:
ActionValue FieldContract FieldToken Fields
transferamountasset.address
transfer_nativeamount
approveamountspenderasset.address
swap_exact_inamountInrouterassetIn, assetOut
swap_exact_outmaxAmountInrouterassetIn, assetOut

Example policies

Small value limit, specific tokens only, Base chain only, low rate limit:
{
  "version": "1",
  "maxValueWei": "1000000000000000000",
  "maxApprovalAmount": "1000000000000000000",
  "contractAllowlist": ["0x2626664c2603336E57B271c5C0b26F421741e481"],
  "tokenAllowlist": [
    "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "0x4200000000000000000000000000000000000006"
  ],
  "allowedChains": [8453],
  "recipientAllowlist": ["0xTrustedRecipient"],
  "maxRiskScore": 30,
  "requireApprovalAbove": { "valueWei": "500000000000000000" },
  "maxTxPerHour": 5
}

Risk scoring

The PreflightService computes a 7-factor risk score (0-100):
FactorWeightDescription
Value magnitudeHighLarger values score higher
Recipient historyMediumUnknown recipients score higher
Contract riskMediumInteractions with unverified contracts
Gas anomalyLowUnusual gas estimates
Approval riskHighUnlimited approvals score very high
Chain riskLowLess-established chains score higher
Source trustLowKnown adapter sources score lower
When the computed risk score exceeds maxRiskScore, the policy decision escalates to require_approval.

Next steps