Policy Engine
All 27 ViolationCodes, evaluation order, public precheck vs full evaluation, and PolicyConfig defaults from the actual aura-policy source.
aura-policy is a pure-Rust crate with no Anchor dependency. It is consumed by aura-core on-chain, by sdk-rs for off-chain pre-validation, and by the devnet smoke binaries. All rule logic, violation codes, and FHE graph specs live here — never duplicated in aura-core or the SDKs.
Entry Points
| Function | Used by | What it skips |
|---|---|---|
evaluate_transaction | Public proposals (propose_transaction) | Nothing — runs all rules |
evaluate_public_precheck | Confidential proposals (before FHE CPI) | per_tx_limit, daily_limit — deferred to Encrypt |
evaluate_transaction_simple | Tests and off-chain tooling | Convenience wrapper |
evaluate_batch | propose_batch instruction | Evaluates a slice, threads state forward |
evaluate_policy_without_spend_mutation | simulate_policy instruction | Runs full rules but does not commit state |
Evaluation Order (evaluate_transaction)
Rules short-circuit on the first failure. No subsequent rules are evaluated after a violation.
Public Precheck vs Full Evaluation
For confidential proposals, evaluate_public_precheck runs the same rules except steps 3 (per_tx_limit) and 4 (daily_limit). Those are deferred to the FHE circuit. If the precheck passes, a note is added to the trace: "encrypted per-transaction and daily-limit checks deferred to Encrypt".
All 27 ViolationCodes
From programs/aura-policy/src/violations/mod.rs:
| Code | Variant | Triggered when |
|---|---|---|
none | None | Transaction approved |
per_transaction_limit | PerTransactionLimit | amount_usd > per_tx_limit_usd |
daily_limit | DailyLimit | spent_today + amount > effective_daily_limit |
bitcoin_manual_review | BitcoinManualReview | Bitcoin tx above bitcoin_manual_review_threshold_usd |
time_window_limit | TimeWindowLimit | Hourly spend would exceed active hourly limit |
velocity_limit | VelocityLimit | Recent-amounts window sum would exceed velocity_limit_usd |
protocol_not_allowed | ProtocolNotAllowed | Protocol ID bit not set in allowed_protocol_bitmap |
slippage_exceeded | SlippageExceeded | Computed slippage > max_slippage_bps |
quote_stale | QuoteStale | quote_age_secs > max_quote_age_secs |
counterparty_risk | CounterpartyRisk | Risk score > max_counterparty_risk_score |
shared_pool_limit | SharedPoolLimit | Swarm pool projected spend > shared_pool_limit_usd |
weekly_limit | WeeklyLimit | 7-day total would exceed weekly_limit_usd |
monthly_limit | MonthlyLimit | 30-day total would exceed monthly_limit_usd |
recipient_daily_limit | RecipientDailyLimit | Per-address daily cap exceeded |
recipient_per_transaction_limit | RecipientPerTransactionLimit | Per-address per-tx cap exceeded |
anomaly_detected | AnomalyDetected | Z-score outlier with action = Deny |
cooldown_not_elapsed | CooldownNotElapsed | Cooldown rule blocked a large transaction |
budget_envelope_daily_limit | BudgetEnvelopeDailyLimit | Scoped envelope daily cap exceeded |
budget_envelope_weekly_limit | BudgetEnvelopeWeeklyLimit | Scoped envelope weekly cap exceeded |
approval_ladder_denied | ApprovalLadderDenied | Approval ladder returned ApprovalLevel::Deny |
execution_scope_paused | ExecutionScopePaused | Transaction matches an active ScopedPauseEntry |
external_dependency_stale | ExternalDependencyStale | Required liveness record is stale |
policy_attestation_missing | PolicyAttestationMissing | Attestation missing or stale |
empty_batch | EmptyBatch | Batch proposal contained no items |
batch_too_large | BatchTooLarge | Batch exceeded maximum item count |
exposure_group_limit_exceeded | ExposureGroupLimitExceeded | Cross-treasury exposure group cap exceeded |
pending_execution_timelock_active | PendingExecutionTimelockActive | Execution timelock still active |
PolicyConfig Defaults
From programs/aura-policy/src/config/limits.rs — PolicyConfig::default():
| Field | Default | Description |
|---|---|---|
daily_limit_usd | 10_000 | USD cents — 24h rolling window |
per_tx_limit_usd | 1_000 | USD cents — single transaction cap |
daytime_hourly_limit_usd | 2_500 | USD cents — 06:00–22:00 UTC |
nighttime_hourly_limit_usd | 500 | USD cents — 22:00–06:00 UTC |
velocity_limit_usd | 5_000 | USD cents — recent-amounts window |
allowed_protocol_bitmap | 0b1_1111 (31) | All 5 protocol bits set |
max_slippage_bps | 100 | 1% |
max_quote_age_secs | Some(300) | 5 minutes |
max_counterparty_risk_score | Some(70) | 0–100 scale |
bitcoin_manual_review_threshold_usd | 5_000 | USD cents = $50 |
shared_pool_limit_usd | None | Disabled |
weekly_limit_usd | None | Disabled |
monthly_limit_usd | None | Disabled |
recipient_limits | [] | No per-address caps |
cooldown_config | None | Disabled |
anomaly_config | None | Disabled |
budget_envelopes | [] | No scoped envelopes |
approval_ladder | None | Disabled |
scoped_pause | empty | No pauses |
liveness_config | all false | No freshness requirements |
Reputation Scaling
effective_daily_limit_usd is computed as:
effective = daily_limit_usd × multiplier_bps(reputation_score) / 10_000Default ReputationPolicy:
| Threshold | Multiplier |
|---|---|
score ≥ high_score_threshold (80) | high_multiplier_bps / 10_000 = 1.5× |
score ≥ medium_score_threshold (50) | 1.0× (baseline) |
| score < 50 | low_multiplier_bps / 10_000 = 0.7× |
If no reputation score is provided (None), the base daily_limit_usd is used unchanged.
Time Windows
active_hourly_limit returns daytime_hourly_limit_usd for hours 6–21 UTC and nighttime_hourly_limit_usd for hours 22–5 UTC. The hourly counter (hourly_spent_usd) resets when the current hour changes.
Transaction Types
From programs/aura-policy/src/types/transaction.rs:
| ID | Variant | Display |
|---|---|---|
| 0 | Transfer | transfer |
| 1 | DeFiSwap | defi_swap |
| 2 | LendingDeposit | lending_deposit |
| 3 | NFTPurchase | nft_purchase |
| 4 | ContractInteraction | contract_interaction |
Regulatory Flags
compute_regulatory_flags returns a u8 bitmask attached to every PolicyDecision:
| Bit | Constant | Meaning |
|---|---|---|
0b0000_0001 | REG_FLAG_CTR_THRESHOLD | Amount exceeds CTR reporting threshold |
0b0000_0010 | REG_FLAG_CROSS_BORDER | Cross-chain transaction |
0b0000_0100 | REG_FLAG_HIGH_RISK_COUNTERPARTY | Risk score above 80 |
0b0000_1000 | REG_FLAG_REQUIRES_KYC | Transaction type requires KYC |
Anomaly Detection
When anomaly_config.enabled = true and state.recent_amounts.len() >= min_sample_size, the engine computes a z-score over the recent amounts window:
z_score_bps = (amount - mean) / std_dev × 10_000If z_score_bps > z_score_threshold_bps, the action is applied:
AnomalyAction | Effect |
|---|---|
Deny | Returns ViolationCode::AnomalyDetected |
FlagForReview | Sets risk_score = max(risk_score, 85), adds risk factor, continues |
RequireGuardianCosign | Requires guardian approval before execution |