> For the complete documentation index, see [llms.txt](https://docs.buoy.finance/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.buoy.finance/protocol-deep-dive/architecture.md).

# Architecture

This section is for readers who want to know exactly how Buoy works under the hood. Nothing here is required to use the product — but if you're evaluating the protocol's design, start here.

## System overview

```
                     HyperEVM (smart contracts)
        ┌──────────────────────────────────────────────┐
        │                                              │
 User ──►  Router ────► VaultFactory ──deploys──► BuoyVault(s)
        │  (gateway)    (registry)          (one per vault:  │
        │     ▲                              shares, USDC,   │
        │     │ settles requests             request state)  │
        └─────┼──────────────────────────────────┬───────────┘
              │                                  │ bridge (USDC)
        ┌─────┴─────┐                     ┌──────▼─────────────┐
        │ Fulfiller │◄────market data─────│     HyperCore      │◄── Leader's terminal
        │ (off-chain│                     │ (the vault's own   │    (agent key)
        │  service) │─────liquidations───►│  account: spot,    │◄── Strategy engine
        └─────┬─────┘                     │  perps, HIP-3/4)   │    (protocol vaults)
              │ indexes txs               └────────────────────┘
        ┌─────▼─────┐
        │  Backend  │────► Web app (vault list, charts, quotes, profiles)
        └───────────┘
```

## On-chain components (HyperEVM)

### Router — the single gateway

Every user action goes through one **Router** contract: deposit requests, withdrawal requests, cancellations, and vault creation. The Router:

* validates requests and escrows funds/shares into the target vault within the same transaction — it never custodies user funds between transactions;
* assigns every request a global ID and collects the fixed request fee (HYPE);
* is the **only** address allowed to trigger settlement on vaults, and only the authorized settlement role can drive it.

### VaultFactory — the registry

The factory deploys new vaults and maintains the canonical on-chain registry of legitimate Buoy vaults (the Router refuses to touch anything not in the registry). It also curates the **builder whitelist** used for builder-fee approvals.

When the protocol deploys a new factory, the outgoing one is kept in the Router's **legacy-factory list** rather than dropped. Vaults created under it keep their full Router surface — settlement, user cancellations, Core→EVM bridging — while their in-flight requests drain. Without that, repointing the Router would instantly cut existing depositors off from `cancelDeposit` / `cancelWithdrawal`. An entry is retired only once nothing under it is left to settle.

### BuoyVault — one contract per vault

Each vault is an independent contract that is simultaneously:

* the **ERC-20 share token** (`buoy<TICKER>`);
* the **custodian** of the vault's EVM-side USDC;
* the **bookkeeper** for pending requests, withdrawal obligations, the high-water mark, and the performance fee.

Vaults are deployed as minimal-proxy clones of a fixed implementation, which makes each vault **immutable once deployed** — no one, including the protocol team, can change a live vault's code. (Upgrading the implementation only affects vaults created afterwards.) The vault's HyperCore interactions — bridging and the CoreWriter actions — sit in a small library linked into the implementation at deploy time, so they are as fixed as the vault itself.

### VaultPolicy — deposit rules

Because a vault's code can never change, rules about *who may enter* live outside it. Every vault created since v3 holds a pointer — set at creation, with no setter — to a shared **VaultPolicy** contract, and asks it on each deposit request and each deposit settlement whether the deposit may proceed. That is where the Leader's [deposit limits](/for-vault-leaders/deposit-limits.md) are stored and checked: the minimum leader share, the TVL cap, and the depositor whitelist with its per-address position caps.

The policy is deliberately powerless beyond saying no: it holds no funds, cannot mint or burn, and is consulted only on the deposit path — the withdrawal path never asks it, and the few bookkeeping calls the vault makes to it while a withdrawal settles cannot fail the withdrawal. The worst a policy can do is close a vault to new money. New kinds of entry rules can ship as a new policy contract for future vaults without touching the vault implementation.

The Router and Factory, by contrast, **are upgradeable** by the protocol admin — this is where new protocol features land. See [Security & Trust](/protocol-deep-dive/security-and-trust.md) for the full powers matrix.

### RewardsDistributor — the referral treasury

Every performance fee is split at the moment it crystallizes: the Leader's portion is minted to the Leader, and the protocol's portion (a fixed share, snapshotted into each vault at creation) is minted to the **RewardsDistributor**. The distributor does two things and nothing else:

* it lets the fulfiller convert those fee shares to USDC through the ordinary withdrawal path (`requestRedeem`, a fee-exempt pass-through to the Router — the USDC comes back to the distributor itself), so in steady state it holds plain USDC;
* it pays referral rewards: `claim(cumulativeAmount, deadline, signature)` verifies a backend signature over the caller's **lifetime** total and pays the difference over what it has already paid that wallet. Signatures are therefore idempotent, cannot be replayed for profit, and cannot pay anyone but the wallet they name.

Who earned what is decided off-chain (see the backend below); the contract enforces only the signature and the per-wallet counter. It is a small UUPS-upgradeable contract, separate from vault custody: nothing in the referral program can touch depositors' capital. The protocol withdraws its own remainder through a dedicated owner function, bounded by the backend's accounting of what is still owed to users. Product-level detail: [How Referrals Work](/referral-program/referral-program.md).

## The two layers: HyperEVM ↔ HyperCore

Buoy's contracts live on **HyperEVM**, but trading happens on **HyperCore** — Hyperliquid's native trading engine. Each vault owns a HyperCore account, and USDC moves between the layers:

* **EVM → Core:** deposited USDC is bridged into the vault's HyperCore spot account so the Leader can trade it.
* **Core → EVM:** when withdrawals need paying, USDC is sent from the vault's Core spot account back to the vault contract.

Both directions are restricted at the contract level to the vault's **own** accounts — there is no code path that bridges vault funds to any third-party address. One technical quirk worth knowing: USDC has **6 decimals on HyperEVM but 8 on HyperCore**; the contracts convert automatically.

### Unified accounts

Vaults are enrolled in HyperCore's **unified-account** mode (the protocol switches each vault before, or alongside, its first capital). One spot USDC balance collateralizes spot, the default perp DEX and every HIP-3 / HIP-4 market: margin is drawn and returned automatically, and the balance is marked to market, so open positions' unrealized PnL is already reflected in it.

This has two consequences worth knowing. Operationally, there is nothing to allocate — the contracts' spot↔perp and HIP-3 transfer functions still exist (and still restrict destinations to the vault's own account) but move nothing in this mode. For valuation, the perp legs contribute **nothing extra** to NAV, because their margin and PnL already live inside the spot balance; adding them would double-count. The NAV code branches on the account's live abstraction mode for exactly this reason.

