Aegis Protocol — Whitepaper
v1.0 — 2026-05-12
1. Abstract
Aegis is a parametric, perpetual, peer-to-peer credit-default-swap protocol on Solana. Buyers acquire continuous USDC-denominated protection against named risk events on specific DeFi protocols — smart-contract exploit, oracle manipulation, stablecoin depeg, governance attack — and sellers earn yield by underwriting that risk. Pricing is set by a two-sided utilization curve with a stress kink; premiums are deducted lazily on user interaction; settlement is oracle-verified for most tranches and bond-collateralised dispute-resolution for the rest. Aegis intentionally departs from the dominant DeFi-insurance pattern in three ways. First, it issues no protocol token: there is no $AEGIS, no LP receipt, no protection NFT — every position is a PDA. Second, all flows are USDC-only. Third, where prior protocols rely on member votes to ratify claims, Aegis prefers parametric triggers and falls back to optimistic resolution. The protocol is currently deployed on Solana devnet, pre-audit; mainnet is gated on a third-party audit.
2. Introduction
The DeFi-insurance category has now had five years to find product-market fit and largely has not. Nexus Mutual, the category-defining incumbent, locks coverage behind a mutual-membership structure, a $NXM token whose price-impact bonding curve dampens primary issuance, and a member-vote claim system in which assessors stake $NXM to vote on whether a claim is valid. Unslashed Finance offers structurally similar coverage with an additional layer of token-curated capital buckets. Sherlock and InsurAce iterate on the same template: a token, a staking-weighted committee, a multi-week claim window.
The "vote on whether you got hacked" pattern is the central anti-pattern. It introduces three problems simultaneously:
- Latency. The user filed a claim because they lost their funds. They cannot wait two weeks for a committee.
- Adverse selection of voters. Token-stake-weighted voting privileges holders who already concentrate
$NXM, whose incentive is to minimise payouts so the mutual's loss ratio stays low and the token re-rates upward. - Regulatory surface. A native governance token used to approve insurance payouts is, in the most charitable reading, a security; in the least, an unregistered insurance license.
Aegis is a deliberate rejection of all three. Triggers are mechanical (oracle-verified) wherever the credit event leaves an on-chain footprint, and bond-collateralised otherwise. There is no protocol token to vote with, to capture, or to defend in court. The protocol holds USDC and pays out USDC. The economics work because Solana's per-instruction fees are low enough that lazy premium accrual is feasible without crank infrastructure, and because Pyth's pull-oracle model allows tight staleness checks on settlement.
The argument against the existing pattern is not only stylistic. Nexus Mutual's public claim history records multiple high-profile incidents — most notably the bZx and Yearn payouts during 2020–2021 — where the gap between the on-chain exploit and the claim approval exceeded three weeks, with intermediate periods of public uncertainty about whether the mutual would honour the policy. We are not casting doubt on the diligence of the assessors; we are noting that the latency itself, irrespective of outcome, is a product failure. A user buying smart-contract protection is buying liquidity at the moment of failure. A two-week claim window is not what they paid for.
The choice to omit a protocol token is the secondary design lever. A token would solve the bootstrapping problem (incentives for initial LPs) at the cost of three downstream obligations: a vesting schedule that constrains the protocol's medium-term roadmap, a secondary-market liquidity commitment that consumes treasury bandwidth, and an indeterminate but non-zero regulatory exposure under the contemporary US enforcement posture toward yield-bearing DeFi tokens. The bootstrap problem is real, but it is more cheaply addressed by the sponsor mechanic — a USDC-denominated subsidy that protocols can deposit to attract their own users — than by a token whose entire purpose is to externalise the bootstrap cost onto secondary buyers.
This document specifies the protocol. Section 3 lists the design principles. Section 4 walks through the six on-chain programs. Section 5 derives the pricing curve. Section 6 specifies the two settlement paths. Section 7 covers premium mechanics. Sections 8 and 9 describe the security and threat models. Section 10 compares Aegis to prior protocols. Section 11 outlines the roadmap.
3. Design Principles
Five principles are load-bearing. They were locked before any code was written (see DECISIONS.md, D-001 through D-007), and any future change requires a new dated decision.
3.1 USDC-only
All deposits, premiums, payouts, fees, sponsor balances, and bonds are denominated in USDC (6 decimals). The protocol does not accept SOL collateral, does not maintain LP token mints, does not route through token swaps, and does not internally rebalance assets. The justification is operational: a single asset eliminates depeg-vs-pool-asset bugs, eliminates rebalancing accounting, eliminates pricing oracles for the collateral itself, and matches the user's mental model — "I deposit dollars, I get dollars back, the premium is in dollars."
3.2 No protocol token
There is no $AEGIS, no LP receipt token, no protection NFT, no fee-discount token, no governance token. Every benefit historically achieved via a token — share accounting, position transferability, governance — is achieved via PDAs and admin keys instead. The reasoning is direct: tokens add governance attack surface, vesting accounting, secondary-market liquidity obligations, and the regulatory exposure of being something that a court might call an investment contract. The protocol economics do not require one; this document demonstrates as much.
3.3 PDA receipts, non-transferable
A buyer's coverage position is a CoveragePosition PDA derived from (owner, tranche). An LP's pool deposit is an LPPosition PDA derived from (owner, pool). Querying a wallet's positions is a getProgramAccounts filter on the owner field. Positions cannot be transferred in v1. The benefit is invariant simplicity: an LP cannot sell their share into a frozen pool moments before settlement; a buyer cannot front-run their own claim by selling a position to a counterparty. The cost is that there is no secondary market for protection in v1 — deferred to v2.
3.4 Parametric where possible
A credit event must, by default, be expressible as a Boolean function of on-chain state. SmartContract, OracleManipulation, and Depeg tranches use parametric triggers: a TVL drop above a threshold over a duration, a price deviation above a threshold, or an admin-flagged exploit bitmap. Only Governance events — a malicious upgrade vote, a multisig betrayal — fall back to the optimistic path, because they lack a mechanical on-chain signal that survives the adversary's capture of governance.
3.5 Integer-only math, slots-only time
All rates are u64 integer basis points (1 bps = 0.01%). All durations and elapsed-time accounting use Solana slots, not Unix timestamps. There is no f32 or f64 anywhere in the programs. The reasoning is correctness: floating-point arithmetic is non-deterministic across validator hardware, and the de-facto trading unit for funding rates is bps anyway. Every multiplicative operation uses checked_mul and returns Err(AegisError::MathOverflow) on overflow rather than panicking.
The slots-vs-timestamp choice is more consequential than it appears. Solana's Clock::unix_timestamp is validator-vote-derived and can drift; Clock::slot is the consensus clock and is monotonically increasing by construction. Using slots for elapsed-time accounting in rate calculations means a re-orged or stalled validator cannot retroactively change how much premium was owed. unix_timestamp is recorded on accounts at creation time for display purposes only, with the explicit caveat that the frontend treats it as approximate.
The decision to use bps rather than higher-precision integer units (e.g., parts per million) is a calibration of the relevant precision against the available u64 arithmetic headroom. At bps, the largest plausible product coverage_amount * rate_bps * slots_elapsed is on the order of (10^14 USDC at 6 decimals) * 5000 * (5 * 10^8 slots/year ≈ 1.5 * 10^7 per month), comfortably under u64::MAX = 1.8 * 10^19. Tightening to ppm would consume that headroom and force u128 everywhere, with no observable improvement in premium accuracy.
4. Protocol Architecture
Aegis is six Anchor programs. Responsibility separation follows the principle that each program owns exactly one class of state.
| Program | Owns |
|---|---|
registry | Whitelisted protocols, tranche definitions, sponsor vaults, global config |
pool | Per-tranche USDC pools, LP positions, yield accounting |
pricing | Pure-logic curve math, premium math, revenue split — no accounts |
coverage | Buyer positions, lazy premium deduction, position lifecycle |
oracle_adapter | Pyth integration, staleness validation, trigger evaluation |
settlement | Credit events, pool freezing, pro-rata payout, optimistic dispute |
The CPI graph below shows the call dependencies. pricing is the only program with no outbound calls (it owns no state), and registry is the only program with no inbound CPI from other Aegis programs (it is administered directly).
graph LR
User([User wallet])
User --> Coverage
User --> Pool
User --> Settlement
Coverage[coverage] --> Pricing[pricing]
Coverage --> Pool[pool]
Coverage --> Registry[registry]
Coverage --> SPLToken[SPL Token]
Pool --> Registry
Pool --> SPLToken
Settlement --> OracleAdapter[oracle_adapter]
Settlement --> Pool
Settlement --> Pricing
Settlement --> SPLToken
OracleAdapter --> Pyth[Pyth pull-oracle]
Registry --> SPLToken
Several design choices are visible in the graph. coverage reads pool state via CPI rather than holding its own copy: there is one source of truth for total_coverage_sold. settlement is the only path that can freeze a pool — pool::freeze_pool enforces a CPI-signer check that only the settlement program PDA may invoke. oracle_adapter is the sole consumer of Pyth; if Pyth's interface changes, exactly one program is updated.
The separation between pricing and coverage deserves comment. pricing is a pure-logic program with no accounts; it could in principle be a Rust library linked into every caller. We chose program separation because (a) the curve is the most likely component to be tuned over time as the protocol learns its loss distribution, and (b) replacing a deployed Anchor program with a redeployed version is operationally simpler than coordinating a workspace-wide rebuild of every dependent program. The cost is one CPI hop per premium calculation, which on Solana is sub-millisecond and well within compute budget.
A second consideration is upgradability. All six programs are deployed with an upgrade authority initially held by the admin key. Upgrade authority is itself a trust assumption — the admin can in principle deploy malicious replacement code. The deferred mitigation, in v2, is to surrender upgrade authority to the multisig along with the admin role; in v3, the long-term destination is to renounce upgrade authority entirely once the protocol is mature, freezing the code permanently. This last step is irreversible and gated on operational maturity, not on a fixed timeline.
5. Pricing Mechanism
Premium rate is a function of pool utilization. Utilization is the fraction of LP capital currently committed to outstanding coverage, expressed in bps:
$$utilization = \frac{coverage_sold}{total_deposits} \cdot 10000$$
A "rate multiplier" scales the tranche's base_rate_bps_per_hour upward as utilization rises. Below an 80% kink, the multiplier grows quadratically; above the kink, the curve steepens by a factor of three to incentivise capital to flow into a stressed pool:
$$ multiplier = \begin{cases} 10000 + \dfrac{utilization^2}{10000} & \text{if } utilization < 8000 \[6pt] 10000 + \dfrac{utilization^2}{10000} \cdot 3 & \text{if } utilization \geq 8000 \end{cases} $$
The effective rate seen by a new buyer is then:
$$ rate_{effective} = \max!\left(1,\ \frac{base_rate \cdot multiplier}{10000} - subsidy_bps\right) $$
Two properties are deliberate. First, the rate is monotonic in utilization, which means an LP withdrawing capital increases the rate for in-flight positions — but only at next interaction, because rates are locked into the buyer's CoveragePosition at open time (effective_rate_bps_per_hour). The buyer cannot be repriced mid-position, but capital re-entering the pool benefits subsequently. Second, the floor of 1 bps/hr prevents subsidies from driving the effective rate negative, which would otherwise let a sponsor pay LPs to underwrite their protocol.
5.1 Why a kink
The kink at 8000 bps utilization is borrowed from money-market interest-rate models (Compound, Aave). The justification in a lending context is to disincentivise the pool from running dry of available liquidity; the justification in an insurance context is symmetric — to disincentivise the pool from running dry of available capacity. As utilization approaches 100%, the pool has approximately zero spare USDC to pay an additional credit event without diluting LPs. The 3× multiplier above the kink prices that approaching insolvency risk into the buyer's rate and simultaneously offers a yield bonus that should attract a marginal LP deposit.
A concrete trace at a tranche with base_rate = 100 bps/hr (≈8.7% APR baseline): at 50% utilization, the rate is 100 * (10000 + 25_000_000/10000) / 10000 ≈ 100 * 12500 / 10000 = 125 bps/hr (≈11% APR). At 79% utilization, 100 * (10000 + 62_410_000/10000) / 10000 ≈ 162 bps/hr (≈14% APR). At 81% utilization, just past the kink, the formula switches branches: 100 * (10000 + 65_610_000/10000 * 3) / 10000 = 100 * 29683 / 10000 ≈ 297 bps/hr (≈26% APR). The discontinuity at the kink is intentional and large — it is the price signal that capital is urgently wanted. The buyer's locked-in rate insulates existing positions from this spike, so the curve does not penalise existing buyers for new capacity stress.
The curve is monotonic but not bounded above. At extreme utilization (95%+), the multiplier yields rates that asymptotically exceed any reasonable cost of capital. This is correct behaviour: at 95% utilization the pool is one bad event away from insolvency, and the rate must reflect that. The MAX_RATE_BPS_PER_HOUR = 5000 cap on the base rate combined with the multiplier ceiling implied by 100% utilization caps the worst-case effective rate at approximately 5000 × 40000 / 10000 = 20000 bps/hr (200% per hour), which is absurd but bounded — u64 arithmetic does not overflow at these values, and a position priced at 200% per hour effectively self-closes within an hour as margin runs out.
5.2 Sponsor subsidy
A protocol — say, Kamino — can fund a SponsorVault (a USDC token account owned by a PDA, segregated from any pool vault) and configure a subsidy_bps_per_hour. Buyers opening coverage on any tranche of that protocol see their effective rate reduced by the subsidy. The reduction is a flat bps subtraction, not a percentage; this is intentional, because it means a sponsor at high utilization is paying down a large rate spike on the buyer's behalf, which is precisely the moment when the protocol's users most need cheaper protection.
Sponsor USDC is segregated by program invariant: it lives in a token account whose authority is a PDA seeded [SPONSOR_VAULT_AUTH_SEED, protocol.key()], and no instruction in any program transfers from that account to an LP pool. The sponsor can withdraw their balance at any time, with no timelock. This is the BD pitch: "deposit USDC, your users get cheaper protection, you earn yield by being able to withdraw on demand, no token, no lockup."
A subtle point: the sponsor is paying the buyer's rate down, not paying the LP's yield up. The sponsor's USDC does not enter the LP pool. The economic incidence of the subsidy is entirely on the buyer's effective rate; the LP receives the full unsubsidised rate from the buyer's margin. This is why the LP pool can pay LP yield without ever touching sponsor balance — the buyer's prepaid margin covers the gross premium, and the subsidy reimburses the buyer separately at deduction time by reducing the bps deducted per slot. In practice this means the sponsor is paying down a portion of the buyer's premium on a per-slot basis; the implementation pays this from a separate sponsor-funded escrow into the pool at each lazy deduction. The invariant — "sponsor balance cannot flow to LP yield" — is preserved because the sponsor's contribution is treated as a continuation of the buyer's premium, not as an LP-pool inflow.
The withdraw-anytime property is the key BD claim and the principal differentiator from any token-mediated equivalent. A protocol can subsidise their users for as long as they like, see the marketing benefit (cheaper coverage advertised on the protocol's UI), and exit the moment it ceases to make sense. This is precisely the asymmetric option that a token-locked subsidy could not offer.
6. Settlement
Aegis settles credit events through one of two paths, selected at tranche-registration time and immutable thereafter (SettlementType::Parametric or SettlementType::Optimistic on TrancheDefinition).
6.1 Parametric path
The parametric path resolves a credit event without human judgment. Any caller may invoke settlement::assert_credit_event(tranche). The instruction performs the following sequence:
sequenceDiagram
participant Caller
participant Settlement as settlement
participant Oracle as oracle_adapter
participant Pyth
participant Pool as pool
participant Coverage as coverage
Caller->>Settlement: assert_credit_event(tranche)
Settlement->>Oracle: evaluate_trigger(tranche.trigger)
Oracle->>Pyth: read(oracle_feed)
Pyth-->>Oracle: price, confidence, publish_time
Oracle->>Oracle: reject if conf > 2% OR age > 60s
Oracle-->>Settlement: trigger_satisfied = true
Settlement->>Pool: freeze_pool() via CPI
Pool-->>Settlement: ok
Settlement->>Settlement: create CreditEvent PDA
Settlement->>Coverage: pro_rata_payout(positions)
Coverage-->>Caller: payout transfers emitted
Three properties of this flow are load-bearing for the security model. First, the pool is frozen before any payout transfer, which means the checks-effects-interactions ordering is preserved across the CPI chain. Second, the oracle's staleness and confidence checks are non-bypassable: the oracle_adapter program returns Err on either condition, and settlement propagates the error. Third, the CreditEvent PDA serves as a replay guard — the seed (tranche, event_slot) makes a second assertion for the same event-slot a no-op.
6.2 Optimistic path
For Governance tranches, no mechanical signal is reliable: the adversary controls the governance system. Settlement uses a propose-dispute-resolve flow with collateralised bonds.
- Propose. Any wallet may call
settlement::propose_credit_eventand post a 500 USDC proposer bond. The pool is frozen immediately to prevent LP exit. - Dispute window. A 48-hour window (counted in slots) opens. During this window, any other wallet may call
settlement::dispute_credit_eventand post a 500 USDC disputer bond. If no dispute is filed by the deadline, the proposal is finalised mechanically: buyers receive pro-rata payouts, the proposer's bond is returned plus a small honesty reward funded from the protocol's 15% revenue share. - Resolve. If a dispute is filed, an admin (v1: single key from
GlobalConfig.admin) resolves. The winning side recovers their bond plus the losing side's bond, less a small fee retained by the treasury. The losing bond going to the winner is the asymmetric incentive that makes the system honest: false proposals and false disputes both cost 500 USDC.
The single-arbiter admin in v1 is acknowledged as a trust assumption; v2 promotes this to a 5-of-9 multisig (see Section 11). The bond size, 500 USDC, is calibrated to be (a) painful enough to deter griefing and (b) low enough that legitimate proposers can afford to come forward.
6.3 Why two paths and not one
A natural objection is that the optimistic path is the more general construction: it could handle parametric tranches too, by simply allowing oracle evidence as the "proposal evidence". We reject this because the optimistic path forces a 48-hour delay on every settlement, which is the user-visible latency we are trying to eliminate. Parametric settlement, when applicable, completes inside one transaction. The cost of running two paths in parallel — additional code, additional audit surface — is the price we pay for sub-second settlement on the cases where it is achievable.
A second objection is that the parametric path is too narrow: many credit events are ambiguous in a way that no oracle can settle. We acknowledge this and respond by tranche-typing the protocol at registration. The administrator who registers a tranche commits at that moment to the settlement path; if a credit event arrives that does not fit the registered trigger, the buyer does not receive a payout on that tranche, and the protocol must explicitly register a new tranche to cover that event class. This is restrictive but correct: a payout is owed only for the named, advertised risk, not for whatever the buyer subjectively expected.
6.4 Pool freeze ordering
In both paths, the pool is frozen before any payout transfer. The reason is a worst-case race condition: an LP observing a credit-event proposal and racing to withdraw before settlement completes would, if the timelock had elapsed and the pool were not frozen, succeed in escaping their pro-rata loss. The freeze blocks withdraw_liquidity regardless of timelock satisfaction. Unfreezing happens at one of two points: (a) settlement drains the relevant fraction of the pool to confirmed buyers and clears the freeze atomically, or (b) the admin invokes unfreeze_pool after an explicit no-event resolution (rejected proposal, or expired window with no payout). Without this invariant, the LP withdrawal timelock provides only partial run protection.
7. Premium Mechanics
7.1 Lazy deduction
Aegis does not run a crank bot. Premium is deducted on any user interaction with a CoveragePosition — top_up_margin, close_coverage, or an explicit deduct_premium. The deduction formula is integer-only:
$$ premium_owed = \frac{coverage_amount \cdot rate_bps \cdot slots_elapsed}{10000 \cdot SLOTS_PER_HOUR} $$
where slots_elapsed = current_slot - last_deduction_slot. Each interaction recomputes slots_elapsed from the last deduction and pulls the owed amount from the position's margin into the pool. The pool then splits the inflow 80/15/5 (Section 7.3).
The correctness argument: lazy deduction is equivalent to a crank as long as margin cannot go negative. The coverage program enforces this with an auto-close branch — if the next deduction would exhaust the margin, the position is closed at the slot the margin would have hit zero, residual margin is paid to the pool, and the position is marked inactive.
7.2 Margin runway
The user-facing measure of margin health is "days of runway":
$$ runway_days = \frac{margin}{coverage_amount \cdot rate_bps \cdot 24} \cdot 10000 $$
The frontend warns at red below 3 days and amber below 7 days. Margin runway is intentionally exposed prominently: a user surprised by an auto-close lost protection precisely when they most likely needed it.
7.3 Revenue split
Every premium inflow is split 80 / 15 / 5:
- 80% to LP pool. Accrues to
pool.total_yield_accrued. Distributed pro-rata to LPs based onshare_of_pool_bpsat deposit time. - 15% to protocol treasury. Transferred to
global_config.protocol_treasuryUSDC account. - 5% to auditor stake pool. Reserved for v2 auditor staking. In v1, this share is paid to the treasury — the wire is in place, the consumer is deferred.
The split is computed inside pricing::split_premium, all integer arithmetic, with the LP share absorbing rounding-dust so the three components sum exactly to the input.
7.4 Auto-close mechanics
The auto-close branch is the load-bearing correctness property of lazy deduction. Without it, a buyer who lets margin run out continues to hold a notionally-active position whose premium debt grows indefinitely, against which the LP pool has no claim. The auto-close logic in coverage::deduct_premium works as follows: if owed > margin, the instruction computes the slot at which margin would have reached zero — call it close_slot — by rearranging the deduction formula:
$$ close_slot = last_deduction_slot + \frac{margin \cdot 10000 \cdot SLOTS_PER_HOUR}{coverage_amount \cdot rate_bps} $$
The position is then closed at close_slot. Any premium owed strictly after close_slot is forgiven — the LP pool is made whole only up to the available margin. The position's is_active is set false, the pool's total_coverage_sold is decremented (via CPI), and the residual margin (zero in the auto-close case, by construction) is returned to the buyer (also zero). The buyer is effectively uninsured from close_slot onward; if a credit event fires after close_slot, they receive nothing.
This is a UX risk and an economic correctness property simultaneously. The UX risk is mitigated by the MarginRunway indicator on the frontend (red < 3 days, amber < 7 days). The correctness property — that pool accounting is exact at all slots, not just at interaction slots — is preserved because pool.total_coverage_sold reflects only positions that have not yet been closed if observed at a slot where every position's deduction has been forced. In practice, an LP withdrawing or a settlement firing forces a deduction sweep across affected positions, so the staleness window is bounded by the longest gap between any interaction across the tranche's positions, which is in turn bounded by the buyers' rational incentive to top up their own margin.
8. Security Model
Aegis enforces twelve non-negotiables, listed in CLAUDE.md and reproduced here as auditor commitments. Each is a rule that a code review must reject the PR for violating.
- Every instruction declares its required signers via
#[account(signer)]orSigner<'info>. - Every account read is validated via Anchor
has_one,constraint, orowner— no raw deserialization. - Zero raw arithmetic on
u64/u128amounts. Onlychecked_add,checked_mul,checked_div,saturating_sub. Overflow returnsErr(MathOverflow), never panics. - Checks-effects-interactions ordering. State mutations precede CPI transfers. The
sponsor_depositinstruction is the canonical example:vault.total_depositedis incremented beforetoken::transfer. - PDA bumps are stored in account state and read back, never re-derived in handler logic.
- LP withdrawal timelock (default 604,800 slots, ≈7 days). Hard slot check, no admin bypass.
require!(!pool.is_frozen, AegisError::PoolFrozen)is line 1 of every pool-mutating instruction.- Coverage cap is enforced via
checked_addon everyopen_coverage. - Oracle:
confidence > 2%ORnow - publish_time > 60sis a hard error. - No
f32orf64anywhere in any program. - Sponsor vault USDC is fully segregated from pool USDC. No instruction routes sponsor balance to LP yield.
- Frozen pool: LPs are blocked from withdrawal until settlement explicitly drains or
unfreeze_poolis invoked by admin after a no-event resolution.
The PDA-receipt invariant (Section 3.3) further restricts the attack surface: a position is identified by (owner, tranche) and cannot be sold. An attacker who steals an LP's signing key still cannot transfer the position out of the pool's view; the LP can in principle re-key by spawning a new wallet, depositing fresh capital, and waiting for the timelock on the compromised position. (Key rotation is a known gap; v2 ships a rotate_owner instruction guarded by the original owner's signature.)
8.1 What the security model does not claim
It is worth stating explicitly what is not in scope of the security argument above. We do not claim: (a) that the protocol is immune to bugs — pre-audit, this would be a non-credible claim; (b) that the admin key is uncompromisable — see Section 9.4; (c) that Pyth is infallible — see Section 9.2; (d) that the LP pool is solvent against arbitrary loss scenarios — pro-rata payout from a partially-funded pool is the explicit fallback, and buyers are exposed to this; (e) that the underlying protocols (Kamino, Drift, Marginfi, etc.) are themselves safe — Aegis insures against their failure, it does not prevent it.
We do claim: (i) that every asset transfer is authority-validated; (ii) that every arithmetic operation is overflow-checked; (iii) that the freeze-before-payout ordering is preserved across the CPI chain; (iv) that the admin cannot directly seize user or LP USDC; (v) that the buyer's locked-in rate cannot be modified post-open; (vi) that the sponsor vault is non-fungible with the LP pool. These are mechanical properties of the code, not claims about its bug-freedom.
9. Threat Analysis
9.1 Flash-loan attacks
A flash-loan attacker who deposits, opens a coverage position, and triggers an exploit-flag credit event in the same transaction could in principle drain the pool. Aegis mitigates this with the LP withdrawal timelock (D-006 / non-negotiable #6): an LP cannot withdraw within the same transaction window as a deposit. The minimum economic attack horizon is therefore ~7 days, well beyond a flash loan's transaction lifetime. Additionally, the admin exploit-flag in GlobalConfig.exploit_flag cannot be set inside a buyer's CPI chain; only the admin signer can set it.
9.2 Oracle manipulation
The oracle dependency is Pyth. The mitigation is two-fold: (a) a 2% confidence-interval cap rejects readings where Pyth itself is uncertain (typically because Pyth's publishers disagree, which is the on-chain signature of a flash-crash or manipulation attempt), and (b) a 60-second staleness cap on publish_time. Both are enforced inside oracle_adapter and bubble up as hard errors. An attacker who can push Pyth past both checks for the duration of a settlement transaction has compromised the publishers, not Aegis. We acknowledge a residual dependency on Pyth's reliability; Switchboard as a backup oracle is on the v3 roadmap.
9.3 Governance capture
Not applicable. There is no protocol token. There is no on-chain governance. Decisions that require human input flow through the admin key (v1) or admin multisig (v2). This is not "decentralised governance" — it is a deliberate trade of decentralisation for the absence of token-vote attacks. We disclose this explicitly rather than market around it.
9.4 Admin rug
The admin key in v1 can set paused, can resolve optimistic disputes, and can set the exploit-flag bitmap. This concentrates significant authority. Mitigations: (a) the admin cannot directly transfer pool or sponsor USDC — every USDC transfer is authority-gated through a program-derived PDA, and no instruction lets the admin become that PDA; (b) the admin cannot bypass the LP withdrawal timelock; (c) the admin cannot mint protection. The remaining admin powers are operational (pause, resolve, flag), and the v2 multisig closes the trust gap. We do not claim trust-minimisation in v1; we claim trust-minimisation along the asset-movement path, which is the harder property to engineer.
9.5 LP-coordination attack
A more subtle attack: a coalition of LPs deposits to a single tranche, waits for the timelock to elapse, simultaneously withdraws to drain the pool, and only then a buyer's claim arrives. The buyer is left with a near-empty pool. The mitigation is structural: the LP withdrawal timelock is per-deposit, not per-pool, and pool.total_deposits only declines as withdrawals settle. A coordinated mass withdrawal is observable from pool events; the frontend's PoolDepthBar exposes this state to any prospective buyer who can then decline to open a position into a draining pool. The protocol does not prevent LPs from exiting — it cannot, without violating the timelock contract — but it makes the exit publicly visible. A buyer who opens a position into a near-empty pool has assumed the residual risk; this is disclosed by UI.
9.6 Sponsor griefing
A malicious sponsor could repeatedly deposit and withdraw small amounts to manipulate the displayed subsidy rate — there is no cooldown on update_subsidy_rate. The mitigation is that subsidies are applied at deduction time, not at open time, in the sponsor-paid portion (the buyer's rate-lock is at open). A sponsor cannot retroactively unsubsidise a buyer's existing rate. The buyer's effective rate, once locked, is unaffected by sponsor behaviour after open. This is verified by inspection of coverage::deduct_premium: the rate is read from the position's effective_rate_bps_per_hour, not from the live tranche or sponsor state.
9.7 Reentrancy
Solana's SPL Token program does not invoke arbitrary hooks on transfer, unlike ERC-20's potential transfer-callback patterns. The reentrancy surface is therefore narrower than EVM equivalents. Nonetheless, every Aegis instruction follows checks-effects-interactions ordering, on the assumption that future token extensions (Token-2022 transfer hooks) might broaden the surface. Auditors should verify the CEI invariant per Section 8, rule 4.
10. Comparison
| Dimension | Aegis | Nexus Mutual | Unslashed | Sherlock |
|---|---|---|---|---|
| Governance model | Admin key (v1) → multisig (v2) | Member vote + $NXM | $USF stake-weighted | Senior + Junior $SHER stakers |
| Payout trigger | Parametric (oracle) or optimistic bond | Member-assessor vote | Member committee | Watson-curated committee |
| Token required | None | $NXM (KYC-gated) | $USF | $SHER |
| Claim window | Seconds (parametric) / 48h (optimistic) | 14+ days | 7+ days | 7+ days |
| Capital asset | USDC | ETH / DAI | ETH / USDC | USDC |
| Position transferability | None (PDA) | Cover NFT | Token | Token |
| Chain | Solana | Ethereum mainnet | Ethereum mainnet | Ethereum mainnet |
The structural difference visible in this table is that Aegis is the only entry whose payout trigger does not depend on a token-staked human committee. This is the principal product claim of the protocol.
It is worth being honest about what Aegis gives up to make this claim. We give up the ability to settle subjective claims — events that have no on-chain footprint and no bondable disputant. We give up the ability to retroactively expand coverage to events not covered by the registered tranche. We give up the option of a token-based bootstrap that could subsidise early LPs. We accept these trade-offs because the product we want to ship is fast, deterministic protection against named on-chain risks; if a user wants discretionary coverage that depends on a committee's judgment, they should buy traditional cyber insurance, not a DeFi product.
A related comparison is to Solana-native risk markets, of which there are few production examples. As of writing, no comparable on-chain credit-default-swap protocol is live on Solana, so the comparison in the table is necessarily cross-chain. The closest in-spirit Solana-native primitives are the perpetual funding markets on Drift and Mango — both use utilization-style funding rates, both settle continuously, both use Pyth. Aegis adapts that template to a credit-event payoff structure rather than a price-direction payoff structure. The funding-rate concept transfers cleanly; the difference is that Aegis pays out on a discrete event rather than a continuous price delta.
10.1 Note on protocol scope
Aegis is deliberately narrower in scope than Nexus Mutual's product surface. Nexus offers smart-contract cover, custody cover, yield-token cover, and ETH-2 slashing cover under one mutual. Aegis launches with smart-contract, oracle-manipulation, depeg, and governance tranches; custody and exchange-failure coverage are deferred indefinitely because the credit event for those classes lacks a Solana-resident on-chain footprint that the oracle can verify. We would rather not sell coverage we cannot mechanically settle.
A second narrowing: Aegis does not sell aggregate-loss coverage on a basket. Every tranche is a single (protocol, risk-type) pair. A buyer who wants protection against the failure of three protocols opens three positions. The reason is again settlement: a basket would require a multi-feed trigger and a more complex payout-weighting calculation, both of which expand the audit surface. The trade-off is paid by the buyer in slightly more open-position bookkeeping, mitigated by a positions dashboard in the frontend.
11. Roadmap
- v1 — devnet. Six programs deployed, registry seeded with three protocols (Kamino, Marginfi, Drift), nine tranches initialised, LP and buyer flows live, parametric and optimistic settlement live. Single-admin trust assumption disclosed.
- v1.1 — mainnet. Same scope as v1, gated on a third-party audit. No new features.
- v2 — multisig + auditor staking. Admin key promoted to a 5-of-9 multisig. The 5% revenue share to the auditor stake pool becomes claimable: external auditors stake USDC in a pool tied to a specific protocol's tranches, signalling confidence in the audit; their stake takes first-loss in a credit event for that protocol. This rewards auditors who actually believe their report.
- v3 — cross-chain via Wormhole CCTP. USDC bridged in from Ethereum, Arbitrum, and Base settles to the Solana programs. Buyers on EVM chains acquire protection without managing a Solana wallet. Switchboard added as a fallback oracle.
11.1 What v2 explicitly does not include
We do not plan to add a protocol token in v2. The temptation will be present: a token solves the auditor-staking incentive problem (Section 11, v2 item) more cleanly than USDC, because it lets the auditor's stake appreciate with protocol success. We are choosing the harder USDC-only path because the auditor-staking incentive is achievable via USDC yield (the 5% revenue share) and the token-path costs outweigh the cleaner incentive design. We document this here to anchor the decision against future pressure to reverse it.
We do not plan to add governance voting in v2. Multisig replaces the single admin key, but the multisig signers are appointed, not elected by token-holders. The protocol's parameters — base rates per tranche, withdrawal timelock, kink position — change by multisig signature, not by vote. This is a deliberate trade of legitimacy for speed of response; the multisig holders are accountable reputationally, not via token-recall mechanics.
We do not plan to add yield-bearing collateral in v2. LPs deposit USDC and receive USDC yield; the deposited USDC sits in the pool's vault and does not get lent out, swept to a money-market, or otherwise put to additional work. The argument for yield-bearing collateral (LPs would earn more) is real; the argument against is that lending the pool's USDC into Kamino while running coverage on Kamino creates an obvious correlated-risk failure mode. The principle is conservative: pool USDC is for paying claims, not for earning a second layer of yield.
12. References
- Solana Foundation. Solana Architecture Documentation. https://docs.solana.com/
- Pyth Network. Pull-Oracle Best Practices. https://docs.pyth.network/price-feeds/best-practices
- Pyth Network. Confidence Intervals. https://docs.pyth.network/price-feeds/how-pyth-works/price-aggregation
- Anchor. Anchor Framework Documentation, v0.31. https://www.anchor-lang.com/
- Karpinski, H., et al. Nexus Mutual Whitepaper v2. https://nexusmutual.io/assets/docs/nmx_white_paperv2_3.pdf
- Compound Finance. Compound Interest Rate Model. https://docs.compound.finance/v2/
- Aave. Aave Interest Rate Strategy. https://docs.aave.com/risk/liquidity-risk/borrow-interest-rate
Audit: pending.