AURA

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

FunctionUsed byWhat it skips
evaluate_transactionPublic proposals (propose_transaction)Nothing — runs all rules
evaluate_public_precheckConfidential proposals (before FHE CPI)per_tx_limit, daily_limit — deferred to Encrypt
evaluate_transaction_simpleTests and off-chain toolingConvenience wrapper
evaluate_batchpropose_batch instructionEvaluates a slice, threads state forward
evaluate_policy_without_spend_mutationsimulate_policy instructionRuns 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:

CodeVariantTriggered when
noneNoneTransaction approved
per_transaction_limitPerTransactionLimitamount_usd > per_tx_limit_usd
daily_limitDailyLimitspent_today + amount > effective_daily_limit
bitcoin_manual_reviewBitcoinManualReviewBitcoin tx above bitcoin_manual_review_threshold_usd
time_window_limitTimeWindowLimitHourly spend would exceed active hourly limit
velocity_limitVelocityLimitRecent-amounts window sum would exceed velocity_limit_usd
protocol_not_allowedProtocolNotAllowedProtocol ID bit not set in allowed_protocol_bitmap
slippage_exceededSlippageExceededComputed slippage > max_slippage_bps
quote_staleQuoteStalequote_age_secs > max_quote_age_secs
counterparty_riskCounterpartyRiskRisk score > max_counterparty_risk_score
shared_pool_limitSharedPoolLimitSwarm pool projected spend > shared_pool_limit_usd
weekly_limitWeeklyLimit7-day total would exceed weekly_limit_usd
monthly_limitMonthlyLimit30-day total would exceed monthly_limit_usd
recipient_daily_limitRecipientDailyLimitPer-address daily cap exceeded
recipient_per_transaction_limitRecipientPerTransactionLimitPer-address per-tx cap exceeded
anomaly_detectedAnomalyDetectedZ-score outlier with action = Deny
cooldown_not_elapsedCooldownNotElapsedCooldown rule blocked a large transaction
budget_envelope_daily_limitBudgetEnvelopeDailyLimitScoped envelope daily cap exceeded
budget_envelope_weekly_limitBudgetEnvelopeWeeklyLimitScoped envelope weekly cap exceeded
approval_ladder_deniedApprovalLadderDeniedApproval ladder returned ApprovalLevel::Deny
execution_scope_pausedExecutionScopePausedTransaction matches an active ScopedPauseEntry
external_dependency_staleExternalDependencyStaleRequired liveness record is stale
policy_attestation_missingPolicyAttestationMissingAttestation missing or stale
empty_batchEmptyBatchBatch proposal contained no items
batch_too_largeBatchTooLargeBatch exceeded maximum item count
exposure_group_limit_exceededExposureGroupLimitExceededCross-treasury exposure group cap exceeded
pending_execution_timelock_activePendingExecutionTimelockActiveExecution timelock still active

PolicyConfig Defaults

From programs/aura-policy/src/config/limits.rsPolicyConfig::default():

FieldDefaultDescription
daily_limit_usd10_000USD cents — 24h rolling window
per_tx_limit_usd1_000USD cents — single transaction cap
daytime_hourly_limit_usd2_500USD cents — 06:00–22:00 UTC
nighttime_hourly_limit_usd500USD cents — 22:00–06:00 UTC
velocity_limit_usd5_000USD cents — recent-amounts window
allowed_protocol_bitmap0b1_1111 (31)All 5 protocol bits set
max_slippage_bps1001%
max_quote_age_secsSome(300)5 minutes
max_counterparty_risk_scoreSome(70)0–100 scale
bitcoin_manual_review_threshold_usd5_000USD cents = $50
shared_pool_limit_usdNoneDisabled
weekly_limit_usdNoneDisabled
monthly_limit_usdNoneDisabled
recipient_limits[]No per-address caps
cooldown_configNoneDisabled
anomaly_configNoneDisabled
budget_envelopes[]No scoped envelopes
approval_ladderNoneDisabled
scoped_pauseemptyNo pauses
liveness_configall falseNo freshness requirements