## Off-chain components

### Fulfiller — the settlement service

A protocol-operated service that watches the Router for new requests, computes each vault's **NAV** from live Hyperliquid data, and settles requests at that valuation (minting shares, locking and paying withdrawals, bridging funds, and liquidating positions when withdrawals require it). Its exact duties and the mechanics of a settlement are covered in [Request Lifecycle](/protocol-deep-dive/request-lifecycle.md), and its valuation method in [NAV & Share Price](/protocol-deep-dive/nav-and-share-price.md).

The fulfiller holds a privileged role on the Router — but a deliberately bounded one: it decides *when and at what valuation* requests settle, while *where funds can go* is fixed by the contracts.

Beyond settlement it performs a few housekeeping duties on each vault's HyperCore account, all of them non-custodial:

* **Batching.** Requests for the same vault are settled together against a single NAV snapshot (`fulfillDeposits` / `fulfillWithdrawals`). An item that can't settle is skipped with an on-chain reason event instead of reverting the batch.
* **Trading-agent upkeep.** HyperCore agent approvals expire and are silently pruned. A periodic sweep re-registers each vault's Leader-set agent under a named slot with the maximum 180-day validity whenever HyperCore stops recognizing it, so trading doesn't quietly stop. Vaults with no HyperCore account yet (no deposit ever bridged) are parked and re-checked hourly.
* **Account setup.** Before a vault's first deposit settles, its Core account is enrolled in unified-account mode and tagged with the protocol's Hyperliquid referral code — both signed by the vault's own agent, both one-time and idempotent.
* **Fee-share redemption.** A periodic sweep looks for vault shares held by the RewardsDistributor (the referral fee from freshly crystallized fees) and redeems them for USDC through the normal withdrawal path, with a value floor derived from the vault's cached NAV so an illiquid vault can never write that claim down to nothing.

Its durable state — request state machines, the indexer cursor, and per-vault agent keys — lives in a database, with agent keys stored **encrypted at rest** (AES-256-GCM) so neither the database nor its backups hold plaintext keys.

### Backend — the read layer

An indexer + REST API that turns on-chain events into what the app shows: vault lists, APR and drawdown analytics, performance charts, live per-venue allocation, depositor leaderboards, deposit/withdraw quotes, and user positions. It's read-only with respect to funds — it holds no keys and cannot move anything. Everything it serves is derived from public chain data and Hyperliquid's public API, and is independently verifiable.

It also holds the off-chain half of a vault's identity: descriptions, avatars, taglines, X links and the leader-declared risk/strategy badges. Those are written by leaders through **EIP-712 signatures verified against the vault's on-chain leader address** — there are no accounts or API keys in the flow — and pass automated text and image moderation before publication.

The backend also keeps the **referral ledger**. For every `ProtocolFeeCrystallized` event (the on-chain name for the referral fee) it values that slice in USDC at that block, reads which vault holders came in under a referral code and how much of the vault they held, and credits the referrer and the invitee their configured shares; whatever is left unattributed — capital that arrived with no referrer — stays with Buoy. A wallet's lifetime total is what the backend signs for `RewardsDistributor.claim`, and the contract's own `claimed` counter — never a parallel database figure — is what the dashboard nets it against. Attributions (who invited whom) are written once, first-touch, from an EIP-712 signature by the invited wallet.

### Strategy engine — for protocol-operated vaults

Not every vault has a human at the keyboard. Buoy also runs an execution engine that holds the trading-agent keys of a small set of **protocol-operated vaults** and trades them to the strategy each vault's public description states.

Architecturally it is just another agent-key holder: it has exactly the powers a Leader's terminal has, and none beyond them — it cannot withdraw, and it shares operator authority over those vaults with the fulfiller, which will force-close positions to fund withdrawals whenever it needs to. The engine therefore re-derives its whole book from live venue state on every tick and converges, rather than assuming it owns the positions.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.buoy.finance/protocol-deep-dive/architecture.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
