Skip to main content
For integrators, operators, and auditors. Covers the three layers, hub-and-spoke and batch patterns, and operational constraints. Stack: Foundry, Solidity 0.8.34, OpenZeppelin v5 upgradeable. Every deploy is a TransparentUpgradeableProxy. Module state uses ERC-7201 namespaced storage (neobank.storage.*).

Three layers

Protocol root creates tenants; each tenant creates funds; each fund is a hub with spokes and execution wallets. Spokes and execution wallets around the hub: Protocol root. FundManagerDeployer: canonical implementations, one FundManager per tenant, protocol fee recipient resolved live by funds. Tenant. FundManager owns eight Factory instances and wires hub + six spokes in one createFund. Also deploys strategies and chooses implementations for future components. Fund instance. Fund plus FundShare, DepositQueue, RedeemQueue, Oracle, FeeManager, RiskManager, and any Strategy wallets.

Pattern 1: Star (hub-and-spoke)

Spokes talk only to the Fund. Spokes hold no role state — admin checks call back into the Fund ACL. Grant and revoke roles in one place. See Access control and roles. Fund behavior comes from modules:

Pattern 2: Batch lifecycle

No continuous AMM pricing. Oracle cuts time into batches. After cutoff, a reporter submits per-asset NAV; after review delay, acceptance settles deposits and redeems and accrues fees inside one Fund.acceptReport. Conventions:
  • Prices — 1e18 asset-per-share: shares = amount × 1e18 / price
  • Native ETH — sentinel 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE
  • Fees — newly minted shares, never assets
  • Cancel until settlement; claims never expire
  • Redeem payouts snapshotted at settlement

Settlement (acceptReport)

Fund.acceptReport(nextCutoffTime) in one call:
1

Assemble asset set

Union of deposit assets, redeem assets, and fee base asset.
2

Accept Oracle report

Oracle.acceptReport: batch closed, no pending suspicious price, every asset inside accept window — then consume reports, update lastAcceptedPrice, advance batch, set next cutoff.
3

Accrue fees

For fee base asset: FeeManager.accrueFees; mint management/performance/protocol fee shares.
4

Settle deposits and redemptions

Per asset: mint user and entry-fee shares for the deposit batch; burn redeemed shares and snapshot redeem payout net of exit fee.
acceptSuspiciousReport is the same path with suspicious-price check bypassed and a stronger role — after manual review.

Redeem funding

Settlement records what each redeem batch is owed. Payout is separate and role-gated. Assets return by pull from a Strategy (cannot refuse) or by transfer from an external wallet / bridge (operational trust). Then FUND_REDEEM_ROLE calls fundRedeem to deliver the snapshotted amount to RedeemQueue.

Strategies

A Strategy is a fund-controlled wallet limited to allowlisted calls keyed by (caller, target, selector), optionally with pinned calldata words. Invariants: Fund can always pull (pullAsset is onlyFund); strategy cannot call Fund (target == fund rejected). Cross-chain execution uses StandaloneStrategy: same allowlist engine, no Fund control. Bridge operationally; reflect results in NAV via Oracle.

Upgrades

Roles govern behavior; ProxyAdmin ownership governs code. Each TransparentUpgradeableProxy has a ProxyAdmin owned by the proxyAdmin chosen at tenant/fund creation. Changing implementations on FundManagerDeployer or a Factory affects future deploys only. Live proxies upgrade through their own ProxyAdmins. 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 suspicious. Reject/resubmit, or use acceptSuspiciousReport after review.
  • Fee base asset must be reported every settlement.
  • External-wallet and cross-chain legs are trust-based. Fund cannot pull those assets back.
  • After createFund, DEFAULT_ADMIN_ROLE must grant operational roles before the fund can run.

Source

Per-contract detail: Contract reference. Source: zentryHQ/redpotion-contracts.