Reputation Scaling

effective_daily_limit_usd is computed as:

effective = daily_limit_usd × multiplier_bps(reputation_score) / 10_000

Default ReputationPolicy:

ThresholdMultiplier
score ≥ high_score_threshold (80)high_multiplier_bps / 10_000 = 1.5×
score ≥ medium_score_threshold (50)1.0× (baseline)
score < 50low_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:

IDVariantDisplay
0Transfertransfer
1DeFiSwapdefi_swap
2LendingDepositlending_deposit
3NFTPurchasenft_purchase
4ContractInteractioncontract_interaction

Regulatory Flags

compute_regulatory_flags returns a u8 bitmask attached to every PolicyDecision:

BitConstantMeaning
0b0000_0001REG_FLAG_CTR_THRESHOLDAmount exceeds CTR reporting threshold
0b0000_0010REG_FLAG_CROSS_BORDERCross-chain transaction
0b0000_0100REG_FLAG_HIGH_RISK_COUNTERPARTYRisk score above 80
0b0000_1000REG_FLAG_REQUIRES_KYCTransaction 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_000

If z_score_bps > z_score_threshold_bps, the action is applied:

AnomalyActionEffect
DenyReturns ViolationCode::AnomalyDetected
FlagForReviewSets risk_score = max(risk_score, 85), adds risk factor, continues
RequireGuardianCosignRequires guardian approval before execution

Policy Templates & Canary Testing

AURA now supports reusable policy templates and safe testing of policy changes through canary deployments.

Policy Templates

Pre-defined or custom policy configurations that can be applied to multiple treasuries:

// Create from scratch or fork a built-in preset
await aura.policy.createTemplate({
  authority: ownerPubkey,
  template: {
    name: "conservative-defi",
    config: { /* full PolicyConfig */ },
    metadata: "Low-risk DeFi strategy with tight limits",
    version: 1,
  },
});

// Apply to treasury
await aura.policy.applyTemplate({
  treasury,
  templateAddress,
});

// Apply with parameterized scaling
await aura.policy.applyTemplateParameterized({
  treasury,
  templateAddress,
  scalingBps: 5000, // 50% of template limits
  limitOverrides: { dailyLimitUsd: 20000 }, // override specific field
});

Built-in presets:

  • RiskAverse — Tight limits, narrow time windows, low counterparty risk
  • Balanced — Default settings from PolicyConfig
  • Aggressive — Wider limits, 24/7 operation, higher risk tolerance
  • DeFiOptimized — Protocol-specific tuning for DEX/lending
  • Payments — High frequency, low amounts, instant settlement

Canary Deployments

Test a candidate policy against live proposals without enforcing it:

// 1. Start canary with candidate policy
await aura.policy.startCanary({
  treasury,
  candidateConfig: { /* proposed PolicyConfig */ },
  minSampleSize: 100, // must score 100 proposals before promotion
});

// 2. Proposals evaluated against both enforced and candidate policies
// Canary tracks: pass/fail counts, deviation patterns, violation distribution

// 3. Promote if canary performs well
await aura.policy.promoteCanary({ treasury });

// Or discard if results are poor
await aura.policy.discardCanary({ treasury });

Canary scoring:

  • Runs in parallel with enforced policy (never blocks proposals)
  • Tracks pass rate, false positive rate, deviation score
  • Requires minimum sample size before promotion
  • Automatically records as new policy version on promotion

Policy Versioning & Rollback

All policy changes create immutable version records:

// Check version history
const versions = await aura.policy.getVersionHistory(treasury);
console.log("Current version:", versions.current);
console.log("Previous versions:", versions.history);

// Rollback to previous version (owner + guardian quorum)
await aura.policy.rollbackToVersion({
  treasury,
  targetVersion: 3, // roll back to version 3
});

Version lifecycle:

  • Every configure_policy, apply_policy_template, or promote_canary creates a new version
  • Versions are sequentially numbered and immutable
  • Rollback requires owner signature + guardian quorum for safety
  • Version metadata includes timestamp, author, change summary

On this page