ORRANGE / Architecture

AI + Policy Architecture

Hamster proposes. The deterministic policy engine decides. This separation is the entire security story.

user prompt


AI proposal (structured JSON)


schema validation (no constraints accepted)


portfolio + fresh prices (server-side)


deterministic TreasuryPolicy verdict


ADVISORY / BLOCKED / EXECUTABLE


user confirmation


fresh state re-fetch + policy re-evaluation


existing STRK20 private transfer

The separation

The LLM is advisory and untrusted. Its output is a JSON proposal that is schema-validated and then evaluated by a pure, deterministic policy engine. The engine has no network access and no LLM — it is a function of (proposal, portfolio, policy). The model can never change the policy, choose a destination outside the allowlist, or emit arbitrary calldata.

What the AI can control

  • Whether to propose an action or a report.
  • Which treasury asset to move, and a human-readable amount string.
  • Concise display copy (diagnosis, recommendation, why, outcome) — never used for decisions.

What the AI can never control

  • Policy values — user-selected, server-validated; model-injected constraints are rejected.
  • Destinations — an explicit allowlist; an empty allowlist denies everything.
  • Execution — only the existing STRK20 private-transfer path, only after re-validation.

Deterministic checks

CheckRule
Exact amountAmounts are parsed to exact bigint base units via the asset’s decimals (parseAmountExact); over-precision is rejected, never rounded.
BalanceProposed base units must not exceed the position’s balance.
Destination allowlistRecipient must be in the approved set. Empty set = deny all execution.
Self-transfer rejectionA recipient equal to the treasury identity is rejected deterministically.
Live price for volatile assetsSTRK/ETH need a fresh (< 60s) AVNU price to authorize execution; a static fallback only feeds advisory analysis.
StablecoinsUSDC/USDT are pinned at $1 (static is authoritative).
Min liquidityUSD liquidity after the action must stay ≥ your guardrail floor (conservative bigint cents).
Max positionNo single position may exceed your cap after the action (integer bps, no float division).
Max per actionThe action’s conservative USD value must stay ≤ your cap.

User-selected policy

The guardrail is chosen by the user (preset or custom) and sent with every analysis request. The server validates bounds (resolveUserPolicy) and returns the effective policy with the response. Values:

  • Min liquid: 0 – $1,000,000
  • Position cap: 1 – 100%
  • Max per action: $1 – $10,000,000

Out-of-bounds or unknown presets are rejected with 400 — never silently clamped.

Execution gate

Confirming runs executeProposal, which re-checks in order: expiry (120 s TTL) → current balances equal analysis-time state → exact bigint amount reconstruction → fresh prices → deterministic policy against fresh state → the injected STRK20 private-transfer path. Any failure returns a specific reason (EXPIRED, STATE_CHANGED, AMOUNT_INVALID, POLICY_REJECTED, EXECUTION_FAILED) and no transfer occurs.

This is the same security posture end to end: proposal → expiry → fresh state → exact amounts → fresh prices → deterministic policy → wallet confirmation → existing privateTransfer. Nothing else can move funds.