HousePool
Inherits: ICfdVault, IHousePool, IPerpsLPActions, Ownable2Step, Pausable
Title: HousePool
Tranched house pool. Senior tranche gets fixed-rate yield with last-loss protection. Junior tranche absorbs first loss but captures surplus revenue.
Note: security-contact: contact@plether.com
Constants
USDC
IERC20 public immutable USDC;
ENGINE
ICfdEngineCore public immutable ENGINE;
ENGINE_PROTOCOL_LENS
ICfdEngineProtocolLens public immutable ENGINE_PROTOCOL_LENS;
MAX_FROZEN_LP_FEE_BPS
uint256 public constant MAX_FROZEN_LP_FEE_BPS = 1000;
TIMELOCK_DELAY
uint256 public constant TIMELOCK_DELAY = 48 hours;
State Variables
orderRouter
address public orderRouter;
seniorVault
address public seniorVault;
juniorVault
address public juniorVault;
pauser
address public pauser;
seniorPrincipal
uint256 public seniorPrincipal;
juniorPrincipal
uint256 public juniorPrincipal;
unpaidSeniorYield
uint256 public unpaidSeniorYield;
seniorHighWaterMark
uint256 public seniorHighWaterMark;
accountedAssets
uint256 public accountedAssets;
unassignedAssets
uint256 public unassignedAssets;
pendingRecapitalizationUsdc
uint256 public pendingRecapitalizationUsdc;
pendingTradingRevenueUsdc
uint256 public pendingTradingRevenueUsdc;
lastReconcileTime
uint256 public lastReconcileTime;
lastSeniorYieldCheckpointTime
uint256 public lastSeniorYieldCheckpointTime;
poolConfig
PoolConfig internal poolConfig;
isTradingActive
bool public override(ICfdVault, IHousePool) isTradingActive;
seniorSeedInitialized
bool public seniorSeedInitialized;
juniorSeedInitialized
bool public juniorSeedInitialized;
pendingPoolConfig
PoolConfig public pendingPoolConfig;
poolConfigActivationTime
uint256 public poolConfigActivationTime;
Functions
onlyPauserOrOwner
modifier onlyPauserOrOwner();
onlyVault
modifier onlyVault();
constructor
constructor(
address _usdc,
address _engine
) Ownable(msg.sender);
Parameters
| Name | Type | Description |
|---|---|---|
_usdc | address | USDC token address used as collateral |
_engine | address | CfdEngine that manages positions and PnL |
setOrderRouter
Set the OrderRouter address (one-time, immutable after set)
function setOrderRouter(
address _router
) external onlyOwner;
setSeniorVault
Set the senior tranche vault address (one-time, immutable after set)
function setSeniorVault(
address _vault
) external onlyOwner;
setJuniorVault
Set the junior tranche vault address (one-time, immutable after set)
function setJuniorVault(
address _vault
) external onlyOwner;
proposePoolConfig
Propose a new pool config, subject to a 48h timelock.
function proposePoolConfig(
PoolConfig calldata newConfig
) external onlyOwner;
finalizePoolConfig
Finalizes the proposed pool config after the timelock expires.
Senior-rate changes require a fresh mark so yield accrual cannot be rerated across a stale interval.
function finalizePoolConfig() external onlyOwner;
cancelPoolConfigProposal
Cancel the pending pool config proposal.
function cancelPoolConfigProposal() external onlyOwner;
setPauser
Updates the dedicated emergency pauser.
The owner retains unpause authority and may still pause directly.
function setPauser(
address newPauser
) external onlyOwner;
pause
Pause deposits into both tranches
function pause() external onlyPauserOrOwner;
unpause
Unpause deposits into both tranches
function unpause() external onlyOwner;
totalAssets
Canonical economic USDC backing recognized by the pool. Unsolicited positive transfers are ignored until explicitly accounted, while raw-balance shortfalls still reduce the effective backing.
function totalAssets() public view returns (uint256);
isSeedLifecycleComplete
function isSeedLifecycleComplete() public view returns (bool);
hasSeedLifecycleStarted
function hasSeedLifecycleStarted() public view override(ICfdVault, IHousePool) returns (bool);
canAcceptOrdinaryDeposits
function canAcceptOrdinaryDeposits() public view override(ICfdVault, IHousePool) returns (bool);
canAcceptTrancheDeposits
function canAcceptTrancheDeposits(
bool isSenior
) public view override returns (bool);
canIncreaseRisk
function canIncreaseRisk() public view override(ICfdVault, IHousePool) returns (bool);
activateTrading
function activateTrading() external onlyOwner;
rawAssets
Raw USDC balance currently held by the pool, including unsolicited transfers.
function rawAssets() public view returns (uint256);
excessAssets
Raw USDC held above canonical accounted assets.
function excessAssets() public view returns (uint256);
accountExcess
Explicitly converts unsolicited USDC into accounted protocol assets.
This admits previously quarantined excess into canonical pool accounting going forward.
function accountExcess() external onlyOwner;
sweepExcess
Sweeps unsolicited USDC that has not been accounted into protocol economics.
function sweepExcess(
address recipient,
uint256 amount
) external onlyOwner;
payOut
Transfers USDC from the pool for protocol-authorized settlement or keeper payments.
function payOut(
address recipient,
uint256 amount
) external;
Parameters
| Name | Type | Description |
|---|---|---|
recipient | address | Address to receive USDC |
amount | uint256 | USDC amount to transfer (6 decimals) |
recordProtocolInflow
Accounts a legitimate protocol-owned inflow into canonical vault assets.
Only the engine or order router may use this path. Unlike accountExcess(), this does
not require raw excess to exist: it is the explicit accounting hook for endogenous
protocol gains and may also be used to restore canonical accounting after a raw-balance
shortfall has already reduced effective assets through totalAssets() = min(raw, accounted).
function recordProtocolInflow(
uint256 amount
) external;
recordClaimantInflow
Records claimant-owned value into the tranche claimant path.
Revenue and recapitalization remain distinct economic buckets, but share one API.
function recordClaimantInflow(
uint256 amount,
ICfdVault.ClaimantInflowKind kind,
ICfdVault.ClaimantInflowCashMode cashMode
) external;
assignUnassignedAssets
Explicitly bootstraps quarantined LP assets into a tranche by minting matching shares.
Prevents later LPs from implicitly capturing value that arrived while no claimant shares existed.
function assignUnassignedAssets(
bool toSenior,
address receiver
) external onlyOwner;
initializeSeedPosition
Seeds a tranche with a permanent minimum share supply backed by real USDC.
Mints bootstrap shares so a tranche never becomes ownerless in steady state.
function initializeSeedPosition(
bool toSenior,
uint256 amount,
address receiver
) external onlyOwner;
depositSenior
Deposit USDC into the senior tranche. Reverts if senior is impaired (below high-water mark).
function depositSenior(
uint256 amount
) external override(IHousePool, IPerpsLPActions) onlyVault whenNotPaused;
Parameters
| Name | Type | Description |
|---|---|---|
amount | uint256 | USDC to deposit (6 decimals) |
withdrawSenior
Withdraw USDC from the senior tranche. Scales high-water mark and unpaid yield proportionally.
function withdrawSenior(
uint256 amount,
address receiver
) external override(IHousePool, IPerpsLPActions) onlyVault;
Parameters
| Name | Type | Description |
|---|---|---|
amount | uint256 | USDC to withdraw (6 decimals) |
receiver | address | Address to receive USDC |
depositJunior
Deposit USDC into the junior tranche.
function depositJunior(
uint256 amount
) external override(IHousePool, IPerpsLPActions) onlyVault whenNotPaused;
Parameters
| Name | Type | Description |
|---|---|---|
amount | uint256 | USDC to deposit (6 decimals) |
withdrawJunior
Withdraw USDC from the junior tranche. Limited to free USDC above senior’s claim.
function withdrawJunior(
uint256 amount,
address receiver
) external override(IHousePool, IPerpsLPActions) onlyVault;
Parameters
| Name | Type | Description |
|---|---|---|
amount | uint256 | USDC to withdraw (6 decimals) |
receiver | address | Address to receive USDC |
getFreeUSDC
Returns USDC not reserved for worst-case position payouts (max of bull/bear liability)
function getFreeUSDC() public view returns (uint256);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | Free USDC available for withdrawals (6 decimals) |
getMaxSeniorWithdraw
Max USDC the senior tranche can withdraw (limited by free USDC)
function getMaxSeniorWithdraw() public view returns (uint256);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | Withdrawable senior USDC, capped at seniorPrincipal (6 decimals) |
getMaxJuniorWithdraw
Max USDC the junior tranche can withdraw (subordinated behind senior)
function getMaxJuniorWithdraw() public view returns (uint256);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | Withdrawable junior USDC, capped at juniorPrincipal (6 decimals) |
getPendingTrancheState
Returns tranche principals and withdrawal caps as if reconcile ran right now.
Read-only preview for ERC4626 consumers that need same-tx parity with reconcile-first vault flows.
function getPendingTrancheState()
external
view
returns (
uint256 seniorPrincipalUsdc,
uint256 juniorPrincipalUsdc,
uint256 maxSeniorWithdrawUsdc,
uint256 maxJuniorWithdrawUsdc
);
isWithdrawalLive
function isWithdrawalLive() external view returns (bool);
seniorRateBps
function seniorRateBps() public view returns (uint256);
markStalenessLimit
function markStalenessLimit() public view returns (uint256);
seniorFrozenLpFeeBps
function seniorFrozenLpFeeBps() public view returns (uint256);
juniorFrozenLpFeeBps
function juniorFrozenLpFeeBps() public view returns (uint256);
isOracleFrozen
function isOracleFrozen() public view override returns (bool);
frozenLpFeeBps
function frozenLpFeeBps(
bool isSenior
) public view override returns (uint256);
getVaultLiquidityView
Snapshot of pool liquidity, tranche principals, and oracle health for frontend consumption
function getVaultLiquidityView() external view returns (VaultLiquidityView memory viewData);
Returns
| Name | Type | Description |
|---|---|---|
viewData | VaultLiquidityView | Struct containing balances, reserves, and status flags |
reconcile
Distributes revenue (senior yield first, junior gets surplus) or absorbs losses (junior first-loss, senior last-loss). Called before any deposit/withdrawal.
function reconcile() external onlyVault;
_requireFreshMark
function _requireFreshMark(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
) internal view;
_requireRateChangeMarkFresh
function _requireRateChangeMarkFresh(
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
) internal view;
_requireBootstrapOracleLive
function _requireBootstrapOracleLive(
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
) internal pure;
_reconcile
function _reconcile(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot
) internal;
_getWithdrawalSnapshot
function _getWithdrawalSnapshot()
internal
view
returns (HousePoolAccountingLib.WithdrawalSnapshot memory snapshot);
_buildHousePoolContext
function _buildHousePoolContext(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
) internal view returns (HousePoolContext memory ctx);
_buildCurrentHousePoolContext
function _buildCurrentHousePoolContext() internal view returns (HousePoolContext memory ctx);
_previewPendingAccountingState
function _previewPendingAccountingState(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
) internal view returns (PendingAccountingState memory pendingState);
_markIsFreshForReconcile
function _markIsFreshForReconcile(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
) internal view returns (bool);
_withdrawalsLive
function _withdrawalsLive(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
) internal view returns (bool);
_validatePoolConfig
function _validatePoolConfig(
PoolConfig memory config
) internal pure;
_checkpointSeniorYieldBeforeRateChange
function _checkpointSeniorYieldBeforeRateChange() internal;
_normalizeUnassignedAssets
function _normalizeUnassignedAssets(
uint256 distributableUsdc
) internal view returns (uint256 normalized);
_juniorShareSupply
function _juniorShareSupply() internal view returns (uint256);
_seniorShareSupply
function _seniorShareSupply() internal view returns (uint256);
_requireNoPendingBootstrap
function _requireNoPendingBootstrap() internal view;
_buildWithdrawalSnapshot
function _buildWithdrawalSnapshot(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
uint256 reservedUnassignedAssets,
bool isProjected
) internal view returns (HousePoolAccountingLib.WithdrawalSnapshot memory snapshot);
_checkpointSeniorYieldBeforePrincipalMutation
function _checkpointSeniorYieldBeforePrincipalMutation(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
) internal;
_applyPendingClaimantBucketsLive
function _applyPendingClaimantBucketsLive(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
) internal;
_applyPendingClaimantBucketsPreview
function _applyPendingClaimantBucketsPreview(
PendingAccountingState memory state
) internal view;
_getPendingClaimantBuckets
function _getPendingClaimantBuckets()
internal
view
returns (HousePoolPendingPreviewLib.ClaimantPendingBuckets memory buckets);
_clearPendingClaimantBuckets
function _clearPendingClaimantBuckets() internal;
_recordPendingClaimantInflow
function _recordPendingClaimantInflow(
ICfdVault.ClaimantInflowKind kind,
uint256 amount
) internal;
_copyPendingAccountingState
function _copyPendingAccountingState(
PendingAccountingState memory state
) internal pure returns (HousePoolPendingPreviewLib.PendingAccountingState memory copiedState);
_pendingClaimantBucketAssets
function _pendingClaimantBucketAssets() internal view returns (uint256);
_getHousePoolInputSnapshot
function _getHousePoolInputSnapshot()
internal
view
returns (HousePoolEngineViewTypes.HousePoolInputSnapshot memory snapshot);
_getHousePoolStatusSnapshot
function _getHousePoolStatusSnapshot()
internal
view
returns (HousePoolEngineViewTypes.HousePoolStatusSnapshot memory snapshot);
_getHousePoolSnapshots
function _getHousePoolSnapshots()
internal
view
returns (
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
);
_requireWithdrawalsLive
function _requireWithdrawalsLive(
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
) internal pure;
_distributeRevenue
function _distributeRevenue(
uint256 revenue
) internal;
_absorbLoss
function _absorbLoss(
uint256 loss
) internal;
_getWaterfallState
function _getWaterfallState() internal view returns (HousePoolWaterfallAccountingLib.WaterfallState memory state);
_setWaterfallState
function _setWaterfallState(
HousePoolWaterfallAccountingLib.WaterfallState memory state
) internal;
Events
Reconciled
event Reconciled(uint256 seniorPrincipal, uint256 juniorPrincipal, int256 delta);
SeniorRateUpdated
event SeniorRateUpdated(uint256 newRateBps);
MarkStalenessLimitUpdated
event MarkStalenessLimitUpdated(uint256 newLimit);
PoolConfigProposed
event PoolConfigProposed(
uint256 seniorRateBps,
uint256 markStalenessLimit,
uint256 seniorFrozenLpFeeBps,
uint256 juniorFrozenLpFeeBps,
uint256 activationTime
);
PoolConfigFinalized
event PoolConfigFinalized();
FrozenLpFeesUpdated
event FrozenLpFeesUpdated(uint256 seniorFeeBps, uint256 juniorFeeBps);
ExcessAccounted
event ExcessAccounted(uint256 amountUsdc, uint256 accountedAssetsUsdc);
ExcessSwept
event ExcessSwept(address indexed recipient, uint256 amountUsdc);
ProtocolInflowAccounted
event ProtocolInflowAccounted(address indexed caller, uint256 amountUsdc, uint256 accountedAssetsUsdc);
ClaimantInflowAccounted
event ClaimantInflowAccounted(
address indexed caller,
ICfdVault.ClaimantInflowKind kind,
ICfdVault.ClaimantInflowCashMode cashMode,
uint256 amountUsdc
);
UnassignedAssetsAssigned
event UnassignedAssetsAssigned(
bool indexed toSenior, address indexed receiver, uint256 amountUsdc, uint256 sharesMinted
);
SeedPositionInitialized
event SeedPositionInitialized(
bool indexed toSenior, address indexed receiver, uint256 amountUsdc, uint256 sharesMinted
);
TradingActivated
event TradingActivated();
PauserUpdated
event PauserUpdated(address indexed previousPauser, address indexed newPauser);
Errors
HousePool__NotAVault
error HousePool__NotAVault();
HousePool__RouterAlreadySet
error HousePool__RouterAlreadySet();
HousePool__SeniorVaultAlreadySet
error HousePool__SeniorVaultAlreadySet();
HousePool__JuniorVaultAlreadySet
error HousePool__JuniorVaultAlreadySet();
HousePool__Unauthorized
error HousePool__Unauthorized();
HousePool__ExceedsMaxSeniorWithdraw
error HousePool__ExceedsMaxSeniorWithdraw();
HousePool__ExceedsMaxJuniorWithdraw
error HousePool__ExceedsMaxJuniorWithdraw();
HousePool__MarkPriceStale
error HousePool__MarkPriceStale();
HousePool__TimelockNotReady
error HousePool__TimelockNotReady();
HousePool__NoProposal
error HousePool__NoProposal();
HousePool__SeniorImpaired
error HousePool__SeniorImpaired();
HousePool__DegradedMode
error HousePool__DegradedMode();
HousePool__ZeroAddress
error HousePool__ZeroAddress();
HousePool__ZeroStaleness
error HousePool__ZeroStaleness();
HousePool__InvalidSeniorRate
error HousePool__InvalidSeniorRate();
HousePool__InvalidFrozenLpFee
error HousePool__InvalidFrozenLpFee();
HousePool__NoExcessAssets
error HousePool__NoExcessAssets();
HousePool__ExcessAmountTooHigh
error HousePool__ExcessAmountTooHigh();
HousePool__PendingBootstrap
error HousePool__PendingBootstrap();
HousePool__NoUnassignedAssets
error HousePool__NoUnassignedAssets();
HousePool__BootstrapSharesZero
error HousePool__BootstrapSharesZero();
HousePool__SeedAlreadyInitialized
error HousePool__SeedAlreadyInitialized();
HousePool__TradingActivationNotReady
error HousePool__TradingActivationNotReady();
HousePool__UnauthorizedPauser
error HousePool__UnauthorizedPauser();
HousePool__OracleFrozen
error HousePool__OracleFrozen();
Structs
VaultLiquidityView
struct VaultLiquidityView {
uint256 totalAssetsUsdc;
uint256 freeUsdc;
uint256 withdrawalReservedUsdc;
uint256 pendingRecapitalizationUsdc;
uint256 pendingTradingRevenueUsdc;
uint256 seniorPrincipalUsdc;
uint256 juniorPrincipalUsdc;
uint256 unpaidSeniorYieldUsdc;
uint256 seniorHighWaterMarkUsdc;
bool markFresh;
bool oracleFrozen;
bool degradedMode;
}
PendingAccountingState
struct PendingAccountingState {
HousePoolWaterfallAccountingLib.WaterfallState waterfall;
uint256 unassignedAssets;
uint256 seniorSupply;
uint256 juniorSupply;
}
HousePoolContext
struct HousePoolContext {
HousePoolEngineViewTypes.HousePoolInputSnapshot accountingSnapshot;
HousePoolEngineViewTypes.HousePoolStatusSnapshot statusSnapshot;
PendingAccountingState pendingState;
}
PoolConfig
struct PoolConfig {
uint256 seniorRateBps;
uint256 markStalenessLimit;
uint256 seniorFrozenLpFeeBps;
uint256 juniorFrozenLpFeeBps;
}