> ## Documentation Index
> Fetch the complete documentation index at: https://docs.redpotion.finance/llms.txt
> Use this file to discover all available pages before exploring further.

# Architecture

> This page is for integrators, operators, and auditors working against the Red Potion contracts. It explains how the system's three layers fit together, the two design patterns that

This page is for integrators, operators, and auditors working against the Red Potion contracts. It explains how the system's three layers fit together, the two design patterns that recur everywhere (hub-and-spoke and the batch lifecycle), and the operational points that matter when deploying and running a fund.

Red Potion is built with [Foundry](https://book.getfoundry.sh/), Solidity `0.8.34`, and OpenZeppelin v5 upgradeable contracts. Every deployed contract is a `TransparentUpgradeableProxy`. All module state uses ERC-7201 namespaced storage (`neobank.storage.*`) to stay upgrade-safe.

## The three layers

```mermaid theme={"dark"}
graph TD
    subgraph Protocol layer
        D[FundManagerDeployer<br/><i>protocol root · canonical impls · protocol fee recipient</i>]
    end
    subgraph Tenant layer
        FM[FundManager<br/><i>one per tenant · owns 8 factories</i>]
        FAC[8 × Factory]
    end
    subgraph Fund instance
        F[Fund<br/><i>hub: assets, orchestration, role registry</i>]
        SH[FundShare<br/><i>ERC-20 shares</i>]
        DQ[DepositQueue]
        RQ[RedeemQueue]
        O[Oracle<br/><i>batches & NAV reports</i>]
        FEE[FeeManager]
        RM[RiskManager]
        ST[Strategy 0..n<br/><i>allowlisted execution</i>]
        EW[External wallets]
    end

    D -- createFundManager --> FM
    FM --- FAC
    FM -- createFund --> F
    F --- SH
    F --- DQ
    F --- RQ
    F --- O
    F --- FEE
    F --- RM
    F -- push/pull assets --> ST
    F -- push assets --> EW
```

**Protocol root.** The [FundManagerDeployer](/developers/contract-reference/fund-manager-deployer) is the single contract the protocol team operates. It holds the canonical implementation address for every contract type, creates one [FundManager](/developers/contract-reference/fund-manager) per tenant, and stores the protocol fee recipient that every fund resolves live.

**Tenant.** Each [FundManager](/developers/contract-reference/fund-manager) is a per-tenant launchpad that owns eight [Factory](/developers/contract-reference/factory) instances — one per component — and wires a complete fund (hub plus six spokes) in a single `createFund` transaction. It also deploys strategies on behalf of its funds and controls which implementation future components use.

**Fund instance.** Each fund is a hub-and-spoke cluster: the [Fund](/developers/contract-reference/fund) hub plus the [FundShare](/developers/contract-reference/fund-share), [DepositQueue](/developers/contract-reference/deposit-queue), [RedeemQueue](/developers/contract-reference/redeem-queue), [Oracle](/developers/contract-reference/oracle), [FeeManager](/developers/contract-reference/fee-manager), and [RiskManager](/developers/contract-reference/risk-manager) spokes, plus any number of [Strategy](/developers/contract-reference/strategy) execution wallets.

## Pattern 1: Star (hub-and-spoke)

The [Fund](/developers/contract-reference/fund) is the hub. Spokes never talk to each other — only to the Fund, which mediates all inter-spoke communication. Just as important, **spokes hold no role state of their own**: their admin functions authorize by calling back into the Fund's access control. The practical result is that every role for a fund and its five governed spokes is granted and revoked in one place — on the Fund. See [Access Control & Roles](/developers/access-control-and-roles).

The Fund contract itself is thin; most of its behavior comes from composable modules mixed into it:

| Module                        | Contributes                                                   |
| ----------------------------- | ------------------------------------------------------------- |
| `FundACLModule` / `FundRoles` | Role registry and all role-name constants                     |
| `QueueModule`                 | Share/queue addresses and settlement math                     |
| `OracleModule`                | Oracle address, batch-id passthrough, accept-report internals |
| `FeeManagerModule`            | Fee accrual internals                                         |
| `RiskManagerModule`           | Queue-facing `checkDeposit`/`checkRedeem` proxies             |
| `StrategyModule`              | Strategy registry and asset push/pull                         |
| `ExternalWalletModule`        | External-wallet whitelist and one-way asset push              |

## Pattern 2: The batch lifecycle

There is no continuous AMM-style pricing. The [Oracle](/developers/contract-reference/oracle) divides time into **batches** separated by cutoff times. Deposits and redemptions queue into the current batch; after the cutoff an off-chain reporter submits a per-asset NAV price; after a mandatory review delay the report is accepted, which settles all deposit and redeem batches at a single fair price and accrues fees — all inside one `Fund.acceptReport` transaction.

```mermaid theme={"dark"}
sequenceDiagram
    actor U as Investor
    participant DQ as DepositQueue
    participant F as Fund
    participant O as Oracle
    participant RQ as RedeemQueue

    U->>DQ: deposit(asset, amount, proof)   — queued into batch N
    Note over O: batch N closes at cutoff
    Note over O: reporter submits prices; review delay passes
    F->>F: acceptReport() — fees accrued, batch N deposits & redeems settled
    U->>DQ: claimDeposit(asset, N) — receive shares
    U->>RQ: redeem(asset, shares)           — queued into batch M
    Note over F: batch M settles (payout snapshotted)
    Note over F: assets return to Fund — pulled from strategies or bridged/transferred back
    F->>RQ: fundRedeem(asset, M) — assets delivered
    U->>RQ: claimRedeem(asset, M) — receive assets
```

Key conventions:

* **Prices** are 1e18-scaled asset-per-share: `shares = amount × 1e18 / price`.
* **Native ETH** is supported everywhere via the sentinel `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`.
* **Fees are paid in newly minted shares**, never in assets.
* Requests are **cancellable until their batch settles**; claims never expire.
* Redemption payouts are **snapshotted at settlement**, so later fee/price changes can't desynchronize accounting.

## Settlement in one transaction

`Fund.acceptReport(nextCutoffTime)` is the heart of the system. In a single call it:

<Steps>
  <Step title="Assemble the asset set">
    Assembles the asset set = union(deposit assets, redeem assets) + the fee base asset.
  </Step>

  <Step title="Accept the Oracle report">
    Calls `Oracle.acceptReport`, which validates the batch is closed, no suspicious price is pending, and every asset is inside its accept window — then consumes pending reports, updates `lastAcceptedPrice`, advances the batch, and sets the next cutoff.
  </Step>

  <Step title="Accrue fees">
    For the fee base asset, calls `FeeManager.accrueFees` and mints management/performance/protocol fee shares.
  </Step>

  <Step title="Settle deposits and redemptions">
    For each asset, mints user and entry-fee shares for the deposit batch (settling it), and burns redeemed shares while snapshotting the redeem payout net of exit fee (settling that batch).
  </Step>
</Steps>

A parallel entrypoint, `acceptSuspiciousReport`, does the same but bypasses the suspicious-price check and requires a stronger role — for use after manual review.

## Redemption funding is a second step

Settlement only *records* what each redeem batch is owed. Paying it out is separate and role-gated, because at settlement the fund's assets are usually deployed. Assets return to the Fund one of two ways: the Fund **pulls** them from a [Strategy](/developers/contract-reference/strategy) (a strategy can never refuse a pull), or an **external wallet / bridge** transfers them back to the Fund address (operational trust — the Fund cannot pull from an external wallet). Once the Fund holds enough, `FUND_REDEEM_ROLE` calls `fundRedeem` to deliver the snapshotted amount to the [RedeemQueue](/developers/contract-reference/redeem-queue) and mark the batch claimable.

## Strategies: bounded execution

A [Strategy](/developers/contract-reference/strategy) is a fund-controlled wallet that deploys capital into external protocols, but only through **allowlisted calls**. The allowlist is keyed per `(caller, target, selector)`, optionally with pinned calldata words for constrained calls (e.g. allow `transfer(address,uint256)` only to a specific recipient, leaving the amount free). Two invariants bound the operator: the Fund can always pull assets back (`pullAsset` is `onlyFund`), and a strategy can never call the Fund (`target == fund` is rejected).

For capital that must execute on a **different chain** than the fund, a [StandaloneStrategy](/developers/contract-reference/standalone-strategy) uses the identical allowlist engine, detached from Fund control. Assets are bridged operationally and results are reflected into NAV via the Oracle.

## Upgrade model

Roles govern behavior; **ProxyAdmin ownership governs code**. Every contract is a `TransparentUpgradeableProxy` whose auto-deployed ProxyAdmin is owned by the `proxyAdmin` address chosen at tenant/fund creation — giving the tenant upgrade authority over all of its funds' contracts. Changing an implementation on the [FundManagerDeployer](/developers/contract-reference/fund-manager-deployer) or a [Factory](/developers/contract-reference/factory) affects only **future** deployments; existing proxies are upgraded through their own ProxyAdmins. The protocol operator cannot push code into a live fund.

## Operational notes

* **Settlement is all-or-nothing per report.** `acceptReport` reverts if any pending report in the asset set is flagged suspicious. Either reject and resubmit the bad price, or use `acceptSuspiciousReport` with the stronger role after review.
* **The fee base asset must always be reported.** Time-based fees and risk valuation depend on it, so it's always part of the settlement asset set.
* **External-wallet and cross-chain legs are trust-based.** The Fund cannot pull assets it pushed to an external wallet or bridged to a StandaloneStrategy; returning them is the controller's responsibility. Size operational trust accordingly.
* **Deployment is multi-step.** A fund is created by `FundManager.createFund`, which wires the hub and all spokes; the fund's `DEFAULT_ADMIN_ROLE` must then grant operational roles (reporter, acceptor, allocator, etc.) before the fund can run.

## Source and further reading

Per-contract detail — responsibilities, flows, and full function tables — lives in the [Contract Reference](/developers/contract-reference/fund). The authoritative source is the [`zentryHQ/red-potion-contract`](https://github.com/zentryHQ/red-potion-contract) repository.
