Policies
Stendar exposes two complementary public policy surfaces:
- a Policy v2 decision contract in
@stendar/policy-contracts - a
PolicyEngineexecution policy layer in@stendar/corefor raw runtime users
Policy v2 decision contract
Section titled “Policy v2 decision contract”Policy v2 lives in @stendar/policy-contracts and defines the shared decision semantics used by public runtime policy adapters.
Decision model (fail-closed)
Section titled “Decision model (fail-closed)”Each evaluation returns one of:
allowdenyreview_requiredapproval_requiredblocked_until_evidence
Fail-closed behavior means unknown, malformed, or out-of-policy evaluations must not auto-allow money-affecting execution.
Legacy local selectors/adapters are retained as compatibility inputs into Policy v2 evidence and normalization. They are not a separate product policy identity.
DeFiRuntime policy layer
Section titled “DeFiRuntime policy layer”PolicyEngine and PolicyRule in @stendar/core remain the execution-engine policy layer for direct DeFiRuntime usage.
Rule order matters. Any deny short-circuits immediately.
Supported PolicyRule types
Section titled “Supported PolicyRule types”spending_limit: cap per-transaction and/or daily USD amountrequire_approval: gate intents above thresholdrate_limit: max transaction count in rolling windowprotocol_allowlist: permit only selected providers/protocol IDstoken_allowlist: permit only selected token identifiersmax_slippage: reject quotes above slippage thresholdmax_drawdown: reject when drawdown exceeds configured percentportfolio_exposure: cap token or protocol concentrationtime_window: allow only specific UTC days/hours
Runtime example policy set
Section titled “Runtime example policy set”import type { PolicyRule } from '@stendar/core';
const policies: PolicyRule[] = [ { id: 'daily-usd-cap', type: 'spending_limit', enabled: true, maxDaily: 5000, currency: 'USD', }, { id: 'max-slippage', type: 'max_slippage', enabled: true, maxSlippageBps: 100, }, { id: 'core-hours', type: 'time_window', enabled: true, allowedWindows: [ { daysOfWeek: [1, 2, 3, 4, 5], startHourUTC: 12, endHourUTC: 22 }, ], },];Advanced runtime policy mix example
Section titled “Advanced runtime policy mix example”import type { PolicyRule } from '@stendar/core';
const advancedPolicies: PolicyRule[] = [ { id: 'manual-approval-large', type: 'require_approval', enabled: true, aboveAmount: 2_000, currency: 'USD', }, { id: 'burst-limit', type: 'rate_limit', enabled: true, maxTransactions: 5, windowMs: 60_000, }, { id: 'protocol-allowlist', type: 'protocol_allowlist', enabled: true, allowedProtocols: ['jupiter', 'kamino', 'lifi'], }, { id: 'protocol-exposure-cap', type: 'portfolio_exposure', enabled: true, scope: 'protocol', maxExposurePercent: 40, }, { id: 'drawdown-circuit-breaker', type: 'max_drawdown', enabled: true, maxDrawdownPercent: 15, },];Attach these to runtime config:
const runtime = new DeFiRuntime({ chains, providers, wallet, policies });Observability
Section titled “Observability”Subscribe to policy:decision events to capture allow/deny reasons and feed Notifications.
How the two surfaces connect
Section titled “How the two surfaces connect”- Public runtime adapters can evaluate against Policy v2 decision contracts.
- Raw runtime paths enforce
PolicyRule[]throughPolicyEngine. - Compatibility adapters bridge legacy selector inputs into Policy v2 and runtime evidence while APIs stabilize.