HousePool
Inherits: ICfdVault, IHousePool, 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
ICfdEngine public immutable ENGINE
TIMELOCK_DELAY
uint256 public constant TIMELOCK_DELAY = 48 hours
State Variables
orderRouter
address public orderRouter
seniorVault
address public seniorVault
juniorVault
address public juniorVault
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
seniorRateBps
uint256 public seniorRateBps
markStalenessLimit
uint256 public markStalenessLimit = 60
isTradingActive
bool public override(ICfdVault, IHousePool) isTradingActive
seniorSeedInitialized
bool public seniorSeedInitialized
juniorSeedInitialized
bool public juniorSeedInitialized
pendingSeniorRate
uint256 public pendingSeniorRate
seniorRateActivationTime
uint256 public seniorRateActivationTime
pendingMarkStalenessLimit
uint256 public pendingMarkStalenessLimit
markStalenessLimitActivationTime
uint256 public markStalenessLimitActivationTime
Functions
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;
proposeSeniorRate
Propose a new senior yield rate, subject to 48h timelock
function proposeSeniorRate(
uint256 _rateBps
) external onlyOwner;
finalizeSeniorRate
Finalize the proposed senior rate after timelock expires.
Syncs funding first. If the mark is stale, the new rate is applied without accruing stale-window senior yield.
function finalizeSeniorRate() external onlyOwner;
cancelSeniorRateProposal
Cancel the pending senior rate proposal
function cancelSeniorRateProposal() external onlyOwner;
proposeMarkStalenessLimit
Propose a new mark-price staleness limit, subject to 48h timelock
function proposeMarkStalenessLimit(
uint256 _limit
) external onlyOwner;
finalizeMarkStalenessLimit
Finalize the proposed staleness limit after timelock expires
function finalizeMarkStalenessLimit() external onlyOwner;
cancelMarkStalenessLimitProposal
Cancel the pending staleness limit proposal
function cancelMarkStalenessLimitProposal() external onlyOwner;
pause
Pause deposits into both tranches
function pause() external onlyOwner;
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. Syncs funding first so the added depth applies only 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. Callable by CfdEngine (PnL/funding) or OrderRouter (keeper bounties).
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;
recordRecapitalizationInflow
Accounts a governance recapitalization inflow and routes it toward senior restoration when possible.
This narrows the cases that fall into generic unassigned accounting when a seeded senior tranche exists.
function recordRecapitalizationInflow(
uint256 amount
) external;
recordTradingRevenueInflow
Accounts LP-owned trading revenue and directly attaches it to seeded claimants when no live principal exists.
Used for realized trader losses / spread capture paths whose economic owner is LP equity rather than protocol fees.
function recordTradingRevenueInflow(
uint256 amount
) 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.
Syncs funding first so the new seed depth only affects funding prospectively, then mints bootstrap shares to ensure 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 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 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 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 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);
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(
ICfdEngine.HousePoolInputSnapshot memory accountingSnapshot,
ICfdEngine.HousePoolStatusSnapshot memory statusSnapshot
) internal view;
_reconcile
function _reconcile(
ICfdEngine.HousePoolInputSnapshot memory accountingSnapshot
) internal;
_getWithdrawalSnapshot
function _getWithdrawalSnapshot()
internal
view
returns (HousePoolAccountingLib.WithdrawalSnapshot memory snapshot);
_buildHousePoolContext
function _buildHousePoolContext(
ICfdEngine.HousePoolInputSnapshot memory accountingSnapshot,
ICfdEngine.HousePoolStatusSnapshot memory statusSnapshot
) internal view returns (HousePoolContext memory ctx);
_syncAndBuildHousePoolContext
function _syncAndBuildHousePoolContext() internal returns (HousePoolContext memory ctx);
_buildCurrentHousePoolContext
function _buildCurrentHousePoolContext() internal view returns (HousePoolContext memory ctx);
_previewPendingAccountingState
function _previewPendingAccountingState(
ICfdEngine.HousePoolInputSnapshot memory accountingSnapshot,
ICfdEngine.HousePoolStatusSnapshot memory statusSnapshot
) internal view returns (PendingAccountingState memory pendingState);
_markIsFreshForReconcile
function _markIsFreshForReconcile(
ICfdEngine.HousePoolInputSnapshot memory accountingSnapshot,
ICfdEngine.HousePoolStatusSnapshot memory statusSnapshot
) internal view returns (bool);
_withdrawalsLive
function _withdrawalsLive(
ICfdEngine.HousePoolInputSnapshot memory accountingSnapshot,
ICfdEngine.HousePoolStatusSnapshot memory statusSnapshot
) internal view returns (bool);
_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(
ICfdEngine.HousePoolInputSnapshot memory accountingSnapshot,
uint256 reservedUnassignedAssets,
bool isProjected
) internal view returns (HousePoolAccountingLib.WithdrawalSnapshot memory snapshot);
_checkpointSeniorYieldBeforePrincipalMutation
function _checkpointSeniorYieldBeforePrincipalMutation(
ICfdEngine.HousePoolInputSnapshot memory accountingSnapshot,
ICfdEngine.HousePoolStatusSnapshot memory statusSnapshot
) internal;
_applyPendingBucketsLive
function _applyPendingBucketsLive(
ICfdEngine.HousePoolInputSnapshot memory accountingSnapshot,
ICfdEngine.HousePoolStatusSnapshot memory statusSnapshot
) internal;
_applyPendingBucketsPreview
function _applyPendingBucketsPreview(
PendingAccountingState memory state
) internal view;
_applyRecapitalizationIntent
function _applyRecapitalizationIntent(
PendingAccountingState memory state,
uint256 amount
) internal pure;
_routeSeededRevenue
function _routeSeededRevenue(
PendingAccountingState memory state,
uint256 amount
) internal pure;
_copyPendingAccountingState
function _copyPendingAccountingState(
PendingAccountingState memory state
) internal pure returns (HousePoolPendingPreviewLib.PendingAccountingState memory copiedState);
_pendingBucketAssets
function _pendingBucketAssets() internal view returns (uint256);
_getHousePoolInputSnapshot
function _getHousePoolInputSnapshot() internal view returns (ICfdEngine.HousePoolInputSnapshot memory snapshot);
_getHousePoolStatusSnapshot
function _getHousePoolStatusSnapshot() internal view returns (ICfdEngine.HousePoolStatusSnapshot memory snapshot);
_getHousePoolSnapshots
function _getHousePoolSnapshots()
internal
view
returns (
ICfdEngine.HousePoolInputSnapshot memory accountingSnapshot,
ICfdEngine.HousePoolStatusSnapshot memory statusSnapshot
);
_requireWithdrawalsLive
function _requireWithdrawalsLive(
ICfdEngine.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);
SeniorRateProposed
event SeniorRateProposed(uint256 newRateBps, uint256 activationTime);
SeniorRateFinalized
event SeniorRateFinalized();
MarkStalenessLimitProposed
event MarkStalenessLimitProposed(uint256 newLimit, uint256 activationTime);
MarkStalenessLimitFinalized
event MarkStalenessLimitFinalized();
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);
RecapitalizationInflowAccounted
event RecapitalizationInflowAccounted(address indexed caller, uint256 amountUsdc, uint256 seniorRestorationUsdc);
TradingRevenueInflowAccounted
event TradingRevenueInflowAccounted(
address indexed caller, uint256 amountUsdc, uint256 seniorAssignedUsdc, uint256 juniorAssignedUsdc
);
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();
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__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();
Structs
VaultLiquidityView
struct VaultLiquidityView {
uint256 totalAssetsUsdc;
uint256 freeUsdc;
uint256 withdrawalReservedUsdc;
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 {
ICfdEngine.HousePoolInputSnapshot accountingSnapshot;
ICfdEngine.HousePoolStatusSnapshot statusSnapshot;
PendingAccountingState pendingState;
}