AURA

Core Accounts

Treasury, dWallet runtime, and trust identity accounts

TreasuryAccount

The root state machine for one agent treasury — owner + AI authority, registered dWallets, the active policy config and spend counters, the pending-proposal queue, reputation, fees, optional multisig and swarm, and lifecycle/safety state.

Seeds:

[b"treasury", owner, agent_id]

The optional multisig stores guardians with optional per-guardian voting weights and an optional required summed weight, powering real M-of-N (and weighted / role-based) approval on the spend path. Each queued pending proposal carries an approvals tally of distinct approvers; approve_pending_execution only marks the Multisig level satisfied once the count or weight quorum is reached.

Immutable identity

owner and agent_id are part of the seed, so they cannot change in place — they define the account's address. Mutable settings are edited via update_treasury_metadata; the policy config via the policy-configuration instructions.

The on-chain record (TreasuryAccount) is the serialized form; instructions deserialize it into the AgentTreasury domain object, mutate that, and write it back. The audit trail is emitted as events rather than persisted in the account. A default_chain field marks the treasury's preferred ("primary") execution chain (set via set_default_chain). Pending proposals can carry optional asset/native/gas transfer metadata; the treasury stores that metadata so the proposal digest, dWallet message, cancellation, expiry, and finalization paths all agree on the same concrete asset payload.

Trust-envelope and agent-identity state lives in a separate TrustIdentityAccount PDA, not on TreasuryAccount, to keep treasury deserialization within the SBF 4096-byte stack-frame limit. The treasury's effective daily limit is still computed as base × reputation_bps × tier_bps / 10_000², where tier_bps is the multiplier for the trust tier stored on that PDA — the tier multiplier is applied on top of the reputation multiplier so both the "earn more rope" and "lose it fast" signals use the same dial.

A recovery_destinations list holds up to 8 per-chain cold-wallet addresses used exclusively by break_glass_recover. Each entry carries a locked_until timestamp: newly registered or updated addresses are locked for 48 hours to prevent an attacker who steals the owner key from immediately redirecting a recovery sweep.

DWalletAccount

Each registered dWallet has its own runtime account — one PDA per (treasury, chain) — holding the controls, multi-asset ledger, and spend reservation that don't fit inside the size-capped treasury account. It is created by init_dwallet_state and closed by remove_dwallet.

Seeds:

[b"dwallet_state", treasury, chain_code]

It stores the lifecycle status (active / frozen / retiring / retired), optional per-tx + daily USD limits and a rolling spend counter, the controlling authority + CPI authority seed (rotation epoch), an optional label, a reservation total, and an asset ledger (up to 16 rows of native amount, USD value, decimals, and an optional price feed account).

The feed account can be refreshed through the raw legacy path or through the verified oracle adapter (set_asset_oracle_feed + refresh_verified_asset_balance), which validates the stored feed account, owner program, publish time, confidence interval, and exponent before updating USD value. When require_balance_oracle_freshness is enabled, raw legacy balance and condition feeds are refused.

The treasury keeps only a cached aggregate balance per dWallet, kept in sync via reconcile_dwallet_balance.

Pending proposals may also store ChainExecutionBinding fields in the treasury queue. Those fields bind EVM replay data, Bitcoin UTXO/sighash data, or Solana blockhash/message data into the dWallet signed message and keep chain-bound proposals open until confirm_settlement observes the required confirmations. Failed broadcasts can be resubmitted with fresh replay fields or abandoned to release wallet reservations.

TrustIdentityAccount

Trust-envelope and agent-identity state is held in its own PDA — one per treasury — so the size-capped TreasuryAccount stays within the SBF 4096-byte stack-frame limit during deserialization. It is created by init_trust_identity and is optional on the proposal path: instructions that accept it fall back to ai_authority-only auth and assume TrustTier::Trusted when it is absent.

Seeds:

[b"trust_identity", treasury]

Four fields track the trust tier: trust_tier (u8 code), threat_score (decaying u16 accumulator), tier_entered_at, and last_clean_activity_at. A trust_config record holds the owner-configurable thresholds and per-tier multipliers. An agents list (up to 8) holds scoped secondary agent authorities; when non-empty, propose_transaction validates callers against it (the primary ai_authority always retains full access). A pending_ownership_handover field holds a timelocked successor nomination.

Each agent entry carries a full capability manifest (scope): allowed chains, tx types, a DeFi protocol bitmap, a privileged-instruction bitmap, per-agent daily and per-transaction USD caps, an optional recipient/asset allow-list, and an optional active-time window — checked on every action by the propose_transaction gate. It also carries on-chain stats (actions_total, denials, last_active_at) and a loosen_unlock_at timelock that gates manifest loosening (tightening is immediate). A treasury-level tripwire_config holds the owner-tunable behavior-signal weights that the gate feeds into threat_score on a breach.

On this page