Architecture Overview
King's Vault V2 is an ERC-4626-based DeFi asset management system. Investors deposit assets into a Vault to receive vault shares; the operations team uses the Controller to manage vaults, strategies, NAV settlement, and configurable performance fee accounting; Keepers deploy idle assets according to strategies into Aave, ERC-4626 vaults, Morpho, or HyperEVM / HyperCore. The current performance fee rate for Ethereum Network Lending, AAVE GHO Saving, and Hyperliquidity Provider (HLP)—the V2 portals documented here—is 0%.
Lending and GHO Saving use separate KingsVaultV2 instances; HLP uses KingsVaultV2Async. The system is divided into six main layers:
| Layer | Contract | Purpose |
|---|---|---|
| Vault | KingsVaultV2 |
Synchronous ERC-4626 vault supporting deposits, withdrawals, dual-pricing conversion, liquidity waterfall replenishment, and emergency redemption. |
| Async Vault | KingsVaultV2Async |
Asynchronous redemption version. Escrows shares during withdrawal, which are batch executed by a Keeper before the Investor can claim assets. |
| Controller | Controller |
UUPS upgradeable central coordinator managing vault registration, strategy registry, fund routing, NAV propose/confirm, and conditional fee-share minting. Fee-share minting is inactive at the current 0% V2 portal fee rate. |
| Strategy Adapters | AaveV3Strategy, ERC4626Strategy, MorphoStrategy; GHO Saving integration |
Deploys vault assets to lending and savings protocols on Ethereum. |
| Cross-chain Strategy | HyperStrategy |
Ethereum-side CCTP V2 strategy responsible for cross-chain burn/mint, remote state synchronization, and asynchronous divest requests. |
| HyperEVM Execution | HyperCoreAllocator, HyperCoreRouter |
HyperEVM side receives assets, mints internal shares, allocates to HyperCore/HLP, and handles cross-chain redemptions. |
GHO Saving routes USDC → GHO → sGHO and reverses that route when underlying assets are needed for a withdrawal. Users hold King's Vault shares, while the strategy accounts for the net USDC recoverable from its sGHO position. This is an Aave savings integration, not an Umbrella staking position.
Roles
The documented V2 custom roles are defined in the Roles library in src/libraries/Constants.sol. The system utilizes OpenZeppelin's AccessControl or AccessControlUpgradeable. The following is an interface-level role summary, not proof of each deployed contract's current grants or upgrade authority; resolve any conflicting descriptions against the verified deployment before use.
| Role | Constant | Scope | Responsibility |
|---|---|---|---|
| Admin | DEFAULT_ADMIN_ROLE |
Controller, Vault, Strategy, Allocator, Router | Authorizes other roles, sets manager, confirms NAV, and manages role grants. Effective UUPS upgrade authority must be verified per deployment. |
| Developer | Roles.DEVELOPER |
Controller, Allocator | Registers vaults, adds/removes strategies, adds HyperCore routers. |
| Keeper | Roles.KEEPER |
Controller, Async Vault, Strategy, Allocator, Router | Executes operations: invest, divest, NAV propose, fee rate adjustments, CCTP relay, async executeRedeem, and HyperCore allocations. The current V2 portal fee rate is 0%. |
| Guardian | Roles.GUARDIAN |
Vault, Controller | Emergency operations: pause, unpause, permanent shutdown, and invocation of strategy exit paths; these do not guarantee remote asset recovery. |
| Investor | Roles.INVESTOR |
Vault, Async Vault | User operations: deposit, mint, withdraw, redeem, claim, emergencyRedeem. |
Role Assignment Notes
| Contract | Initial Roles |
|---|---|
Controller.initialize(owner, manager) |
owner receives DEFAULT_ADMIN_ROLE; manager is only the fee receiver, not automatically a role holder. |
KingsVaultV2 constructor |
owner_ receives DEFAULT_ADMIN_ROLE and Roles.GUARDIAN; vault starts paused. |
KingsVaultV2Async constructor |
Same as KingsVaultV2. Keeper role must be granted on the async vault for executeRedeem(). |
AaveV3Strategy, ERC4626Strategy, MorphoStrategy, HyperStrategy, HyperCoreRouter constructors |
owner_ receives DEFAULT_ADMIN_ROLE. |
HyperCoreAllocator.initialize(...) |
owner_ receives DEFAULT_ADMIN_ROLE. |
Important implementation detail: KingsVaultV2 does not use a Roles.CONTROLLER constant. Controller-only functions check msg.sender == CONTROLLER through the immutable CONTROLLER address.
For strategy execution through Controller.fundInvest(), Controller.fundDivest(), Controller.fundReplenishOnlyForVault(), and Controller.strategyRevoke(), the strategy sees msg.sender as the Controller contract. Therefore, the Controller proxy must be granted Roles.KEEPER on each concrete strategy that enforces onlyRole(Roles.KEEPER).
Architecture
flowchart TD
Investor["Investor"] --> Vault["KingsVaultV2 / KingsVaultV2Async"]
Admin["Admin"] --> Controller["Controller"]
Developer["Developer"] --> Controller
Keeper["Keeper"] --> Controller
Guardian["Guardian"] --> Vault
Guardian --> Controller
Controller --> Vault
Controller --> Strategies["Strategies"]
Strategies --> Aave["Aave V3"]
Strategies --> ERC4626["External ERC4626 Vault"]
Strategies --> Saving["GHO Saving: USDC → GHO → sGHO"]
Strategies --> HyperStrategy["HyperStrategy"]
HyperStrategy --> CCTP["CCTP V2"]
CCTP --> Allocator["HyperCoreAllocator"]
Allocator --> Router["HyperCoreRouter"]
Router --> HyperCore["HyperCore / HLP"]
Asset Accounting
KingsVaultV2.totalAssets() returns:
idleAssets() + Controller.totalStrategyAssets(address(this))
For the synchronous vault, idleAssets() means tokens physically held by the vault contract. The async variant excludes assets reserved for executed claims. Strategy assets are counted through each registered strategy's totalAssets(); for HyperStrategy this includes cached remote state, while Saving requires net USDC-recoverable valuation after applicable route costs. Reported NAV is not the same as immediately available withdrawal liquidity.
Dual Pricing
Vault share conversion compares the current ERC-4626 spot value, derived from strategy-reported assets, with the confirmed Controller mark-to-market values. "Spot" does not imply a fresh cross-chain read or a guaranteed executable exit quote.
| Direction | Function Path | Code Behavior |
|---|---|---|
| Assets to shares | _convertToShares(assets, rounding) |
Computes both spot shares and marked shares. If rounding is Ceil, returns the larger value. Otherwise returns the smaller value. |
| Shares to assets | _convertToAssets(shares, rounding) |
Computes both spot assets and marked assets. If rounding is Ceil, returns the larger value. Otherwise returns the smaller value. |
Because OpenZeppelin ERC-4626 uses different rounding modes for deposit, mint, withdraw, and redeem, the effective result depends on the user action:
| User Action | ERC-4626 Preview | Effect |
|---|---|---|
deposit(assets) |
assets to shares, floor | mints the lower of spot/marked shares. |
mint(shares) |
shares to assets, ceil | requires the higher of spot/marked assets. |
withdraw(assets) |
assets to shares, ceil | burns the higher of spot/marked shares. |
redeem(shares) |
shares to assets, floor | pays the lower of spot/marked assets. |