Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

HousePool

Git Source

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

NameTypeDescription
_usdcaddressUSDC token address used as collateral
_engineaddressCfdEngine 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

NameTypeDescription
recipientaddressAddress to receive USDC
amountuint256USDC 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

NameTypeDescription
amountuint256USDC 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

NameTypeDescription
amountuint256USDC to withdraw (6 decimals)
receiveraddressAddress to receive USDC

depositJunior

Deposit USDC into the junior tranche.

function depositJunior(
    uint256 amount
) external override(IHousePool, IPerpsLPActions) onlyVault whenNotPaused;

Parameters

NameTypeDescription
amountuint256USDC 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

NameTypeDescription
amountuint256USDC to withdraw (6 decimals)
receiveraddressAddress 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

NameTypeDescription
<none>uint256Free 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

NameTypeDescription
<none>uint256Withdrawable 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

NameTypeDescription
<none>uint256Withdrawable 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

NameTypeDescription
viewDataVaultLiquidityViewStruct 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;
}