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

Plether Protocol

CI Coverage License: AGPL v3 Solidity

Plether is a DeFi protocol for synthetic dollar-denominated tokens with inverse and direct exposure to the US Dollar Index (USDX). Users deposit USDC to mint paired tokens that track USD strength, enabling speculation and hedging on dollar movements.

How It Works

The protocol creates two synthetic tokens from USDC collateral:

  • plDXY-BEAR - Appreciates when USD weakens (USDX falls)
  • plDXY-BULL - Appreciates when USD strengthens (USDX rises)

These tokens are always minted and burned in pairs, maintaining a zero-sum relationship. When you deposit 100 USDC, you receive equal amounts of both tokens. The combined value of a BEAR + BULL pair always equals the original USDC deposit.

How It Works

Architecture

Core Contracts

ContractDescription
SyntheticSplitterCentral protocol contract. Accepts USDC, mints/burns token pairs. Permissionless deployToAdapter() pushes idle USDC to yield. EIP-2612 permit support on mint.
SyntheticTokenERC20 + ERC20FlashMint implementation for plDXY-BEAR and plDXY-BULL

Staking Layer

ContractDescription
StakedTokenERC-4626 vault wrapper (splDXY-BEAR, splDXY-BULL) with streaming rewards to prevent reward sniping
RewardDistributorDistributes USDC yield to StakedToken vaults, favoring the underperforming token

Oracle Layer

ContractDescription
BasketOracleComputes plDXY as weighted basket of 6 price feeds, with bound validation against Curve EMA price
PythAdapterAdapts Pyth Network feeds to Chainlink’s AggregatorV3Interface (used for SEK/USD)
MorphoOracleAdapts BasketOracle to Morpho Blue’s oracle scale (24 decimals for USDC/plDXY)
StakedOracleWraps underlying oracle to price ERC-4626 staked token shares

BasketOracle Design

The BasketOracle computes a USDX-like index using normalized arithmetic weighting rather than the geometric weighting of the official ICE USDX index:

Price = Σ(Weight_i × Price_i / BasePrice_i)

Each currency’s contribution is normalized by its base price, ensuring the intended USDX weights are preserved regardless of absolute FX rate scales. Without normalization, low-priced currencies like JPY (~$0.007) would be nearly ignored compared to EUR (~$1.08), causing severe weight distortion.

This design enables gas-efficient on-chain computation and eliminates rebalancing requirements, which guarantees protocol solvency.

Inverse Relationship: Because the oracle measures the USD value of a foreign currency basket, it moves inversely to the real USDX index. When the dollar strengthens, USDX rises but our basket value falls (foreign currencies are worth less in USD terms). This is why plDXY-BEAR appreciates when the basket value rises (dollar weakens).

Fixed Base Prices and Weights (immutable, set at deployment based on January 1, 2026 prices):

CurrencyWeightBase Price (USD)
EUR57.6%1.1750
JPY13.6%0.00638
GBP11.9%1.3448
CAD9.1%0.7288
SEK4.2%0.1086
CHF3.6%1.2610

Both weights and base prices are permanently fixed and cannot be changed after deployment.

Routing Layer

ContractDescription
ZapRouterSingle-sided plDXY-BULL minting and burning using flash mints. Permit support.
LeverageRouterLeveraged plDXY-BEAR positions via Morpho Blue flash loans. Open/close/add/remove collateral. Permit support.
BullLeverageRouterLeveraged plDXY-BULL positions via Morpho + plDXY-BEAR flash mints. Open/close/add/remove collateral. Permit support.

Yield Adapters (ERC-4626)

ContractDescription
VaultAdapterERC-4626 wrapper for Morpho Vault vault yield. Owner can claimRewards() from external distributors (Merkl, URD).

InvarCoin (INVAR)

ContractDescription
InvarCoinGlobal purchasing power vault backed 50/50 by USDC + plDXY-BEAR via Curve LP

InvarCoin is a passive savings token that maintains exposure to a basket of global currencies. Users deposit USDC, which the vault pairs with plDXY-BEAR through Curve to create a balanced position that hedges against USD weakness.

Deposit flow: USDC in → mint INVAR shares (priced against optimistic NAV to prevent dilution).

Deposit Flow

Withdraw flow: Burn INVAR → receive USDC from local buffer + JIT Curve LP unwinding. An EMA-based slippage floor prevents MEV sandwich amplification on the Curve leg.

Withdraw Flow

LP deposit: Advanced path for depositing USDC + BEAR directly into Curve LP.

LP Deposit Flow

LP withdraw: Balanced exit returning pro-rata USDC + BEAR. lpWithdraw intentionally works when paused, serving as the emergency exit.

LP Withdraw Flow

Yield: Curve LP trading fees accrue as virtual price growth. Keepers call harvest() to mint INVAR proportional to the fee yield and donate it to sINVAR (StakedToken) stakers via a 1-hour streaming window. Only fee yield is captured — price appreciation of the underlying assets is excluded via VP-based cost tracking.

Operational setup sequence:

  • Deploy InvarCoin and StakedToken, then call proposeStakedInvarCoin(sINVAR)
  • Wait STAKED_INVAR_TIMELOCK (7 days), then call finalizeStakedInvarCoin() before relying on harvest/donation flows
  • Propose the reward sink with proposeGaugeRewardsReceiver(receiver)
  • Wait GAUGE_REWARDS_TIMELOCK (7 days), then call finalizeGaugeRewardsReceiver()
  • Mark CRV and any other gauge incentives with protectRewardToken(token) so they cannot be swept with rescueToken()
  • After claiming rewards, route protected balances only through sweepGaugeRewards(token)

Keeper operations:

  • deployToCurve() — pushes excess USDC buffer (>2% target) into single-sided Curve LP
  • replenishBuffer() — burns Curve LP to restore the 2% USDC buffer
  • harvest() — captures LP fee yield and streams to sINVAR stakers

Safety:

  • Dual LP pricing: pessimistic (min of EMA, oracle) for withdrawals, optimistic (max) for deposits
  • Spot-vs-EMA deviation guard (0.5%) blocks deposits/deployments during pool manipulation
  • Virtual shares (1e18/1e6) prevent first-depositor inflation attacks
  • totalAssets() is a best-effort NAV view for UX/monitoring; use totalAssetsValidated() for strict oracle-validated accounting reads
  • _harvestSafe() gracefully skips when Curve VP reads fail; if yield is pending, strict oracle validation is still enforced
  • setEmergencyMode() pauses deposits and single-sided withdrawals without discarding LP accounting; emergencyWithdrawFromCurve() only zeroes LP tracking after assets are actually recovered
  • stakedInvarCoin and gaugeRewardsReceiver both use 7-day timelocked propose/finalize flows
  • Protected reward tokens cannot be rescued arbitrarily and must be swept to the configured reward receiver
  • L2 sequencer uptime validation is enforced on state-changing oracle-critical flows (deposit/lpDeposit/harvest/deploy/replenish)

Ecosystem Integrations

Token Flow

Token Flow

  • Chainlink - Price feeds for EUR/USD, JPY/USD, GBP/USD, CAD/USD, CHF/USD
  • Pyth Network - Price feed for SEK/USD (via PythAdapter)
  • Curve Finance - AMM pools for USDC/plDXY-BEAR swaps
  • Morpho Vault - Yield generation on idle USDC reserves via VaultAdapter

Bear Leverage

Bear Leverage

Flash loan USDC from Morpho → swap to plDXY-BEAR on Curve → stake → deposit splDXY-BEAR as Morpho collateral.

Bull Leverage

Bull Leverage

Flash loan USDC from Morpho → mint BEAR+BULL pairs → sell BEAR on Curve → stake BULL → deposit splDXY-BULL as Morpho collateral.

Both routers use fee-free Morpho flash loans and a fixed debt model: debt = principal × (leverage - 1).

Staking & Rewards

Staking & Rewards

  • StakedToken - ERC-4626 vaults (splDXY-BEAR, splDXY-BULL) that receive streaming USDC rewards
  • RewardDistributor - Permissionless distributeRewards() allocates yield from SyntheticSplitter, favoring the underperforming token’s stakers to incentivize price convergence

Protocol Mechanics

Liquidity Management

The SyntheticSplitter maintains a 10% local buffer of USDC for redemptions. Anyone can call deployToAdapter() to push excess USDC to yield adapters, targeting 90% deployment. This generates yield while ensuring liquidity for normal operations.

If adapter liquidity is constrained (e.g., high Morpho utilization), the owner can pause the protocol and use withdrawFromAdapter() for gradual extraction as liquidity becomes available.

Leverage

Users can open leveraged positions through the routers:

  1. LeverageRouter (Bear): Morpho flash loan USDC → Swap to plDXY-BEAR → Stake → Deposit to Morpho as collateral → Borrow USDC to repay flash loan
  2. BullLeverageRouter (Bull): Morpho flash loan USDC → Mint pairs → Sell plDXY-BEAR → Stake plDXY-BULL → Deposit to Morpho → Borrow to repay

Both routers use a fixed debt model: debt = principal × (leverage - 1). For 2x leverage with $100 principal, Morpho debt is always $100.

Morpho Blue provides fee-free flash loans, making leveraged positions more capital-efficient.

After opening, users can adjust positions with addCollateral() and removeCollateral() without closing.

Both routers include MEV protection via user-defined slippage caps (max 1%). All USDC entry points support EIP-2612 permits for gasless approvals.

Reward Distribution

The RewardDistributor receives yield from SyntheticSplitter and allocates it to StakedToken vaults based on the price discrepancy between the oracle and Curve EMA:

  • ≥2% discrepancy: 100% to underperforming token stakers
  • <2% discrepancy: Quadratic interpolation from 50/50 toward 100/0
  • 0% discrepancy: 50/50 split

This mechanism incentivizes arbitrageurs to correct price deviations by rewarding stakers of the underpriced token. A 0.1% caller reward incentivizes permissionless distribution.

Lifecycle States

The protocol operates in three states:

  1. ACTIVE - Normal operations (mint, burn, swap). If Chainlink and Curve EMA prices diverge >2%, BasketOracle reverts, blocking minting, leverage, and reward distribution until prices converge. Burns and swaps remain available—the 10% liquid buffer ensures users can always exit.
  2. PAUSED - Emergency pause (minting and reward distribution blocked, burning allowed so users can exit, gradual adapter withdrawal enabled)
  3. SETTLED - End-of-life when plDXY hits CAP price (only redemptions allowed)

Development

Prerequisites

Build

forge build

Test

forge test              # Run all tests
forge test -vvv         # Verbose output
forge coverage          # Generate coverage report

Fork Tests

Fork tests run against mainnet state using real Chainlink oracles, Curve pools, and Morpho Blue. They require an RPC URL:

# Set RPC URL (or add to .env file)
export MAINNET_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY

# Run all fork tests
forge test --match-path "test/fork/*.sol" --fork-url $MAINNET_RPC_URL -vvv

# Or source from .env
source .env && forge test --match-path "test/fork/*.sol" --fork-url $MAINNET_RPC_URL -vvv

Fork test files:

FileDescription
BaseForkTest.solShared base contract, constants, and test helpers
ZapRouterFork.t.solZapRouter integration with real Curve swaps
FullCycleFork.t.solComplete mint → yield → burn lifecycle
LeverageRouterFork.t.solBear and Bull leverage via real Morpho
SlippageProtectionFork.t.solMEV protection and slippage scenarios
LiquidationFork.t.solInterest accrual and liquidation mechanics
BasketOracleFork.t.solFull 6-feed plDXY basket oracle validation
RewardDistributorFork.t.solReward distribution with real oracle prices
YieldIntegrationFork.t.solE2E yield pipeline: Morpho vault → harvest → distribute → staker share price
PermitFork.t.solEIP-2612 permit-based deposits
SlippageReport.t.solSlippage analysis across trade sizes

Run a specific fork test file:

source .env && forge test --match-path test/fork/LeverageRouterFork.t.sol --fork-url $MAINNET_RPC_URL -vvv

Testnet Deployment

Sepolia

Deploy to Sepolia testnet with a custom Morpho Blue instance (the public Morpho on Sepolia has no enabled IRMs/LLTVs):

# Required environment variables in .env:
# TEST_PRIVATE_KEY=0x...  (your deployer private key)
# SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/YOUR_KEY

# Deploy (43 transactions - may take a few minutes)
source .env && forge script script/DeployToSepolia.s.sol --tc DeployToSepolia \
  --rpc-url $SEPOLIA_RPC_URL \
  --broadcast

# Verify contracts on Etherscan (optional)
# ETHERSCAN_API_KEY=... in .env
source .env && forge verify-contract <ADDRESS> <CONTRACT> \
  --chain sepolia --etherscan-api-key $ETHERSCAN_API_KEY

The Sepolia deployment script:

  • Deploys its own Morpho Blue instance with a ZeroRateIrm (0% interest for testnet)
  • Creates all protocol contracts, oracles, and routers
  • Seeds Curve pool and Morpho markets with liquidity
  • Mints 100k MockUSDC to the deployer

Anvil (Local)

For frontend development and testing without spending real ETH:

# 1. Start local Anvil node forking Ethereum mainnet
anvil --fork-url $MAINNET_RPC_URL --chain-id 31337

# 2. Deploy all contracts with real Chainlink/Pyth oracles (mints 100k USDC to deployer)
TEST_PRIVATE_KEY=0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d \
forge script script/DeployToAnvilFork.s.sol --tc DeployToAnvilFork \
  --rpc-url http://127.0.0.1:8545 \
  --broadcast

# 3. (Optional) Simulate yield accrual (1% of adapter assets)
cast send <MOCK_YIELD_ADAPTER> "generateYield()" \
  --rpc-url http://127.0.0.1:8545 \
  --private-key 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d

# 4. (Optional) Seed Morpho markets for leverage testing
#    Morpho seeding is built into DeployToTest.s.sol for testnet deploys.
#    For Anvil fork, create markets manually using cast commands.

The Anvil fork deployment uses real mainnet oracles (Chainlink for EUR/JPY/GBP/CAD/CHF, Pyth for SEK) with prices frozen at the fork block. MockUSDC and MockYieldAdapter are still used for flexible testing.

Anvil Test Accounts (pre-funded with 10,000 ETH each):

AccountAddressPrivate Key
#00xf39Fd6e51aad88F6F4ce6aB8827279cffFb922660xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
#10x70997970C51812dc3A010C7d01b50e0d17dc79C80x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d

MetaMask Setup:

  1. Import a test private key (Settings → Import Account)
  2. Add network: RPC http://127.0.0.1:8545, Chain ID 31337

Format

forge fmt               # Format code
forge fmt --check       # Check formatting

Documentation

View Reference Documentation

Generate HTML documentation locally from NatSpec comments:

forge doc               # Generate docs to ./docs
forge doc --serve       # Serve docs locally at http://localhost:3000
forge doc --build       # Build static site to ./docs/book

Security

  • All contracts use OpenZeppelin’s battle-tested implementations
  • Reentrancy protection on state-changing functions
  • 7-day timelock for critical governance changes
  • Oracle staleness checks (8–24 hour timeouts depending on context)
  • Oracle bound validation against Curve EMA to prevent price manipulation
  • Flash loan callback validation (initiator + lender checks)
  • Yield adapter uses Morpho Vault vault accounting for yield generation

For detailed security assumptions, trust model, and emergency procedures, see SECURITY.md.

License

AGPL-3.0

Disclaimer

This software is provided “as is” without warranty of any kind. Use at your own risk. This protocol has not been audited. Do not use in production without a professional security audit.

Contents

FlashLoanBase

Git Source

Inherits: IERC3156FlashBorrower, IMorphoFlashLoanCallback

Title: FlashLoanBase

Abstract base for flash loan borrowers with validation logic.

Supports both Morpho flash loans and ERC-3156 flash mints.

Constants

CALLBACK_SUCCESS

ERC-3156 callback success return value.

bytes32 internal constant CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan")

Functions

_validateFlashLoan

Validates ERC-3156 flash loan callback parameters.

function _validateFlashLoan(
    address lender,
    address expectedLender,
    address initiator
) internal view;

Parameters

NameTypeDescription
lenderaddressActual msg.sender.
expectedLenderaddressExpected flash lender address.
initiatoraddressInitiator passed to callback (must be this contract).

_validateLender

Validates that msg.sender is the expected lender.

function _validateLender(
    address lender,
    address expectedLender
) internal pure;

Parameters

NameTypeDescription
lenderaddressActual msg.sender.
expectedLenderaddressExpected flash lender address.

Errors

FlashLoan__InvalidLender

Thrown when flash loan callback called by wrong lender.

error FlashLoan__InvalidLender();

FlashLoan__InvalidInitiator

Thrown when flash loan initiator is not this contract.

error FlashLoan__InvalidInitiator();

FlashLoan__InvalidOperation

Thrown when callback receives unknown operation type.

error FlashLoan__InvalidOperation();

LeverageRouterBase

Git Source

Inherits: FlashLoanBase, Ownable2Step, Pausable, ReentrancyGuard

Title: LeverageRouterBase

Abstract base for leverage routers with shared validation and admin logic.

Common infrastructure for LeverageRouter (plDXY-BEAR) and BullLeverageRouter (plDXY-BULL).

Note: security-contact: contact@plether.com

Constants

MAX_SLIPPAGE_BPS

Maximum slippage in basis points (1% = 100 bps).

uint256 public constant MAX_SLIPPAGE_BPS = 100

EXCHANGE_RATE_BUFFER_BPS

Buffer for exchange rate drift protection (1% = 100 bps).

uint256 public constant EXCHANGE_RATE_BUFFER_BPS = 100

USDC_INDEX

USDC index in Curve USDC/plDXY-BEAR pool.

uint256 public constant USDC_INDEX = 0

PLDXY_BEAR_INDEX

plDXY-BEAR index in Curve USDC/plDXY-BEAR pool.

uint256 public constant PLDXY_BEAR_INDEX = 1

OP_OPEN

Operation type: open leverage position.

uint8 internal constant OP_OPEN = 1

OP_CLOSE

Operation type: close leverage position.

uint8 internal constant OP_CLOSE = 2

MORPHO

Morpho Blue lending protocol.

IMorpho public immutable MORPHO

CURVE_POOL

Curve pool for USDC/plDXY-BEAR swaps.

ICurvePool public immutable CURVE_POOL

USDC

USDC stablecoin.

IERC20 public immutable USDC

PLDXY_BEAR

plDXY-BEAR token.

IERC20 public immutable PLDXY_BEAR

State Variables

marketParams

Morpho market configuration.

MarketParams public marketParams

Functions

constructor

Initializes base router with core dependencies.

constructor(
    address _morpho,
    address _curvePool,
    address _usdc,
    address _plDxyBear
) Ownable(msg.sender);

Parameters

NameTypeDescription
_morphoaddressMorpho Blue protocol address.
_curvePooladdressCurve USDC/plDXY-BEAR pool address.
_usdcaddressUSDC token address.
_plDxyBearaddressplDXY-BEAR token address.

pause

Pause the router. Blocks openLeverage and closeLeverage.

function pause() external onlyOwner;

unpause

Unpause the router.

function unpause() external onlyOwner;

getActualDebt

Returns the user’s current debt in this market (includes accrued interest).

function getActualDebt(
    address user
) external view returns (uint256 debt);

Parameters

NameTypeDescription
useraddressThe address to query debt for.

Returns

NameTypeDescription
debtuint256The actual debt amount in USDC (rounded up).

getCollateral

Returns the user’s collateral in this market.

function getCollateral(
    address user
) external view returns (uint256 collateral);

Parameters

NameTypeDescription
useraddressThe address to query collateral for.

Returns

NameTypeDescription
collateraluint256The collateral amount in staked token shares.

_marketId

Computes market ID from marketParams.

function _marketId() internal view returns (bytes32);

_getActualDebt

Computes actual debt from Morpho position, rounded up to ensure full repayment.

function _getActualDebt(
    address user
) internal view returns (uint256);

_getBorrowShares

Returns user’s borrow shares from Morpho position.

function _getBorrowShares(
    address user
) internal view returns (uint256);

_getCollateral

Returns user’s collateral from Morpho position.

function _getCollateral(
    address user
) internal view returns (uint256);

Errors

LeverageRouterBase__ZeroAddress

Thrown when zero address provided.

error LeverageRouterBase__ZeroAddress();

LeverageRouterBase__ZeroPrincipal

Thrown when principal is zero.

error LeverageRouterBase__ZeroPrincipal();

LeverageRouterBase__ZeroCollateral

Thrown when collateral is zero.

error LeverageRouterBase__ZeroCollateral();

LeverageRouterBase__Expired

Thrown when deadline has passed.

error LeverageRouterBase__Expired();

LeverageRouterBase__LeverageTooLow

Thrown when leverage multiplier <= 1x.

error LeverageRouterBase__LeverageTooLow();

LeverageRouterBase__SlippageExceedsMax

Thrown when slippage exceeds MAX_SLIPPAGE_BPS.

error LeverageRouterBase__SlippageExceedsMax();

LeverageRouterBase__NotAuthorized

Thrown when user hasn’t authorized router in Morpho.

error LeverageRouterBase__NotAuthorized();

LeverageRouterBase__InsufficientOutput

Thrown when swap output is insufficient.

error LeverageRouterBase__InsufficientOutput();

LeverageRouterBase__InvalidCurvePrice

Thrown when Curve price query returns zero.

error LeverageRouterBase__InvalidCurvePrice();

LeverageRouterBase__SplitterNotActive

Thrown when Splitter is not active.

error LeverageRouterBase__SplitterNotActive();

LeverageRouterBase__ZeroAmount

Thrown when amount is zero.

error LeverageRouterBase__ZeroAmount();

LeverageRouterBase__NoPosition

Thrown when user has no position in Morpho.

error LeverageRouterBase__NoPosition();

LeverageRouterBase__Unhealthy

Thrown when withdrawal would make position unhealthy.

error LeverageRouterBase__Unhealthy();

LeverageRouterBase__AmountTooSmall

Thrown when amount is too small after conversion.

error LeverageRouterBase__AmountTooSmall();

LeverageRouterBase__PermitFailed

error LeverageRouterBase__PermitFailed();

LeverageRouterBase__BelowMinAmountOut

Thrown when output is below user-specified minimum (MEV protection).

error LeverageRouterBase__BelowMinAmountOut();

Contents

AggregatorV3Interface

Git Source

Title: AggregatorV3Interface

Chainlink price feed interface.

Standard interface for Chainlink oracles. See https://docs.chain.link/data-feeds.

Functions

decimals

Returns the number of decimals in the price.

function decimals() external view returns (uint8);

description

Returns a human-readable description of the feed.

function description() external view returns (string memory);

version

Returns the feed version number.

function version() external view returns (uint256);

getRoundData

Returns historical round data.

function getRoundData(
    uint80 _roundId
)
    external
    view
    returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);

Parameters

NameTypeDescription
_roundIduint80The round ID to query.

Returns

NameTypeDescription
roundIduint80The round ID.
answerint256The price answer.
startedAtuint256Timestamp when round started.
updatedAtuint256Timestamp of last update.
answeredInRounduint80The round in which answer was computed.

latestRoundData

Returns the latest round data.

function latestRoundData()
    external
    view
    returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);

Returns

NameTypeDescription
roundIduint80The current round ID.
answerint256The latest price.
startedAtuint256Timestamp when round started.
updatedAtuint256Timestamp of last update.
answeredInRounduint80The round in which answer was computed.

ICurveGauge

Git Source

Functions

lp_token

function lp_token() external view returns (address);

deposit

function deposit(
    uint256 amount
) external;

withdraw

function withdraw(
    uint256 amount
) external;

claim_rewards

function claim_rewards() external;

balanceOf

function balanceOf(
    address
) external view returns (uint256);

ICurveMinter

Git Source

Functions

mint

function mint(
    address gauge
) external;

ICurvePool

Git Source

Title: ICurvePool

Interface for Curve StableSwap pools.

Used for USDC/plDXY-BEAR swaps. Indices: USDC=0, plDXY-BEAR=1.

Functions

get_dy

Calculates expected output for a swap.

function get_dy(
    uint256 i,
    uint256 j,
    uint256 dx
) external view returns (uint256);

Parameters

NameTypeDescription
iuint256Input token index.
juint256Output token index.
dxuint256Input amount.

Returns

NameTypeDescription
<none>uint256Expected output amount.

exchange

Executes a token swap.

function exchange(
    uint256 i,
    uint256 j,
    uint256 dx,
    uint256 min_dy
) external payable returns (uint256);

Parameters

NameTypeDescription
iuint256Input token index.
juint256Output token index.
dxuint256Input amount.
min_dyuint256Minimum output (slippage protection).

Returns

NameTypeDescription
<none>uint256Actual output amount.

price_oracle

Returns EMA oracle price (18 decimals).

function price_oracle() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256Price of token1 in terms of token0.

ICurveTwocrypto

Git Source

Functions

add_liquidity

function add_liquidity(
    uint256[2] calldata amounts,
    uint256 min_mint_amount
) external returns (uint256);

remove_liquidity_one_coin

function remove_liquidity_one_coin(
    uint256 token_amount,
    uint256 i,
    uint256 min_amount
) external returns (uint256);

remove_liquidity

function remove_liquidity(
    uint256 amount,
    uint256[2] calldata min_amounts
) external returns (uint256[2] memory);

get_virtual_price

function get_virtual_price() external view returns (uint256);

lp_price

function lp_price() external view returns (uint256);

calc_token_amount

function calc_token_amount(
    uint256[2] calldata amounts,
    bool deposit
) external view returns (uint256);

calc_withdraw_one_coin

function calc_withdraw_one_coin(
    uint256 token_amount,
    uint256 i
) external view returns (uint256);

IInvarCoin

Git Source

Functions

donateUsdc

function donateUsdc(
    uint256 usdcAmount
) external;

totalAssets

function totalAssets() external view returns (uint256);

MarketParams

Git Source

Morpho Blue market configuration.

struct MarketParams {
address loanToken;
address collateralToken;
address oracle;
address irm;
uint256 lltv;
}

Properties

NameTypeDescription
loanTokenaddressAsset being borrowed.
collateralTokenaddressAsset used as collateral.
oracleaddressPrice oracle for collateral valuation.
irmaddressInterest rate model contract.
lltvuint256Liquidation loan-to-value ratio.

IMorpho

Git Source

Title: IMorpho

Minimal interface for Morpho Blue lending protocol.

See https://docs.morpho.org for full documentation.

Functions

setAuthorization

Set authorization for an address to act on behalf of the caller

function setAuthorization(
    address authorized,
    bool newIsAuthorized
) external;

isAuthorized

Check if an address is authorized to act on behalf of another

function isAuthorized(
    address authorizer,
    address authorized
) external view returns (bool);

createMarket

Create a new market

function createMarket(
    MarketParams memory marketParams
) external;

idToMarketParams

Get market ID from params

function idToMarketParams(
    bytes32 id
) external view returns (MarketParams memory);

supply

Supply loan assets to a Morpho market as a lender

function supply(
    MarketParams memory marketParams,
    uint256 assets,
    uint256 shares,
    address onBehalfOf,
    bytes calldata data
) external returns (uint256 assetsSupplied, uint256 sharesSupplied);

withdraw

Withdraw loan assets from a Morpho market as a lender

function withdraw(
    MarketParams memory marketParams,
    uint256 assets,
    uint256 shares,
    address onBehalfOf,
    address receiver
) external returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn);

supplyCollateral

Supply collateral to a Morpho market as a borrower

function supplyCollateral(
    MarketParams memory marketParams,
    uint256 assets,
    address onBehalfOf,
    bytes calldata data
) external;

withdrawCollateral

Withdraw collateral from a Morpho market as a borrower

function withdrawCollateral(
    MarketParams memory marketParams,
    uint256 assets,
    address onBehalfOf,
    address receiver
) external;

borrow

Borrow assets from a Morpho market

function borrow(
    MarketParams memory marketParams,
    uint256 assets,
    uint256 shares,
    address onBehalfOf,
    address receiver
) external returns (uint256 assetsBorrowed, uint256 sharesIssued);

repay

Repay borrowed assets to a Morpho market

function repay(
    MarketParams memory marketParams,
    uint256 assets,
    uint256 shares,
    address onBehalfOf,
    bytes calldata data
) external returns (uint256 assetsRepaid, uint256 sharesRepaid);

accrueInterest

Accrue interest for a market

function accrueInterest(
    MarketParams memory marketParams
) external;

liquidate

Liquidate an unhealthy position

function liquidate(
    MarketParams memory marketParams,
    address borrower,
    uint256 seizedAssets,
    uint256 repaidShares,
    bytes calldata data
) external returns (uint256 assetsSeized, uint256 assetsRepaid);

Parameters

NameTypeDescription
marketParamsMarketParamsThe market parameters
borroweraddressThe address of the borrower to liquidate
seizedAssetsuint256The amount of collateral to seize
repaidSharesuint256The amount of debt shares to repay (alternative to seizedAssets)
databytesCallback data

flashLoan

Execute a flash loan

Morpho flash loans are fee-free. Callback must repay exact amount.

function flashLoan(
    address token,
    uint256 assets,
    bytes calldata data
) external;

Parameters

NameTypeDescription
tokenaddressThe token to flash loan
assetsuint256The amount of tokens to flash loan
databytesArbitrary data to pass to the callback

position

Get position data for a user in a market

function position(
    bytes32 id,
    address user
) external view returns (uint256 supplyShares, uint128 borrowShares, uint128 collateral);

market

Get market data

function market(
    bytes32 id
)
    external
    view
    returns (
        uint128 totalSupplyAssets,
        uint128 totalSupplyShares,
        uint128 totalBorrowAssets,
        uint128 totalBorrowShares,
        uint128 lastUpdate,
        uint128 fee
    );

Structs

MarketState

Market state for IRM calculations.

struct MarketState {
    uint128 totalSupplyAssets;
    uint128 totalSupplyShares;
    uint128 totalBorrowAssets;
    uint128 totalBorrowShares;
    uint128 lastUpdate;
    uint128 fee;
}

IMorphoFlashLoanCallback

Git Source

Title: IMorphoFlashLoanCallback

Callback interface for Morpho flash loan receivers.

Functions

onMorphoFlashLoan

Called by Morpho during flash loan execution.

function onMorphoFlashLoan(
    uint256 assets,
    bytes calldata data
) external;

Parameters

NameTypeDescription
assetsuint256Amount of tokens borrowed.
databytesArbitrary data passed through from flashLoan call.

PythStructs

Git Source

Title: Pyth Price Structs

Structs

Price

struct Price {
    int64 price;
    uint64 conf;
    int32 expo;
    uint256 publishTime;
}

IPyth

Git Source

Title: Pyth Network Interface (minimal)

Minimal interface for reading Pyth price feeds.

Functions

getPriceUnsafe

Returns the price without staleness checks.

function getPriceUnsafe(
    bytes32 id
) external view returns (PythStructs.Price memory price);

Parameters

NameTypeDescription
idbytes32The Pyth price feed ID.

Returns

NameTypeDescription
pricePythStructs.PriceThe price data.

getPriceNoOlderThan

Returns the price if it’s no older than age seconds.

function getPriceNoOlderThan(
    bytes32 id,
    uint256 age
) external view returns (PythStructs.Price memory price);

Parameters

NameTypeDescription
idbytes32The Pyth price feed ID.
ageuint256Maximum acceptable age in seconds.

Returns

NameTypeDescription
pricePythStructs.PriceThe price data.

updatePriceFeeds

Updates price feeds with signed data from Pyth.

function updatePriceFeeds(
    bytes[] calldata updateData
) external payable;

Parameters

NameTypeDescription
updateDatabytes[]Array of price update data.

getUpdateFee

Returns the fee required to update price feeds.

function getUpdateFee(
    bytes[] calldata updateData
) external view returns (uint256 feeAmount);

Parameters

NameTypeDescription
updateDatabytes[]Array of price update data.

Returns

NameTypeDescription
feeAmountuint256The required fee in wei.

IRewardDistributor

Git Source

Title: IRewardDistributor

Interface for the RewardDistributor contract that allocates staking rewards based on price discrepancy between oracle and Curve pool.

Functions

distributeRewards

Permissionless function to distribute accumulated USDC rewards.

Calculates price discrepancy, acquires tokens, and donates to vaults.

function distributeRewards() external returns (uint256 callerReward);

Returns

NameTypeDescription
callerRewarduint256Amount of USDC sent to caller as incentive.

distributeRewardsWithPriceUpdate

Distributes rewards after updating the Pyth oracle price.

Bundles Pyth price update with reward distribution. Pass empty array if no update needed.

function distributeRewardsWithPriceUpdate(
    bytes[] calldata pythUpdateData
) external payable returns (uint256 callerReward);

Parameters

NameTypeDescription
pythUpdateDatabytes[]Price update data from Pyth Hermes API.

Returns

NameTypeDescription
callerRewarduint256Amount of USDC sent to caller as incentive.

previewDistribution

Preview the distribution without executing.

function previewDistribution()
    external
    view
    returns (uint256 bearPct, uint256 bullPct, uint256 usdcBalance, uint256 callerReward);

Returns

NameTypeDescription
bearPctuint256Expected percentage to BEAR stakers (basis points).
bullPctuint256Expected percentage to BULL stakers (basis points).
usdcBalanceuint256Current USDC balance available for distribution.
callerRewarduint256Expected caller reward.

Events

RewardsDistributed

Emitted when rewards are distributed to staking vaults.

event RewardsDistributed(
    uint256 bearAmount, uint256 bullAmount, uint256 invarUsdcAmount, uint256 bearPct, uint256 bullPct
);

Parameters

NameTypeDescription
bearAmountuint256Amount of plDXY-BEAR donated to StakedBear.
bullAmountuint256Amount of plDXY-BULL donated to StakedBull.
invarUsdcAmountuint256Amount of USDC donated to InvarCoin.
bearPctuint256Percentage of rewards allocated to BEAR stakers (basis points).
bullPctuint256Percentage of rewards allocated to BULL stakers (basis points).

Errors

RewardDistributor__DistributionTooSoon

Thrown when distribution is attempted before cooldown expires.

error RewardDistributor__DistributionTooSoon();

RewardDistributor__NoRewards

Thrown when there are no rewards to distribute.

error RewardDistributor__NoRewards();

RewardDistributor__SplitterNotActive

Thrown when the SyntheticSplitter is not in ACTIVE status.

error RewardDistributor__SplitterNotActive();

RewardDistributor__ZeroAddress

Thrown when a constructor parameter is zero address.

error RewardDistributor__ZeroAddress();

RewardDistributor__RefundFailed

Thrown when ETH refund to caller fails.

error RewardDistributor__RefundFailed();

RewardDistributor__InvalidPrice

Thrown when oracle returns zero or negative price.

error RewardDistributor__InvalidPrice();

ISyntheticSplitter

Git Source

Title: ISyntheticSplitter

Minimal interface for external contracts to interact with SyntheticSplitter.

Used by ZapRouter and other integrations.

Functions

mint

Deposits collateral to mint equal amounts of plDXY-BEAR and plDXY-BULL tokens.

Requires approval on USDC. Amount is in 18-decimal token units.

function mint(
    uint256 amount
) external;

Parameters

NameTypeDescription
amountuint256The amount of token pairs to mint.

mintWithPermit

Deposits collateral to mint tokens with a USDC permit signature (gasless approval).

function mintWithPermit(
    uint256 amount,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
) external;

Parameters

NameTypeDescription
amountuint256The amount of token pairs to mint.
deadlineuint256Unix timestamp after which the permit and transaction revert.
vuint8Signature recovery byte.
rbytes32Signature r component.
sbytes32Signature s component.

burn

Burns equal amounts of plDXY-BEAR and plDXY-BULL tokens to retrieve collateral.

Works when not liquidated. May be restricted when paused and insolvent.

function burn(
    uint256 amount
) external;

Parameters

NameTypeDescription
amountuint256The amount of token pairs to burn.

emergencyRedeem

Emergency exit after liquidation. Burns plDXY-BEAR for its full CAP value.

Only works when protocol is liquidated (price >= CAP).

function emergencyRedeem(
    uint256 amount
) external;

Parameters

NameTypeDescription
amountuint256The amount of plDXY-BEAR tokens to burn.

currentStatus

Returns the current protocol lifecycle status.

function currentStatus() external view returns (Status);

Returns

NameTypeDescription
<none>StatusThe current Status enum value.

CAP

Returns the protocol CAP price (8 decimals, oracle format).

function CAP() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256The CAP value in 8 decimal format (e.g., 2e8 = $2.00).

liquidationTimestamp

Returns the timestamp when the protocol was liquidated.

function liquidationTimestamp() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256The liquidation timestamp (0 if not liquidated).

treasury

Returns the treasury address.

function treasury() external view returns (address);

Returns

NameTypeDescription
<none>addressThe treasury address.

Enums

Status

Defines the current lifecycle state of the protocol.

enum Status {
    ACTIVE,
    PAUSED,
    SETTLED
}

Variants

NameDescription
ACTIVENormal operations. Minting and burning enabled.
PAUSEDSecurity pause. Minting disabled, burn may be restricted if insolvent.
SETTLEDEnd of life. Cap breached. Only emergencyRedeem enabled.

IYieldAdapter

Git Source

Title: IYieldAdapter

Extended interface for yield adapters that support interest accrual.

Optional extension to IERC4626 for adapters with pending interest.

Functions

accrueInterest

Forces the underlying protocol to accrue pending interest.

Call before reading totalAssets() if exact values are needed for calculations.

function accrueInterest() external;

Contents

DecimalConstants

Git Source

Title: DecimalConstants

Shared decimal scaling constants for the Plether protocol.

Centralizes decimal conversions to prevent scaling bugs.

Constants

ONE_WAD

One unit with 18 decimals (standard ERC20/leverage scale).

uint256 internal constant ONE_WAD = 1e18

ONE_USDC

One USDC (6 decimals).

uint256 internal constant ONE_USDC = 1e6

USDC_TO_TOKEN_SCALE

USDC (6 dec) + Chainlink (8 dec) -> Token (18 dec): 10^20.

uint256 internal constant USDC_TO_TOKEN_SCALE = 1e20

Chainlink (8 dec) -> Morpho (36 + loanDec - collateralDec = 24 dec): 10^16.

uint256 internal constant CHAINLINK_TO_MORPHO_SCALE = 1e16

Chainlink (8 dec) -> Token (18 dec): 10^10.

uint256 internal constant CHAINLINK_TO_TOKEN_SCALE = 1e10

IIrm

Git Source

Title: IIrm

Minimal interface for Morpho Blue Interest Rate Models.

Functions

borrowRateView

Returns the borrow rate per second (scaled by 1e18).

function borrowRateView(
    MarketParams memory marketParams,
    IMorpho.MarketState memory market
) external view returns (uint256);

MorphoBalancesLib

Git Source

Title: MorphoBalancesLib

Library to compute expected Morpho balances including pending interest.

Mirrors Morpho Blue’s internal interest accrual logic for accurate view functions.

Constants

WAD

uint256 internal constant WAD = 1e18

Functions

expectedTotalSupplyAssets

Computes expected total supply assets including pending interest.

function expectedTotalSupplyAssets(
    IMorpho morpho,
    MarketParams memory marketParams
) internal view returns (uint256 expectedSupplyAssets);

Parameters

NameTypeDescription
morphoIMorphoMorpho Blue contract.
marketParamsMarketParamsMarket parameters.

Returns

NameTypeDescription
expectedSupplyAssetsuint256Total supply assets after pending interest accrual.

expectedSupplyAssets

Converts supply shares to expected assets including pending interest.

function expectedSupplyAssets(
    IMorpho morpho,
    MarketParams memory marketParams,
    uint256 shares
) internal view returns (uint256 assets);

Parameters

NameTypeDescription
morphoIMorphoMorpho Blue contract.
marketParamsMarketParamsMarket parameters.
sharesuint256Supply shares to convert.

Returns

NameTypeDescription
assetsuint256Expected asset amount.

OracleLib

Git Source

Title: OracleLib

Library for common oracle validation patterns.

Provides reusable functions for sequencer checks, staleness validation, and price validation.

Functions

checkSequencer

Check if the L2 sequencer is up and grace period has passed.

Skips check if sequencerFeed is address(0) (e.g., on L1 or testnets).

function checkSequencer(
    AggregatorV3Interface sequencerFeed,
    uint256 gracePeriod
) internal view;

Parameters

NameTypeDescription
sequencerFeedAggregatorV3InterfaceThe Chainlink sequencer uptime feed.
gracePerioduint256The grace period in seconds after sequencer comes back up.

checkStaleness

Check if the oracle price is stale.

function checkStaleness(
    uint256 updatedAt,
    uint256 timeout
) internal view;

Parameters

NameTypeDescription
updatedAtuint256The timestamp when the price was last updated.
timeoutuint256The maximum age in seconds for a valid price.

checkStalenessAt

Check staleness relative to a specific reference timestamp instead of block.timestamp.

function checkStalenessAt(
    uint256 updatedAt,
    uint256 timeout,
    uint256 referenceTime
) internal pure;

Parameters

NameTypeDescription
updatedAtuint256The timestamp when the price was last updated.
timeoutuint256The maximum age in seconds for a valid price.
referenceTimeuint256The timestamp to measure staleness against.

verifyHistoricalPrice

Verifies a caller-provided hint round is the correct price at a target timestamp.

Avoids backward traversal that breaks on Chainlink phase boundaries.

function verifyHistoricalPrice(
    AggregatorV3Interface feed,
    uint256 targetTimestamp,
    uint80 hintRoundId
) internal view returns (int256 price, uint256 updatedAt);

Parameters

NameTypeDescription
feedAggregatorV3InterfaceThe Chainlink price feed.
targetTimestampuint256The timestamp to look up the price for.
hintRoundIduint80The round ID that the caller claims was active at targetTimestamp.

Returns

NameTypeDescription
priceint256The price at the target timestamp.
updatedAtuint256The timestamp of the round found.

getValidatedPrice

Get a validated price from an oracle with staleness and sequencer checks.

Reverts on zero or negative prices to prevent operations during oracle failures.

function getValidatedPrice(
    AggregatorV3Interface oracle,
    AggregatorV3Interface sequencerFeed,
    uint256 gracePeriod,
    uint256 timeout
) internal view returns (uint256 price);

Parameters

NameTypeDescription
oracleAggregatorV3InterfaceThe price oracle.
sequencerFeedAggregatorV3InterfaceThe sequencer uptime feed (can be address(0) to skip).
gracePerioduint256The sequencer grace period in seconds.
timeoutuint256The staleness timeout in seconds.

Returns

NameTypeDescription
priceuint256The validated price.

tryGetValidatedPrice

Non-reverting variant of getValidatedPrice for best-effort oracle reads.

function tryGetValidatedPrice(
    AggregatorV3Interface oracle,
    AggregatorV3Interface sequencerFeed,
    uint256 gracePeriod,
    uint256 timeout
) internal view returns (bool success, uint256 price);

Returns

NameTypeDescription
successboolTrue if the price passed all validation checks.
priceuint256The validated price (0 if success is false).

Errors

OracleLib__SequencerDown

error OracleLib__SequencerDown();

OracleLib__SequencerGracePeriod

error OracleLib__SequencerGracePeriod();

OracleLib__StalePrice

error OracleLib__StalePrice();

OracleLib__InvalidPrice

error OracleLib__InvalidPrice();

OracleLib__NoPriceAtExpiry

error OracleLib__NoPriceAtExpiry();

OracleLib__InsufficientGas

error OracleLib__InsufficientGas();

Contents

DOVZapRouter

Git Source

Inherits: FlashLoanBase, ReentrancyGuard, Ownable2Step

Title: DOVZapRouter

Coordinates USDC→splDXY zaps across BEAR and BULL DOVs.

Mints pairs for the overlapping USDC amount (zero slippage), routes excess through Curve or flash mint.

Note: security-contact: contact@plether.com

Constants

USDC_INDEX

uint256 public constant USDC_INDEX = 0

PLDXY_BEAR_INDEX

uint256 public constant PLDXY_BEAR_INDEX = 1

SAFETY_BUFFER_BPS

uint256 public constant SAFETY_BUFFER_BPS = 50

SPLITTER

ISyntheticSplitter public immutable SPLITTER

CURVE_POOL

ICurvePool public immutable CURVE_POOL

USDC

IERC20 public immutable USDC

PLDXY_BEAR

IERC20 public immutable PLDXY_BEAR

PLDXY_BULL

IERC20 public immutable PLDXY_BULL

STAKED_BEAR

IERC4626 public immutable STAKED_BEAR

STAKED_BULL

IERC4626 public immutable STAKED_BULL

BEAR_DOV

PletherDOV public immutable BEAR_DOV

BULL_DOV

PletherDOV public immutable BULL_DOV

CAP

uint256 public immutable CAP

CAP_PRICE

uint256 public immutable CAP_PRICE

Functions

constructor

constructor(
    address _splitter,
    address _curvePool,
    address _usdc,
    address _plDxyBear,
    address _plDxyBull,
    address _stakedBear,
    address _stakedBull,
    address _bearDov,
    address _bullDov
) Ownable(msg.sender);

coordinatedZapAndStartEpochs

Pulls USDC from both DOVs, mints matched pairs, routes excess, starts epoch auctions.

function coordinatedZapAndStartEpochs(
    EpochParams calldata bearParams,
    EpochParams calldata bullParams,
    uint256 minBearSwapOut,
    uint256 minBullSwapOut
) external onlyOwner nonReentrant;

_flashZapBull

function _flashZapBull(
    uint256 usdcAmount,
    uint256 minSwapOut
) internal;

onFlashLoan

function onFlashLoan(
    address initiator,
    address,
    uint256 amount,
    uint256 fee,
    bytes calldata data
) external override returns (bytes32);

onMorphoFlashLoan

function onMorphoFlashLoan(
    uint256,
    bytes calldata
) external pure override;

Events

CoordinatedZap

event CoordinatedZap(uint256 bearUsdc, uint256 bullUsdc, uint256 matchedAmount);

Errors

DOVZapRouter__SolvencyBreach

error DOVZapRouter__SolvencyBreach();

DOVZapRouter__BearPriceAboveCap

error DOVZapRouter__BearPriceAboveCap();

Structs

EpochParams

struct EpochParams {
    uint256 strike;
    uint256 expiry;
    uint256 maxPremium;
    uint256 minPremium;
    uint256 duration;
}

ISettlementOracle

Git Source

Functions

getSettlementPrices

function getSettlementPrices(
    uint256 expiry,
    uint80[] calldata roundHints
) external view returns (uint256 bearPrice, uint256 bullPrice);

IOptionToken

Git Source

Functions

initialize

function initialize(
    string memory name,
    string memory symbol,
    address marginEngine
) external;

mint

function mint(
    address to,
    uint256 amount
) external;

burn

function burn(
    address from,
    uint256 amount
) external;

totalSupply

function totalSupply() external view returns (uint256);

MarginEngine

Git Source

Inherits: ReentrancyGuard, AccessControl

Title: MarginEngine

Core options clearinghouse for Plether DOVs.

Enforces 100% margin requirements and Fractional In-Kind Settlement via StakedTokens.

Note: security-contact: contact@plether.com

Constants

SERIES_CREATOR_ROLE

bytes32 public constant SERIES_CREATOR_ROLE = keccak256("SERIES_CREATOR_ROLE")

SPLITTER

ISyntheticSplitter public immutable SPLITTER

ORACLE

ISettlementOracle public immutable ORACLE

STAKED_BEAR

IERC4626 public immutable STAKED_BEAR

STAKED_BULL

IERC4626 public immutable STAKED_BULL

OPTION_IMPLEMENTATION

address public immutable OPTION_IMPLEMENTATION

CAP

uint256 public immutable CAP

State Variables

nextSeriesId

uint256 public nextSeriesId = 1

series

mapping(uint256 => Series) public series

seriesCreator

mapping(uint256 => address) public seriesCreator

writerLockedShares

mapping(uint256 => mapping(address => uint256)) public writerLockedShares

writerOptions

mapping(uint256 => mapping(address => uint256)) public writerOptions

totalSeriesShares

mapping(uint256 => uint256) public totalSeriesShares

totalSeriesMinted

mapping(uint256 => uint256) public totalSeriesMinted

totalSeriesExercisedShares

mapping(uint256 => uint256) public totalSeriesExercisedShares

settlementTimestamp

mapping(uint256 => uint256) public settlementTimestamp

Functions

constructor

constructor(
    address _splitter,
    address _oracle,
    address _stakedBear,
    address _stakedBull,
    address _optionImplementation
) ;

createSeries

Admin function to deploy a new Option Token Series via EIP-1167.

function createSeries(
    bool isBull,
    uint256 strike,
    uint256 expiry,
    string memory name,
    string memory symbol
) external onlyRole(SERIES_CREATOR_ROLE) returns (uint256 seriesId);

mintOptions

Writers (DOVs) call this to lock splDXY yield-bearing shares and mint options.

Ensures exact 1:1 backing of the underlying asset capacity.

function mintOptions(
    uint256 seriesId,
    uint256 optionsAmount
) external nonReentrant;

settle

Locks the settlement price and exchange rate at expiration.

Callable by anyone. Triggers “Early Acceleration” if protocol liquidates mid-cycle.

function settle(
    uint256 seriesId,
    uint80[] calldata roundHints
) external;

Parameters

NameTypeDescription
seriesIduint256
roundHintsuint80[]Chainlink round IDs for oracle lookup (one per feed component).

adminSettle

Admin fallback for oracle failures — settles with a manually provided price.

2-day grace period after expiry gives the oracle time to recover first.

function adminSettle(
    uint256 seriesId,
    uint256 settlementPrice
) external onlyRole(DEFAULT_ADMIN_ROLE);

exercise

Buyers burn ITM Options to extract their fractional payout of the collateral pool.

Share conversion uses the settlement-time rate for economically correct payouts.

function exercise(
    uint256 seriesId,
    uint256 optionsAmount
) external nonReentrant;

unlockCollateral

Writers unlock their remaining splDXY shares post-settlement.

Uses global debt pro-rata to stay consistent with the exercise cap. globalDebtShares represents the theoretical max debt assuming 100% exercise. If some option holders don’t exercise, their unclaimed share of globalDebtShares remains locked until sweepUnclaimedShares is called after 90 days.

function unlockCollateral(
    uint256 seriesId
) external nonReentrant;

sweepUnclaimedShares

Sweeps unclaimed exercise shares 90 days after settlement.

Returns shares reserved for unexercised ITM options to the admin for distribution.

function sweepUnclaimedShares(
    uint256 seriesId
) external onlyRole(DEFAULT_ADMIN_ROLE) nonReentrant;

_getGlobalDebtShares

function _getGlobalDebtShares(
    Series storage s,
    uint256 totalMinted,
    uint256 totalShares
) private view returns (uint256 globalDebtShares);

_snapshotShareRate

function _snapshotShareRate(
    Series storage s
) private view returns (uint256);

_transferVaultShares

function _transferVaultShares(
    bool isBull,
    address to,
    uint256 amount
) private;

Events

SeriesCreated

event SeriesCreated(uint256 indexed seriesId, address optionToken, bool isBull, uint256 strike, uint256 expiry);

OptionsMinted

event OptionsMinted(uint256 indexed seriesId, address indexed writer, uint256 optionsAmount, uint256 sharesLocked);

SeriesSettled

event SeriesSettled(uint256 indexed seriesId, uint256 settlementPrice, uint256 settlementShareRate);

OptionsExercised

event OptionsExercised(
    uint256 indexed seriesId, address indexed buyer, uint256 optionsAmount, uint256 sharesReceived
);

CollateralUnlocked

event CollateralUnlocked(
    uint256 indexed seriesId, address indexed writer, uint256 optionsAmount, uint256 sharesReturned
);

UnclaimedSharesSwept

event UnclaimedSharesSwept(uint256 indexed seriesId, uint256 sharesSwept);

Errors

MarginEngine__InvalidParams

error MarginEngine__InvalidParams();

MarginEngine__Expired

error MarginEngine__Expired();

MarginEngine__NotExpired

error MarginEngine__NotExpired();

MarginEngine__AlreadySettled

error MarginEngine__AlreadySettled();

MarginEngine__NotSettled

error MarginEngine__NotSettled();

MarginEngine__OptionIsOTM

error MarginEngine__OptionIsOTM();

MarginEngine__ZeroAmount

error MarginEngine__ZeroAmount();

MarginEngine__SplitterNotActive

error MarginEngine__SplitterNotActive();

MarginEngine__AdminSettleTooEarly

error MarginEngine__AdminSettleTooEarly();

MarginEngine__SweepTooEarly

error MarginEngine__SweepTooEarly();

MarginEngine__Unauthorized

error MarginEngine__Unauthorized();

Structs

Series

struct Series {
    bool isBull;
    uint256 strike;
    uint256 expiry;
    address optionToken;
    uint256 settlementPrice;
    uint256 settlementShareRate;
    bool isSettled;
}

OptionToken

Git Source

Title: OptionToken

EIP-1167 Minimal Proxy Implementation for Option Series.

Constants

decimals

uint8 public constant decimals = 18

State Variables

name

string public name

symbol

string public symbol

totalSupply

uint256 public totalSupply

balanceOf

mapping(address => uint256) public balanceOf

allowance

mapping(address => mapping(address => uint256)) public allowance

marginEngine

address public marginEngine

_initialized

bool private _initialized

Functions

constructor

constructor() ;

onlyEngine

modifier onlyEngine() ;

initialize

Initialize the proxy (called once by MarginEngine).

function initialize(
    string memory _name,
    string memory _symbol,
    address _marginEngine
) external;

mint

function mint(
    address to,
    uint256 amount
) external onlyEngine;

burn

function burn(
    address from,
    uint256 amount
) external onlyEngine;

approve

function approve(
    address spender,
    uint256 amount
) external returns (bool);

transfer

function transfer(
    address to,
    uint256 amount
) external returns (bool);

transferFrom

function transferFrom(
    address from,
    address to,
    uint256 amount
) external returns (bool);

Events

Transfer

event Transfer(address indexed from, address indexed to, uint256 value);

Approval

event Approval(address indexed owner, address indexed spender, uint256 value);

Initialized

event Initialized(string name, string symbol, address marginEngine);

Errors

OptionToken__AlreadyInitialized

error OptionToken__AlreadyInitialized();

OptionToken__Unauthorized

error OptionToken__Unauthorized();

OptionToken__InsufficientBalance

error OptionToken__InsufficientBalance();

OptionToken__InsufficientAllowance

error OptionToken__InsufficientAllowance();

OptionToken__ZeroAddress

error OptionToken__ZeroAddress();

IMarginEngine

Git Source

Functions

createSeries

function createSeries(
    bool isBull,
    uint256 strike,
    uint256 expiry,
    string memory name,
    string memory sym
) external returns (uint256);

mintOptions

function mintOptions(
    uint256 seriesId,
    uint256 optionsAmount
) external;

settle

function settle(
    uint256 seriesId,
    uint80[] calldata roundHints
) external;

unlockCollateral

function unlockCollateral(
    uint256 seriesId
) external;

exercise

function exercise(
    uint256 seriesId,
    uint256 optionsAmount
) external;

series

function series(
    uint256 seriesId
) external view returns (bool, uint256, uint256, address, uint256, uint256, bool);

SPLITTER

function SPLITTER() external view returns (address);

Errors

MarginEngine__ZeroAmount

error MarginEngine__ZeroAmount();

PletherDOV

Git Source

Inherits: ERC20, ReentrancyGuard, Ownable2Step

Title: PletherDOV

Automated Covered Call Vault for Plether synthetic assets.

Natively holds splDXY to prevent weekly AMM slippage. Implements on-chain Dutch Auctions.

Note: security-contact: contact@plether.com

Constants

MARGIN_ENGINE

IMarginEngine public immutable MARGIN_ENGINE

STAKED_TOKEN

IERC4626 public immutable STAKED_TOKEN

USDC

IERC20 public immutable USDC

IS_BULL

bool public immutable IS_BULL

State Variables

currentState

State public currentState = State.UNLOCKED

currentEpochId

uint256 public currentEpochId = 0

zapKeeper

address public zapKeeper

epochs

mapping(uint256 => Epoch) public epochs

pendingUsdcDeposits

uint256 public pendingUsdcDeposits

userUsdcDeposits

mapping(address => uint256) public userUsdcDeposits

userDepositEpoch

mapping(address => uint256) public userDepositEpoch

epochDeposits

mapping(uint256 => EpochDeposits) public epochDeposits

_preZapSplDXYBalance

uint256 internal _preZapSplDXYBalance

_preZapDepositUsdc

uint256 internal _preZapDepositUsdc

_preZapPremiumUsdc

uint256 internal _preZapPremiumUsdc

_zapSnapshotTaken

bool internal _zapSnapshotTaken

Functions

constructor

constructor(
    string memory _name,
    string memory _symbol,
    address _marginEngine,
    address _stakedToken,
    address _usdc,
    bool _isBull
) ERC20(_name, _symbol) Ownable(msg.sender);

initializeShares

Mints initial shares to the owner for seed capital already held by the vault.

Must be called before the first epoch if the vault holds pre-seeded splDXY.

function initializeShares() external onlyOwner;

deposit

Queue USDC to be deposited into the DOV at the start of the next epoch.

Auto-claims shares from any previous epoch deposit before recording the new one.

function deposit(
    uint256 amount
) external nonReentrant;

withdrawDeposit

Withdraw queued USDC that has not yet been processed into an epoch.

function withdrawDeposit(
    uint256 amount
) external nonReentrant;

claimShares

Claims DOV shares earned from a previous epoch’s processed deposit.

function claimShares() external nonReentrant;

withdraw

Redeems vault shares for proportional splDXY (and any premium USDC).

Only callable during UNLOCKED. Auto-claims pending deposit shares first.

function withdraw(
    uint256 shares
) external nonReentrant;

setZapKeeper

function setZapKeeper(
    address _keeper
) external onlyOwner;

releaseUsdcForZap

Releases all USDC held by this DOV to the caller (zapKeeper only).

Snapshots pre-zap state for share calculation in startEpochAuction.

function releaseUsdcForZap() external returns (uint256 amount);

startEpochAuction

Step 1: Rolls the vault into a new epoch, mints options, starts Dutch Auction.

If deposits are pending, releaseUsdcForZap must have been called first to snapshot pre-zap state. Deposit shares are minted proportionally based on the zap conversion.

function startEpochAuction(
    uint256 strike,
    uint256 expiry,
    uint256 maxPremium,
    uint256 minPremium,
    uint256 duration
) external nonReentrant;

getCurrentOptionPrice

Calculates the current linearly decaying price per option.

function getCurrentOptionPrice() public view returns (uint256);

fillAuction

Step 2: Market Makers call this to buy the entire batch of options.

Premium calculation: optionsMinted (18 decimals) * currentPremium (6 decimals) / 1e18 = totalPremiumUsdc (6 decimals). Relies on OptionToken.decimals() == 18.

function fillAuction() external nonReentrant;

cancelAuction

Cancels an expired auction that received no fill, returning the vault to UNLOCKED.

Also allows immediate cancellation when the Splitter has liquidated.

function cancelAuction() external nonReentrant;

exerciseUnsoldOptions

Exercises unsold option tokens held by the DOV after a cancelled auction.

Skips exercise for OTM options so keeper batch transactions don’t revert.

function exerciseUnsoldOptions(
    uint256 epochId
) external nonReentrant;

reclaimCollateral

Reclaims collateral from an unsold series after it has been settled.

function reclaimCollateral(
    uint256 epochId
) external nonReentrant;

settleEpoch

Step 3: At expiration, settles the series and unlocks remaining collateral.

function settleEpoch(
    uint80[] calldata roundHints
) external nonReentrant;

Parameters

NameTypeDescription
roundHintsuint80[]Chainlink round IDs for oracle lookup (one per feed component). Ignored if the series is already settled.

emergencyWithdraw

Recovers stranded funds after Splitter liquidation (protocol end-of-life).

Only callable by owner when the Splitter has permanently settled.

function emergencyWithdraw(
    IERC20 token
) external onlyOwner;

pendingSharesOf

Returns the number of shares a user can claim from a processed deposit.

function pendingSharesOf(
    address user
) external view returns (uint256);

totalVaultAssets

Returns the vault’s total assets excluding pending deposits.

function totalVaultAssets() external view returns (uint256 splDXYShares, uint256 usdcBalance);

_claimShares

Claims DOV shares for a user whose deposit was processed in a previous epoch.

function _claimShares(
    address user
) internal;

_calculatePendingShares

function _calculatePendingShares(
    address user
) private view returns (uint256);

_mintDepositShares

Computes and mints aggregate shares for all depositors whose USDC was zapped. Uses the pre-zap snapshot from releaseUsdcForZap to attribute splDXY proportionally between existing shareholders (premium) and new depositors (deposit USDC).

function _mintDepositShares() internal;

Events

DepositQueued

event DepositQueued(address indexed user, uint256 amount);

DepositWithdrawn

event DepositWithdrawn(address indexed user, uint256 amount);

EpochRolled

event EpochRolled(uint256 indexed epochId, uint256 seriesId, uint256 optionsMinted);

AuctionFilled

event AuctionFilled(uint256 indexed epochId, address indexed buyer, uint256 premiumPaid);

AuctionCancelled

event AuctionCancelled(uint256 indexed epochId);

EpochSettled

event EpochSettled(uint256 indexed epochId, uint256 collateralReturned);

EmergencyWithdraw

event EmergencyWithdraw(address indexed token, uint256 amount);

ZapKeeperSet

event ZapKeeperSet(address indexed keeper);

SharesInitialized

event SharesInitialized(address indexed owner, uint256 shares);

DepositSharesMinted

event DepositSharesMinted(uint256 indexed epochId, uint256 totalShares, uint256 totalDepositsUsdc);

SharesClaimed

event SharesClaimed(address indexed user, uint256 shares);

Withdrawn

event Withdrawn(address indexed user, uint256 shares, uint256 splDXYAmount, uint256 usdcAmount);

Errors

PletherDOV__WrongState

error PletherDOV__WrongState();

PletherDOV__ZeroAmount

error PletherDOV__ZeroAmount();

PletherDOV__AuctionEnded

error PletherDOV__AuctionEnded();

PletherDOV__AuctionNotExpired

error PletherDOV__AuctionNotExpired();

PletherDOV__SplitterNotSettled

error PletherDOV__SplitterNotSettled();

PletherDOV__InvalidParams

error PletherDOV__InvalidParams();

PletherDOV__InsufficientDeposit

error PletherDOV__InsufficientDeposit();

PletherDOV__DepositProcessed

error PletherDOV__DepositProcessed();

PletherDOV__Unauthorized

error PletherDOV__Unauthorized();

PletherDOV__AlreadyInitialized

error PletherDOV__AlreadyInitialized();

PletherDOV__NotInitialized

error PletherDOV__NotInitialized();

PletherDOV__DepositsNotZapped

error PletherDOV__DepositsNotZapped();

PletherDOV__NothingToClaim

error PletherDOV__NothingToClaim();

Structs

Epoch

struct Epoch {
    uint256 seriesId;
    uint256 optionsMinted;
    uint256 auctionStartTime;
    uint256 maxPremium; // Max USDC price per option (6 decimals)
    uint256 minPremium; // Min USDC price per option (6 decimals)
    uint256 auctionDuration;
    address winningMaker;
}

EpochDeposits

struct EpochDeposits {
    uint256 totalUsdc;
    uint256 sharesMinted;
}

Enums

State

enum State {
    UNLOCKED,
    AUCTIONING,
    LOCKED
}

Contents

BasketOracle

Git Source

Inherits: AggregatorV3Interface, Ownable2Step

Title: BasketOracle

Aggregates multiple Chainlink feeds into a normalized weighted plDXY basket price.

Price = Sum(Weight_i * Price_i / BasePrice_i). Normalization preserves intended currency weights.

Note: security-contact: contact@plether.com

Constants

DECIMALS

Chainlink standard decimals for fiat/USD pairs.

uint8 public constant DECIMALS = 8

DESCRIPTION

Oracle description string.

string public constant DESCRIPTION = "plDXY Fixed Basket (Bounded)"

TIMELOCK_DELAY

Timelock delay for Curve pool updates (7 days).

uint256 public constant TIMELOCK_DELAY = 7 days

MAX_DEVIATION_BPS

Maximum allowed deviation from Curve spot (basis points).

uint256 public immutable MAX_DEVIATION_BPS

CAP

Protocol CAP price (8 decimals). Theoretical price is clamped to this before deviation check.

uint256 public immutable CAP

State Variables

components

Array of currency components (EUR, JPY, GBP, CAD, SEK, CHF).

Component[] public components

curvePool

Curve pool for deviation validation.

ICurvePool public curvePool

pendingCurvePool

Pending Curve pool for timelock-protected updates.

address public pendingCurvePool

hasPendingProposal

Whether a proposal is active (needed because address(0) is a valid proposal).

bool public hasPendingProposal

curvePoolActivationTime

Timestamp when pending Curve pool can be finalized.

uint256 public curvePoolActivationTime

Functions

constructor

Creates basket oracle with currency components.

constructor(
    address[] memory _feeds,
    uint256[] memory _quantities,
    uint256[] memory _basePrices,
    uint256 _maxDeviationBps,
    uint256 _cap,
    address _owner
) Ownable(_owner);

Parameters

NameTypeDescription
_feedsaddress[]Array of Chainlink feed addresses.
_quantitiesuint256[]Array of basket weights (1e18 precision).
_basePricesuint256[]Array of base prices for normalization (8 decimals).
_maxDeviationBpsuint256Maximum deviation from Curve (e.g., 200 = 2%).
_capuint256Protocol CAP price (8 decimals). Clamps theoretical price in deviation check.
_owneraddressAdmin address for Curve pool management.

setCurvePool

Sets the Curve pool for deviation validation (initial setup only).

function setCurvePool(
    address _curvePool
) external onlyOwner;

Parameters

NameTypeDescription
_curvePooladdressCurve USDC/plDXY-BEAR pool address.

proposeCurvePool

Proposes a new Curve pool (requires 7-day timelock).

function proposeCurvePool(
    address _newPool
) external onlyOwner;

Parameters

NameTypeDescription
_newPooladdressNew Curve pool address.

finalizeCurvePool

Finalizes the Curve pool update after timelock expires.

function finalizeCurvePool() external onlyOwner;

latestRoundData

Returns the aggregated basket price from all component feeds.

function latestRoundData() public view returns (uint80, int256, uint256, uint256, uint80);

Returns

NameTypeDescription
<none>uint80roundId Mock round ID (always 1).
<none>int256answer The calculated basket price in 8 decimals.
<none>uint256startedAt Oldest component updatedAt (no separate round start; same as updatedAt).
<none>uint256updatedAt Oldest component updatedAt (weakest link for staleness checks).
<none>uint80answeredInRound Mock answered round (always 1).

_checkDeviation

Validates basket price against Curve spot. Reverts on excessive deviation. Intentionally acts as a global circuit breaker: if Chainlink and Curve EMA diverge beyond MAX_DEVIATION_BPS, all consumers (SyntheticSplitter, MorphoOracle, StakedOracle) are frozen — including Morpho liquidations. This is the desired behavior: large divergence signals either a compromised feed or a manipulated pool, and freezing is safer than acting on potentially bad price data.

function _checkDeviation(
    uint256 theoreticalDxy8Dec
) internal view;

Parameters

NameTypeDescription
theoreticalDxy8Decuint256Computed basket price (8 decimals).

decimals

Returns oracle decimals (8).

function decimals() external pure returns (uint8);

description

Returns oracle description.

function description() external pure returns (string memory);

version

Returns oracle version (1).

function version() external pure returns (uint256);

getRoundData

Returns data for a specific round ID.

Only round ID 1 is supported (synthetic basket has no historical rounds).

function getRoundData(
    uint80 _roundId
) external view returns (uint80, int256, uint256, uint256, uint80);

Events

CurvePoolProposed

Emitted when a new Curve pool is proposed.

event CurvePoolProposed(address indexed newPool, uint256 activationTime);

CurvePoolUpdated

Emitted when Curve pool is updated.

event CurvePoolUpdated(address indexed oldPool, address indexed newPool);

Errors

BasketOracle__InvalidPrice

Thrown when a component feed returns invalid price.

error BasketOracle__InvalidPrice(address feed);

BasketOracle__LengthMismatch

Thrown when feeds and quantities arrays have different lengths.

error BasketOracle__LengthMismatch();

BasketOracle__PriceDeviation

Thrown when basket price deviates too far from Curve spot.

error BasketOracle__PriceDeviation(uint256 theoretical, uint256 spot);

BasketOracle__AlreadySet

Thrown when Curve pool is already configured.

error BasketOracle__AlreadySet();

BasketOracle__TimelockActive

Thrown when timelock period has not elapsed.

error BasketOracle__TimelockActive();

BasketOracle__InvalidProposal

Thrown when no pending proposal exists.

error BasketOracle__InvalidProposal();

BasketOracle__InvalidDeviation

Thrown when max deviation is zero.

error BasketOracle__InvalidDeviation();

BasketOracle__InvalidBasePrice

Thrown when a base price is zero.

error BasketOracle__InvalidBasePrice();

BasketOracle__InvalidWeights

Thrown when quantities don’t sum to 1e18.

error BasketOracle__InvalidWeights();

BasketOracle__InvalidRoundId

error BasketOracle__InvalidRoundId();

Structs

Component

Component feed with its basket weight and base price for normalization.

struct Component {
    AggregatorV3Interface feed;
    uint256 quantity;
    uint256 basePrice;
}

IMorphoOracle

Git Source

Interface for Morpho-compatible price oracles.

Functions

price

Returns price of 1 collateral unit in loan asset terms (Morpho scale: 36 + loanDec - colDec = 24 decimals).

function price() external view returns (uint256);

MorphoOracle

Git Source

Inherits: IMorphoOracle

Title: MorphoOracle

Adapts BasketOracle price to Morpho Blue’s oracle scale (24 decimals for USDC/plDXY).

Supports both plDXY-BEAR (direct) and plDXY-BULL (inverse) pricing.

Note: security-contact: contact@plether.com

Constants

BASKET_ORACLE

Source price feed (BasketOracle).

AggregatorV3Interface public immutable BASKET_ORACLE

CAP

Protocol CAP price (8 decimals).

uint256 public immutable CAP

IS_INVERSE

If true, returns CAP - Price (for plDXY-BULL).

bool public immutable IS_INVERSE

STALENESS_TIMEOUT

Maximum age for valid oracle price.

uint256 public constant STALENESS_TIMEOUT = 24 hours

Functions

constructor

Creates Morpho-compatible oracle wrapper.

constructor(
    address _basketOracle,
    uint256 _cap,
    bool _isInverse
) ;

Parameters

NameTypeDescription
_basketOracleaddressBasketOracle address.
_capuint256Protocol CAP (8 decimals, e.g., 2e8 = $2.00).
_isInverseboolTrue for plDXY-BULL (CAP - Price), false for plDXY-BEAR.

price

Returns collateral price in Morpho scale (24 decimals for USDC(6)/plDXY(18)).

Morpho expects: 36 + loanDecimals - collateralDecimals = 36 + 6 - 18 = 24. BEAR (IS_INVERSE=false): min(basketPrice, CAP) * CHAINLINK_TO_MORPHO_SCALE. BULL (IS_INVERSE=true): (CAP - basketPrice) * CHAINLINK_TO_MORPHO_SCALE. Returns 1 (not 0) when BULL price would be zero to avoid Morpho division errors.

function price() external view override returns (uint256);

Returns

NameTypeDescription
<none>uint256Price of 1 plDXY token in USDC terms (24 decimals).

Errors

MorphoOracle__InvalidPrice

Thrown when source oracle returns zero or negative price.

error MorphoOracle__InvalidPrice();

MorphoOracle__StalePrice

Thrown when source oracle data is stale.

error MorphoOracle__StalePrice();

MorphoOracle__ZeroAddress

Thrown when zero address provided to constructor.

error MorphoOracle__ZeroAddress();

PythAdapter

Git Source

Inherits: AggregatorV3Interface

Title: PythAdapter

Adapts Pyth Network price feeds to Chainlink’s AggregatorV3Interface.

Pyth is pull-based: prices must be pushed on-chain before reading. This adapter reads the latest price and converts it to 8 decimals. Supports price inversion for feeds like USD/SEK → SEK/USD.

Note: security-contact: contact@plether.com

Constants

PYTH

IPyth public immutable PYTH

PRICE_ID

bytes32 public immutable PRICE_ID

MAX_STALENESS

uint256 public immutable MAX_STALENESS

MAX_CONFIDENCE_BPS

uint256 public immutable MAX_CONFIDENCE_BPS

INVERSE

bool public immutable INVERSE

DECIMALS

uint8 public constant DECIMALS = 8

State Variables

DESCRIPTION

string public DESCRIPTION

Functions

constructor

constructor(
    address pyth_,
    bytes32 priceId_,
    uint256 maxStaleness_,
    string memory description_,
    bool inverse_,
    uint256 maxConfidenceBps_
) ;

Parameters

NameTypeDescription
pyth_addressPyth contract address on this chain.
priceId_bytes32Pyth price feed ID (e.g., USD/SEK).
maxStaleness_uint256Maximum age of price in seconds before considered stale.
description_stringHuman-readable description (e.g., “SEK / USD”).
inverse_boolIf true, inverts the price (e.g., USD/SEK → SEK/USD).
maxConfidenceBps_uint256Maximum confidence interval as basis points of price (e.g., 500 = 5%).

latestRoundData

Returns the latest price data in Chainlink-compatible format.

Converts Pyth’s variable exponent to fixed 8 decimals. Reports block.timestamp as updatedAt (self-attestation): this adapter validates freshness internally against publishTime using MAX_STALENESS, then attests “price valid as of now.” Downstream consumers (BasketOracle, SyntheticSplitter) see a fresh timestamp and skip their own staleness check, avoiding double-timeout rejection during weekend forex market closures.

function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80);

Returns

NameTypeDescription
<none>uint80roundId Always returns 1 (Pyth doesn’t use rounds).
<none>int256answer Price in 8 decimals.
<none>uint256startedAt Current block timestamp (adapter attestation time).
<none>uint256updatedAt Current block timestamp (adapter attestation time).
<none>uint80answeredInRound Always returns 1.

getRoundData

Returns data for a specific round ID.

Only round ID 1 is supported (Pyth doesn’t use rounds).

function getRoundData(
    uint80 _roundId
) external view returns (uint80, int256, uint256, uint256, uint80);

decimals

Returns the number of decimals (always 8 for compatibility).

function decimals() external pure returns (uint8);

description

Returns the price feed description.

function description() external view returns (string memory);

version

Returns the adapter version.

function version() external pure returns (uint256);

updatePrice

Updates the Pyth price feed with new data.

Anyone can call this to push fresh prices on-chain.

function updatePrice(
    bytes[] calldata updateData
) external payable;

Parameters

NameTypeDescription
updateDatabytes[]Price update data from Pyth’s Hermes API.

getUpdateFee

Returns the fee required to update the price.

function getUpdateFee(
    bytes[] calldata updateData
) external view returns (uint256 fee);

Parameters

NameTypeDescription
updateDatabytes[]Price update data to calculate fee for.

Returns

NameTypeDescription
feeuint256Fee in wei.

_convertTo8Decimals

Converts Pyth price to 8 decimals.

Pyth uses variable exponents (e.g., -8, -6). This normalizes to -8.

function _convertTo8Decimals(
    int64 price,
    int32 expo
) internal pure returns (int256);

Parameters

NameTypeDescription
priceint64Pyth price value.
expoint32Pyth exponent (negative for decimal places).

Returns

NameTypeDescription
<none>int256Normalized price in 8 decimals.

_invertTo8Decimals

Inverts Pyth price and converts to 8 decimals.

For converting USD/SEK to SEK/USD: 1 / (price * 10^expo) * 10^8

function _invertTo8Decimals(
    int64 price,
    int32 expo
) internal pure returns (int256);

Parameters

NameTypeDescription
priceint64Pyth price value.
expoint32Pyth exponent (negative for decimal places).

Returns

NameTypeDescription
<none>int256Inverted price in 8 decimals.

Errors

PythAdapter__StalePrice

error PythAdapter__StalePrice(uint256 publishTime, uint256 maxAge);

PythAdapter__InvalidPrice

error PythAdapter__InvalidPrice();

PythAdapter__ConfidenceTooWide

error PythAdapter__ConfidenceTooWide(uint64 conf, int64 price);

PythAdapter__InvalidRoundId

error PythAdapter__InvalidRoundId();

PythAdapter__RefundFailed

error PythAdapter__RefundFailed();

SettlementOracle

Git Source

Title: SettlementOracle

Pure theoretical oracle for option settlement.

Uses historical Chainlink round data to look up prices at expiry, eliminating the settlement window and preventing lookback MEV.

Note: security-contact: contact@plether.com

Constants

CAP

uint256 public immutable CAP

SEQUENCER_UPTIME_FEED

AggregatorV3Interface public immutable SEQUENCER_UPTIME_FEED

SEQUENCER_GRACE_PERIOD

uint256 public constant SEQUENCER_GRACE_PERIOD = 1 hours

ORACLE_TIMEOUT

uint256 public constant ORACLE_TIMEOUT = 24 hours

State Variables

components

Component[] public components

Functions

constructor

constructor(
    address[] memory _feeds,
    uint256[] memory _quantities,
    uint256[] memory _basePrices,
    uint256 _cap,
    address _sequencerUptimeFeed
) ;

getSettlementPrices

Returns the pure theoretical settlement prices at a given expiry timestamp.

function getSettlementPrices(
    uint256 expiry,
    uint80[] calldata roundHints
) external view returns (uint256 bearPrice, uint256 bullPrice);

Parameters

NameTypeDescription
expiryuint256The timestamp at which to look up prices.
roundHintsuint80[]Caller-provided Chainlink round IDs (one per component) active at expiry.

Returns

NameTypeDescription
bearPriceuint256min(BasketPrice, CAP) in 8 decimals
bullPriceuint256CAP - bearPrice in 8 decimals

Errors

SettlementOracle__InvalidPrice

error SettlementOracle__InvalidPrice(address feed);

SettlementOracle__LengthMismatch

error SettlementOracle__LengthMismatch();

SettlementOracle__WrongHintCount

error SettlementOracle__WrongHintCount();

SettlementOracle__InvalidBasePrice

error SettlementOracle__InvalidBasePrice();

SettlementOracle__InvalidWeights

error SettlementOracle__InvalidWeights();

Structs

Component

struct Component {
    AggregatorV3Interface feed;
    uint256 quantity;
    uint256 basePrice;
}

IOracle

Git Source

Interface for price oracles.

Functions

price

Returns price of 1 collateral unit in loan asset terms.

function price() external view returns (uint256);

StakedOracle

Git Source

Inherits: IOracle

Title: StakedOracle

Prices ERC4626 vault shares by combining underlying price with exchange rate.

Price = UnderlyingPrice * ExchangeRate. Used for splDXY-BEAR/splDXY-BULL in Morpho.

Note: security-contact: contact@plether.com

Constants

VAULT

The staking vault (splDXY-BEAR or splDXY-BULL).

IERC4626 public immutable VAULT

UNDERLYING_ORACLE

Oracle for the underlying plDXY token.

IOracle public immutable UNDERLYING_ORACLE

SHARE_DECIMALS

Decimal multiplier for vault shares (accounts for ERC4626 decimal offset).

uint256 public immutable SHARE_DECIMALS

Functions

constructor

Creates staked oracle for a vault.

constructor(
    address _vault,
    address _underlyingOracle
) ;

Parameters

NameTypeDescription
_vaultaddressERC4626 staking vault address.
_underlyingOracleaddressPrice oracle for the underlying plDXY token.

price

Returns price of 1 vault share including accrued yield.

function price() external view override returns (uint256);

Returns

NameTypeDescription
<none>uint256Price in Morpho scale (24 decimals: underlying price * exchange rate).

Errors

StakedOracle__InvalidPrice

Thrown when underlying oracle returns zero price.

error StakedOracle__InvalidPrice();

StakedOracle__ZeroAddress

Thrown when zero address provided to constructor.

error StakedOracle__ZeroAddress();

Contents

Contents

ICfdEngine

Git Source

Stateful CFD trading engine: processes orders, settles funding, and liquidates positions.

Functions

clearinghouse

Margin clearinghouse address used for account margin locking/unlocking

function clearinghouse() external view returns (address);

orderRouter

Current order router allowed to execute orders through the engine.

function orderRouter() external view returns (address);

USDC

Settlement token used for fees, margin, and payouts

function USDC() external view returns (IERC20);

lastMarkPrice

Last mark price observed by the engine (8 decimals)

function lastMarkPrice() external view returns (uint256);

processOrder

Settles funding and processes an open/close order at the given oracle price

function processOrder(
    CfdTypes.Order memory order,
    uint256 currentOraclePrice,
    uint256 vaultDepthUsdc,
    uint64 publishTime
) external;

Parameters

NameTypeDescription
orderCfdTypes.OrderOrder to execute (contains accountId, market, direction, size)
currentOraclePriceuint256Mark price from the oracle (8 decimals)
vaultDepthUsdcuint256Available vault liquidity, used for open-interest caps (6 decimals)
publishTimeuint64Oracle publish timestamp, used for funding rate accrual

processOrderTyped

Router-facing order execution entrypoint with typed business-rule failures.

Reverts with CfdEngine__TypedOrderFailure for expected order invalidations so the router can apply deterministic failed-order bounty policy without selector matching.

function processOrderTyped(
    CfdTypes.Order memory order,
    uint256 currentOraclePrice,
    uint256 vaultDepthUsdc,
    uint64 publishTime
) external;

previewOpenRevertCode

Returns the current open-path revert code using canonical vault depth and a caller-supplied oracle snapshot.

function previewOpenRevertCode(
    bytes32 accountId,
    CfdTypes.Side side,
    uint256 sizeDelta,
    uint256 marginDelta,
    uint256 oraclePrice,
    uint64 publishTime
) external view returns (uint8 code);

previewOpenFailurePolicyCategory

Returns the semantic commit-time policy category for the current open-path invalidation, if any.

function previewOpenFailurePolicyCategory(
    bytes32 accountId,
    CfdTypes.Side side,
    uint256 sizeDelta,
    uint256 marginDelta,
    uint256 oraclePrice,
    uint64 publishTime
) external view returns (CfdEnginePlanTypes.OpenFailurePolicyCategory category);

recordDeferredClearerBounty

Records a deferred clearer bounty when immediate vault payment is unavailable.

Deferred keeper bounties are later claimed as clearinghouse credit, not direct wallet transfer.

function recordDeferredClearerBounty(
    address keeper,
    uint256 amountUsdc
) external;

getDeferredClaimHead

function getDeferredClaimHead() external view returns (DeferredClaim memory claim);

getDeferredTraderStatus

function getDeferredTraderStatus(
    bytes32 accountId
) external view returns (DeferredTraderStatus memory status);

getDeferredClearerStatus

function getDeferredClearerStatus(
    address keeper
) external view returns (DeferredClearerStatus memory status);

reserveCloseOrderExecutionBounty

Reserves close-order execution bounty from free settlement first, then active position margin.

function reserveCloseOrderExecutionBounty(
    bytes32 accountId,
    uint256 amountUsdc,
    address recipient
) external;

absorbRouterCancellationFee

Pulls router-custodied cancellation fees into protocol revenue.

function absorbRouterCancellationFee(
    uint256 amountUsdc
) external;

recordRouterProtocolFee

Books router-delivered protocol-owned inflow as accumulated fees after the router has already paid the vault.

function recordRouterProtocolFee(
    uint256 amountUsdc
) external;

liquidatePosition

Liquidates an undercollateralized position, returns keeper bounty in USDC

function liquidatePosition(
    bytes32 accountId,
    uint256 currentOraclePrice,
    uint256 vaultDepthUsdc,
    uint64 publishTime
) external returns (uint256 keeperBountyUsdc);

Parameters

NameTypeDescription
accountIdbytes32Account holding the position to liquidate
currentOraclePriceuint256Mark price from the oracle (8 decimals)
vaultDepthUsdcuint256Available vault liquidity (6 decimals)
publishTimeuint64Oracle publish timestamp

Returns

NameTypeDescription
keeperBountyUsdcuint256Bounty paid to the liquidation keeper (6 decimals)

previewLiquidation

Canonical liquidation preview using the vault’s current accounted depth.

function previewLiquidation(
    bytes32 accountId,
    uint256 oraclePrice
) external view returns (LiquidationPreview memory preview);

simulateLiquidation

Hypothetical liquidation simulation at a caller-supplied vault depth.

function simulateLiquidation(
    bytes32 accountId,
    uint256 oraclePrice,
    uint256 vaultDepthUsdc
) external view returns (LiquidationPreview memory preview);

getSideState

Returns the accounting state for a given side.

function getSideState(
    CfdTypes.Side side
) external view returns (SideState memory);

getMaxLiability

Worst-case directional liability after taking the max of bull/bear payout bounds.

function getMaxLiability() external view returns (uint256);

getAccountLedgerView

Compact per-account ledger view spanning clearinghouse, router escrow, and deferred trader payout state.

function getAccountLedgerView(
    bytes32 accountId
) external view returns (AccountLedgerView memory viewData);

getAccountLedgerSnapshot

Expanded per-account ledger snapshot for debugging account health and settlement reachability across protocol components.

function getAccountLedgerSnapshot(
    bytes32 accountId
) external view returns (AccountLedgerSnapshot memory snapshot);

getProtocolAccountingSnapshot

Canonical protocol-wide accounting snapshot across physical assets, liabilities, fees, bad debt, and deferred obligations.

function getProtocolAccountingSnapshot() external view returns (ProtocolAccountingSnapshot memory snapshot);

accumulatedFeesUsdc

Accumulated execution fees awaiting withdrawal (6 decimals)

function accumulatedFeesUsdc() external view returns (uint256);

getWithdrawalReservedUsdc

Total withdrawal reserve required by current protocol liabilities.

function getWithdrawalReservedUsdc() external view returns (uint256);

getHousePoolInputSnapshot

Canonical accounting snapshot consumed by HousePool.

function getHousePoolInputSnapshot(
    uint256 markStalenessLimit
) external view returns (HousePoolInputSnapshot memory snapshot);

Parameters

NameTypeDescription
markStalenessLimituint256Normal live-market staleness limit configured by HousePool.

getHousePoolStatusSnapshot

Canonical non-accounting market/status snapshot consumed by HousePool.

function getHousePoolStatusSnapshot() external view returns (HousePoolStatusSnapshot memory snapshot);

totalDeferredPayoutUsdc

Deferred profitable-close payouts still owed to traders.

function totalDeferredPayoutUsdc() external view returns (uint256);

totalDeferredClearerBountyUsdc

Deferred liquidation bounties still owed after failed immediate payout.

function totalDeferredClearerBountyUsdc() external view returns (uint256);

deferredClaimHeadId

function deferredClaimHeadId() external view returns (uint64);

getUnrealizedTraderPnl

Aggregate unrealized PnL of all open positions at lastMarkPrice. Positive = traders winning (house liability). Negative = traders losing (house asset).

function getUnrealizedTraderPnl() external view returns (int256);

getUnrealizedFundingPnl

Aggregate unrealized funding PnL across all open positions. Positive = traders are net funding receivers (vault liability).

function getUnrealizedFundingPnl() external view returns (int256);

getCappedFundingPnl

Aggregate unrealized funding PnL with negative per-side funding capped by backing margin. Positive = traders are net funding receivers after clipping uncollectible debts.

function getCappedFundingPnl() external view returns (int256);

getLiabilityOnlyFundingPnl

Aggregate funding liabilities only, excluding any trader debts owed to the vault. Used by withdrawal firewalls that must assume funding receivables are uncollectible until physically seized.

function getLiabilityOnlyFundingPnl() external view returns (uint256);

getVaultMtmAdjustment

Combined MtM liability: per-side (PnL + funding), clamped at zero. Positive = vault owes traders (unrealized liability). Zero = traders losing or neutral. Unrealized trader losses are not counted as vault assets.

function getVaultMtmAdjustment() external view returns (uint256);

lastMarkTime

Timestamp of the last mark price update

function lastMarkTime() external view returns (uint64);

hasLiveLiability

Returns true when the engine currently has open bounded liability that depends on mark freshness.

function hasLiveLiability() external view returns (bool);

syncFunding

Materializes accrued funding into storage so subsequent reads reflect current state.

function syncFunding() external;

updateMarkPrice

Push a fresh mark price without processing an order

function updateMarkPrice(
    uint256 price,
    uint64 publishTime
) external;

Parameters

NameTypeDescription
priceuint256New mark price (8 decimals)
publishTimeuint64Oracle publish timestamp for the price update

CAP_PRICE

Protocol cap price (8 decimals). Oracle prices are clamped to this.

function CAP_PRICE() external view returns (uint256);

isFadWindow

True during weekend FX closure or admin-configured FAD days

function isFadWindow() external view returns (bool);

fadMaxStaleness

Maximum oracle staleness allowed during FAD windows

function fadMaxStaleness() external view returns (uint256);

isOracleFrozen

True only when FX markets are actually closed and oracle freshness can be relaxed.

function isOracleFrozen() external view returns (bool);

hasOpenPosition

Returns true when the account currently has an open position.

function hasOpenPosition(
    bytes32 accountId
) external view returns (bool);

getPositionSize

Returns the current position size for an account (18 decimals).

function getPositionSize(
    bytes32 accountId
) external view returns (uint256);

getPositionSide

Returns the stored side for an open position.

function getPositionSide(
    bytes32 accountId
) external view returns (CfdTypes.Side);

degradedMode

True when the engine has latched degraded mode after a close revealed insolvency.

function degradedMode() external view returns (bool);

fadDayOverrides

Whether a given day number is an admin-configured FAD override

function fadDayOverrides(
    uint256 dayNumber
) external view returns (bool);

getProtocolPhase

function getProtocolPhase() external view returns (ProtocolPhase);

getProtocolStatus

function getProtocolStatus() external view returns (ProtocolStatus memory);

Errors

CfdEngine__TypedOrderFailure

error CfdEngine__TypedOrderFailure(
    CfdEnginePlanTypes.ExecutionFailurePolicyCategory failureCategory, uint8 failureCode, bool isClose
);

CfdEngine__MarkPriceOutOfOrder

error CfdEngine__MarkPriceOutOfOrder();

Structs

AccountLedgerView

Compact per-account ledger view spanning trader-owned settlement buckets and router-reserved order state.

settlementBalanceUsdc, freeSettlementUsdc, activePositionMarginUsdc, otherLockedMarginUsdc, and deferredPayoutUsdc are trader-owned value or obligations recorded by the protocol. activePositionMarginUsdc is the canonical clearinghouse custody bucket for live position backing, while engine economic position margin is exposed separately on AccountLedgerSnapshot.margin. executionEscrowUsdc is router-custodied order bounty escrow attributed to the account. committedMarginUsdc remains trader-owned settlement reserved for queued orders inside the clearinghouse.

struct AccountLedgerView {
    uint256 settlementBalanceUsdc;
    uint256 freeSettlementUsdc;
    uint256 activePositionMarginUsdc;
    uint256 otherLockedMarginUsdc;
    uint256 executionEscrowUsdc;
    uint256 committedMarginUsdc;
    uint256 deferredPayoutUsdc;
    uint256 pendingOrderCount;
}

AccountLedgerSnapshot

Expanded per-account ledger snapshot for debugging account health, reachability, and queued-order state.

Extends AccountLedgerView with typed clearinghouse locked-margin buckets, terminal settlement reachability, equity, buying power, and live position risk. margin is the engine’s economic position margin, while positionMarginBucketUsdc is the clearinghouse custody bucket that should back it.

struct AccountLedgerSnapshot {
    uint256 settlementBalanceUsdc;
    uint256 freeSettlementUsdc;
    uint256 activePositionMarginUsdc;
    uint256 otherLockedMarginUsdc;
    uint256 positionMarginBucketUsdc;
    uint256 committedOrderMarginBucketUsdc;
    uint256 reservedSettlementBucketUsdc;
    uint256 executionEscrowUsdc;
    uint256 committedMarginUsdc;
    uint256 deferredPayoutUsdc;
    uint256 pendingOrderCount;
    uint256 closeReachableUsdc;
    uint256 terminalReachableUsdc;
    uint256 accountEquityUsdc;
    uint256 freeBuyingPowerUsdc;
    bool hasPosition;
    CfdTypes.Side side;
    uint256 size;
    uint256 margin;
    uint256 entryPrice;
    int256 unrealizedPnlUsdc;
    int256 pendingFundingUsdc;
    int256 netEquityUsdc;
    bool liquidatable;
}

ProtocolAccountingSnapshot

struct ProtocolAccountingSnapshot {
    uint256 vaultAssetsUsdc;
    uint256 netPhysicalAssetsUsdc;
    uint256 maxLiabilityUsdc;
    uint256 effectiveSolvencyAssetsUsdc;
    uint256 withdrawalReservedUsdc;
    uint256 freeUsdc;
    uint256 accumulatedFeesUsdc;
    uint256 accumulatedBadDebtUsdc;
    int256 cappedFundingPnlUsdc;
    uint256 liabilityOnlyFundingPnlUsdc;
    uint256 totalDeferredPayoutUsdc;
    uint256 totalDeferredClearerBountyUsdc;
    bool degradedMode;
    bool hasLiveLiability;
}

HousePoolInputSnapshot

struct HousePoolInputSnapshot {
    uint256 physicalAssetsUsdc;
    uint256 netPhysicalAssetsUsdc;
    uint256 maxLiabilityUsdc;
    uint256 withdrawalFundingLiabilityUsdc;
    uint256 unrealizedMtmLiabilityUsdc;
    uint256 deferredTraderPayoutUsdc;
    uint256 deferredClearerBountyUsdc;
    uint256 protocolFeesUsdc;
    bool markFreshnessRequired;
    uint256 maxMarkStaleness;
}

HousePoolStatusSnapshot

struct HousePoolStatusSnapshot {
    uint64 lastMarkTime;
    bool oracleFrozen;
    bool degradedMode;
}

SideState

struct SideState {
    uint256 maxProfitUsdc;
    uint256 openInterest;
    uint256 entryNotional;
    uint256 totalMargin;
    int256 fundingIndex;
    int256 entryFunding;
}

LiquidationPreview

struct LiquidationPreview {
    bool liquidatable;
    uint256 oraclePrice;
    int256 equityUsdc;
    int256 pnlUsdc;
    int256 fundingUsdc;
    uint256 reachableCollateralUsdc;
    uint256 keeperBountyUsdc;
    uint256 seizedCollateralUsdc;
    uint256 settlementRetainedUsdc;
    uint256 freshTraderPayoutUsdc;
    uint256 existingDeferredConsumedUsdc;
    uint256 existingDeferredRemainingUsdc;
    uint256 immediatePayoutUsdc;
    uint256 deferredPayoutUsdc;
    uint256 badDebtUsdc;
    bool triggersDegradedMode;
    bool postOpDegradedMode;
    uint256 effectiveAssetsAfterUsdc;
    uint256 maxLiabilityAfterUsdc;
    int256 solvencyFundingPnlUsdc;
}

DeferredClaim

struct DeferredClaim {
    DeferredClaimType claimType;
    bytes32 accountId;
    address keeper;
    uint256 remainingUsdc;
    uint64 prevClaimId;
    uint64 nextClaimId;
}

DeferredTraderStatus

struct DeferredTraderStatus {
    uint64 claimId;
    uint256 deferredPayoutUsdc;
    bool isHead;
    bool claimableNow;
}

DeferredClearerStatus

struct DeferredClearerStatus {
    uint64 claimId;
    uint256 deferredBountyUsdc;
    bool isHead;
    bool claimableNow;
}

ProtocolStatus

struct ProtocolStatus {
    ProtocolPhase phase;
    uint64 lastMarkTime;
    uint256 lastMarkPrice;
    bool oracleFrozen;
    bool fadWindow;
    uint256 fadMaxStaleness;
}

Enums

DeferredClaimType

enum DeferredClaimType {
    TraderPayout,
    ClearerBounty
}

ProtocolPhase

High-level protocol lifecycle used by external status consumers. Active means the engine is wired and the vault has enabled live risk-taking.

enum ProtocolPhase {
    Configuring,
    Active,
    Degraded
}

ICfdVault

Git Source

Vault that custodies USDC backing the CFD trading system.

Functions

totalAssets

Canonical economic USDC backing recognized by the vault (6 decimals). Ignores unsolicited positive token transfers until explicitly accounted, but still reflects raw-balance shortfalls if assets leave the vault unexpectedly.

function totalAssets() external view returns (uint256);

payOut

Transfers USDC from the vault to a recipient

function payOut(
    address recipient,
    uint256 amount
) external;

Parameters

NameTypeDescription
recipientaddressAddress to receive USDC
amountuint256USDC amount to transfer (6 decimals)

recordProtocolInflow

Increases canonical vault assets to recognize a legitimate protocol-owned inflow.

This is the controlled accounting path for endogenous protocol gains that should increase economic vault depth. It does not require raw excess to be present and may also be used to restore canonical accounting after a raw-balance shortfall has already reduced totalAssets() via the min(rawBalance, accountedAssets) boundary. Reverts if the caller is unauthorized.

function recordProtocolInflow(
    uint256 amount
) external;

recordRecapitalizationInflow

Records an explicit recapitalization inflow intended to restore senior first.

function recordRecapitalizationInflow(
    uint256 amount
) external;

recordTradingRevenueInflow

Records LP-owned trading revenue and directly attaches it to seeded claimants when both tranches are otherwise at zero principal.

function recordTradingRevenueInflow(
    uint256 amount
) external;

markStalenessLimit

Maximum age for mark price freshness checks outside FAD mode (seconds)

function markStalenessLimit() external view returns (uint256);

isSeedLifecycleComplete

Returns true once both tranche seed positions exist.

function isSeedLifecycleComplete() external view returns (bool);

hasSeedLifecycleStarted

Returns true if bootstrap seeding has started for either tranche.

function hasSeedLifecycleStarted() external view returns (bool);

canAcceptOrdinaryDeposits

Returns true once ordinary LP deposits are allowed.

function canAcceptOrdinaryDeposits() external view returns (bool);

canIncreaseRisk

Returns true once risk-increasing trader actions are allowed.

function canIncreaseRisk() external view returns (bool);

isTradingActive

Returns true if owner has activated trading after seed completion.

function isTradingActive() external view returns (bool);

IHousePool

Git Source

Two-tranche USDC pool that acts as counterparty to CFD traders. Senior tranche earns fixed yield; junior absorbs first-loss and excess profit.

Functions

seniorPrincipal

Total USDC attributed to the senior tranche (6 decimals)

function seniorPrincipal() external view returns (uint256);

juniorPrincipal

Total USDC attributed to the junior tranche (6 decimals)

function juniorPrincipal() external view returns (uint256);

seniorHighWaterMark

Senior high-water mark used to block dilutive recapitalizing deposits.

function seniorHighWaterMark() external view returns (uint256);

unassignedAssets

Accounted LP assets currently quarantined pending explicit bootstrap / assignment (6 decimals)

function unassignedAssets() external view returns (uint256);

depositSenior

function depositSenior(
    uint256 amount
) external;

withdrawSenior

function withdrawSenior(
    uint256 amount,
    address receiver
) external;

depositJunior

function depositJunior(
    uint256 amount
) external;

withdrawJunior

function withdrawJunior(
    uint256 amount,
    address receiver
) external;

assignUnassignedAssets

Explicitly bootstraps quarantined LP assets into a tranche and mints matching shares.

function assignUnassignedAssets(
    bool toSenior,
    address receiver
) external;

initializeSeedPosition

Seeds a tranche with permanent share-backed minimum ownership using real USDC.

Canonical deployment should initialize both tranche seeds before enabling ordinary LP lifecycle.

function initializeSeedPosition(
    bool toSenior,
    uint256 amount,
    address receiver
) external;

getMaxSeniorWithdraw

Max withdrawable by senior, capped by free USDC

function getMaxSeniorWithdraw() external view returns (uint256);

getMaxJuniorWithdraw

Max withdrawable by junior, subordinated behind senior

function getMaxJuniorWithdraw() external view returns (uint256);

getPendingTrancheState

Read-only tranche state as if reconcile() ran immediately with current inputs.

function getPendingTrancheState()
    external
    view
    returns (
        uint256 seniorPrincipalUsdc,
        uint256 juniorPrincipalUsdc,
        uint256 maxSeniorWithdrawUsdc,
        uint256 maxJuniorWithdrawUsdc
    );

Returns

NameTypeDescription
seniorPrincipalUsdcuint256Simulated senior principal after reconcile (6 decimals)
juniorPrincipalUsdcuint256Simulated junior principal after reconcile (6 decimals)
maxSeniorWithdrawUsdcuint256Simulated senior withdrawal cap after reconcile (6 decimals)
maxJuniorWithdrawUsdcuint256Simulated junior withdrawal cap after reconcile (6 decimals)

reconcile

Settles revenue/loss waterfall between tranches

function reconcile() external;

isWithdrawalLive

Whether withdrawals are currently possible (not degraded, mark is fresh)

function isWithdrawalLive() external view returns (bool);

hasSeedLifecycleStarted

function hasSeedLifecycleStarted() external view returns (bool);

canAcceptOrdinaryDeposits

function canAcceptOrdinaryDeposits() external view returns (bool);

canAcceptTrancheDeposits

function canAcceptTrancheDeposits(
    bool isSenior
) external view returns (bool);

canIncreaseRisk

function canIncreaseRisk() external view returns (bool);

isTradingActive

function isTradingActive() external view returns (bool);

IMarginClearinghouse

Git Source

USDC-only cross-margin account system that holds settlement balances and settles PnL for CFD positions.

Functions

balanceUsdc

Returns the settlement USDC balance for an account.

function balanceUsdc(
    bytes32 accountId
) external view returns (uint256);

lockedMarginUsdc

Returns the locked USDC margin for an account

function lockedMarginUsdc(
    bytes32 accountId
) external view returns (uint256);

getLockedMarginBuckets

Returns the typed locked-margin buckets for an account.

function getLockedMarginBuckets(
    bytes32 accountId
) external view returns (LockedMarginBuckets memory buckets);

getOrderReservation

Returns the reservation record for a specific order id.

function getOrderReservation(
    uint64 orderId
) external view returns (OrderReservation memory reservation);

getAccountReservationSummary

Returns the aggregate active reservation summary for an account.

function getAccountReservationSummary(
    bytes32 accountId
) external view returns (AccountReservationSummary memory summary);

lockPositionMargin

Locks trader-owned settlement into the active position margin bucket.

function lockPositionMargin(
    bytes32 accountId,
    uint256 amountUsdc
) external;

unlockPositionMargin

Unlocks active position margin back into free settlement.

function unlockPositionMargin(
    bytes32 accountId,
    uint256 amountUsdc
) external;

lockCommittedOrderMargin

Locks trader-owned settlement into the committed-order bucket reserved for queued open orders.

function lockCommittedOrderMargin(
    bytes32 accountId,
    uint256 amountUsdc
) external;

reserveCommittedOrderMargin

Reserves committed-order margin for a specific order id inside the clearinghouse reservation ledger.

function reserveCommittedOrderMargin(
    bytes32 accountId,
    uint64 orderId,
    uint256 amountUsdc
) external;

unlockCommittedOrderMargin

Unlocks committed-order margin back into free settlement when a queued open order is released.

function unlockCommittedOrderMargin(
    bytes32 accountId,
    uint256 amountUsdc
) external;

releaseOrderReservation

Releases any remaining reservation balance for an order back into free settlement.

function releaseOrderReservation(
    uint64 orderId
) external returns (uint256 releasedUsdc);

releaseOrderReservationIfActive

Releases any remaining reservation balance for an order if it is still active.

function releaseOrderReservationIfActive(
    uint64 orderId
) external returns (uint256 releasedUsdc);

consumeOrderReservation

Consumes a specific amount from an order reservation, capped by its remaining balance.

function consumeOrderReservation(
    uint64 orderId,
    uint256 amountUsdc
) external returns (uint256 consumedUsdc);

consumeAccountOrderReservations

Consumes active order reservations for an account in FIFO reservation order.

function consumeAccountOrderReservations(
    bytes32 accountId,
    uint256 amountUsdc
) external returns (uint256 consumedUsdc);

consumeOrderReservationsById

Consumes the supplied active order reservations in FIFO order until the requested amount is exhausted.

function consumeOrderReservationsById(
    uint64[] calldata orderIds,
    uint256 amountUsdc
) external returns (uint256 consumedUsdc);

lockReservedSettlement

Locks settlement into a reserved bucket excluded from generic order/position margin release paths.

function lockReservedSettlement(
    bytes32 accountId,
    uint256 amountUsdc
) external;

unlockReservedSettlement

Unlocks settlement from the reserved bucket back into free settlement.

function unlockReservedSettlement(
    bytes32 accountId,
    uint256 amountUsdc
) external;

settleUsdc

Adjusts USDC balance for funding, PnL, or rebates (+credit, -debit)

function settleUsdc(
    bytes32 accountId,
    int256 amount
) external;

creditSettlementAndLockMargin

Credits settlement USDC and locks the same amount as active margin.

function creditSettlementAndLockMargin(
    bytes32 accountId,
    uint256 amountUsdc
) external;

applyOpenCost

Applies an open/increase trade cost by debiting or crediting settlement and updating locked margin.

function applyOpenCost(
    bytes32 accountId,
    uint256 marginDeltaUsdc,
    int256 tradeCostUsdc,
    address recipient
) external returns (int256 netMarginChangeUsdc);

consumeFundingLoss

Consumes funding loss from free settlement plus the active position margin bucket.

function consumeFundingLoss(
    bytes32 accountId,
    uint256 lockedPositionMarginUsdc,
    uint256 lossUsdc,
    address recipient
) external returns (uint256 marginConsumedUsdc, uint256 freeSettlementConsumedUsdc, uint256 uncoveredUsdc);

consumeCloseLoss

Consumes close-path losses from settlement buckets while preserving the remaining live position margin and reserved escrow.

function consumeCloseLoss(
    bytes32 accountId,
    uint64[] calldata reservationOrderIds,
    uint256 lossUsdc,
    uint256 protectedLockedMarginUsdc,
    bool includeOtherLockedMargin,
    address recipient
) external returns (uint256 seizedUsdc, uint256 shortfallUsdc);

applyLiquidationSettlementPlan

Applies a pre-planned liquidation settlement mutation while preserving reserved escrow.

function applyLiquidationSettlementPlan(
    bytes32 accountId,
    uint64[] calldata reservationOrderIds,
    LiquidationSettlementPlan calldata plan,
    address recipient
) external returns (uint256 seizedUsdc);

seizeUsdc

Transfers settlement USDC from an account to a recipient (losses, fees, or bad debt)

function seizeUsdc(
    bytes32 accountId,
    uint256 amount,
    address recipient
) external;

seizePositionMarginUsdc

Transfers settlement USDC from active position margin to a recipient and unlocks the same amount.

function seizePositionMarginUsdc(
    bytes32 accountId,
    uint256 amount,
    address recipient
) external;

getAccountUsdcBuckets

function getAccountUsdcBuckets(
    bytes32 accountId
) external view returns (AccountUsdcBuckets memory buckets);

getAccountEquityUsdc

Returns total account equity in settlement USDC (6 decimals)

function getAccountEquityUsdc(
    bytes32 accountId
) external view returns (uint256);

getFreeBuyingPowerUsdc

Returns strictly free buying power after subtracting locked margin (6 decimals)

function getFreeBuyingPowerUsdc(
    bytes32 accountId
) external view returns (uint256);

getFreeSettlementBalanceUsdc

Returns free settlement-asset balance after subtracting locked margin (6 decimals)

function getFreeSettlementBalanceUsdc(
    bytes32 accountId
) external view returns (uint256);

getTerminalReachableUsdc

Returns settlement-asset balance reachable during a terminal settlement path.

function getTerminalReachableUsdc(
    bytes32 accountId
) external view returns (uint256);

getSettlementReachableUsdc

Returns settlement-asset balance reachable for a terminal or partial settlement path.

Protects only the explicitly supplied remaining locked margin bucket and treats all other settlement-asset balance as reachable for loss collection.

function getSettlementReachableUsdc(
    bytes32 accountId,
    uint256 protectedLockedMarginUsdc
) external view returns (uint256);

Structs

LockedMarginBuckets

struct LockedMarginBuckets {
    // Canonical custody bucket backing currently live positions.
    uint256 positionMarginUsdc;
    uint256 committedOrderMarginUsdc;
    uint256 reservedSettlementUsdc;
    uint256 totalLockedMarginUsdc;
}

OrderReservation

struct OrderReservation {
    bytes32 accountId;
    ReservationBucket bucket;
    ReservationStatus status;
    uint96 originalAmountUsdc;
    uint96 remainingAmountUsdc;
}

AccountReservationSummary

struct AccountReservationSummary {
    uint256 activeCommittedOrderMarginUsdc;
    uint256 activeReservedSettlementUsdc;
    uint256 activeReservationCount;
}

AccountUsdcBuckets

struct AccountUsdcBuckets {
    uint256 settlementBalanceUsdc;
    uint256 totalLockedMarginUsdc;
    uint256 activePositionMarginUsdc;
    uint256 otherLockedMarginUsdc;
    uint256 freeSettlementUsdc;
}

LiquidationSettlementPlan

struct LiquidationSettlementPlan {
    uint256 settlementRetainedUsdc;
    uint256 settlementSeizedUsdc;
    uint256 freshTraderPayoutUsdc;
    uint256 badDebtUsdc;
    uint256 positionMarginUnlockedUsdc;
    uint256 otherLockedMarginUnlockedUsdc;
}

Enums

MarginBucket

enum MarginBucket {
    Position,
    CommittedOrder,
    ReservedSettlement
}

ReservationBucket

enum ReservationBucket {
    CommittedOrder,
    ReservedSettlement
}

ReservationStatus

enum ReservationStatus {
    None,
    Active,
    Consumed,
    Released
}

IOrderRouterAccounting

Git Source

Shared accounting-facing subset of OrderRouter used by engine views and margin bookkeeping.

Functions

syncMarginQueue

Prunes any zero-remaining committed-order reservations out of the router’s margin queue for an account.

function syncMarginQueue(
    bytes32 accountId
) external;

getAccountEscrow

Returns aggregate queued escrow attributed to an account across all pending orders.

function getAccountEscrow(
    bytes32 accountId
) external view returns (AccountEscrowView memory escrow);

getAccountOrderSummary

Returns aggregate queued order state attributed to an account.

Committed margin value is derived from the clearinghouse reservation summary; the router only owns queue structure.

function getAccountOrderSummary(
    bytes32 accountId
) external view returns (AccountOrderSummary memory summary);

getPendingOrdersForAccount

Returns pending orders for an account with escrow-aware queue details.

function getPendingOrdersForAccount(
    bytes32 accountId
) external view returns (PendingOrderView[] memory pending);

pendingOrderCounts

Returns the number of pending orders currently attributed to an account.

function pendingOrderCounts(
    bytes32 accountId
) external view returns (uint256);

getMarginReservationIds

Returns the current router-maintained margin-queue order ids for an account in FIFO order.

This is a structural traversal helper; committed-margin value remains owned by the clearinghouse reservation ledger.

function getMarginReservationIds(
    bytes32 accountId
) external view returns (uint64[] memory orderIds);

Structs

AccountEscrowView

Router/accounting view of queued order escrow attributed to an account.

committedMarginUsdc is derived from canonical MarginClearinghouse reservation state. executionBountyUsdc is router-custodied bounty escrow reserved for queued orders.

struct AccountEscrowView {
    uint256 committedMarginUsdc;
    uint256 executionBountyUsdc;
    uint256 pendingOrderCount;
}

AccountOrderSummary

struct AccountOrderSummary {
    uint256 pendingOrderCount;
    uint256 pendingCloseSize;
    uint256 committedMarginUsdc;
    uint256 executionBountyUsdc;
    bool hasTerminalCloseQueued;
}

PendingOrderView

struct PendingOrderView {
    uint64 orderId;
    bool isClose;
    CfdTypes.Side side;
    uint256 sizeDelta;
    uint256 marginDelta;
    uint256 targetPrice;
    uint64 commitTime;
    uint64 commitBlock;
    uint64 retryAfterTimestamp;
    uint256 committedMarginUsdc;
    uint256 executionBountyUsdc;
}

Enums

OrderStatus

enum OrderStatus {
    None,
    Pending,
    Executed,
    Failed
}

ITrancheVaultBootstrap

Git Source

Functions

previewDeposit

function previewDeposit(
    uint256 assets
) external view returns (uint256 shares);

bootstrapMint

function bootstrapMint(
    uint256 shares,
    address receiver
) external;

configureSeedPosition

function configureSeedPosition(
    address receiver,
    uint256 floorShares
) external;

IWithdrawGuard

Git Source

Pre-withdrawal hook that prevents clearinghouse withdrawals while positions are open.

Functions

checkWithdraw

Reverts if the account is not allowed to withdraw from the clearinghouse. Implementations may inspect current clearinghouse balances after tentative debit.

function checkWithdraw(
    bytes32 accountId
) external view;

Parameters

NameTypeDescription
accountIdbytes32Cross-margin account to check

Contents

CashPriorityLib

Git Source

Functions

reserveFreshPayouts

function reserveFreshPayouts(
    uint256 physicalAssetsUsdc,
    uint256 protocolFeesUsdc,
    uint256 deferredTraderPayoutUsdc,
    uint256 deferredClearerBountyUsdc
) internal pure returns (SeniorCashReservation memory reservation);

reserveDeferredHeadClaim

function reserveDeferredHeadClaim(
    uint256 physicalAssetsUsdc,
    uint256 protocolFeesUsdc,
    uint256 deferredTraderPayoutUsdc,
    uint256 deferredClearerBountyUsdc,
    uint256 headClaimAmountUsdc
) internal pure returns (SeniorCashReservation memory reservation);

reservedSeniorCashUsdc

function reservedSeniorCashUsdc(
    uint256 deferredTraderPayoutUsdc,
    uint256 deferredClearerBountyUsdc
) internal pure returns (uint256);

availableCashForFreshPayouts

function availableCashForFreshPayouts(
    uint256 physicalAssetsUsdc,
    uint256 protocolFeesUsdc,
    uint256 deferredTraderPayoutUsdc,
    uint256 deferredClearerBountyUsdc
) internal pure returns (uint256);

availableCashForDeferredClaim

function availableCashForDeferredClaim(
    uint256 physicalAssetsUsdc,
    uint256 protocolFeesUsdc,
    uint256 deferredTraderPayoutUsdc,
    uint256 deferredClearerBountyUsdc,
    uint256 claimAmountUsdc
) internal pure returns (uint256);

availableCashForProtocolFeeWithdrawal

function availableCashForProtocolFeeWithdrawal(
    uint256 physicalAssetsUsdc,
    uint256 protocolFeesUsdc,
    uint256 deferredTraderPayoutUsdc,
    uint256 deferredClearerBountyUsdc
) internal pure returns (uint256);

canPayFreshPayout

function canPayFreshPayout(
    uint256 physicalAssetsUsdc,
    uint256 protocolFeesUsdc,
    uint256 deferredTraderPayoutUsdc,
    uint256 deferredClearerBountyUsdc,
    uint256 amountUsdc
) internal pure returns (bool);

canPayDeferredClaim

function canPayDeferredClaim(
    uint256 physicalAssetsUsdc,
    uint256 protocolFeesUsdc,
    uint256 deferredTraderPayoutUsdc,
    uint256 deferredClearerBountyUsdc,
    uint256 claimAmountUsdc
) internal pure returns (bool);

canWithdrawProtocolFees

function canWithdrawProtocolFees(
    uint256 physicalAssetsUsdc,
    uint256 protocolFeesUsdc,
    uint256 deferredTraderPayoutUsdc,
    uint256 deferredClearerBountyUsdc,
    uint256 amountUsdc
) internal pure returns (bool);

_saturatingSub

function _saturatingSub(
    uint256 lhs,
    uint256 rhs
) private pure returns (uint256);

_buildSeniorCashReservation

function _buildSeniorCashReservation(
    uint256 physicalAssetsUsdc,
    uint256 protocolFeesUsdc,
    uint256 deferredTraderPayoutUsdc,
    uint256 deferredClearerBountyUsdc
) private pure returns (SeniorCashReservation memory reservation);

Structs

SeniorCashReservation

struct SeniorCashReservation {
    uint256 physicalAssetsUsdc;
    uint256 protocolFeesUsdc;
    uint256 deferredTraderPayoutUsdc;
    uint256 deferredClearerBountyUsdc;
    uint256 totalSeniorClaimsUsdc;
    uint256 reservedSeniorCashUsdc;
    uint256 protocolFeeWithdrawalUsdc;
    uint256 freeCashUsdc;
    uint256 headClaimServiceableUsdc;
}

CfdEnginePlanLib

Git Source

Title: CfdEnginePlanLib

Pure plan functions for the CfdEngine plan→apply architecture. Each function takes a RawSnapshot and returns a typed delta describing all effects. No storage reads, no external calls — purely deterministic over memory inputs.

Functions

computeOpenMarginAfter

function computeOpenMarginAfter(
    uint256 marginAfterFunding,
    int256 netMarginChange
) internal pure returns (bool drained, uint256 marginAfter);

computeSideTotalMarginAfterOpen

function computeSideTotalMarginAfterOpen(
    uint256 sideTotalMarginAfterFunding,
    uint256 effectivePositionMarginAfterFunding,
    uint256 positionMarginAfterOpen
) internal pure returns (uint256 sideTotalMarginAfterOpen);

getOpenFailurePolicyCategory

function getOpenFailurePolicyCategory(
    CfdEnginePlanTypes.OpenRevertCode code
) internal pure returns (CfdEnginePlanTypes.OpenFailurePolicyCategory);

getExecutionFailurePolicyCategory

function getExecutionFailurePolicyCategory(
    CfdEnginePlanTypes.OpenRevertCode code
) internal pure returns (CfdEnginePlanTypes.ExecutionFailurePolicyCategory);

getExecutionFailurePolicyCategory

function getExecutionFailurePolicyCategory(
    CfdEnginePlanTypes.CloseRevertCode code
) internal pure returns (CfdEnginePlanTypes.ExecutionFailurePolicyCategory);

_selectedAndOpposite

function _selectedAndOpposite(
    CfdEnginePlanTypes.RawSnapshot memory snap,
    CfdTypes.Side side
)
    private
    pure
    returns (CfdEnginePlanTypes.SideSnapshot memory selected, CfdEnginePlanTypes.SideSnapshot memory opposite);

_absSkewUsdc

function _absSkewUsdc(
    CfdEnginePlanTypes.SideSnapshot memory bull,
    CfdEnginePlanTypes.SideSnapshot memory bear,
    uint256 price
) private pure returns (uint256);

_postOpenSkewUsdc

function _postOpenSkewUsdc(
    CfdEnginePlanTypes.SideSnapshot memory bull,
    CfdEnginePlanTypes.SideSnapshot memory bear,
    CfdTypes.Side side,
    uint256 sizeDelta,
    uint256 price
) private pure returns (uint256);

_computeGlobalFundingPnl

function _computeGlobalFundingPnl(
    CfdEnginePlanTypes.SideSnapshot memory bull,
    CfdEnginePlanTypes.SideSnapshot memory bear
) private pure returns (int256 bullFunding, int256 bearFunding);

_isCollectedFundingLoss

function _isCollectedFundingLoss(
    CfdEnginePlanTypes.FundingPayoutType payoutType
) private pure returns (bool);

_solvencyCappedFundingPnl

function _solvencyCappedFundingPnl(
    CfdEnginePlanTypes.SideSnapshot memory bull,
    CfdEnginePlanTypes.SideSnapshot memory bear
) private pure returns (int256);

_planDeferredPayoutConsumption

function _planDeferredPayoutConsumption(
    uint256 deferredPayoutUsdc,
    uint256 shortfallUsdc,
    bool shortfallAlreadyIncludesDeferred
) private pure returns (uint256 consumedUsdc, uint256 remainingUsdc, uint256 badDebtUsdc);

_planCloseDeferredPayoutConsumption

function _planCloseDeferredPayoutConsumption(
    uint256 deferredPayoutUsdc,
    CfdEngineSettlementLib.CloseSettlementResult memory lossResult
)
    private
    pure
    returns (uint256 consumedUsdc, uint256 remainingUsdc, uint256 feeRecoveredUsdc, uint256 badDebtUsdc);

planGlobalFunding

function planGlobalFunding(
    CfdEnginePlanTypes.RawSnapshot memory snap,
    uint256 executionPrice,
    uint64 publishTime
) internal pure returns (CfdEnginePlanTypes.GlobalFundingDelta memory gfd);

planFunding

function planFunding(
    CfdEnginePlanTypes.RawSnapshot memory snap,
    uint256 executionPrice,
    uint64 publishTime,
    bool isClose,
    bool isFullClose
) internal pure returns (CfdEnginePlanTypes.FundingDelta memory fd);

planOpen

function planOpen(
    CfdEnginePlanTypes.RawSnapshot memory snap,
    CfdTypes.Order memory order,
    uint256 executionPrice,
    uint64 publishTime
) internal pure returns (CfdEnginePlanTypes.OpenDelta memory delta);

_buildPostOpenRiskState

function _buildPostOpenRiskState(
    CfdEnginePlanTypes.RawSnapshot memory snap,
    CfdEnginePlanTypes.OpenDelta memory delta
) private pure returns (PositionRiskAccountingLib.PositionRiskState memory riskState);

_isOpenInsolventAfterPlan

function _isOpenInsolventAfterPlan(
    CfdEnginePlanTypes.RawSnapshot memory snap,
    CfdTypes.Side side,
    CfdEnginePlanTypes.OpenDelta memory delta,
    CfdEnginePlanTypes.SideSnapshot memory bull,
    CfdEnginePlanTypes.SideSnapshot memory bear
) private pure returns (bool);

planClose

function planClose(
    CfdEnginePlanTypes.RawSnapshot memory snap,
    CfdTypes.Order memory order,
    uint256 executionPrice,
    uint64 publishTime
) internal pure returns (CfdEnginePlanTypes.CloseDelta memory delta);

_computeCloseSolvency

function _computeCloseSolvency(
    CfdEnginePlanTypes.RawSnapshot memory snap,
    CfdEnginePlanTypes.CloseDelta memory delta,
    CfdEnginePlanTypes.SideSnapshot memory bull,
    CfdEnginePlanTypes.SideSnapshot memory bear
) private pure returns (CfdEnginePlanTypes.SolvencyPreview memory sp);

_buildCloseSettlementBuckets

function _buildCloseSettlementBuckets(
    CfdEnginePlanTypes.RawSnapshot memory snap,
    uint256 marginToFreeUsdc,
    CfdEnginePlanTypes.FundingDelta memory fd,
    bool includeOtherLockedMargin
) private pure returns (IMarginClearinghouse.AccountUsdcBuckets memory);

planLiquidation

function planLiquidation(
    CfdEnginePlanTypes.RawSnapshot memory snap,
    uint256 executionPrice,
    uint64 publishTime
) internal pure returns (CfdEnginePlanTypes.LiquidationDelta memory delta);

Constants

Git Source

EXECUTION_FEE_BPS

uint256 constant EXECUTION_FEE_BPS = 4

CfdEngineSettlementLib

Git Source

Functions

collectSettlementDeficit

function collectSettlementDeficit(
    uint256 availableUsdc,
    uint256 owedUsdc
) internal pure returns (DebtCollectionResult memory result);

closeSettlementResult

function closeSettlementResult(
    uint256 availableUsdc,
    uint256 owedUsdc,
    uint256 execFeeUsdc
) internal pure returns (CloseSettlementResult memory result);

closeSettlementResultForTerminalBuckets

function closeSettlementResultForTerminalBuckets(
    IMarginClearinghouse.AccountUsdcBuckets memory buckets,
    uint256 protectedLockedMarginUsdc,
    uint256 owedUsdc,
    uint256 execFeeUsdc
) internal pure returns (CloseSettlementResult memory result);

liquidationSettlementResult

function liquidationSettlementResult(
    uint256 accountBalanceUsdc,
    int256 residualUsdc
) internal pure returns (LiquidationSettlementResult memory result);

Structs

DebtCollectionResult

struct DebtCollectionResult {
    uint256 seizedUsdc;
    uint256 shortfallUsdc;
}

CloseSettlementResult

struct CloseSettlementResult {
    uint256 seizedUsdc;
    uint256 shortfallUsdc;
    uint256 collectedExecFeeUsdc;
    uint256 badDebtUsdc;
}

LiquidationSettlementResult

struct LiquidationSettlementResult {
    uint256 targetBalanceUsdc;
    uint256 seizedUsdc;
    uint256 payoutUsdc;
    uint256 badDebtUsdc;
}

CfdEngineSnapshotsLib

Git Source

Functions

buildFundingSnapshot

function buildFundingSnapshot(
    int256 bullFunding,
    int256 bearFunding,
    uint256 totalBullMargin,
    uint256 totalBearMargin
) internal pure returns (FundingSnapshot memory snapshot);

getWithdrawalReservedUsdc

function getWithdrawalReservedUsdc(
    uint256 maxLiability,
    uint256 protocolFees,
    uint256 fundingLiability
) internal pure returns (uint256 reservedUsdc);

Structs

FundingSnapshot

struct FundingSnapshot {
    int256 bullFunding;
    int256 bearFunding;
    int256 solvencyFunding;
    uint256 withdrawalFundingLiability;
}

SolvencySnapshot

struct SolvencySnapshot {
    uint256 physicalAssets;
    uint256 protocolFees;
    uint256 netPhysicalAssets;
    uint256 maxLiability;
    int256 solvencyFunding;
    uint256 effectiveSolvencyAssets;
}

CloseAccountingLib

Git Source

Functions

buildCloseState

function buildCloseState(
    uint256 positionSize,
    uint256 positionMarginUsdc,
    uint256 entryPrice,
    uint256 maxProfitUsdc,
    int256 vpiAccrued,
    CfdTypes.Side side,
    uint256 sizeDelta,
    uint256 oraclePrice,
    uint256 capPrice,
    uint256 preSkewUsdc,
    uint256 postSkewUsdc,
    uint256 vaultDepthUsdc,
    uint256 vpiFactor,
    uint256 executionFeeBps,
    int256 fundingSettlementUsdc
) internal pure returns (CloseState memory state);

Structs

CloseState

struct CloseState {
    int256 realizedPnlUsdc;
    uint256 marginToFreeUsdc;
    uint256 remainingMarginUsdc;
    uint256 remainingSize;
    uint256 maxProfitReductionUsdc;
    int256 proportionalAccrualUsdc;
    int256 vpiDeltaUsdc;
    uint256 executionFeeUsdc;
    int256 netSettlementUsdc;
}

HousePoolAccountingLib

Git Source

Functions

buildWithdrawalSnapshot

function buildWithdrawalSnapshot(
    ICfdEngine.HousePoolInputSnapshot memory engineSnapshot
) internal pure returns (WithdrawalSnapshot memory snapshot);

buildReconcileSnapshot

function buildReconcileSnapshot(
    ICfdEngine.HousePoolInputSnapshot memory engineSnapshot
) internal pure returns (ReconcileSnapshot memory snapshot);

getMarkFreshnessPolicy

function getMarkFreshnessPolicy(
    ICfdEngine.HousePoolInputSnapshot memory accountingSnapshot
) internal pure returns (MarkFreshnessPolicy memory policy);

isMarkFresh

function isMarkFresh(
    uint64 lastMarkTime,
    uint256 limit,
    uint256 currentTimestamp
) internal pure returns (bool);

Structs

WithdrawalSnapshot

struct WithdrawalSnapshot {
    uint256 physicalAssets;
    uint256 maxLiability;
    uint256 protocolFees;
    uint256 reserved;
    uint256 freeUsdc;
}

ReconcileSnapshot

struct ReconcileSnapshot {
    uint256 physicalAssets;
    uint256 protocolFees;
    uint256 deferredLiabilities;
    uint256 cashMinusFees;
    uint256 mtm;
    uint256 distributable;
}

MarkFreshnessPolicy

struct MarkFreshnessPolicy {
    bool required;
    uint256 maxStaleness;
}

HousePoolFreshnessLib

Git Source

Functions

markIsFreshForReconcile

function markIsFreshForReconcile(
    ICfdEngine.HousePoolInputSnapshot memory accountingSnapshot,
    ICfdEngine.HousePoolStatusSnapshot memory statusSnapshot,
    uint256 currentTimestamp
) internal pure returns (bool);

withdrawalsLive

function withdrawalsLive(
    ICfdEngine.HousePoolInputSnapshot memory accountingSnapshot,
    ICfdEngine.HousePoolStatusSnapshot memory statusSnapshot,
    uint256 currentTimestamp
) internal pure returns (bool);

markFresh

function markFresh(
    ICfdEngine.HousePoolInputSnapshot memory accountingSnapshot,
    ICfdEngine.HousePoolStatusSnapshot memory statusSnapshot,
    uint256 currentTimestamp
) internal pure returns (bool);

HousePoolPendingLivePlanLib

Git Source

Functions

planApplyPendingBuckets

function planApplyPendingBuckets(
    HousePoolPendingPreviewLib.PendingAccountingState memory state,
    uint256 currentSeniorPrincipal,
    uint256 pendingRecapitalizationUsdc,
    uint256 pendingTradingRevenueUsdc
) internal pure returns (PendingLivePlan memory plan);

Structs

PendingLivePlan

struct PendingLivePlan {
    HousePoolPendingPreviewLib.PendingAccountingState state;
    bool seniorPrincipalChanged;
}

HousePoolPendingPreviewLib

Git Source

Functions

applyPendingBucketsPreview

function applyPendingBucketsPreview(
    PendingAccountingState memory state,
    uint256 pendingRecapitalizationUsdc,
    uint256 pendingTradingRevenueUsdc
) internal pure;

applyRecapitalizationIntent

function applyRecapitalizationIntent(
    PendingAccountingState memory state,
    uint256 amount
) internal pure;

routeSeededRevenue

function routeSeededRevenue(
    PendingAccountingState memory state,
    uint256 amount
) internal pure;

Structs

PendingAccountingState

struct PendingAccountingState {
    HousePoolWaterfallAccountingLib.WaterfallState waterfall;
    uint256 unassignedAssets;
    uint256 seniorSupply;
    uint256 juniorSupply;
}

HousePoolReconcilePlanLib

Git Source

Functions

planReconcile

function planReconcile(
    HousePoolPendingPreviewLib.PendingAccountingState memory state,
    HousePoolAccountingLib.ReconcileSnapshot memory snapshot,
    uint256 pendingBucketAssets,
    uint256 seniorRateBps,
    uint256 yieldElapsed,
    bool markFresh
) internal pure returns (ReconcilePlan memory plan);

juniorRevenueWithoutOwners

function juniorRevenueWithoutOwners(
    ReconcilePlan memory plan
) internal pure returns (uint256);

Structs

ReconcilePlan

struct ReconcilePlan {
    HousePoolPendingPreviewLib.PendingAccountingState state;
    uint256 yieldAccrued;
    bool markFresh;
    bool juniorSupplyZero;
    bool claimedEquityZero;
    bool revenue;
    uint256 deltaUsdc;
    uint256 juniorPrincipalBeforeRevenue;
}

HousePoolSeedLifecycleLib

Git Source

Functions

isSeedLifecycleComplete

function isSeedLifecycleComplete(
    bool seniorSeedInitialized,
    bool juniorSeedInitialized
) internal pure returns (bool);

hasSeedLifecycleStarted

function hasSeedLifecycleStarted(
    bool seniorSeedInitialized,
    bool juniorSeedInitialized
) internal pure returns (bool);

canAcceptOrdinaryDeposits

function canAcceptOrdinaryDeposits(
    bool seniorSeedInitialized,
    bool juniorSeedInitialized,
    bool isTradingActive
) internal pure returns (bool);

canIncreaseRisk

function canIncreaseRisk(
    bool seniorSeedInitialized,
    bool juniorSeedInitialized,
    bool isTradingActive
) internal pure returns (bool);

tradingActivationReady

function tradingActivationReady(
    bool seniorSeedInitialized,
    bool juniorSeedInitialized
) internal pure returns (bool);

hasPendingBootstrap

function hasPendingBootstrap(
    uint256 unassignedAssets
) internal pure returns (bool);

HousePoolTrancheGateLib

Git Source

Functions

trancheDepositsAllowed

function trancheDepositsAllowed(
    bool ordinaryDepositsAllowed,
    bool paused,
    uint256 unassignedAssets,
    bool markFreshForReconcile,
    uint256 projectedUnassignedAssets,
    bool isSenior,
    uint256 projectedSeniorPrincipal,
    uint256 projectedSeniorHighWaterMark
) internal pure returns (bool);

HousePoolWaterfallAccountingLib

Git Source

Constants

BPS

uint256 internal constant BPS = 10_000

SECONDS_PER_YEAR

uint256 internal constant SECONDS_PER_YEAR = 31_536_000

Functions

accrueSeniorYield

function accrueSeniorYield(
    uint256 seniorPrincipal,
    uint256 seniorRateBps,
    uint256 elapsed
) internal pure returns (uint256);

planReconcile

function planReconcile(
    uint256 seniorPrincipal,
    uint256 juniorPrincipal,
    uint256 distributableUsdc,
    uint256 seniorRateBps,
    uint256 elapsed
) internal pure returns (ReconcilePlan memory plan);

scaleSeniorOnWithdraw

function scaleSeniorOnWithdraw(
    WaterfallState memory state,
    uint256 withdrawAmountUsdc
) internal pure returns (WaterfallState memory nextState);

distributeRevenue

function distributeRevenue(
    WaterfallState memory state,
    uint256 revenueUsdc
) internal pure returns (WaterfallState memory nextState);

absorbLoss

function absorbLoss(
    WaterfallState memory state,
    uint256 lossUsdc
) internal pure returns (WaterfallState memory nextState);

Structs

WaterfallState

struct WaterfallState {
    uint256 seniorPrincipal;
    uint256 juniorPrincipal;
    uint256 unpaidSeniorYield;
    uint256 seniorHighWaterMark;
}

ReconcilePlan

struct ReconcilePlan {
    uint256 yieldAccrued;
    bool isRevenue;
    uint256 deltaUsdc;
}

HousePoolWithdrawalPreviewLib

Git Source

Functions

reserveAssets

function reserveAssets(
    HousePoolAccountingLib.WithdrawalSnapshot memory snapshot,
    uint256 reservedAssets
) internal pure returns (HousePoolAccountingLib.WithdrawalSnapshot memory nextSnapshot);

seniorWithdrawCap

function seniorWithdrawCap(
    uint256 freeUsdc,
    uint256 seniorPrincipal
) internal pure returns (uint256);

juniorWithdrawCap

function juniorWithdrawCap(
    uint256 freeUsdc,
    uint256 seniorPrincipal,
    uint256 juniorPrincipal
) internal pure returns (uint256);

LiquidationAccountingLib

Git Source

Functions

buildLiquidationState

function buildLiquidationState(
    uint256 size,
    uint256 oraclePrice,
    uint256 reachableCollateralUsdc,
    int256 fundingUsdc,
    int256 pnlUsdc,
    uint256 maintMarginBps,
    uint256 minBountyUsdc,
    uint256 bountyBps,
    uint256 tokenScale
) internal pure returns (LiquidationState memory state);

settlementForState

function settlementForState(
    LiquidationState memory state
) internal pure returns (CfdEngineSettlementLib.LiquidationSettlementResult memory result);

Structs

LiquidationState

struct LiquidationState {
    int256 equityUsdc;
    uint256 reachableCollateralUsdc;
    uint256 maintenanceMarginUsdc;
    uint256 keeperBountyUsdc;
}

MarginClearinghouseAccountingLib

Git Source

Functions

buildAccountUsdcBuckets

function buildAccountUsdcBuckets(
    uint256 settlementBalanceUsdc,
    uint256 positionMarginUsdc,
    uint256 committedOrderMarginUsdc,
    uint256 reservedSettlementUsdc
) internal pure returns (IMarginClearinghouse.AccountUsdcBuckets memory buckets);

buildPartialCloseUsdcBuckets

function buildPartialCloseUsdcBuckets(
    uint256 settlementBalanceUsdc,
    uint256 positionMarginUsdc,
    uint256 committedOrderMarginUsdc,
    uint256 reservedSettlementUsdc
) internal pure returns (IMarginClearinghouse.AccountUsdcBuckets memory buckets);

planFundingLossConsumption

function planFundingLossConsumption(
    IMarginClearinghouse.AccountUsdcBuckets memory buckets,
    uint256 lossUsdc
) internal pure returns (SettlementConsumption memory consumption);

getTerminalReachableUsdc

function getTerminalReachableUsdc(
    IMarginClearinghouse.AccountUsdcBuckets memory buckets
) internal pure returns (uint256 reachableUsdc);

getSettlementReachableUsdc

function getSettlementReachableUsdc(
    IMarginClearinghouse.AccountUsdcBuckets memory buckets,
    uint256 protectedLockedMarginUsdc
) internal pure returns (uint256 reachableUsdc);

planTerminalLossConsumption

function planTerminalLossConsumption(
    IMarginClearinghouse.AccountUsdcBuckets memory buckets,
    uint256 protectedLockedMarginUsdc,
    uint256 lossUsdc
) internal pure returns (SettlementConsumption memory consumption);

applyFundingLossMutation

function applyFundingLossMutation(
    IMarginClearinghouse.AccountUsdcBuckets memory,
    SettlementConsumption memory consumption
) internal pure returns (BucketMutation memory mutation);

applyTerminalLossMutation

function applyTerminalLossMutation(
    IMarginClearinghouse.AccountUsdcBuckets memory,
    uint256,
    SettlementConsumption memory consumption
) internal pure returns (BucketMutation memory mutation);

planLiquidationResidual

function planLiquidationResidual(
    IMarginClearinghouse.AccountUsdcBuckets memory buckets,
    int256 residualUsdc
) internal pure returns (LiquidationResidualPlan memory plan);

Structs

SettlementConsumption

struct SettlementConsumption {
    uint256 freeSettlementConsumedUsdc;
    uint256 activeMarginConsumedUsdc;
    uint256 otherLockedMarginConsumedUsdc;
    uint256 totalConsumedUsdc;
    uint256 uncoveredUsdc;
}

BucketMutation

struct BucketMutation {
    uint256 settlementDebitUsdc;
    uint256 positionMarginUnlockedUsdc;
    uint256 otherLockedMarginUnlockedUsdc;
}

LiquidationResidualPlan

struct LiquidationResidualPlan {
    uint256 settlementRetainedUsdc;
    uint256 settlementSeizedUsdc;
    uint256 freshTraderPayoutUsdc;
    uint256 badDebtUsdc;
    BucketMutation mutation;
}

MarketCalendarLib

Git Source

Constants

SECONDS_PER_DAY

uint256 internal constant SECONDS_PER_DAY = 86_400

SECONDS_PER_HOUR

uint256 internal constant SECONDS_PER_HOUR = 3600

Functions

isFadWindow

function isFadWindow(
    uint256 timestamp,
    bool todayOverride,
    bool tomorrowOverride,
    uint256 fadRunwaySeconds
) internal pure returns (bool);

isOracleFrozen

function isOracleFrozen(
    uint256 timestamp,
    bool todayOverride
) internal pure returns (bool);

_dayAndHour

function _dayAndHour(
    uint256 timestamp
) private pure returns (uint256 dayOfWeek, uint256 hourOfDay);

OpenAccountingLib

Git Source

Functions

buildOpenState

function buildOpenState(
    OpenInputs memory inputs
) internal pure returns (OpenState memory state);

effectiveMarginAfterTradeCost

function effectiveMarginAfterTradeCost(
    uint256 marginUsdc,
    int256 tradeCostUsdc
) internal pure returns (uint256 effectiveMarginUsdc);

Structs

OpenInputs

struct OpenInputs {
    uint256 currentSize;
    uint256 currentEntryPrice;
    CfdTypes.Side side;
    uint256 sizeDelta;
    uint256 price;
    uint256 capPrice;
    uint256 preSkewUsdc;
    uint256 postSkewUsdc;
    uint256 vaultDepthUsdc;
    uint256 executionFeeBps;
    int256 currentFundingIndex;
    CfdTypes.RiskParams riskParams;
}

OpenState

struct OpenState {
    uint256 addedMaxProfitUsdc;
    uint256 oldEntryNotional;
    uint256 newEntryPrice;
    uint256 newSize;
    uint256 newEntryNotional;
    uint256 postSkewUsdc;
    int256 positionFundingContribution;
    int256 vpiUsdc;
    uint256 notionalUsdc;
    uint256 executionFeeUsdc;
    int256 tradeCostUsdc;
    uint256 maintenanceMarginUsdc;
    uint256 initialMarginRequirementUsdc;
}

OrderFailurePolicyLib

Git Source

Functions

isPredictablyInvalidOpen

function isPredictablyInvalidOpen(
    CfdEnginePlanTypes.OpenFailurePolicyCategory category
) internal pure returns (bool);

failureDomainForExecutionCategory

function failureDomainForExecutionCategory(
    CfdEnginePlanTypes.ExecutionFailurePolicyCategory category
) internal pure returns (FailureDomain);

bountyPolicyForFailure

function bountyPolicyForFailure(
    FailureContext memory context
) internal pure returns (FailedOrderBountyPolicy);

Structs

RoutedFailure

struct RoutedFailure {
    FailureDomain domain;
    uint8 code;
    bool isClose;
}

FailureContext

struct FailureContext {
    RoutedFailure failure;
    FailureSource source;
    bool closeOnly;
    bool oracleFrozen;
    bool isFad;
    bool degradedMode;
}

Enums

FailedOrderBountyPolicy

enum FailedOrderBountyPolicy {
    None,
    ClearerFull,
    RefundUser
}

FailureSource

enum FailureSource {
    RouterPolicy,
    EngineTyped,
    UntypedRevert,
    Expired
}

FailureDomain

enum FailureDomain {
    UserInvalid,
    ProtocolStateInvalidated,
    Retryable,
    Expired
}

RouterFailureCode

enum RouterFailureCode {
    None,
    CloseOnlyOracleFrozen,
    CloseOnlyFad
}

OrderOraclePolicyLib

Git Source

Functions

getOracleExecutionPolicy

function getOracleExecutionPolicy(
    OracleAction action,
    bool oracleFrozen,
    bool isFad,
    uint256 liveExecutionStaleness,
    uint256 liveLiquidationStaleness,
    uint256 fadMaxStaleness
) internal pure returns (OracleExecutionPolicy memory policy);

isStale

function isStale(
    uint64 oraclePublishTime,
    uint256 maxStaleness,
    uint256 currentTimestamp
) internal pure returns (bool);

Structs

OracleExecutionPolicy

struct OracleExecutionPolicy {
    bool oracleFrozen;
    bool isFad;
    bool closeOnly;
    bool mevChecks;
    uint256 maxStaleness;
}

Enums

OracleAction

enum OracleAction {
    OrderExecution,
    MarkRefresh,
    Liquidation
}

PositionRiskAccountingLib

Git Source

Functions

getPendingFunding

function getPendingFunding(
    CfdTypes.Position memory pos,
    int256 currentIndex
) internal pure returns (int256 fundingUsdc);

previewPendingFunding

function previewPendingFunding(
    CfdTypes.Position memory pos,
    int256 bullFundingIndex,
    int256 bearFundingIndex,
    uint256 lastMarkPrice,
    uint256 bullOi,
    uint256 bearOi,
    uint64 lastFundingTime,
    uint256 currentTimestamp,
    uint256 vaultDepthUsdc,
    CfdTypes.RiskParams memory riskParams
) internal pure returns (int256 fundingUsdc);

computeFundingStep

function computeFundingStep(
    FundingStepInputs memory inputs
) internal pure returns (FundingStepResult memory result);

buildPositionRiskState

function buildPositionRiskState(
    CfdTypes.Position memory pos,
    uint256 price,
    uint256 capPrice,
    int256 pendingFundingUsdc,
    uint256 reachableCollateralUsdc,
    uint256 requiredBps
) internal pure returns (PositionRiskState memory state);

Structs

FundingStepInputs

struct FundingStepInputs {
    uint256 price;
    uint256 bullOi;
    uint256 bearOi;
    uint256 timeDelta;
    uint256 vaultDepthUsdc;
    CfdTypes.RiskParams riskParams;
}

FundingStepResult

struct FundingStepResult {
    uint256 absSkewUsdc;
    int256 bullFundingIndexDelta;
    int256 bearFundingIndexDelta;
}

PositionRiskState

struct PositionRiskState {
    int256 pendingFundingUsdc;
    int256 unrealizedPnlUsdc;
    int256 equityUsdc;
    uint256 currentNotionalUsdc;
    uint256 maintenanceMarginUsdc;
    bool liquidatable;
}

SolvencyAccountingLib

Git Source

Functions

getMaxLiability

function getMaxLiability(
    uint256 bullMaxProfitUsdc,
    uint256 bearMaxProfitUsdc
) internal pure returns (uint256);

getMaxLiabilityAfterClose

function getMaxLiabilityAfterClose(
    uint256 bullMaxProfitUsdc,
    uint256 bearMaxProfitUsdc,
    CfdTypes.Side side,
    uint256 maxProfitReductionUsdc
) internal pure returns (uint256);

buildSolvencyState

function buildSolvencyState(
    uint256 physicalAssetsUsdc,
    uint256 protocolFeesUsdc,
    uint256 maxLiabilityUsdc,
    int256 solvencyFundingPnlUsdc,
    uint256 deferredTraderPayoutUsdc,
    uint256 deferredClearerBountyUsdc
) internal pure returns (SolvencyState memory state);

effectiveAssetsAfterPendingPayout

function effectiveAssetsAfterPendingPayout(
    SolvencyState memory state,
    uint256 pendingVaultPayoutUsdc
) internal pure returns (uint256);

isInsolvent

function isInsolvent(
    SolvencyState memory state
) internal pure returns (bool);

previewPostOpSolvency

function previewPostOpSolvency(
    SolvencyState memory currentState,
    PreviewDelta memory delta,
    bool alreadyDegraded
) internal pure returns (PreviewResult memory result);

_applySignedDelta

function _applySignedDelta(
    uint256 value,
    int256 delta
) private pure returns (uint256 updatedValue);

Structs

PreviewDelta

struct PreviewDelta {
    int256 physicalAssetsDeltaUsdc;
    uint256 protocolFeesDeltaUsdc;
    uint256 maxLiabilityAfterUsdc;
    int256 deferredTraderPayoutDeltaUsdc;
    int256 deferredLiquidationBountyDeltaUsdc;
    uint256 pendingVaultPayoutUsdc;
}

PreviewResult

struct PreviewResult {
    uint256 effectiveAssetsAfterUsdc;
    uint256 maxLiabilityAfterUsdc;
    bool triggersDegradedMode;
    bool postOpDegradedMode;
}

SolvencyState

struct SolvencyState {
    uint256 physicalAssetsUsdc;
    uint256 protocolFeesUsdc;
    uint256 netPhysicalAssetsUsdc;
    uint256 maxLiabilityUsdc;
    int256 solvencyFundingPnlUsdc;
    uint256 deferredTraderPayoutUsdc;
    uint256 deferredClearerBountyUsdc;
    uint256 effectiveAssetsUsdc;
}

WithdrawalAccountingLib

Git Source

Functions

buildWithdrawalState

function buildWithdrawalState(
    uint256 physicalAssetsUsdc,
    uint256 maxLiabilityUsdc,
    uint256 protocolFeesUsdc,
    uint256 fundingLiabilityUsdc,
    uint256 deferredTraderPayoutUsdc,
    uint256 deferredClearerBountyUsdc
) internal pure returns (WithdrawalState memory state);

Structs

WithdrawalState

struct WithdrawalState {
    uint256 physicalAssetsUsdc;
    uint256 maxLiabilityUsdc;
    uint256 protocolFeesUsdc;
    uint256 fundingLiabilityUsdc;
    uint256 deferredTraderPayoutUsdc;
    uint256 deferredClearerBountyUsdc;
    uint256 reservedUsdc;
    uint256 freeUsdc;
}

Contents

OrderEscrowAccounting

Git Source

Inherits: IOrderRouterAccounting

Constants

engine

ICfdEngine public immutable engine

clearinghouse

IMarginClearinghouse internal immutable clearinghouse

USDC

IERC20 internal immutable USDC

State Variables

orderRecords

mapping(uint64 => OrderRecord) internal orderRecords

pendingOrderCounts

mapping(bytes32 => uint256) public pendingOrderCounts

pendingCloseSize

mapping(bytes32 => uint256) public pendingCloseSize

marginHeadOrderId

mapping(bytes32 => uint64) public marginHeadOrderId

marginTailOrderId

mapping(bytes32 => uint64) public marginTailOrderId

claimableUsdc

mapping(address => uint256) public claimableUsdc

Functions

constructor

constructor(
    address _engine
) ;

getAccountEscrow

function getAccountEscrow(
    bytes32 accountId
) public view override returns (IOrderRouterAccounting.AccountEscrowView memory escrow);

getAccountOrderSummary

function getAccountOrderSummary(
    bytes32 accountId
) public view returns (IOrderRouterAccounting.AccountOrderSummary memory summary);

_summarizePendingOrders

function _summarizePendingOrders(
    bytes32 accountId
)
    internal
    view
    returns (
        uint256 pendingOrderCount,
        uint256 executionBountyUsdc,
        uint256 pendingCloseSize_,
        bool hasTerminalCloseQueued
    );

getMarginReservationIds

function getMarginReservationIds(
    bytes32 accountId
) public view override returns (uint64[] memory orderIds);

_reserveExecutionBounty

function _reserveExecutionBounty(
    bytes32 accountId,
    uint64 orderId,
    uint256 executionBountyUsdc,
    bool isClose
) internal;

_reserveCommittedMargin

function _reserveCommittedMargin(
    bytes32 accountId,
    uint64 orderId,
    bool isClose,
    uint256 marginDelta
) internal;

_consumeOrderEscrow

function _consumeOrderEscrow(
    uint64 orderId,
    bool success,
    uint8 failedPolicy
) internal returns (uint256 executionBountyUsdc);

_collectExecutionBounty

function _collectExecutionBounty(
    uint64 orderId
) internal returns (uint256 executionBountyUsdc);

_refundExecutionBounty

function _refundExecutionBounty(
    uint64 orderId
) internal;

_tryTransferUsdc

function _tryTransferUsdc(
    address to,
    uint256 amount
) internal returns (bool success);

_releaseCommittedMargin

function _releaseCommittedMargin(
    uint64 orderId
) internal;

_linkMarginOrder

function _linkMarginOrder(
    bytes32 accountId,
    uint64 orderId
) internal;

_unlinkMarginOrder

function _unlinkMarginOrder(
    bytes32 accountId,
    uint64 orderId
) internal;

_pruneMarginQueue

function _pruneMarginQueue(
    bytes32 accountId
) internal;

_orderRecord

function _orderRecord(
    uint64 orderId
) internal view virtual returns (OrderRecord storage record);

_pendingHeadOrderId

function _pendingHeadOrderId(
    bytes32 accountId
) internal view virtual returns (uint64);

_reserveCloseExecutionBounty

function _reserveCloseExecutionBounty(
    bytes32 accountId,
    uint256 executionBountyUsdc
) internal virtual;

_revertInsufficientFreeEquity

function _revertInsufficientFreeEquity() internal pure virtual;

_revertMarginOrderLinkCorrupted

function _revertMarginOrderLinkCorrupted() internal pure virtual;

Structs

OrderRecord

struct OrderRecord {
    CfdTypes.Order core;
    IOrderRouterAccounting.OrderStatus status;
    uint256 executionBountyUsdc;
    uint64 retryAfterTimestamp;
    uint64 nextPendingOrderId;
    uint64 prevPendingOrderId;
    uint64 nextGlobalOrderId;
    uint64 prevGlobalOrderId;
    uint64 nextMarginOrderId;
    uint64 prevMarginOrderId;
    bool inMarginQueue;
}

CfdEngine

Git Source

Inherits: IWithdrawGuard, Ownable2Step, ReentrancyGuardTransient

Title: CfdEngine

The core mathematical ledger for Plether CFDs.

Settles all funds through the MarginClearinghouse and CfdVault.

Note: security-contact: contact@plether.com

Constants

CAP_PRICE

uint256 public immutable CAP_PRICE

USDC

IERC20 public immutable USDC

clearinghouse

IMarginClearinghouse public immutable clearinghouse

EXECUTION_FEE_BPS

uint256 public constant EXECUTION_FEE_BPS = 4

TIMELOCK_DELAY

uint256 public constant TIMELOCK_DELAY = 48 hours

State Variables

vault

ICfdVault public vault

sides

SideState[2] public sides

lastMarkPrice

uint256 public lastMarkPrice

lastMarkTime

uint64 public lastMarkTime

accumulatedFeesUsdc

uint256 public accumulatedFeesUsdc

accumulatedBadDebtUsdc

uint256 public accumulatedBadDebtUsdc

degradedMode

bool public degradedMode

lastFundingTime

uint64 public lastFundingTime

riskParams

CfdTypes.RiskParams public riskParams

_positions

mapping(bytes32 => StoredPosition) internal _positions

deferredPayoutUsdc

mapping(bytes32 => uint256) public deferredPayoutUsdc

totalDeferredPayoutUsdc

uint256 public totalDeferredPayoutUsdc

deferredClearerBountyUsdc

mapping(address => uint256) public deferredClearerBountyUsdc

totalDeferredClearerBountyUsdc

uint256 public totalDeferredClearerBountyUsdc

deferredClaims

mapping(uint64 => ICfdEngine.DeferredClaim) public deferredClaims

nextDeferredClaimId

uint64 public nextDeferredClaimId = 1

deferredClaimHeadId

uint64 public deferredClaimHeadId

deferredClaimTailId

uint64 public deferredClaimTailId

traderDeferredClaimIdByAccount

mapping(bytes32 => uint64) public traderDeferredClaimIdByAccount

clearerDeferredClaimIdByKeeper

mapping(address => uint64) public clearerDeferredClaimIdByKeeper

orderRouter

address public orderRouter

fadDayOverrides

mapping(uint256 => bool) public fadDayOverrides

fadMaxStaleness

uint256 public fadMaxStaleness = 3 days

fadRunwaySeconds

uint256 public fadRunwaySeconds = 3 hours

engineMarkStalenessLimit

uint256 public engineMarkStalenessLimit = 60

pendingRiskParams

CfdTypes.RiskParams public pendingRiskParams

riskParamsActivationTime

uint256 public riskParamsActivationTime

_pendingAddFadDays

uint256[] private _pendingAddFadDays

addFadDaysActivationTime

uint256 public addFadDaysActivationTime

_pendingRemoveFadDays

uint256[] private _pendingRemoveFadDays

removeFadDaysActivationTime

uint256 public removeFadDaysActivationTime

pendingFadMaxStaleness

uint256 public pendingFadMaxStaleness

fadMaxStalenessActivationTime

uint256 public fadMaxStalenessActivationTime

pendingFadRunway

uint256 public pendingFadRunway

fadRunwayActivationTime

uint256 public fadRunwayActivationTime

pendingEngineMarkStalenessLimit

uint256 public pendingEngineMarkStalenessLimit

engineMarkStalenessActivationTime

uint256 public engineMarkStalenessActivationTime

Functions

_sideIndex

function _sideIndex(
    CfdTypes.Side side
) internal pure returns (uint256);

_sideState

function _sideState(
    CfdTypes.Side side
) internal view returns (SideState storage state);

_oppositeSide

function _oppositeSide(
    CfdTypes.Side side
) internal pure returns (CfdTypes.Side);

_sideAndOppositeStates

function _sideAndOppositeStates(
    CfdTypes.Side side
) internal view returns (SideState storage selected, SideState storage opposite);

_bullAndBearStates

function _bullAndBearStates() internal view returns (SideState storage bullState, SideState storage bearState);

getSideState

function getSideState(
    CfdTypes.Side side
) public view returns (ICfdEngine.SideState memory state);

_requireTimelockReady

function _requireTimelockReady(
    uint256 activationTime
) internal view;

onlyRouter

modifier onlyRouter() ;

constructor

constructor(
    address _usdc,
    address _clearinghouse,
    uint256 _capPrice,
    CfdTypes.RiskParams memory _riskParams
) Ownable(msg.sender);

Parameters

NameTypeDescription
_usdcaddressUSDC token used as margin and settlement currency
_clearinghouseaddressMargin clearinghouse that custodies trader balances
_capPriceuint256Maximum oracle price — positions are clamped here (also determines BULL max profit)
_riskParamsCfdTypes.RiskParamsInitial risk parameters (margin requirements, funding curve, bounty config)

setVault

One-time setter for the HousePool vault backing all positions

function setVault(
    address _vault
) external onlyOwner;

setOrderRouter

One-time setter for the authorized OrderRouter

function setOrderRouter(
    address _router
) external onlyOwner;

proposeRiskParams

Proposes new risk parameters (margin BPS, funding curve, bounty config) subject to timelock

function proposeRiskParams(
    CfdTypes.RiskParams memory _riskParams
) external onlyOwner;

finalizeRiskParams

Applies proposed risk parameters after timelock expires; settles funding first

function finalizeRiskParams() external onlyOwner;

cancelRiskParamsProposal

Cancels a pending risk parameters proposal

function cancelRiskParamsProposal() external onlyOwner;

proposeAddFadDays

Proposes adding FAD (Friday Afternoon Deleverage) override days — elevated margin on those dates

function proposeAddFadDays(
    uint256[] calldata timestamps
) external onlyOwner;

finalizeAddFadDays

Applies proposed FAD day additions after timelock expires

function finalizeAddFadDays() external onlyOwner;

cancelAddFadDaysProposal

Cancels a pending add-FAD-days proposal

function cancelAddFadDaysProposal() external onlyOwner;

proposeRemoveFadDays

Proposes removing FAD override days (restores normal margin on those dates)

function proposeRemoveFadDays(
    uint256[] calldata timestamps
) external onlyOwner;

finalizeRemoveFadDays

Applies proposed FAD day removals after timelock expires

function finalizeRemoveFadDays() external onlyOwner;

cancelRemoveFadDaysProposal

Cancels a pending remove-FAD-days proposal

function cancelRemoveFadDaysProposal() external onlyOwner;

proposeFadMaxStaleness

Proposes a new fadMaxStaleness — max age of the last mark price before FAD kicks in

function proposeFadMaxStaleness(
    uint256 _seconds
) external onlyOwner;

finalizeFadMaxStaleness

Applies proposed fadMaxStaleness after timelock expires

function finalizeFadMaxStaleness() external onlyOwner;

cancelFadMaxStalenessProposal

Cancels a pending fadMaxStaleness proposal

function cancelFadMaxStalenessProposal() external onlyOwner;

proposeFadRunway

Proposes a new fadRunway — how many seconds before an FAD day the elevated margin activates

function proposeFadRunway(
    uint256 _seconds
) external onlyOwner;

finalizeFadRunway

Applies proposed fadRunway after timelock expires

function finalizeFadRunway() external onlyOwner;

cancelFadRunwayProposal

Cancels a pending fadRunway proposal

function cancelFadRunwayProposal() external onlyOwner;

proposeEngineMarkStalenessLimit

function proposeEngineMarkStalenessLimit(
    uint256 newStaleness
) external onlyOwner;

finalizeEngineMarkStalenessLimit

function finalizeEngineMarkStalenessLimit() external onlyOwner;

cancelEngineMarkStalenessLimitProposal

function cancelEngineMarkStalenessLimitProposal() external onlyOwner;

withdrawFees

Withdraws accumulated execution fees from the vault to a recipient

function withdrawFees(
    address recipient
) external onlyOwner;

absorbRouterCancellationFee

Pulls router-custodied cancellation fees into the vault and books them as protocol revenue.

function absorbRouterCancellationFee(
    uint256 amountUsdc
) external onlyRouter;

recordRouterProtocolFee

Books router-delivered protocol-owned inflow as protocol fees after the router has already synced funding and funded the vault.

function recordRouterProtocolFee(
    uint256 amountUsdc
) external onlyRouter;

addMargin

Adds isolated margin to an existing open position without changing size.

function addMargin(
    bytes32 accountId,
    uint256 amount
) external nonReentrant;

claimDeferredPayout

Claims a previously deferred profitable close payout into the clearinghouse.

The payout remains subject to current vault cash availability. Funds are credited to the clearinghouse first, so traders access them through the normal account-balance path.

function claimDeferredPayout(
    bytes32 accountId
) external nonReentrant;

claimDeferredClearerBounty

Claims a previously deferred clearer bounty when the vault has replenished cash.

Deferred keeper bounties settle to clearinghouse credit for the recorded keeper address-derived account, rather than attempting a direct USDC wallet transfer.

function claimDeferredClearerBounty() external nonReentrant;

recordDeferredClearerBounty

Records a liquidation bounty that could not be paid immediately because vault cash was unavailable.

function recordDeferredClearerBounty(
    address keeper,
    uint256 amountUsdc
) external onlyRouter;

reserveCloseOrderExecutionBounty

function reserveCloseOrderExecutionBounty(
    bytes32 accountId,
    uint256 amountUsdc,
    address recipient
) external onlyRouter;

clearBadDebt

Reduces accumulated bad debt after governance-confirmed recapitalization

function clearBadDebt(
    uint256 amount
) external onlyOwner;

Parameters

NameTypeDescription
amountuint256USDC amount of bad debt to clear (6 decimals)

clearDegradedMode

function clearDegradedMode() external onlyOwner;

checkWithdraw

Reverts if the account has an open position that would be undercollateralized after withdrawal

function checkWithdraw(
    bytes32 accountId
) external view override;

Parameters

NameTypeDescription
accountIdbytes32Clearinghouse account to check

syncFunding

Materializes accrued funding into storage so subsequent reads reflect current state. O(1) gas, idempotent (no-op if called twice in the same block).

function syncFunding() external;

_syncFunding

Canonical internal funding sync. Every function that changes vault cash or reads funding-dependent state must call this first. Using a dedicated helper instead of inline _updateFunding(lastMarkPrice, vault.totalAssets()) ensures new call sites cannot silently skip the sync.

function _syncFunding() internal;

_syncFundingForMarkUpdate

function _syncFundingForMarkUpdate() internal;

_updateFunding

function _updateFunding(
    uint256 currentOraclePrice,
    uint256 vaultDepthUsdc
) internal;

getPendingFunding

Returns unsettled funding owed to (+) or by (-) a position in USDC (6 decimals)

function getPendingFunding(
    CfdTypes.Position memory pos
) public view returns (int256 fundingUsdc);

Parameters

NameTypeDescription
posCfdTypes.PositionThe position to compute pending funding for

Returns

NameTypeDescription
fundingUsdcint256Positive if the position is owed funding, negative if it owes

processOrder

Executes an order: settles funding, then increases or decreases the position. Called exclusively by OrderRouter after MEV and slippage checks pass.

function processOrder(
    CfdTypes.Order memory order,
    uint256 currentOraclePrice,
    uint256 vaultDepthUsdc,
    uint64 publishTime
) external onlyRouter nonReentrant;

Parameters

NameTypeDescription
orderCfdTypes.OrderThe order to execute (account, side, size delta, margin delta, isClose)
currentOraclePriceuint256Pyth oracle price (8 decimals), clamped to CAP_PRICE
vaultDepthUsdcuint256HousePool total assets — used to scale funding rate
publishTimeuint64Pyth publish timestamp, stored as lastMarkTime

processOrderTyped

Router-facing order execution entrypoint with typed business-rule failures.

function processOrderTyped(
    CfdTypes.Order memory order,
    uint256 currentOraclePrice,
    uint256 vaultDepthUsdc,
    uint64 publishTime
) external onlyRouter nonReentrant;

_processOrder

function _processOrder(
    CfdTypes.Order memory order,
    uint256 currentOraclePrice,
    uint256 vaultDepthUsdc,
    uint64 publishTime,
    bool typedFailures
) internal;

_syncTotalSideMargin

function _syncTotalSideMargin(
    CfdTypes.Side side,
    uint256 marginBefore,
    uint256 marginAfter
) internal;

_syncMarginQueue

function _syncMarginQueue(
    bytes32 accountId,
    uint256 consumedCommittedReservationUsdc
) internal;

_payOrRecordDeferredTraderPayout

function _payOrRecordDeferredTraderPayout(
    bytes32 accountId,
    uint256 amountUsdc
) internal;

_enqueueOrAccrueDeferredTraderPayout

function _enqueueOrAccrueDeferredTraderPayout(
    bytes32 accountId,
    uint256 amountUsdc
) internal;

_enqueueOrAccrueDeferredClearerBounty

function _enqueueOrAccrueDeferredClearerBounty(
    address keeper,
    uint256 amountUsdc
) internal;

_accountVaultCashInflow

function _accountVaultCashInflow(
    VaultCashInflow memory inflow
) internal;

_canPayFreshVaultPayout

function _canPayFreshVaultPayout(
    uint256 amountUsdc
) internal view returns (bool);

_canWithdrawProtocolFees

function _canWithdrawProtocolFees(
    uint256 amountUsdc
) internal view returns (bool);

_availableCashForFreshVaultPayouts

function _availableCashForFreshVaultPayouts() internal view returns (uint256);

_claimableHeadAmountUsdc

function _claimableHeadAmountUsdc() internal view returns (uint256);

_freshVaultReservation

function _freshVaultReservation() internal view returns (CashPriorityLib.SeniorCashReservation memory reservation);

_headDeferredClaimReservation

function _headDeferredClaimReservation(
    uint256 headClaimAmountUsdc
) internal view returns (CashPriorityLib.SeniorCashReservation memory reservation);

_enqueueDeferredClaim

function _enqueueDeferredClaim(
    ICfdEngine.DeferredClaimType claimType,
    bytes32 accountId,
    address keeper,
    uint256 amountUsdc
) internal returns (uint64 claimId);

_popDeferredClaimHead

function _popDeferredClaimHead() internal;

_unlinkDeferredClaim

function _unlinkDeferredClaim(
    uint64 claimId
) internal;

isFadWindow

Returns true during the Friday Afternoon Deleverage (FAD) window (Friday 19:00 UTC → Sunday 22:00 UTC), on admin-configured FAD days, or within fadRunwaySeconds before an admin FAD day (deleverage runway).

function isFadWindow() public view returns (bool);

isOracleFrozen

Returns true only when FX markets are closed and oracle freshness can be relaxed. Distinct from FAD, which starts earlier for deleveraging risk controls.

function isOracleFrozen() public view returns (bool);

hasOpenPosition

function hasOpenPosition(
    bytes32 accountId
) external view returns (bool);

positions

function positions(
    bytes32 accountId
)
    external
    view
    returns (
        uint256 size,
        uint256 margin,
        uint256 entryPrice,
        uint256 maxProfitUsdc,
        int256 entryFundingIndex,
        CfdTypes.Side side,
        uint64 lastUpdateTime,
        int256 vpiAccrued
    );

getPositionSize

function getPositionSize(
    bytes32 accountId
) external view returns (uint256);

getAccountCollateralView

function getAccountCollateralView(
    bytes32 accountId
) external view returns (AccountCollateralView memory viewData);

getAccountLedgerView

function getAccountLedgerView(
    bytes32 accountId
) external view returns (ICfdEngine.AccountLedgerView memory viewData);

getAccountLedgerSnapshot

function getAccountLedgerSnapshot(
    bytes32 accountId
) external view returns (ICfdEngine.AccountLedgerSnapshot memory snapshot);

_buildAccountLedgerSnapshot

function _buildAccountLedgerSnapshot(
    bytes32 accountId
) internal view returns (ICfdEngine.AccountLedgerSnapshot memory snapshot);

getPositionView

function getPositionView(
    bytes32 accountId
) external view returns (PositionView memory viewData);

getProtocolAccountingView

function getProtocolAccountingView() external view returns (ProtocolAccountingView memory viewData);

getProtocolAccountingSnapshot

function getProtocolAccountingSnapshot()
    external
    view
    returns (ICfdEngine.ProtocolAccountingSnapshot memory snapshot);

_buildProtocolAccountingSnapshot

function _buildProtocolAccountingSnapshot()
    internal
    view
    returns (ICfdEngine.ProtocolAccountingSnapshot memory snapshot);

previewOpenRevertCode

function previewOpenRevertCode(
    bytes32 accountId,
    CfdTypes.Side side,
    uint256 sizeDelta,
    uint256 marginDelta,
    uint256 oraclePrice,
    uint64 publishTime
) external view returns (uint8 code);

previewOpenFailurePolicyCategory

function previewOpenFailurePolicyCategory(
    bytes32 accountId,
    CfdTypes.Side side,
    uint256 sizeDelta,
    uint256 marginDelta,
    uint256 oraclePrice,
    uint64 publishTime
) external view returns (CfdEnginePlanTypes.OpenFailurePolicyCategory category);

getDeferredPayoutStatus

function getDeferredPayoutStatus(
    bytes32 accountId,
    address keeper
) external view returns (DeferredPayoutStatus memory status);

getDeferredClaimHead

function getDeferredClaimHead() external view returns (ICfdEngine.DeferredClaim memory claim);

getDeferredTraderStatus

function getDeferredTraderStatus(
    bytes32 accountId
) public view returns (ICfdEngine.DeferredTraderStatus memory status);

getDeferredClearerStatus

function getDeferredClearerStatus(
    address keeper
) public view returns (ICfdEngine.DeferredClearerStatus memory status);

previewClose

Canonical close preview using the vault’s current accounted depth.

function previewClose(
    bytes32 accountId,
    uint256 sizeDelta,
    uint256 oraclePrice
) external view returns (ClosePreview memory preview);

simulateClose

Hypothetical close simulation at a caller-supplied vault depth.

function simulateClose(
    bytes32 accountId,
    uint256 sizeDelta,
    uint256 oraclePrice,
    uint256 vaultDepthUsdc
) external view returns (ClosePreview memory preview);

_previewClose

function _previewClose(
    bytes32 accountId,
    uint256 sizeDelta,
    uint256 oraclePrice,
    uint256 vaultDepthUsdc
) internal view returns (ClosePreview memory preview);

previewLiquidation

Canonical liquidation preview using the vault’s current accounted depth.

function previewLiquidation(
    bytes32 accountId,
    uint256 oraclePrice
) external view returns (LiquidationPreview memory preview);

simulateLiquidation

Hypothetical liquidation simulation at a caller-supplied vault depth.

function simulateLiquidation(
    bytes32 accountId,
    uint256 oraclePrice,
    uint256 vaultDepthUsdc
) external view returns (LiquidationPreview memory preview);

_previewLiquidation

function _previewLiquidation(
    bytes32 accountId,
    uint256 oraclePrice,
    uint256 vaultDepthUsdc
) internal view returns (LiquidationPreview memory preview);

_applyLiquidationPreviewForfeiture

function _applyLiquidationPreviewForfeiture(
    bytes32 accountId,
    CfdEnginePlanTypes.RawSnapshot memory snap
) internal view;

getPositionSide

function getPositionSide(
    bytes32 accountId
) external view returns (CfdTypes.Side);

getMaintenanceMarginUsdc

Returns the maintenance margin requirement in USDC (6 decimals). Uses fadMarginBps during the FAD window, maintMarginBps otherwise.

function getMaintenanceMarginUsdc(
    uint256 size,
    uint256 currentOraclePrice
) public view returns (uint256);

Parameters

NameTypeDescription
sizeuint256Position size in tokens (18 decimals)
currentOraclePriceuint256Oracle price (8 decimals)

liquidatePosition

Liquidates an undercollateralized position. Surplus equity (after bounty) is returned to the user. In bad-debt cases (equity < bounty), all remaining margin is seized by the vault.

function liquidatePosition(
    bytes32 accountId,
    uint256 currentOraclePrice,
    uint256 vaultDepthUsdc,
    uint64 publishTime
) external onlyRouter nonReentrant returns (uint256 keeperBountyUsdc);

Parameters

NameTypeDescription
accountIdbytes32Clearinghouse account that owns the position
currentOraclePriceuint256Pyth oracle price (8 decimals), clamped to CAP_PRICE
vaultDepthUsdcuint256HousePool total assets — used to scale funding rate
publishTimeuint64Pyth publish timestamp, stored as lastMarkTime

Returns

NameTypeDescription
keeperBountyUsdcuint256Bounty paid to the liquidation keeper (USDC, 6 decimals)

_assertPostSolvency

function _assertPostSolvency() internal view;

_maxLiability

function _maxLiability() internal view returns (uint256);

_getWithdrawalReservedUsdc

function _getWithdrawalReservedUsdc() internal view returns (uint256 reservedUsdc);

_buildHousePoolInputSnapshot

function _buildHousePoolInputSnapshot(
    uint256 markStalenessLimit
) internal view returns (ICfdEngine.HousePoolInputSnapshot memory snapshot);

_buildHousePoolStatusSnapshot

function _buildHousePoolStatusSnapshot()
    internal
    view
    returns (ICfdEngine.HousePoolStatusSnapshot memory snapshot);

_buildAdjustedSolvencyState

function _buildAdjustedSolvencyState() internal view returns (SolvencyAccountingLib.SolvencyState memory);

_buildAdjustedSolvencySnapshot

function _buildAdjustedSolvencySnapshot()
    internal
    view
    returns (CfdEngineSnapshotsLib.SolvencySnapshot memory snapshot);

_buildRawSnapshot

function _buildRawSnapshot(
    bytes32 accountId,
    uint256,
    uint256 vaultDepthUsdc,
    uint64
) internal view returns (CfdEnginePlanTypes.RawSnapshot memory snap);

_copySideSnapshot

function _copySideSnapshot(
    SideState storage state
) internal view returns (CfdEnginePlanTypes.SideSnapshot memory snap);

_getProjectedPendingFunding

function _getProjectedPendingFunding(
    bytes32 accountId,
    CfdTypes.Position memory pos
) internal view returns (int256 fundingUsdc);

_buildProjectedPositionRiskState

function _buildProjectedPositionRiskState(
    bytes32 accountId,
    CfdTypes.Position memory pos,
    uint256 price,
    uint256 reachableUsdc,
    uint256 riskBps
) internal view returns (PositionRiskAccountingLib.PositionRiskState memory riskState);

_tryGetFreshLiveMarkPrice

function _tryGetFreshLiveMarkPrice() internal view returns (bool fresh, uint256 price);

_revertIfOpenInvalid

function _revertIfOpenInvalid(
    CfdEnginePlanTypes.OpenRevertCode code
) internal pure;

_revertIfOpenInvalidTyped

function _revertIfOpenInvalidTyped(
    CfdEnginePlanTypes.OpenRevertCode code
) internal pure;

_revertIfCloseInvalid

function _revertIfCloseInvalid(
    CfdEnginePlanTypes.CloseRevertCode code
) internal pure;

_revertIfCloseInvalidTyped

function _revertIfCloseInvalidTyped(
    CfdEnginePlanTypes.CloseRevertCode code
) internal pure;

_applyFundingAndMark

function _applyFundingAndMark(
    int256 bullDelta,
    int256 bearDelta,
    uint256 absSkew,
    uint64 newFundingTime,
    uint256 newMarkPrice,
    uint64 newMarkTime
) internal;

_applyFundingSettlement

function _applyFundingSettlement(
    CfdEnginePlanTypes.FundingDelta memory fd,
    bytes32 accountId,
    StoredPosition storage pos,
    CfdTypes.Side marginSide
) internal returns (uint256 marginAfterFunding);

_applyOpen

function _applyOpen(
    CfdEnginePlanTypes.OpenDelta memory delta
) internal;

_applyClose

function _applyClose(
    CfdEnginePlanTypes.CloseDelta memory delta
) internal;

_applyLiquidation

function _applyLiquidation(
    CfdEnginePlanTypes.LiquidationDelta memory delta
) internal returns (uint256 keeperBountyUsdc);

_enterDegradedModeIfInsolvent

function _enterDegradedModeIfInsolvent(
    bytes32 accountId,
    uint256 pendingVaultPayoutUsdc
) internal;

_physicalReachableCollateralUsdc

function _physicalReachableCollateralUsdc(
    bytes32 accountId
) internal view returns (uint256);

_positionMarginBucketUsdc

function _positionMarginBucketUsdc(
    bytes32 accountId
) internal view returns (uint256);

_loadPosition

function _loadPosition(
    bytes32 accountId
) internal view returns (CfdTypes.Position memory pos);

_liveMarkStalenessLimit

function _liveMarkStalenessLimit() internal view returns (uint256);

_consumeDeferredTraderPayout

function _consumeDeferredTraderPayout(
    bytes32 accountId,
    uint256 amountUsdc
) internal;

_computeGlobalFundingPnl

function _computeGlobalFundingPnl() internal view returns (int256 bullFunding, int256 bearFunding);

_getProjectedFundingIndices

function _getProjectedFundingIndices() internal view returns (int256 bullFundingIndex, int256 bearFundingIndex);

_buildFundingSnapshot

function _buildFundingSnapshot() internal view returns (CfdEngineSnapshotsLib.FundingSnapshot memory snapshot);

_getSolvencyCappedFundingPnl

function _getSolvencyCappedFundingPnl() internal view returns (int256);

_canProjectFundingStep

function _canProjectFundingStep() internal view returns (bool);

_buildFundingStep

function _buildFundingStep(
    uint256 price,
    uint256 vaultDepthUsdc
) internal view returns (PositionRiskAccountingLib.FundingStepResult memory step);

_getLiabilityOnlyFundingPnl

function _getLiabilityOnlyFundingPnl() internal view returns (uint256);

_validateRiskParams

function _validateRiskParams(
    CfdTypes.RiskParams memory _riskParams
) internal pure;

_getUnrealizedFundingPnl

function _getUnrealizedFundingPnl() internal view returns (int256);

getUnrealizedFundingPnl

Aggregate unsettled funding across all positions (uncapped, for reporting only)

function getUnrealizedFundingPnl() external view returns (int256);

Returns

NameTypeDescription
<none>int256Net funding PnL in USDC (6 decimals), positive = traders are owed funding

getCappedFundingPnl

Aggregate unsettled funding across all positions with uncollectible debts capped by margin.

function getCappedFundingPnl() external view returns (int256);

Returns

NameTypeDescription
<none>int256Net funding PnL in USDC (6 decimals), positive = traders are owed funding

getLiabilityOnlyFundingPnl

Aggregate unsettled funding liabilities only, ignoring trader debts owed to the vault.

function getLiabilityOnlyFundingPnl() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256Funding liabilities the vault should conservatively reserve for withdrawals (6 decimals)

getMaxLiability

Returns the protocol’s worst-case directional liability.

function getMaxLiability() external view returns (uint256);

getWithdrawalReservedUsdc

Returns the total USDC reserve required for withdrawals.

function getWithdrawalReservedUsdc() external view returns (uint256);

getHousePoolInputSnapshot

function getHousePoolInputSnapshot(
    uint256 markStalenessLimit
) external view returns (ICfdEngine.HousePoolInputSnapshot memory snapshot);

getHousePoolStatusSnapshot

function getHousePoolStatusSnapshot() external view returns (ICfdEngine.HousePoolStatusSnapshot memory snapshot);

updateMarkPrice

Updates the cached mark price without settling funding or processing trades

function updateMarkPrice(
    uint256 price,
    uint64 publishTime
) external onlyRouter;

Parameters

NameTypeDescription
priceuint256Oracle price (8 decimals), clamped to CAP_PRICE
publishTimeuint64Pyth publish timestamp

hasLiveLiability

Returns true when the protocol still has live bounded directional liability.

function hasLiveLiability() external view returns (bool);

getUnrealizedTraderPnl

Aggregate unrealized PnL of all open positions at lastMarkPrice. Positive = traders winning (house liability). Negative = traders losing (house asset).

function getUnrealizedTraderPnl() external view returns (int256);

Returns

NameTypeDescription
<none>int256Net trader PnL in USDC (6 decimals), sign from the traders’ perspective

getVaultMtmAdjustment

Combined MtM: per-side (PnL + funding), clamped at zero per side then summed. Positive = vault owes traders (unrealized liability). Zero = traders losing or neutral.

function getVaultMtmAdjustment() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256Net MtM liability the vault must reserve, in USDC (6 decimals). Non-negative by construction.

_getVaultMtmLiability

function _getVaultMtmLiability() internal view returns (uint256);

_getProtocolPhase

function _getProtocolPhase() internal view returns (ICfdEngine.ProtocolPhase);

getProtocolPhase

function getProtocolPhase() external view returns (ICfdEngine.ProtocolPhase);

getProtocolStatus

function getProtocolStatus() external view returns (ICfdEngine.ProtocolStatus memory status);

Events

FundingUpdated

event FundingUpdated(int256 bullIndex, int256 bearIndex, uint256 absSkewUsdc);

PositionOpened

event PositionOpened(
    bytes32 indexed accountId, CfdTypes.Side side, uint256 sizeDelta, uint256 price, uint256 marginDelta
);

PositionClosed

event PositionClosed(bytes32 indexed accountId, CfdTypes.Side side, uint256 sizeDelta, uint256 price, int256 pnl);

PositionLiquidated

event PositionLiquidated(
    bytes32 indexed accountId, CfdTypes.Side side, uint256 size, uint256 price, uint256 keeperBounty
);

MarginAdded

event MarginAdded(bytes32 indexed accountId, uint256 amount);

FadDaysAdded

event FadDaysAdded(uint256[] timestamps);

FadDaysRemoved

event FadDaysRemoved(uint256[] timestamps);

FadMaxStalenessUpdated

event FadMaxStalenessUpdated(uint256 newStaleness);

FadRunwayUpdated

event FadRunwayUpdated(uint256 newRunway);

EngineMarkStalenessLimitProposed

event EngineMarkStalenessLimitProposed(uint256 newStaleness, uint256 activationTime);

EngineMarkStalenessLimitUpdated

event EngineMarkStalenessLimitUpdated(uint256 newStaleness);

RiskParamsProposed

event RiskParamsProposed(uint256 activationTime);

RiskParamsFinalized

event RiskParamsFinalized();

AddFadDaysProposed

event AddFadDaysProposed(uint256[] timestamps, uint256 activationTime);

AddFadDaysFinalized

event AddFadDaysFinalized();

RemoveFadDaysProposed

event RemoveFadDaysProposed(uint256[] timestamps, uint256 activationTime);

RemoveFadDaysFinalized

event RemoveFadDaysFinalized();

FadMaxStalenessProposed

event FadMaxStalenessProposed(uint256 newStaleness, uint256 activationTime);

FadMaxStalenessFinalized

event FadMaxStalenessFinalized();

FadRunwayProposed

event FadRunwayProposed(uint256 newRunway, uint256 activationTime);

FadRunwayFinalized

event FadRunwayFinalized();

BadDebtCleared

event BadDebtCleared(uint256 amount, uint256 remaining);

DegradedModeEntered

event DegradedModeEntered(uint256 effectiveAssets, uint256 maxLiability, bytes32 indexed triggeringAccount);

DegradedModeCleared

event DegradedModeCleared();

DeferredPayoutRecorded

event DeferredPayoutRecorded(bytes32 indexed accountId, uint256 amountUsdc);

DeferredPayoutClaimed

event DeferredPayoutClaimed(bytes32 indexed accountId, uint256 amountUsdc);

DeferredClearerBountyRecorded

event DeferredClearerBountyRecorded(address indexed keeper, uint256 amountUsdc);

DeferredClearerBountyClaimed

event DeferredClearerBountyClaimed(address indexed keeper, uint256 amountUsdc);

Errors

CfdEngine__Unauthorized

error CfdEngine__Unauthorized();

CfdEngine__VaultAlreadySet

error CfdEngine__VaultAlreadySet();

CfdEngine__RouterAlreadySet

error CfdEngine__RouterAlreadySet();

CfdEngine__NoFeesToWithdraw

error CfdEngine__NoFeesToWithdraw();

CfdEngine__NoDeferredPayout

error CfdEngine__NoDeferredPayout();

CfdEngine__InsufficientVaultLiquidity

error CfdEngine__InsufficientVaultLiquidity();

CfdEngine__NoDeferredClearerBounty

error CfdEngine__NoDeferredClearerBounty();

CfdEngine__DeferredClaimNotAtHead

error CfdEngine__DeferredClaimNotAtHead();

CfdEngine__MustCloseOpposingPosition

error CfdEngine__MustCloseOpposingPosition();

CfdEngine__FundingExceedsMargin

error CfdEngine__FundingExceedsMargin();

CfdEngine__VaultSolvencyExceeded

error CfdEngine__VaultSolvencyExceeded();

CfdEngine__MarginDrainedByFees

error CfdEngine__MarginDrainedByFees();

CfdEngine__CloseSizeExceedsPosition

error CfdEngine__CloseSizeExceedsPosition();

CfdEngine__NoPositionToLiquidate

error CfdEngine__NoPositionToLiquidate();

CfdEngine__PositionIsSolvent

error CfdEngine__PositionIsSolvent();

CfdEngine__PostOpSolvencyBreach

error CfdEngine__PostOpSolvencyBreach();

CfdEngine__InsufficientInitialMargin

error CfdEngine__InsufficientInitialMargin();

CfdEngine__PositionTooSmall

error CfdEngine__PositionTooSmall();

CfdEngine__WithdrawBlockedByOpenPosition

error CfdEngine__WithdrawBlockedByOpenPosition();

CfdEngine__EmptyDays

error CfdEngine__EmptyDays();

CfdEngine__ZeroStaleness

error CfdEngine__ZeroStaleness();

CfdEngine__RunwayTooLong

error CfdEngine__RunwayTooLong();

CfdEngine__PartialCloseUnderwaterFunding

error CfdEngine__PartialCloseUnderwaterFunding();

CfdEngine__DustPosition

error CfdEngine__DustPosition();

CfdEngine__MarkPriceStale

error CfdEngine__MarkPriceStale();

CfdEngine__MarkPriceOutOfOrder

error CfdEngine__MarkPriceOutOfOrder();

CfdEngine__NotAccountOwner

error CfdEngine__NotAccountOwner();

CfdEngine__NoOpenPosition

error CfdEngine__NoOpenPosition();

CfdEngine__TimelockNotReady

error CfdEngine__TimelockNotReady();

CfdEngine__NoProposal

error CfdEngine__NoProposal();

CfdEngine__BadDebtTooLarge

error CfdEngine__BadDebtTooLarge();

CfdEngine__InvalidRiskParams

error CfdEngine__InvalidRiskParams();

CfdEngine__SkewTooHigh

error CfdEngine__SkewTooHigh();

CfdEngine__DegradedMode

error CfdEngine__DegradedMode();

CfdEngine__NotDegraded

error CfdEngine__NotDegraded();

CfdEngine__StillInsolvent

error CfdEngine__StillInsolvent();

CfdEngine__ZeroAddress

error CfdEngine__ZeroAddress();

CfdEngine__InsufficientCloseOrderBountyBacking

error CfdEngine__InsufficientCloseOrderBountyBacking();

CfdEngine__InvalidVaultCashInflow

error CfdEngine__InvalidVaultCashInflow();

Structs

AccountCollateralView

struct AccountCollateralView {
    uint256 settlementBalanceUsdc;
    uint256 lockedMarginUsdc;
    // Clearinghouse custody bucket for currently locked live position backing.
    uint256 activePositionMarginUsdc;
    uint256 otherLockedMarginUsdc;
    uint256 freeSettlementUsdc;
    // Current UI helper only; this does not include terminally reachable queued committed margin.
    uint256 closeReachableUsdc;
    uint256 terminalReachableUsdc;
    uint256 accountEquityUsdc;
    uint256 freeBuyingPowerUsdc;
    uint256 deferredPayoutUsdc;
}

PositionView

struct PositionView {
    bool exists;
    CfdTypes.Side side;
    uint256 size;
    uint256 margin;
    uint256 entryPrice;
    uint256 entryNotionalUsdc;
    uint256 physicalReachableCollateralUsdc;
    uint256 nettableDeferredPayoutUsdc;
    int256 unrealizedPnlUsdc;
    int256 pendingFundingUsdc;
    int256 netEquityUsdc;
    uint256 maxProfitUsdc;
    bool liquidatable;
}

ProtocolAccountingView

struct ProtocolAccountingView {
    uint256 vaultAssetsUsdc;
    uint256 maxLiabilityUsdc;
    uint256 withdrawalReservedUsdc;
    uint256 freeUsdc;
    uint256 accumulatedFeesUsdc;
    int256 cappedFundingPnlUsdc;
    uint256 liabilityOnlyFundingPnlUsdc;
    uint256 totalDeferredPayoutUsdc;
    uint256 totalDeferredClearerBountyUsdc;
    bool degradedMode;
    bool hasLiveLiability;
}

ClosePreview

struct ClosePreview {
    bool valid;
    CfdTypes.CloseInvalidReason invalidReason;
    uint256 executionPrice;
    uint256 sizeDelta;
    int256 realizedPnlUsdc;
    int256 fundingUsdc;
    int256 vpiDeltaUsdc;
    uint256 vpiUsdc;
    uint256 executionFeeUsdc;
    uint256 freshTraderPayoutUsdc;
    uint256 existingDeferredConsumedUsdc;
    uint256 existingDeferredRemainingUsdc;
    uint256 immediatePayoutUsdc;
    uint256 deferredPayoutUsdc;
    uint256 seizedCollateralUsdc;
    uint256 badDebtUsdc;
    uint256 remainingSize;
    uint256 remainingMargin;
    bool triggersDegradedMode;
    bool postOpDegradedMode;
    uint256 effectiveAssetsAfterUsdc;
    uint256 maxLiabilityAfterUsdc;
    int256 solvencyFundingPnlUsdc;
}

LiquidationPreview

struct LiquidationPreview {
    bool liquidatable;
    uint256 oraclePrice;
    int256 equityUsdc;
    int256 pnlUsdc;
    int256 fundingUsdc;
    uint256 reachableCollateralUsdc;
    uint256 keeperBountyUsdc;
    uint256 seizedCollateralUsdc;
    uint256 settlementRetainedUsdc;
    uint256 freshTraderPayoutUsdc;
    uint256 existingDeferredConsumedUsdc;
    uint256 existingDeferredRemainingUsdc;
    uint256 immediatePayoutUsdc;
    uint256 deferredPayoutUsdc;
    uint256 badDebtUsdc;
    bool triggersDegradedMode;
    bool postOpDegradedMode;
    uint256 effectiveAssetsAfterUsdc;
    uint256 maxLiabilityAfterUsdc;
    int256 solvencyFundingPnlUsdc;
}

DeferredPayoutStatus

struct DeferredPayoutStatus {
    uint256 deferredTraderPayoutUsdc;
    bool traderPayoutClaimableNow;
    uint256 deferredClearerBountyUsdc;
    bool liquidationBountyClaimableNow;
}

SideState

struct SideState {
    uint256 maxProfitUsdc;
    uint256 openInterest;
    uint256 entryNotional;
    // Cached aggregate of engine economic position margins for this side; not a custody bucket.
    uint256 totalMargin;
    int256 fundingIndex;
    int256 entryFunding;
}

VaultCashInflow

struct VaultCashInflow {
    uint256 physicalCashReceivedUsdc;
    uint256 protocolOwnedUsdc;
    uint256 lpOwnedUsdc;
}

StoredPosition

struct StoredPosition {
    uint256 size;
    uint256 entryPrice;
    uint256 maxProfitUsdc;
    int256 entryFundingIndex;
    CfdTypes.Side side;
    uint64 lastUpdateTime;
    int256 vpiAccrued;
}

CfdEnginePlanTypes

Git Source

Title: CfdEnginePlanTypes

Snapshot and delta structs for the plan→apply architecture. Plan functions are pure over a RawSnapshot and return typed deltas. Apply functions consume deltas to perform state mutations and external calls.

Structs

SideSnapshot

struct SideSnapshot {
    uint256 maxProfitUsdc;
    uint256 openInterest;
    uint256 entryNotional;
    uint256 totalMargin;
    int256 fundingIndex;
    int256 entryFunding;
}

RawSnapshot

struct RawSnapshot {
    CfdTypes.Position position;
    bytes32 accountId;

    uint256 currentTimestamp;
    uint64 lastFundingTime;
    uint256 lastMarkPrice;
    uint64 lastMarkTime;

    SideSnapshot bullSide;
    SideSnapshot bearSide;

    uint256 fundingVaultDepthUsdc;
    uint256 vaultAssetsUsdc;
    uint256 vaultCashUsdc;

    IMarginClearinghouse.AccountUsdcBuckets accountBuckets;
    IMarginClearinghouse.LockedMarginBuckets lockedBuckets;

    uint64[] marginReservationIds;

    uint256 accumulatedFeesUsdc;
    uint256 accumulatedBadDebtUsdc;
    uint256 totalDeferredPayoutUsdc;
    uint256 totalDeferredClearerBountyUsdc;
    uint256 deferredPayoutForAccount;
    bool degradedMode;

    uint256 capPrice;
    CfdTypes.RiskParams riskParams;
    bool isFadWindow;
    bool liveMarkFreshForFunding;
}

GlobalFundingDelta

struct GlobalFundingDelta {
    int256 bullFundingIndexDelta;
    int256 bearFundingIndexDelta;
    uint256 fundingAbsSkewUsdc;
    uint64 newLastFundingTime;
    uint256 newLastMarkPrice;
    uint64 newLastMarkTime;
}

FundingDelta

struct FundingDelta {
    int256 bullFundingIndexDelta;
    int256 bearFundingIndexDelta;
    uint256 fundingAbsSkewUsdc;
    uint64 newLastFundingTime;

    uint256 newLastMarkPrice;
    uint64 newLastMarkTime;

    int256 pendingFundingUsdc;
    int256 closeFundingSettlementUsdc;
    FundingPayoutType payoutType;

    uint256 fundingVaultPayoutUsdc;
    uint256 fundingClearinghouseCreditUsdc;

    uint256 fundingLossConsumedFromMargin;
    uint256 fundingLossConsumedFromFree;
    uint256 fundingLossUncovered;

    uint256 posMarginIncrease;
    uint256 posMarginDecrease;

    int256 sideEntryFundingDelta;
    int256 newPosEntryFundingIndex;
}

SolvencyPreview

struct SolvencyPreview {
    uint256 effectiveAssetsAfterUsdc;
    uint256 maxLiabilityAfterUsdc;
    int256 solvencyFundingPnlUsdc;
    bool triggersDegradedMode;
    bool postOpDegradedMode;
}

OpenDelta

struct OpenDelta {
    bool valid;
    OpenRevertCode revertCode;

    FundingDelta funding;
    OpenAccountingLib.OpenState openState;

    CfdTypes.Side posSide;
    uint256 newPosSize;
    uint256 newPosEntryPrice;
    int256 posVpiAccruedDelta;
    uint256 posMaxProfitIncrease;
    uint256 positionMarginAfterOpen;

    uint256 sideOiIncrease;
    int256 sideEntryNotionalDelta;
    int256 sideEntryFundingContribution;
    uint256 sideMaxProfitIncrease;

    int256 tradeCostUsdc;
    uint256 marginDeltaUsdc;
    int256 netMarginChange;
    uint256 vaultRebatePayoutUsdc;

    uint256 executionFeeUsdc;

    uint256 sideTotalMarginBefore;
    uint256 sideTotalMarginAfterFunding;
    uint256 sideTotalMarginAfterOpen;

    bytes32 accountId;
    uint256 sizeDelta;
    uint256 price;
    uint256 effectivePositionMarginAfterFunding;
}

CloseDelta

struct CloseDelta {
    bool valid;
    CloseRevertCode revertCode;

    FundingDelta funding;
    CloseAccountingLib.CloseState closeState;
    uint256 postBullOi;
    uint256 postBearOi;

    uint256 posMarginAfter;
    uint256 posSizeDelta;
    uint256 posMaxProfitReduction;
    int256 posVpiAccruedReduction;
    bool deletePosition;

    CfdTypes.Side side;
    uint256 sideOiDecrease;
    uint256 sideEntryNotionalReduction;
    int256 sideEntryFundingReduction;
    uint256 sideMaxProfitReduction;

    uint256 unlockMarginUsdc;

    SettlementType settlementType;

    uint256 freshTraderPayoutUsdc;
    bool freshPayoutIsImmediate;
    bool freshPayoutIsDeferred;
    uint256 existingDeferredConsumedUsdc;
    uint256 existingDeferredRemainingUsdc;
    uint256 deferredFeeRecoveryUsdc;

    CfdEngineSettlementLib.CloseSettlementResult lossResult;
    MarginClearinghouseAccountingLib.SettlementConsumption lossConsumption;
    uint256 syncMarginQueueAmount;

    uint256 executionFeeUsdc;
    uint256 badDebtUsdc;

    uint256 totalMarginBefore;
    uint256 totalMarginAfterFunding;
    uint256 totalMarginAfterClose;

    SolvencyPreview solvency;

    bytes32 accountId;
    uint256 sizeDelta;
    uint256 price;
    int256 realizedPnlUsdc;
}

LiquidationDelta

struct LiquidationDelta {
    bool liquidatable;

    GlobalFundingDelta funding;

    PositionRiskAccountingLib.PositionRiskState riskState;
    LiquidationAccountingLib.LiquidationState liquidationState;

    CfdTypes.Side side;
    uint256 posSize;
    uint256 posMargin;
    uint256 posMaxProfit;
    uint256 posEntryPrice;
    int256 posEntryFundingIndex;

    uint256 sideOiDecrease;
    uint256 sideMaxProfitDecrease;
    uint256 sideEntryNotionalReduction;
    int256 sideEntryFundingReduction;
    uint256 sideTotalMarginReduction;

    uint256 keeperBountyUsdc;
    uint256 liquidationReachableCollateralUsdc;

    int256 residualUsdc;
    MarginClearinghouseAccountingLib.LiquidationResidualPlan residualPlan;

    uint256 settlementRetainedUsdc;
    uint256 freshTraderPayoutUsdc;
    bool freshPayoutIsImmediate;
    bool freshPayoutIsDeferred;
    uint256 existingDeferredConsumedUsdc;
    uint256 existingDeferredRemainingUsdc;

    uint256 syncMarginQueueAmount;

    uint256 badDebtUsdc;

    SolvencyPreview solvency;

    bytes32 accountId;
    uint256 price;
}

Enums

OpenFailurePolicyCategory

enum OpenFailurePolicyCategory {
    None,
    CommitTimeRejectable,
    ExecutionTimeUserInvalid,
    ExecutionTimeProtocolStateInvalidated
}

ExecutionFailurePolicyCategory

enum ExecutionFailurePolicyCategory {
    None,
    UserInvalid,
    ProtocolStateInvalidated
}

FundingPayoutType

enum FundingPayoutType {
    NONE,
    MARGIN_CREDIT,
    CLOSE_SETTLEMENT,
    DEFERRED_PAYOUT,
    LOSS_CONSUMED,
    LOSS_UNCOVERED_REVERT,
    LOSS_UNCOVERED_CLOSE
}

OpenRevertCode

enum OpenRevertCode {
    OK,
    MUST_CLOSE_OPPOSING,
    DEGRADED_MODE,
    POSITION_TOO_SMALL,
    SKEW_TOO_HIGH,
    MARGIN_DRAINED_BY_FEES,
    INSUFFICIENT_INITIAL_MARGIN,
    SOLVENCY_EXCEEDED,
    FUNDING_EXCEEDS_MARGIN
}

CloseRevertCode

enum CloseRevertCode {
    OK,
    CLOSE_SIZE_EXCEEDS,
    DUST_POSITION,
    PARTIAL_CLOSE_UNDERWATER,
    FUNDING_PARTIAL_CLOSE_UNDERWATER
}

SettlementType

enum SettlementType {
    ZERO,
    GAIN,
    LOSS
}

CfdMath

Git Source

Title: CfdMath

Pure stateless math library for PnL, Price Impact, and Funding

Note: security-contact: contact@plether.com

Constants

WAD

uint256 internal constant WAD = 1e18

SECONDS_PER_YEAR

uint256 internal constant SECONDS_PER_YEAR = 31_536_000

USDC_TO_TOKEN_SCALE

uint256 internal constant USDC_TO_TOKEN_SCALE = 1e20

FUNDING_INDEX_SCALE

uint256 internal constant FUNDING_INDEX_SCALE = 1e30

Functions

calculatePnL

Calculates Unrealized PnL strictly bounded by the protocol CAP

function calculatePnL(
    CfdTypes.Position memory pos,
    uint256 currentOraclePrice,
    uint256 capPrice
) internal pure returns (bool isProfit, uint256 pnlUsdc);

Parameters

NameTypeDescription
posCfdTypes.PositionThe position to evaluate
currentOraclePriceuint256Current oracle price (8 decimals)
capPriceuint256Protocol cap price (8 decimals)

Returns

NameTypeDescription
isProfitboolTrue if the position is in profit
pnlUsdcuint256Absolute PnL value in USDC (6 decimals)

calculateMaxProfit

Calculates the absolute maximum payout a trade can ever achieve

function calculateMaxProfit(
    uint256 size,
    uint256 entryPrice,
    CfdTypes.Side side,
    uint256 capPrice
) internal pure returns (uint256 maxProfitUsdc);

Parameters

NameTypeDescription
sizeuint256Notional size (18 decimals)
entryPriceuint256Entry oracle price (8 decimals)
sideCfdTypes.SideBULL or BEAR
capPriceuint256Protocol cap price (8 decimals)

Returns

NameTypeDescription
maxProfitUsdcuint256Maximum possible profit in USDC (6 decimals)

_getSkewCost

Calculates the cost of a specific skew state. C(S) = 0.5 * k * (S^2 / D)

function _getSkewCost(
    uint256 skewUsdc,
    uint256 depthUsdc,
    uint256 vpiFactorWad
) private pure returns (uint256 costUsdc);

Parameters

NameTypeDescription
skewUsdcuint256The absolute directional imbalance in USDC (6 decimals)
depthUsdcuint256The total free USDC in the House Pool (6 decimals)
vpiFactorWaduint256The ‘k’ impact parameter (18 decimals)

Returns

NameTypeDescription
costUsdcuint256The theoretical cost to reach this skew (6 decimals)

calculateVPI

Calculates the VPI charge/rebate for a trade.

If postCost > preCost, result is positive (Charge Trader). If postCost < preCost, result is negative (Rebate Trader / MM Incentive).

function calculateVPI(
    uint256 preSkewUsdc,
    uint256 postSkewUsdc,
    uint256 depthUsdc,
    uint256 vpiFactorWad
) internal pure returns (int256 vpiUsdc);

getAnnualizedFundingRate

Returns the annualized funding rate based on the kinked curve. Linear ramp up to kinkSkewRatio, quadratic acceleration above it.

function getAnnualizedFundingRate(
    uint256 absSkewUsdc,
    uint256 depthUsdc,
    CfdTypes.RiskParams memory params
) internal pure returns (uint256 annualizedRateWad);

Parameters

NameTypeDescription
absSkewUsdcuint256Absolute directional imbalance in USDC (6 decimals)
depthUsdcuint256Total pool depth in USDC (6 decimals)
paramsCfdTypes.RiskParamsRisk parameters defining the funding curve shape

Returns

NameTypeDescription
annualizedRateWaduint256Annualized rate (18 decimals WAD)

CfdTypes

Git Source

Title: CfdTypes

Core data structures for the Plether CFD Engine

Note: security-contact: contact@plether.com

Structs

Position

A user’s active position in a specific market.

margin is the engine’s canonical economic position-margin state used for risk and state transitions. It is intentionally distinct from the clearinghouse custody bucket that holds the locked funds backing it.

struct Position {
    uint256 size; // [18 dec] Notional size in synthetic tokens
    uint256 margin; // [6 dec] Isolated margin backing this position
    uint256 entryPrice; // [8 dec] Oracle price of BEAR at execution
    uint256 maxProfitUsdc; // [6 dec] Cumulative max profit tracked to avoid truncation underflow
    int256 entryFundingIndex; // [18 dec WAD] Global funding index at the time of entry
    Side side; // [uint8] Trade direction
    uint64 lastUpdateTime; // [uint64] Timestamp of last modification
    int256 vpiAccrued; // [6 dec] Cumulative VPI charges (+) and rebates (-) across the position's lifetime
}

Order

An intent submitted by a user, waiting for Keeper execution

struct Order {
    bytes32 accountId; // Maps to MarginClearinghouse unified account
    uint256 sizeDelta; // [18 dec] Amount of size to add/remove
    uint256 marginDelta; // [6 dec] Amount of margin to add/remove
    uint256 targetPrice; // [8 dec] Slippage protection limit
    uint64 commitTime; // Timestamp of intent submission (MEV shield)
    uint64 commitBlock; // Block number of intent submission (same-block execution shield)
    uint64 orderId; // Strict FIFO execution queue ID
    Side side; // [uint8] BULL or BEAR
    bool isClose; // [bool] True if strictly closing/reducing
}

RiskParams

Global configuration parameters for the VPI and Funding engines

struct RiskParams {
    uint256 vpiFactor; // [18 dec WAD] Impact severity 'k'
    uint256 maxSkewRatio; // [18 dec WAD] Hard cliff e.g., 40% (0.40e18)
    uint256 kinkSkewRatio; // [18 dec WAD] Inflection point e.g., 25% (0.25e18)
    uint256 baseApy; // [18 dec WAD] Rate at the kink e.g., 15% (0.15e18)
    uint256 maxApy; // [18 dec WAD] Rate at the wall e.g., 300% (3.00e18)
    uint256 maintMarginBps; // e.g., 100 (1%)
    uint256 initMarginBps; // e.g., 150 (1.5%)
    uint256 fadMarginBps; // e.g., 300 (3%)
    uint256 minBountyUsdc; // e.g., 5_000_000 ($5 USDC floor)
    uint256 bountyBps; // e.g., 15 (0.15% of Notional Size)
}

Enums

Side

BULL profits when USD strengthens (oracle price drops). BEAR profits when USD weakens (oracle price rises).

enum Side {
    BULL,
    BEAR
}

CloseInvalidReason

enum CloseInvalidReason {
    None,
    NoPosition,
    BadSize,
    PartialCloseUnderwater,
    DustPosition
}

HousePool

Git Source

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

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;

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

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;

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

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 onlyVault;

Parameters

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

depositJunior

Deposit USDC into the junior tranche.

function depositJunior(
    uint256 amount
) external 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 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);

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(
    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;
}

MarginClearinghouse

Git Source

Inherits: Ownable2Step

Title: MarginClearinghouse

USDC-only cross-margin account manager for Plether.

Holds settlement balances and locked margin for CFD accounts.

Note: security-contact: contact@plether.com

Constants

settlementAsset

address public immutable settlementAsset

State Variables

settlementBalances

mapping(bytes32 => uint256) internal settlementBalances

positionMarginUsdc

mapping(bytes32 => uint256) internal positionMarginUsdc

committedOrderMarginUsdc

mapping(bytes32 => uint256) internal committedOrderMarginUsdc

reservedSettlementUsdc

mapping(bytes32 => uint256) internal reservedSettlementUsdc

orderReservations

mapping(uint64 => IMarginClearinghouse.OrderReservation) internal orderReservations

reservationIdsByAccount

mapping(bytes32 => uint64[]) internal reservationIdsByAccount

reservationHeadIndexByAccount

mapping(bytes32 => uint256) internal reservationHeadIndexByAccount

activeCommittedOrderReservationUsdc

mapping(bytes32 => uint256) internal activeCommittedOrderReservationUsdc

activeReservedSettlementReservationUsdc

mapping(bytes32 => uint256) internal activeReservedSettlementReservationUsdc

activeReservationCount

mapping(bytes32 => uint256) internal activeReservationCount

engine

address public engine

Functions

onlyOperator

modifier onlyOperator() ;

constructor

constructor(
    address _settlementAsset
) Ownable(msg.sender);

Parameters

NameTypeDescription
_settlementAssetaddressUSDC address used for PnL settlement and margin backing

setEngine

Sets the CfdEngine address (one-time, reverts if already set).

function setEngine(
    address _engine
) external onlyOwner;

deposit

Deposits settlement USDC into the specified margin account.

function deposit(
    bytes32 accountId,
    uint256 amount
) external;

Parameters

NameTypeDescription
accountIdbytes32Deterministic account ID derived from msg.sender address
amountuint256Token amount to transfer in

withdraw

Withdraws settlement USDC from a margin account.

function withdraw(
    bytes32 accountId,
    uint256 amount
) external;

Parameters

NameTypeDescription
accountIdbytes32Deterministic account ID derived from msg.sender address
amountuint256USDC amount to withdraw

getAccountEquityUsdc

Returns the total USD buying power of the account (6 decimals).

function getAccountEquityUsdc(
    bytes32 accountId
) public view returns (uint256 totalEquityUsdc);

Parameters

NameTypeDescription
accountIdbytes32Account to value

Returns

NameTypeDescription
totalEquityUsdcuint256Settlement balance in USDC (6 decimals)

getFreeBuyingPowerUsdc

Returns strictly unencumbered purchasing power

function getFreeBuyingPowerUsdc(
    bytes32 accountId
) public view returns (uint256);

Parameters

NameTypeDescription
accountIdbytes32Account to query

Returns

NameTypeDescription
<none>uint256Equity minus locked margin, floored at zero (6 decimals)

getAccountUsdcBuckets

Returns the explicit USDC bucket split after subtracting the clearinghouse’s typed locked-margin buckets.

function getAccountUsdcBuckets(
    bytes32 accountId
) public view returns (IMarginClearinghouse.AccountUsdcBuckets memory buckets);

getFreeSettlementBalanceUsdc

function getFreeSettlementBalanceUsdc(
    bytes32 accountId
) public view returns (uint256);

getTerminalReachableUsdc

Returns settlement balance reachable by a terminal settlement path.

function getTerminalReachableUsdc(
    bytes32 accountId
) public view returns (uint256);

getSettlementReachableUsdc

Returns settlement balance reachable after protecting only an explicitly remaining margin bucket.

This is the canonical helper for terminal settlement paths: full closes and liquidations should pass zero protected margin, while partial closes should protect only the residual position margin that remains open after settlement.

function getSettlementReachableUsdc(
    bytes32 accountId,
    uint256 protectedLockedMarginUsdc
) public view returns (uint256);

lockPositionMargin

Locks margin to back a new CFD trade. Requires sufficient USDC to back settlement (non-USDC equity alone is insufficient).

function lockPositionMargin(
    bytes32 accountId,
    uint256 amountUsdc
) external onlyOperator;

Parameters

NameTypeDescription
accountIdbytes32Account to lock margin on
amountUsdcuint256USDC amount to lock (6 decimals)

unlockPositionMargin

Unlocks active position margin when a CFD trade closes

function unlockPositionMargin(
    bytes32 accountId,
    uint256 amountUsdc
) external onlyOperator;

Parameters

NameTypeDescription
accountIdbytes32Account to unlock margin on
amountUsdcuint256USDC amount to unlock (6 decimals), clamped to current locked amount

lockCommittedOrderMargin

Locks margin to back a pending order commitment.

function lockCommittedOrderMargin(
    bytes32 accountId,
    uint256 amountUsdc
) external onlyOperator;

Parameters

NameTypeDescription
accountIdbytes32Account to lock margin on
amountUsdcuint256USDC amount to lock (6 decimals)

reserveCommittedOrderMargin

function reserveCommittedOrderMargin(
    bytes32 accountId,
    uint64 orderId,
    uint256 amountUsdc
) external onlyOperator;

unlockCommittedOrderMargin

Unlocks committed order margin when an order is cancelled or filled.

function unlockCommittedOrderMargin(
    bytes32 accountId,
    uint256 amountUsdc
) external onlyOperator;

Parameters

NameTypeDescription
accountIdbytes32Account to unlock margin on
amountUsdcuint256USDC amount to unlock (6 decimals)

releaseOrderReservation

function releaseOrderReservation(
    uint64 orderId
) external onlyOperator returns (uint256 releasedUsdc);

releaseOrderReservationIfActive

function releaseOrderReservationIfActive(
    uint64 orderId
) external onlyOperator returns (uint256 releasedUsdc);

consumeOrderReservation

function consumeOrderReservation(
    uint64 orderId,
    uint256 amountUsdc
) external onlyOperator returns (uint256 consumedUsdc);

consumeAccountOrderReservations

function consumeAccountOrderReservations(
    bytes32 accountId,
    uint256 amountUsdc
) external onlyOperator returns (uint256 consumedUsdc);

consumeOrderReservationsById

function consumeOrderReservationsById(
    uint64[] calldata orderIds,
    uint256 amountUsdc
) external onlyOperator returns (uint256 consumedUsdc);

_consumeOrderReservationsById

function _consumeOrderReservationsById(
    uint64[] memory orderIds,
    uint256 amountUsdc
) internal returns (uint256 consumedUsdc);

_consumeAccountOrderReservations

function _consumeAccountOrderReservations(
    bytes32 accountId,
    uint256 amountUsdc,
    bool consumeBuckets
) internal returns (uint256 consumedUsdc);

_releaseReservation

function _releaseReservation(
    IMarginClearinghouse.OrderReservation storage reservation,
    bool consumeBuckets
) internal returns (uint256 releasedUsdc);

_consumeReservation

function _consumeReservation(
    IMarginClearinghouse.OrderReservation storage reservation,
    uint256 amountUsdc,
    bool consumeBuckets,
    IMarginClearinghouse.ReservationStatus terminalStatus
) internal;

_decreaseActiveReservation

function _decreaseActiveReservation(
    bytes32 accountId,
    IMarginClearinghouse.ReservationBucket bucket,
    uint256 amountUsdc
) internal;

lockReservedSettlement

function lockReservedSettlement(
    bytes32 accountId,
    uint256 amountUsdc
) external onlyOperator;

unlockReservedSettlement

function unlockReservedSettlement(
    bytes32 accountId,
    uint256 amountUsdc
) external onlyOperator;

settleUsdc

Adjusts USDC balance to settle funding, PnL, and VPI rebates. Positive amounts credit the account; negative amounts debit it.

function settleUsdc(
    bytes32 accountId,
    int256 amount
) external onlyOperator;

Parameters

NameTypeDescription
accountIdbytes32Account to settle
amountint256Signed USDC delta: positive credits, negative debits (6 decimals)

creditSettlementAndLockMargin

Credits settlement USDC and locks the same amount as active margin.

function creditSettlementAndLockMargin(
    bytes32 accountId,
    uint256 amountUsdc
) external onlyOperator;

applyOpenCost

Applies an open/increase trade cost by debiting or crediting settlement and updating locked margin.

function applyOpenCost(
    bytes32 accountId,
    uint256 marginDeltaUsdc,
    int256 tradeCostUsdc,
    address recipient
) external onlyOperator returns (int256 netMarginChangeUsdc);

consumeFundingLoss

Consumes a funding loss from free settlement first, then from the active position margin bucket.

Unrelated locked margin remains protected.

function consumeFundingLoss(
    bytes32 accountId,
    uint256,
    uint256 lossUsdc,
    address recipient
)
    external
    onlyOperator
    returns (uint256 marginConsumedUsdc, uint256 freeSettlementConsumedUsdc, uint256 uncoveredUsdc);

consumeCloseLoss

Consumes close-path losses from settlement buckets while preserving any explicitly protected remaining position margin.

function consumeCloseLoss(
    bytes32 accountId,
    uint64[] calldata reservationOrderIds,
    uint256 lossUsdc,
    uint256 protectedLockedMarginUsdc,
    bool includeOtherLockedMargin,
    address recipient
) external onlyOperator returns (uint256 seizedUsdc, uint256 shortfallUsdc);

applyLiquidationSettlementPlan

Applies a pre-planned liquidation settlement mutation.

Releases the active position margin bucket and covered committed margin exactly as planned.

function applyLiquidationSettlementPlan(
    bytes32 accountId,
    uint64[] calldata reservationOrderIds,
    IMarginClearinghouse.LiquidationSettlementPlan calldata plan,
    address recipient
) external onlyOperator returns (uint256 seizedUsdc);

_buildAccountUsdcBuckets

function _buildAccountUsdcBuckets(
    bytes32 accountId
) internal view returns (IMarginClearinghouse.AccountUsdcBuckets memory buckets);

_planFundingLossConsumption

function _planFundingLossConsumption(
    bytes32 accountId,
    uint256 lossUsdc
) internal view returns (MarginClearinghouseAccountingLib.SettlementConsumption memory consumption);

_creditSettlementUsdc

function _creditSettlementUsdc(
    bytes32 accountId,
    uint256 amountUsdc
) internal;

_debitSettlementUsdc

function _debitSettlementUsdc(
    bytes32 accountId,
    uint256 amountUsdc
) internal;

_lockMargin

function _lockMargin(
    bytes32 accountId,
    IMarginClearinghouse.MarginBucket bucket,
    uint256 amountUsdc
) internal;

_unlockMargin

function _unlockMargin(
    bytes32 accountId,
    IMarginClearinghouse.MarginBucket bucket,
    uint256 amountUsdc
) internal;

_consumeOtherLockedMargin

Consumes non-position locked margin by priority: committed-order margin first, then reserved settlement. Queued order margin is released before reserved settlement because failed/cancelled order intents are softer obligations than explicitly reserved settlement buckets.

function _consumeOtherLockedMargin(
    bytes32 accountId,
    uint256 amountUsdc
) internal;

_consumeOtherLockedMarginViaReservations

function _consumeOtherLockedMarginViaReservations(
    bytes32 accountId,
    uint64[] calldata reservationOrderIds,
    uint256 amountUsdc
) internal;

_consumeReservationBucket

function _consumeReservationBucket(
    bytes32 accountId,
    IMarginClearinghouse.ReservationBucket bucket,
    uint256 amountUsdc
) internal;

_activeReservation

function _activeReservation(
    uint64 orderId
) internal view returns (IMarginClearinghouse.OrderReservation storage reservation);

_closeReservation

function _closeReservation(
    IMarginClearinghouse.OrderReservation storage reservation,
    IMarginClearinghouse.ReservationStatus terminalStatus
) internal;

_advanceReservationHead

function _advanceReservationHead(
    bytes32 accountId
) internal;

_consumeLockedMargin

function _consumeLockedMargin(
    bytes32 accountId,
    IMarginClearinghouse.MarginBucket bucket,
    uint256 amountUsdc
) internal;

_bucketStorage

function _bucketStorage(
    IMarginClearinghouse.MarginBucket bucket,
    bytes32 accountId
) internal view returns (uint256 bucketValue);

_setBucketStorage

function _setBucketStorage(
    IMarginClearinghouse.MarginBucket bucket,
    bytes32 accountId,
    uint256 amountUsdc
) internal;

_totalLockedMarginUsdc

function _totalLockedMarginUsdc(
    bytes32 accountId
) internal view returns (uint256);

seizeUsdc

Transfers settlement USDC from an account to the calling operator.

The recipient must equal msg.sender, so operators can only pull seized funds into their own contract/account and must forward them explicitly afterward.

function seizeUsdc(
    bytes32 accountId,
    uint256 amount,
    address recipient
) external onlyOperator;

Parameters

NameTypeDescription
accountIdbytes32Account to seize from
amountuint256USDC amount to seize
recipientaddressRecipient of seized tokens (must equal msg.sender)

seizePositionMarginUsdc

function seizePositionMarginUsdc(
    bytes32 accountId,
    uint256 amount,
    address recipient
) external onlyOperator;

balanceUsdc

function balanceUsdc(
    bytes32 accountId
) external view returns (uint256);

lockedMarginUsdc

function lockedMarginUsdc(
    bytes32 accountId
) external view returns (uint256);

getLockedMarginBuckets

function getLockedMarginBuckets(
    bytes32 accountId
) external view returns (IMarginClearinghouse.LockedMarginBuckets memory buckets);

getOrderReservation

function getOrderReservation(
    uint64 orderId
) external view returns (IMarginClearinghouse.OrderReservation memory reservation);

getAccountReservationSummary

function getAccountReservationSummary(
    bytes32 accountId
) external view returns (IMarginClearinghouse.AccountReservationSummary memory summary);

reservationHeadIndex

function reservationHeadIndex(
    bytes32 accountId
) external view returns (uint256);

_toUint96

function _toUint96(
    uint256 value
) internal pure returns (uint96);

Events

Deposit

event Deposit(bytes32 indexed accountId, address indexed asset, uint256 amount);

Withdraw

event Withdraw(bytes32 indexed accountId, address indexed asset, uint256 amount);

MarginLocked

event MarginLocked(bytes32 indexed accountId, IMarginClearinghouse.MarginBucket indexed bucket, uint256 amountUsdc);

MarginUnlocked

event MarginUnlocked(
    bytes32 indexed accountId, IMarginClearinghouse.MarginBucket indexed bucket, uint256 amountUsdc
);

ReservationCreated

event ReservationCreated(
    uint64 indexed orderId,
    bytes32 indexed accountId,
    IMarginClearinghouse.ReservationBucket indexed bucket,
    uint256 amountUsdc
);

ReservationConsumed

event ReservationConsumed(
    uint64 indexed orderId, bytes32 indexed accountId, uint256 amountUsdc, uint256 remainingAmountUsdc
);

ReservationReleased

event ReservationReleased(uint64 indexed orderId, bytes32 indexed accountId, uint256 amountUsdc);

AssetSeized

event AssetSeized(bytes32 indexed accountId, address indexed asset, uint256 amount, address recipient);

Errors

MarginClearinghouse__NotOperator

error MarginClearinghouse__NotOperator();

MarginClearinghouse__NotAccountOwner

error MarginClearinghouse__NotAccountOwner();

MarginClearinghouse__ZeroAmount

error MarginClearinghouse__ZeroAmount();

MarginClearinghouse__InsufficientBalance

error MarginClearinghouse__InsufficientBalance();

MarginClearinghouse__InsufficientFreeEquity

error MarginClearinghouse__InsufficientFreeEquity();

MarginClearinghouse__InsufficientUsdcForSettlement

error MarginClearinghouse__InsufficientUsdcForSettlement();

MarginClearinghouse__InsufficientAssetToSeize

error MarginClearinghouse__InsufficientAssetToSeize();

MarginClearinghouse__InvalidSeizeRecipient

error MarginClearinghouse__InvalidSeizeRecipient();

MarginClearinghouse__InvalidMarginBucket

error MarginClearinghouse__InvalidMarginBucket();

MarginClearinghouse__ReservationAlreadyExists

error MarginClearinghouse__ReservationAlreadyExists();

MarginClearinghouse__ReservationNotActive

error MarginClearinghouse__ReservationNotActive();

MarginClearinghouse__IncompleteReservationCoverage

error MarginClearinghouse__IncompleteReservationCoverage();

MarginClearinghouse__EngineAlreadySet

error MarginClearinghouse__EngineAlreadySet();

MarginClearinghouse__ZeroAddress

error MarginClearinghouse__ZeroAddress();

MarginClearinghouse__InsufficientBucketMargin

error MarginClearinghouse__InsufficientBucketMargin();

MarginClearinghouse__AmountOverflow

error MarginClearinghouse__AmountOverflow();

OrderRouter

Git Source

Inherits: Ownable2Step, Pausable, OrderEscrowAccounting

Title: OrderRouter (The MEV Shield)

Manages Commit-Reveal, MEV protection, and the un-brickable FIFO queue.

Holds only non-trader-owned keeper execution reserves. Trader collateral remains in MarginClearinghouse.

Note: security-contact: contact@plether.com

Constants

PANIC_SELECTOR

bytes4 internal constant PANIC_SELECTOR = 0x4e487b71

TYPED_ORDER_FAILURE_SELECTOR

bytes4 internal constant TYPED_ORDER_FAILURE_SELECTOR = ICfdEngine.CfdEngine__TypedOrderFailure.selector

MARK_PRICE_OUT_OF_ORDER_SELECTOR

bytes4 internal constant MARK_PRICE_OUT_OF_ORDER_SELECTOR = ICfdEngine.CfdEngine__MarkPriceOutOfOrder.selector

vault

ICfdVault internal immutable vault

TIMELOCK_DELAY

uint256 public constant TIMELOCK_DELAY = 48 hours

MIN_ENGINE_GAS

uint256 internal constant MIN_ENGINE_GAS = 600_000

MIN_MEV_PUBLISH_DELAY

uint256 internal constant MIN_MEV_PUBLISH_DELAY = 5

DEFAULT_MAX_ORDER_AGE

uint256 internal constant DEFAULT_MAX_ORDER_AGE = 60

MAX_EXPIRED_ORDER_SKIPS_PER_CALL

uint256 internal constant MAX_EXPIRED_ORDER_SKIPS_PER_CALL = 32

MAX_BATCH_ORDER_SCANS

uint256 internal constant MAX_BATCH_ORDER_SCANS = 64

MAX_PRUNE_ORDERS_PER_CALL

uint256 internal constant MAX_PRUNE_ORDERS_PER_CALL = 64

RETRYABLE_SKIP_COOLDOWN

uint64 internal constant RETRYABLE_SKIP_COOLDOWN = 5

OPEN_ORDER_EXECUTION_BOUNTY_BPS

uint256 internal constant OPEN_ORDER_EXECUTION_BOUNTY_BPS = 1

MIN_OPEN_ORDER_EXECUTION_BOUNTY_USDC

uint256 internal constant MIN_OPEN_ORDER_EXECUTION_BOUNTY_USDC = 50_000

MAX_OPEN_ORDER_EXECUTION_BOUNTY_USDC

uint256 internal constant MAX_OPEN_ORDER_EXECUTION_BOUNTY_USDC = DecimalConstants.ONE_USDC

CLOSE_ORDER_EXECUTION_BOUNTY_USDC

uint256 internal constant CLOSE_ORDER_EXECUTION_BOUNTY_USDC = DecimalConstants.ONE_USDC

MAX_PENDING_ORDERS

uint256 public constant MAX_PENDING_ORDERS = 5

State Variables

pyth

IPyth public pyth

pythFeedIds

bytes32[] public pythFeedIds

quantities

uint256[] public quantities

basePrices

uint256[] public basePrices

inversions

bool[] public inversions

nextCommitId

uint64 public nextCommitId = 1

nextExecuteId

uint64 public nextExecuteId = 1

maxOrderAge

uint256 public maxOrderAge

pendingMaxOrderAge

uint256 public pendingMaxOrderAge

maxOrderAgeActivationTime

uint256 public maxOrderAgeActivationTime

orderExecutionStalenessLimit

uint256 public orderExecutionStalenessLimit = 60

pendingOrderExecutionStalenessLimit

uint256 public pendingOrderExecutionStalenessLimit

orderExecutionStalenessActivationTime

uint256 public orderExecutionStalenessActivationTime

liquidationStalenessLimit

uint256 public liquidationStalenessLimit = 15

pendingLiquidationStalenessLimit

uint256 public pendingLiquidationStalenessLimit

liquidationStalenessActivationTime

uint256 public liquidationStalenessActivationTime

claimableEth

mapping(address => uint256) public claimableEth

pendingHeadOrderId

mapping(bytes32 => uint64) public pendingHeadOrderId

pendingTailOrderId

mapping(bytes32 => uint64) public pendingTailOrderId

globalTailOrderId

uint64 public globalTailOrderId

Functions

onlyEngine

modifier onlyEngine() ;

constructor

constructor(
    address _engine,
    address _vault,
    address _pyth,
    bytes32[] memory _feedIds,
    uint256[] memory _quantities,
    uint256[] memory _basePrices,
    bool[] memory _inversions
) Ownable(msg.sender) OrderEscrowAccounting(_engine);

Parameters

NameTypeDescription
_engineaddressCfdEngine that processes trades and liquidations
_vaultaddressCfdVault used for vault depth queries and liquidation bounty payouts
_pythaddressPyth oracle contract (address(0) enables mock mode on Anvil)
_feedIdsbytes32[]Pyth price feed IDs for each basket component
_quantitiesuint256[]Weight of each component (must sum to 1e18)
_basePricesuint256[]Base price per component for normalization (8 decimals)
_inversionsbool[]Whether to invert each feed (e.g. USD/JPY -> JPY/USD)

proposeMaxOrderAge

Proposes a new maxOrderAge value, subject to 48h timelock.

function proposeMaxOrderAge(
    uint256 _maxOrderAge
) external onlyOwner;

finalizeMaxOrderAge

Finalizes the pending maxOrderAge after timelock expires.

function finalizeMaxOrderAge() external onlyOwner;

cancelMaxOrderAgeProposal

Cancels the pending maxOrderAge proposal.

function cancelMaxOrderAgeProposal() external onlyOwner;

proposeOrderExecutionStalenessLimit

function proposeOrderExecutionStalenessLimit(
    uint256 limit
) external onlyOwner;

finalizeOrderExecutionStalenessLimit

function finalizeOrderExecutionStalenessLimit() external onlyOwner;

cancelOrderExecutionStalenessLimitProposal

function cancelOrderExecutionStalenessLimitProposal() external onlyOwner;

proposeLiquidationStalenessLimit

function proposeLiquidationStalenessLimit(
    uint256 limit
) external onlyOwner;

finalizeLiquidationStalenessLimit

function finalizeLiquidationStalenessLimit() external onlyOwner;

cancelLiquidationStalenessLimitProposal

function cancelLiquidationStalenessLimitProposal() external onlyOwner;

pause

function pause() external onlyOwner;

unpause

function unpause() external onlyOwner;

commitOrder

Submits a trade intent to the FIFO queue. Margin and the order’s execution bounty are reserved immediately.

function commitOrder(
    CfdTypes.Side side,
    uint256 sizeDelta,
    uint256 marginDelta,
    uint256 targetPrice,
    bool isClose
) external;

Parameters

NameTypeDescription
sideCfdTypes.SideBULL or BEAR
sizeDeltauint256Position size change (18 decimals)
marginDeltauint256Margin to add or remove (6 decimals, USDC)
targetPriceuint256Slippage limit price (8 decimals, 0 = market order)
isCloseboolTrue to allow execution even when paused or in FAD close-only mode

quoteOpenOrderExecutionBountyUsdc

Quotes the reserved USDC execution bounty for a new open order using the latest engine mark price.

Falls back to 1.00 USD if the engine has not observed a mark yet. Result is floored at 0.05 USDC and capped at 1 USDC for non-close intents.

function quoteOpenOrderExecutionBountyUsdc(
    uint256 sizeDelta
) external view returns (uint256 executionBountyUsdc);

Parameters

NameTypeDescription
sizeDeltauint256Order size in 18-decimal notional units

Returns

NameTypeDescription
executionBountyUsdcuint256Reserved execution bounty in 6-decimal USDC units

quoteCloseOrderExecutionBountyUsdc

Quotes the flat reserved USDC execution bounty for a close order.

function quoteCloseOrderExecutionBountyUsdc() external pure returns (uint256 executionBountyUsdc);

orders

function orders(
    uint64 orderId
) external view returns (bytes32, uint256, uint256, uint256, uint64, uint64, uint64, CfdTypes.Side, bool);

committedMargins

function committedMargins(
    uint64 orderId
) external view returns (uint256);

executionBountyReserves

function executionBountyReserves(
    uint64 orderId
) external view returns (uint256);

isInMarginQueue

function isInMarginQueue(
    uint64 orderId
) external view returns (bool);

getOrderRecord

function getOrderRecord(
    uint64 orderId
) external view returns (OrderRecord memory);

syncMarginQueue

Returns the total queued escrow state for an account across all pending orders.

function syncMarginQueue(
    bytes32 accountId
) external onlyEngine;

getPendingOrdersForAccount

function getPendingOrdersForAccount(
    bytes32 accountId
) external view returns (IOrderRouterAccounting.PendingOrderView[] memory pending);

executeOrder

Keeper executes the current global queue head. Validates oracle freshness and publish-time ordering against the order commit, checks slippage, then delegates to CfdEngine. Terminal invalid/expired orders pay from router-custodied execution bounty, while retryable slippage misses are requeued to the global tail with cooldown so keepers cannot burn out-of-market intents or pin the FIFO head.

function executeOrder(
    uint64 orderId,
    bytes[] calldata pythUpdateData
) external payable;

Parameters

NameTypeDescription
orderIduint64Must equal the current global queue head (expired orders are auto-skipped)
pythUpdateDatabytes[]Pyth price update blobs; attach ETH to cover the Pyth fee

executeOrderBatch

Executes queued pending orders against a single Pyth price tick. Updates Pyth once, then loops through the FIFO queue. Aggregates reserved USDC execution bounties across processed orders and refunds excess ETH in a single transfer.

function executeOrderBatch(
    uint64 maxOrderId,
    bytes[] calldata pythUpdateData
) external payable;

Parameters

NameTypeDescription
maxOrderIduint64Inclusive upper bound on committed order ids the batch may begin processing from
pythUpdateDatabytes[]Pyth price update blobs; attach ETH to cover the Pyth fee

_skipStaleOrders

function _skipStaleOrders(
    uint64 upToId,
    uint256 maxSkips
) internal returns (uint256 skipped);

_currentRouterExecutionContext

function _currentRouterExecutionContext() internal view returns (RouterExecutionContext memory context);

_routedCloseOnlyFailure

function _routedCloseOnlyFailure(
    CfdTypes.Order memory order,
    bool oracleFrozen,
    bool isFadWindow,
    bool degradedMode,
    bool closeOnly
) internal pure returns (OrderFailurePolicyLib.FailureContext memory failure);

_processTypedOrderExecution

function _processTypedOrderExecution(
    CfdTypes.Order memory order,
    uint256 executionPrice,
    uint256 vaultDepth,
    uint64 oraclePublishTime,
    bool oracleFrozen,
    bool isFadWindow,
    bool degradedMode
)
    internal
    returns (
        bool success,
        OrderFailReason failureReason,
        OrderFailurePolicyLib.FailedOrderBountyPolicy failureBountyPolicy
    );

pruneExpiredOrders

function pruneExpiredOrders(
    uint64 upToId,
    uint256 maxPrunes
) external;

_resolveOraclePrice

function _resolveOraclePrice(
    bytes[] calldata pythUpdateData,
    uint256 mockFallbackPrice
) internal returns (uint256 price, uint64 publishTime, uint256 pythFee);

_sendEth

function _sendEth(
    address to,
    uint256 amount
) internal;

_pendingOrder

function _pendingOrder(
    uint64 orderId
) internal view returns (OrderRecord storage record, CfdTypes.Order memory order);

_getQueuedPositionView

function _getQueuedPositionView(
    bytes32 accountId
) internal view returns (QueuedPositionView memory queuedPosition);

_failedOrderBountyPolicy

function _failedOrderBountyPolicy(
    OrderFailurePolicyLib.FailureContext memory context
) internal pure returns (OrderFailurePolicyLib.FailedOrderBountyPolicy);

_decodeTypedOrderFailure

function _decodeTypedOrderFailure(
    bytes memory revertData
)
    internal
    pure
    returns (CfdEnginePlanTypes.ExecutionFailurePolicyCategory failureCategory, uint8 failureCode, bool isClose);

_cleanupOrder

function _cleanupOrder(
    uint64 orderId,
    bool success,
    OrderFailurePolicyLib.FailedOrderBountyPolicy failedPolicy
) internal returns (uint256 executionBountyUsdc);

_finalizeExecution

function _finalizeExecution(
    uint64 orderId,
    uint256 pythFee,
    bool success,
    OrderFailurePolicyLib.FailedOrderBountyPolicy failedPolicy
) internal;

_routedExpiryFailure

function _routedExpiryFailure(
    CfdTypes.Order memory order
) internal view returns (OrderFailurePolicyLib.FailureContext memory context);

_routedRouterPolicyFailure

function _routedRouterPolicyFailure(
    CfdTypes.Order memory order,
    OrderFailurePolicyLib.RouterFailureCode failureCode,
    bool oracleFrozen,
    bool isFad,
    bool degradedMode,
    bool closeOnly
) internal pure returns (OrderFailurePolicyLib.FailureContext memory context);

_routedFailureFromEngineRevert

function _routedFailureFromEngineRevert(
    CfdTypes.Order memory order,
    bytes memory revertData,
    bool oracleFrozen,
    bool isFad,
    bool degradedMode
) internal pure returns (OrderFailurePolicyLib.FailureContext memory context);

_payOrDeferLiquidationBounty

Immediate liquidation bounties still pay directly to the executing keeper wallet. If immediate payment is unavailable or direct transfer fails, the bounty is deferred and later settles as clearinghouse credit via claimDeferredClearerBounty().

function _payOrDeferLiquidationBounty(
    uint256 liquidationBountyUsdc
) internal;

_forfeitEscrowedOrderBountiesOnLiquidation

function _forfeitEscrowedOrderBountiesOnLiquidation(
    bytes32 accountId
) internal;

_clearLiquidatedAccountOrders

function _clearLiquidatedAccountOrders(
    bytes32 accountId
) internal;

_quoteOpenOrderExecutionBountyUsdc

function _quoteOpenOrderExecutionBountyUsdc(
    uint256 sizeDelta,
    uint256 price
) internal pure returns (uint256);

_quoteCloseOrderExecutionBountyUsdc

function _quoteCloseOrderExecutionBountyUsdc() internal pure returns (uint256);

_commitReferencePrice

function _commitReferencePrice() internal view returns (uint256 price);

_canUseCommitMarkForOpenPrefilter

function _canUseCommitMarkForOpenPrefilter() internal view returns (bool);

_linkPendingOrder

function _linkPendingOrder(
    bytes32 accountId,
    uint64 orderId
) internal;

_linkGlobalOrder

function _linkGlobalOrder(
    uint64 orderId
) internal;

_unlinkGlobalOrder

function _unlinkGlobalOrder(
    uint64 orderId
) internal;

_skipRetryableOrder

function _skipRetryableOrder(
    uint64 orderId,
    OrderFailReason reason
) internal;

_unlinkPendingOrder

function _unlinkPendingOrder(
    bytes32 accountId,
    uint64 orderId
) internal;

_reserveCloseExecutionBounty

function _reserveCloseExecutionBounty(
    bytes32 accountId,
    uint256 executionBountyUsdc
) internal override;

_deleteOrder

function _deleteOrder(
    uint64 orderId,
    bool advanceHead,
    IOrderRouterAccounting.OrderStatus terminalStatus
) internal;

_releaseCommittedMarginForExecution

function _releaseCommittedMarginForExecution(
    uint64 orderId
) internal;

claimEth

Claims ETH stuck from failed refund transfers.

function claimEth() external;

claimUsdc

Claims USDC bounty refunds that could not be pushed during failed-order cleanup.

function claimUsdc() external;

_computeBasketPrice

function _computeBasketPrice() internal view returns (uint256 basketPrice, uint256 minPublishTime);

_checkSlippage

Opens vs closes have opposing slippage directions: BULL open wants HIGH entry (more room for drop) → exec >= target BULL close wants LOW exit (lock in profit) → exec <= target BEAR open wants LOW entry (more room for rise) → exec <= target BEAR close wants HIGH exit (lock in profit) → exec >= target targetPrice == 0 disables the check (market order).

function _checkSlippage(
    CfdTypes.Order memory order,
    uint256 executionPrice
) internal pure returns (bool);

_isOracleFrozen

Returns true only when FX markets are actually closed and Pyth feeds have stopped publishing. Distinct from isFadWindow() which starts 3 hours earlier for margin purposes. Uses Friday 22:00 UTC (conservative vs 21:00 EDT summer) to guarantee zero latency arbitrage.

function _isOracleFrozen() internal view returns (bool);

_isCloseOnlyWindow

function _isCloseOnlyWindow() internal view returns (bool);

_invertPythPrice

Inverts a Pyth price (e.g. USD/JPY → JPY/USD) and returns 8-decimal output. Formula: 10^(8 - expo) / price

function _invertPythPrice(
    int64 price,
    int32 expo
) internal pure returns (uint256);

_normalizePythPrice

Converts a Pyth price to 8-decimal format. Scales up/down based on exponent difference from -8.

function _normalizePythPrice(
    int64 price,
    int32 expo
) internal pure returns (uint256);

updateMarkPrice

Push a fresh mark price to the engine without processing an order. Required before LP deposits/withdrawals when mark is stale.

function updateMarkPrice(
    bytes[] calldata pythUpdateData
) external payable;

Parameters

NameTypeDescription
pythUpdateDatabytes[]Pyth price update blobs; attach ETH to cover the Pyth fee

executeLiquidation

Keeper-triggered liquidation using the canonical live-market staleness policy. Forfeits any queued-order execution escrow to the vault instead of crediting it back to trader settlement, then pays the liquidation keeper bounty in USDC directly from the vault.

function executeLiquidation(
    bytes32 accountId,
    bytes[] calldata pythUpdateData
) external payable;

Parameters

NameTypeDescription
accountIdbytes32The account to liquidate (bytes32-encoded address)
pythUpdateDatabytes[]Pyth price update blobs; attach ETH to cover the Pyth fee

_pendingHeadOrderId

function _pendingHeadOrderId(
    bytes32 accountId
) internal view override returns (uint64);

_revertInsufficientFreeEquity

function _revertInsufficientFreeEquity() internal pure override;

_revertMarginOrderLinkCorrupted

function _revertMarginOrderLinkCorrupted() internal pure override;

Events

OrderCommitted

event OrderCommitted(uint64 indexed orderId, bytes32 indexed accountId, CfdTypes.Side side);

OrderExecuted

event OrderExecuted(uint64 indexed orderId, uint256 executionPrice);

OrderFailed

event OrderFailed(uint64 indexed orderId, OrderFailReason reason);

OrderSkipped

event OrderSkipped(uint64 indexed orderId, OrderFailReason reason, uint64 retryAfterTimestamp);

Errors

OrderRouter__ZeroSize

error OrderRouter__ZeroSize();

OrderRouter__CloseMarginDeltaNotAllowed

error OrderRouter__CloseMarginDeltaNotAllowed();

OrderRouter__TimelockNotReady

error OrderRouter__TimelockNotReady();

OrderRouter__NoProposal

error OrderRouter__NoProposal();

OrderRouter__FIFOViolation

error OrderRouter__FIFOViolation();

OrderRouter__OrderNotPending

error OrderRouter__OrderNotPending();

OrderRouter__InsufficientPythFee

error OrderRouter__InsufficientPythFee();

OrderRouter__MockModeDisabled

error OrderRouter__MockModeDisabled();

OrderRouter__NoOrdersToExecute

error OrderRouter__NoOrdersToExecute();

OrderRouter__MaxOrderIdNotCommitted

error OrderRouter__MaxOrderIdNotCommitted();

OrderRouter__OraclePriceTooStale

error OrderRouter__OraclePriceTooStale();

OrderRouter__NothingToClaim

error OrderRouter__NothingToClaim();

OrderRouter__EthTransferFailed

error OrderRouter__EthTransferFailed();

OrderRouter__OraclePriceNegative

error OrderRouter__OraclePriceNegative();

OrderRouter__MevOraclePriceTooStale

error OrderRouter__MevOraclePriceTooStale();

OrderRouter__LengthMismatch

error OrderRouter__LengthMismatch();

OrderRouter__InvalidWeights

error OrderRouter__InvalidWeights();

OrderRouter__InvalidBasePrice

error OrderRouter__InvalidBasePrice();

OrderRouter__EmptyFeeds

error OrderRouter__EmptyFeeds();

OrderRouter__MevDetected

error OrderRouter__MevDetected();

OrderRouter__MissingPythUpdateData

error OrderRouter__MissingPythUpdateData();

OrderRouter__OracleFrozen

error OrderRouter__OracleFrozen();

OrderRouter__InsufficientGas

error OrderRouter__InsufficientGas();

OrderRouter__NoOpenPosition

error OrderRouter__NoOpenPosition();

OrderRouter__CloseSideMismatch

error OrderRouter__CloseSideMismatch();

OrderRouter__CloseSizeExceedsPosition

error OrderRouter__CloseSizeExceedsPosition();

OrderRouter__InsufficientFreeEquity

error OrderRouter__InsufficientFreeEquity();

OrderRouter__MarginOrderLinkCorrupted

error OrderRouter__MarginOrderLinkCorrupted();

OrderRouter__PendingOrderLinkCorrupted

error OrderRouter__PendingOrderLinkCorrupted();

OrderRouter__Unauthorized

error OrderRouter__Unauthorized();

OrderRouter__TooManyPendingOrders

error OrderRouter__TooManyPendingOrders();

OrderRouter__DegradedMode

error OrderRouter__DegradedMode();

OrderRouter__CloseOnlyMode

error OrderRouter__CloseOnlyMode();

OrderRouter__SeedLifecycleIncomplete

error OrderRouter__SeedLifecycleIncomplete();

OrderRouter__TradingNotActive

error OrderRouter__TradingNotActive();

OrderRouter__RetryCooldownActive

error OrderRouter__RetryCooldownActive();

OrderRouter__OraclePublishTimeOutOfOrder

error OrderRouter__OraclePublishTimeOutOfOrder();

OrderRouter__InvalidStalenessLimit

error OrderRouter__InvalidStalenessLimit();

OrderRouter__PredictableOpenInvalid

error OrderRouter__PredictableOpenInvalid(uint8 code);

Structs

QueuedPositionView

struct QueuedPositionView {
    bool exists;
    CfdTypes.Side side;
    uint256 size;
}

RouterExecutionContext

struct RouterExecutionContext {
    bool oracleFrozen;
    bool isFadWindow;
    bool degradedMode;
    OrderOraclePolicyLib.OracleExecutionPolicy policy;
}

Enums

OrderFailReason

enum OrderFailReason {
    Expired,
    CloseOnlyOracleFrozen,
    CloseOnlyFad,
    SlippageExceeded,
    EnginePanic,
    AccountLiquidated,
    EngineRevert
}

TrancheVault

Git Source

Inherits: ERC4626

Title: TrancheVault

ERC4626 share token for a HousePool tranche (senior or junior). Routes all deposits/withdrawals through HousePool.

Note: security-contact: contact@plether.com

Constants

POOL

IHousePool public immutable POOL

IS_SENIOR

bool public immutable IS_SENIOR

DEPOSIT_COOLDOWN

uint256 public constant DEPOSIT_COOLDOWN = 1 hours

State Variables

lastDepositTime

mapping(address => uint256) public lastDepositTime

seedReceiver

address public seedReceiver

seedShareFloor

uint256 public seedShareFloor

Functions

constructor

constructor(
    IERC20 _usdc,
    address _pool,
    bool _isSenior,
    string memory _name,
    string memory _symbol
) ERC4626(_usdc) ERC20(_name, _symbol);

Parameters

NameTypeDescription
_usdcIERC20Underlying USDC token used as the vault asset
_pooladdressHousePool that holds USDC and manages the tranche waterfall
_isSeniorboolTrue for the senior tranche, false for junior
_namestringERC20 share token name
_symbolstringERC20 share token symbol

_decimalsOffset

Virtual share offset mitigates ERC4626 first-depositor inflation attack

function _decimalsOffset() internal pure override returns (uint8);

_update

Enforces a deposit cooldown on share transfers. Prevents flash-deposit-then-transfer to bypass the withdrawal cooldown. Propagates the sender’s cooldown to the receiver if it is more recent.

function _update(
    address from,
    address to,
    uint256 amount
) internal override;

totalAssets

function totalAssets() public view override returns (uint256);

deposit

function deposit(
    uint256 assets,
    address receiver
) public override returns (uint256);

mint

function mint(
    uint256 shares,
    address receiver
) public override returns (uint256);

maxDeposit

function maxDeposit(
    address receiver
) public view override returns (uint256);

maxMint

function maxMint(
    address receiver
) public view override returns (uint256);

withdraw

function withdraw(
    uint256 assets,
    address receiver,
    address _owner
) public override returns (uint256);

redeem

function redeem(
    uint256 shares,
    address receiver,
    address _owner
) public override returns (uint256);

maxWithdraw

function maxWithdraw(
    address _owner
) public view override returns (uint256);

maxRedeem

function maxRedeem(
    address _owner
) public view override returns (uint256);

_deposit

function _deposit(
    address caller,
    address receiver,
    uint256 assets,
    uint256 shares
) internal override;

_withdraw

function _withdraw(
    address caller,
    address receiver,
    address _owner,
    uint256 assets,
    uint256 shares
) internal override;

bootstrapMint

Mints shares to explicitly bootstrap previously quarantined pool assets into this tranche.

Only the pool may call this. The pool must have already assigned matching assets to the tranche principal.

function bootstrapMint(
    uint256 shares,
    address receiver
) external;

configureSeedPosition

Registers or increases the permanent seed-share floor for this tranche.

The pool must mint the corresponding shares before or within the same flow.

function configureSeedPosition(
    address receiver,
    uint256 floorShares
) external;

_unlockedOwnerShares

function _unlockedOwnerShares(
    address _owner
) internal view returns (uint256 ownerShares);

_isTerminallyWiped

function _isTerminallyWiped() internal view returns (bool);

_requireActiveTranche

function _requireActiveTranche() internal view;

_requireLifecycleActiveForOrdinaryDeposit

function _requireLifecycleActiveForOrdinaryDeposit() internal view;

_ordinaryDepositsAllowed

function _ordinaryDepositsAllowed() internal view returns (bool);

_canDepositNow

function _canDepositNow() internal view returns (bool);

Errors

TrancheVault__DepositCooldown

error TrancheVault__DepositCooldown();

TrancheVault__TransferDuringCooldown

error TrancheVault__TransferDuringCooldown();

TrancheVault__TrancheImpaired

error TrancheVault__TrancheImpaired();

TrancheVault__ThirdPartyDepositForExistingHolder

error TrancheVault__ThirdPartyDepositForExistingHolder();

TrancheVault__NotPool

error TrancheVault__NotPool();

TrancheVault__SeedFloorBreached

error TrancheVault__SeedFloorBreached();

TrancheVault__InvalidSeedPosition

error TrancheVault__InvalidSeedPosition();

TrancheVault__TerminallyWiped

error TrancheVault__TerminallyWiped();

TrancheVault__TradingNotActive

error TrancheVault__TradingNotActive();

BullLeverageRouter

Git Source

Inherits: LeverageRouterBase

Title: BullLeverageRouter

Leverage router for plDXY-BULL positions via Morpho Blue.

Uses Morpho flash loans + Splitter minting to acquire plDXY-BULL, then deposits as Morpho collateral. Close operation uses a single plDXY-BEAR flash mint for simplicity and gas efficiency. Uses Morpho’s fee-free flash loans for capital efficiency.

STATE MACHINE - OPEN LEVERAGE: ┌─────────────────────────────────────────────────────────────────────────┐ │ openLeverage(principal, leverage) │ │ 1. Pull USDC from user │ │ 2. Flash loan additional USDC from Morpho (fee-free) │ │ └──► onMorphoFlashLoan(OP_OPEN) │ │ └──► _executeOpen() │ │ 1. Mint plDXY-BEAR + plDXY-BULL pairs via Splitter │ │ 2. Sell plDXY-BEAR on Curve → USDC │ │ 3. Stake plDXY-BULL → splDXY-BULL │ │ 4. Deposit splDXY-BULL to Morpho (user’s collateral) │ │ 5. Borrow USDC from Morpho to cover flash repayment │ │ 6. Emit LeverageOpened event │ └─────────────────────────────────────────────────────────────────────────┘

STATE MACHINE - CLOSE LEVERAGE (Single Flash Mint): ┌─────────────────────────────────────────────────────────────────────────┐ │ closeLeverage(debtToRepay, collateralToWithdraw) │ │ 1. Flash mint plDXY-BEAR (collateral + extra for debt repayment) │ │ └──► onFlashLoan(OP_CLOSE) │ │ └──► _executeClose() │ │ 1. Sell extra plDXY-BEAR on Curve → USDC │ │ 2. Repay user’s Morpho debt with USDC from sale │ │ 3. Withdraw user’s splDXY-BULL from Morpho │ │ 4. Unstake splDXY-BULL → plDXY-BULL │ │ 5. Redeem plDXY-BEAR + plDXY-BULL → USDC │ │ 6. Buy plDXY-BEAR on Curve to repay flash mint │ │ 7. Transfer remaining USDC to user │ │ 8. Emit LeverageClosed event │ └─────────────────────────────────────────────────────────────────────────┘

STATE MACHINE - ADD COLLATERAL (Morpho Flash Loan): ┌─────────────────────────────────────────────────────────────────────────┐ │ addCollateral(usdcAmount) │ │ 1. Pull USDC from user │ │ 2. Flash loan USDC from Morpho (F = U × bearPrice / bullPrice) │ │ └──► onMorphoFlashLoan(OP_ADD_COLLATERAL) │ │ └──► _executeAddCollateral() │ │ 1. Mint plDXY-BEAR + plDXY-BULL pairs via Splitter │ │ 2. Sell ALL plDXY-BEAR on Curve → USDC │ │ 3. Stake plDXY-BULL → splDXY-BULL │ │ 4. Deposit splDXY-BULL to Morpho (user’s collateral) │ │ 5. Repay flash loan from BEAR sale proceeds │ │ 6. Emit CollateralAdded event │ └─────────────────────────────────────────────────────────────────────────┘

Note: security-contact: contact@plether.com

Constants

SPLITTER

SyntheticSplitter for minting/burning token pairs.

ISyntheticSplitter public immutable SPLITTER

PLDXY_BULL

plDXY-BULL token (collateral for bull positions).

IERC20 public immutable PLDXY_BULL

STAKED_PLDXY_BULL

StakedToken vault for plDXY-BULL (used as Morpho collateral).

IERC4626 public immutable STAKED_PLDXY_BULL

CAP

Protocol CAP price (8 decimals, oracle format).

uint256 public immutable CAP

ORACLE

Oracle for plDXY basket price (returns BEAR price in 8 decimals).

AggregatorV3Interface public immutable ORACLE

SEQUENCER_UPTIME_FEED

Chainlink L2 sequencer uptime feed (address(0) on L1).

AggregatorV3Interface public immutable SEQUENCER_UPTIME_FEED

ORACLE_TIMEOUT

Maximum age for a valid oracle price.

uint256 public constant ORACLE_TIMEOUT = 24 hours

SEQUENCER_GRACE_PERIOD

Grace period after L2 sequencer restarts before accepting prices.

uint256 public constant SEQUENCER_GRACE_PERIOD = 1 hours

OP_REMOVE_COLLATERAL

Operation type: remove collateral (flash mint).

uint8 internal constant OP_REMOVE_COLLATERAL = 3

OP_ADD_COLLATERAL

Operation type: add collateral (Morpho flash loan).

uint8 internal constant OP_ADD_COLLATERAL = 4

Functions

constructor

Deploys BullLeverageRouter with Morpho market configuration.

constructor(
    address _morpho,
    address _splitter,
    address _curvePool,
    address _usdc,
    address _plDxyBear,
    address _plDxyBull,
    address _stakedPlDxyBull,
    MarketParams memory _marketParams,
    address _sequencerUptimeFeed
) LeverageRouterBase(_morpho, _curvePool, _usdc, _plDxyBear);

Parameters

NameTypeDescription
_morphoaddressMorpho Blue protocol address.
_splitteraddressSyntheticSplitter contract address.
_curvePooladdressCurve USDC/plDXY-BEAR pool address.
_usdcaddressUSDC token address.
_plDxyBearaddressplDXY-BEAR token address.
_plDxyBulladdressplDXY-BULL token address.
_stakedPlDxyBulladdresssplDXY-BULL staking vault address.
_marketParamsMarketParamsMorpho market parameters for splDXY-BULL/USDC.
_sequencerUptimeFeedaddressChainlink L2 sequencer feed (address(0) on L1/testnet).

openLeverage

Open a Leveraged plDXY-BULL Position in one transaction.

Mints pairs via Splitter, sells plDXY-BEAR on Curve, deposits plDXY-BULL to Morpho. Uses fixed debt model (same as BEAR router) - Morpho debt equals principal * (leverage - 1).

function openLeverage(
    uint256 principal,
    uint256 leverage,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
principaluint256Amount of USDC user sends.
leverageuint256Multiplier (e.g. 3x = 3e18).
maxSlippageBpsuint256Maximum slippage tolerance in basis points (e.g., 50 = 0.5%). Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction.
minAmountOutuint256
deadlineuint256Unix timestamp after which the transaction reverts.

openLeverageWithPermit

Open a leveraged plDXY-BULL position with a USDC permit signature (gasless approval).

function openLeverageWithPermit(
    uint256 principal,
    uint256 leverage,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
principaluint256Amount of USDC user sends.
leverageuint256Multiplier (e.g. 3x = 3e18).
maxSlippageBpsuint256Maximum slippage tolerance in basis points.
minAmountOutuint256
deadlineuint256Unix timestamp after which the permit and transaction revert.
vuint8Signature recovery byte.
rbytes32Signature r component.
sbytes32Signature s component.

_openLeverageCore

function _openLeverageCore(
    uint256 principal,
    uint256 leverage,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline
) internal;

closeLeverage

Close a Leveraged plDXY-BULL Position in one transaction.

Uses a single plDXY-BEAR flash mint to unwind positions efficiently. Queries actual debt from Morpho to ensure full repayment even if interest accrued.

function closeLeverage(
    uint256 collateralToWithdraw,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
collateralToWithdrawuint256Amount of splDXY-BULL shares to withdraw from Morpho. NOTE: This is staked token shares, not underlying plDXY-BULL amount. Use STAKED_PLDXY_BULL.previewRedeem() to convert shares to underlying.
maxSlippageBpsuint256Maximum slippage tolerance in basis points. Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction.
minAmountOutuint256
deadlineuint256Unix timestamp after which the transaction reverts.

addCollateral

Add collateral to an existing leveraged position.

Uses Morpho flash loan so user’s USDC input ≈ collateral value added. Flow: Flash loan USDC → Mint pairs → Sell ALL BEAR to repay flash loan → Keep BULL as collateral. Formula: flashLoan = userUSDC × bearPrice / bullPrice

function addCollateral(
    uint256 usdcAmount,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
usdcAmountuint256Amount of USDC representing desired collateral value.
maxSlippageBpsuint256Maximum slippage tolerance in basis points. Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction.
minAmountOutuint256
deadlineuint256Unix timestamp after which the transaction reverts.

addCollateralWithPermit

Add collateral with a USDC permit signature (gasless approval).

function addCollateralWithPermit(
    uint256 usdcAmount,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
usdcAmountuint256Amount of USDC representing desired collateral value.
maxSlippageBpsuint256Maximum slippage tolerance in basis points.
minAmountOutuint256
deadlineuint256Unix timestamp after which the permit and transaction revert.
vuint8Signature recovery byte.
rbytes32Signature r component.
sbytes32Signature s component.

_addCollateralCore

function _addCollateralCore(
    uint256 usdcAmount,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline
) internal;

removeCollateral

Remove collateral from an existing leveraged position.

Uses flash mint of BEAR to redeem pairs, then buys back BEAR with USDC. Reverts if the resulting position would be unhealthy.

function removeCollateral(
    uint256 collateralToWithdraw,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
collateralToWithdrawuint256Amount of splDXY-BULL shares to withdraw. NOTE: This is staked token shares, not underlying plDXY-BULL amount.
maxSlippageBpsuint256Maximum slippage tolerance in basis points. Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction.
minAmountOutuint256
deadlineuint256Unix timestamp after which the transaction reverts.

onMorphoFlashLoan

Morpho flash loan callback for USDC flash loans (OP_OPEN, OP_ADD_COLLATERAL).

function onMorphoFlashLoan(
    uint256 amount,
    bytes calldata data
) external override;

Parameters

NameTypeDescription
amountuint256Amount of USDC borrowed.
databytesEncoded operation parameters.

onFlashLoan

ERC-3156 flash loan callback for plDXY-BEAR flash mints.

function onFlashLoan(
    address initiator,
    address,
    uint256 amount,
    uint256 fee,
    bytes calldata data
) external override returns (bytes32);

Parameters

NameTypeDescription
initiatoraddressAddress that initiated the flash loan (must be this contract).
<none>address
amountuint256Amount of plDXY-BEAR borrowed.
feeuint256Flash loan fee (always 0 for SyntheticToken).
databytesEncoded operation parameters.

Returns

NameTypeDescription
<none>bytes32CALLBACK_SUCCESS on successful execution.

_executeOpen

Executes open leverage operation within Morpho flash loan callback.

function _executeOpen(
    uint256 loanAmount,
    bytes calldata data
) private;

Parameters

NameTypeDescription
loanAmountuint256Amount of USDC borrowed from Morpho.
databytesEncoded parameters (op, user, deadline, principal, leverage, targetDebt, maxSlippageBps, minSwapOut, minAmountOut).

_executeAddCollateral

Executes add collateral operation within Morpho flash loan callback.

function _executeAddCollateral(
    uint256 flashLoanAmount,
    bytes calldata data
) private;

Parameters

NameTypeDescription
flashLoanAmountuint256Amount of USDC flash loaned.
databytesEncoded parameters (op, user, deadline, usdcAmount, maxSlippageBps, minSwapOut, minAmountOut).

_executeClose

Executes close leverage operation within plDXY-BEAR flash mint callback.

function _executeClose(
    uint256 flashAmount,
    uint256 flashFee,
    bytes calldata data
) private;

Parameters

NameTypeDescription
flashAmountuint256Amount of plDXY-BEAR flash minted.
flashFeeuint256Flash mint fee (always 0).
databytesEncoded parameters (op, user, deadline, collateralToWithdraw, debtToRepay, borrowShares, extraBearForDebt, maxSlippageBps, minAmountOut).

_executeRemoveCollateral

Executes remove collateral operation within plDXY-BEAR flash mint callback.

function _executeRemoveCollateral(
    uint256 flashAmount,
    uint256 flashFee,
    bytes calldata data
) private;

Parameters

NameTypeDescription
flashAmountuint256Amount of plDXY-BEAR flash minted.
flashFeeuint256Flash mint fee (always 0).
databytesEncoded parameters (op, user, deadline, collateralToWithdraw, maxSlippageBps, minAmountOut).

previewOpenLeverage

Preview the result of opening a leveraged plDXY-BULL position.

BULL leverage requires a larger flash loan than BEAR because minting happens at CAP price, not market price. The flash loan is repaid by: bearSaleProceeds + morphoBorrow. Morpho debt still follows the fixed model: principal * (leverage - 1).

function previewOpenLeverage(
    uint256 principal,
    uint256 leverage
) external view returns (uint256 loanAmount, uint256 totalUSDC, uint256 expectedPlDxyBull, uint256 expectedDebt);

Parameters

NameTypeDescription
principaluint256Amount of USDC user will send.
leverageuint256Multiplier (e.g. 2x = 2e18).

Returns

NameTypeDescription
loanAmountuint256Amount of USDC to flash loan.
totalUSDCuint256Total USDC for minting pairs (principal + loan).
expectedPlDxyBulluint256Expected plDXY-BULL tokens received.
expectedDebtuint256Expected Morpho debt (fixed: principal * (leverage - 1)).

previewCloseLeverage

Preview the result of closing a leveraged plDXY-BULL position.

function previewCloseLeverage(
    uint256 debtToRepay,
    uint256 collateralToWithdraw
) external view returns (uint256 expectedUSDC, uint256 usdcForBearBuyback, uint256 expectedReturn);

Parameters

NameTypeDescription
debtToRepayuint256Amount of USDC debt to repay.
collateralToWithdrawuint256Amount of plDXY-BULL collateral to withdraw.

Returns

NameTypeDescription
expectedUSDCuint256Expected USDC from redeeming pairs.
usdcForBearBuybackuint256Expected USDC needed to buy back plDXY-BEAR.
expectedReturnuint256Expected USDC returned to user after all repayments.

previewAddCollateral

Preview the result of adding collateral.

Uses flash loan so user’s USDC input ≈ collateral value added.

function previewAddCollateral(
    uint256 usdcAmount
)
    external
    view
    returns (uint256 flashLoanAmount, uint256 totalUSDC, uint256 expectedPlDxyBull, uint256 expectedStakedShares);

Parameters

NameTypeDescription
usdcAmountuint256Amount of USDC representing desired collateral value.

Returns

NameTypeDescription
flashLoanAmountuint256Amount of USDC to flash loan.
totalUSDCuint256Total USDC for minting pairs.
expectedPlDxyBulluint256Expected plDXY-BULL tokens to receive.
expectedStakedSharesuint256Expected splDXY-BULL shares to receive.

previewRemoveCollateral

Preview the result of removing collateral.

function previewRemoveCollateral(
    uint256 collateralToWithdraw
)
    external
    view
    returns (
        uint256 expectedPlDxyBull,
        uint256 expectedUsdcFromBurn,
        uint256 usdcForBearBuyback,
        uint256 expectedReturn
    );

Parameters

NameTypeDescription
collateralToWithdrawuint256Amount of splDXY-BULL shares to withdraw.

Returns

NameTypeDescription
expectedPlDxyBulluint256Expected plDXY-BULL from unstaking.
expectedUsdcFromBurnuint256Expected USDC from burning pairs.
usdcForBearBuybackuint256Expected USDC needed to buy back flash-minted BEAR.
expectedReturnuint256Expected USDC returned to user.

_calculateOpenParams

Calculates parameters for opening a leveraged position.

function _calculateOpenParams(
    uint256 principal,
    uint256 leverage
) private view returns (OpenParams memory params);

_getValidatedOraclePrice

Returns validated oracle prices with staleness, sequencer, and CAP checks.

function _getValidatedOraclePrice() private view returns (uint256 bearPrice, uint256 bullPrice);

_estimateBearForUsdcSale

Estimates BEAR needed to sell for a target USDC amount using binary search on Curve.

function _estimateBearForUsdcSale(
    uint256 targetUsdc
) private view returns (uint256);

_estimateUsdcForBearBuyback

Estimates USDC needed to buy BEAR using binary search on Curve.

function _estimateUsdcForBearBuyback(
    uint256 bearAmount
) private view returns (uint256);

_binarySearchCurve

Binary search for minimum input to Curve such that get_dy(i, j, input) >= targetOut.

function _binarySearchCurve(
    uint256 i,
    uint256 j,
    uint256 oneUnit,
    uint256 targetOut
) private view returns (uint256);

Parameters

NameTypeDescription
iuint256Curve pool input index.
juint256Curve pool output index.
oneUnituint256One unit of the input token (1e18 for BEAR, 1e6 for USDC).
targetOutuint256Desired minimum output from the swap.

Returns

NameTypeDescription
<none>uint256Minimum input amount that produces at least targetOut.

Events

LeverageOpened

Emitted when a leveraged plDXY-BULL position is opened.

event LeverageOpened(
    address indexed user,
    uint256 principal,
    uint256 leverage,
    uint256 loanAmount,
    uint256 plDxyBullReceived,
    uint256 debtIncurred,
    uint256 maxSlippageBps
);

LeverageClosed

Emitted when a leveraged plDXY-BULL position is closed.

event LeverageClosed(
    address indexed user,
    uint256 debtRepaid,
    uint256 collateralWithdrawn,
    uint256 usdcReturned,
    uint256 maxSlippageBps
);

CollateralAdded

Emitted when collateral is added to a position.

Net USDC cost = usdcAmount - usdcReturned (BEAR sale proceeds returned to user).

event CollateralAdded(
    address indexed user, uint256 usdcAmount, uint256 usdcReturned, uint256 collateralAdded, uint256 maxSlippageBps
);

CollateralRemoved

Emitted when collateral is removed from a position.

event CollateralRemoved(
    address indexed user, uint256 collateralWithdrawn, uint256 usdcReturned, uint256 maxSlippageBps
);

Structs

OpenParams

struct OpenParams {
    uint256 targetDebt;
    uint256 loanAmount;
    uint256 tokensToMint;
    uint256 expectedBearSale;
}

InvarCoin

Git Source

Inherits: ERC20, ERC20Permit, Ownable2Step, Pausable, ReentrancyGuard

Title: InvarCoin (INVAR)

Global purchasing power token backed 50/50 by USDC + plDXY-BEAR via Curve LP.

INVAR is a vault token whose backing is held as Curve USDC/plDXY-BEAR LP tokens. Users deposit USDC, which is single-sided deployed to Curve. The vault earns Curve trading fee yield (virtual price growth), which is harvested and donated to sINVAR stakers. LP tokens are valued with dual pricing to prevent manipulation:

  • totalAssets() and harvest use pessimistic pricing (min of EMA, oracle) for conservative NAV.
  • totalAssetsValidated() provides strict oracle-validated NAV (reverts on stale/invalid oracle).
  • deposit() uses optimistic NAV (max of EMA, oracle) so new depositors cannot dilute existing holders.
  • lpDeposit() values minted LP pessimistically so depositors cannot extract value from stale-high EMA.
  • withdraw() and lpWithdraw() use pro-rata asset distribution (no NAV pricing needed). The oracle-derived LP price mirrors the twocrypto-ng formula: 2 * virtualPrice * sqrt(bearPrice). A 2% USDC buffer (BUFFER_TARGET_BPS) is maintained locally for gas-efficient withdrawals. Excess USDC is deployed to Curve via permissionless keeper calls (deployToCurve). Virtual shares (1e18 INVAR / 1e6 USDC) protect against inflation attacks on the first deposit.

Note: security-contact: contact@plether.com

Constants

USDC

USDC collateral token (6 decimals).

IERC20 public immutable USDC

BEAR

plDXY-BEAR synthetic token (18 decimals).

IERC20 public immutable BEAR

CURVE_LP_TOKEN

Curve USDC/plDXY-BEAR LP token.

IERC20 public immutable CURVE_LP_TOKEN

CURVE_POOL

Curve twocrypto-ng pool for USDC/plDXY-BEAR.

ICurveTwocrypto public immutable CURVE_POOL

BASKET_ORACLE

Chainlink BasketOracle — weighted basket of 6 FX feeds, returns foreign currencies priced in USD (8 decimals).

AggregatorV3Interface public immutable BASKET_ORACLE

SEQUENCER_UPTIME_FEED

L2 sequencer uptime feed for staleness protection (address(0) on L1).

AggregatorV3Interface public immutable SEQUENCER_UPTIME_FEED

CRV_MINTER

Curve Minter for CRV emissions on L1 (address(0) on L2 where claim_rewards handles CRV).

ICurveMinter public immutable CRV_MINTER

BUFFER_TARGET_BPS

uint256 public constant BUFFER_TARGET_BPS = 200

DEPLOY_THRESHOLD

uint256 public constant DEPLOY_THRESHOLD = 1000e6

MAX_SPOT_DEVIATION_BPS

uint256 public constant MAX_SPOT_DEVIATION_BPS = 50

ORACLE_TIMEOUT

uint256 public constant ORACLE_TIMEOUT = 24 hours

SEQUENCER_GRACE_PERIOD

uint256 public constant SEQUENCER_GRACE_PERIOD = 1 hours

VIRTUAL_SHARES

uint256 public constant VIRTUAL_SHARES = 1e18

VIRTUAL_ASSETS

uint256 public constant VIRTUAL_ASSETS = 1e6

USDC_INDEX

uint256 private constant USDC_INDEX = 0

BPS

uint256 private constant BPS = 10_000

STAKED_INVAR_TIMELOCK

uint256 public constant STAKED_INVAR_TIMELOCK = 7 days

GAUGE_TIMELOCK

uint256 public constant GAUGE_TIMELOCK = 7 days

GAUGE_REWARDS_TIMELOCK

uint256 public constant GAUGE_REWARDS_TIMELOCK = 7 days

State Variables

stakedInvarCoin

sINVAR staking contract that receives harvested yield.

StakedToken public stakedInvarCoin

pendingStakedInvarCoin

address public pendingStakedInvarCoin

stakedInvarCoinActivationTime

uint256 public stakedInvarCoinActivationTime

curveLpCostVp

Cumulative virtual-price cost basis of tracked LP tokens (18 decimals).

Used to isolate fee yield (VP growth) from price appreciation. Only LP tokens deployed by the vault are tracked — donated LP is excluded to prevent yield manipulation.

uint256 public curveLpCostVp

trackedLpBalance

LP token balance deployed by the vault (excludes donated LP).

uint256 public trackedLpBalance

emergencyActive

True when emergency mode is active — blocks deposits and single-sided withdrawals.

bool public emergencyActive

curveGauge

ICurveGauge public curveGauge

gaugeStakedLp

Internally-tracked LP balance staked in the gauge (avoids external balanceOf dependency).

uint256 public gaugeStakedLp

pendingGauge

address public pendingGauge

gaugeActivationTime

uint256 public gaugeActivationTime

approvedGauges

mapping(address => bool) public approvedGauges

gaugeRewardsReceiver

address public gaugeRewardsReceiver

pendingGaugeRewardsReceiver

address public pendingGaugeRewardsReceiver

gaugeRewardsReceiverActivationTime

uint256 public gaugeRewardsReceiverActivationTime

protectedRewardTokens

mapping(address => bool) public protectedRewardTokens

Functions

constructor

constructor(
    address _usdc,
    address _bear,
    address _curveLpToken,
    address _curvePool,
    address _oracle,
    address _sequencerUptimeFeed,
    address _crvMinter
) ERC20("InvarCoin", "INVAR") ERC20Permit("InvarCoin") Ownable(msg.sender);

Parameters

NameTypeDescription
_usdcaddressUSDC token address.
_bearaddressplDXY-BEAR token address.
_curveLpTokenaddressCurve USDC/plDXY-BEAR LP token address.
_curvePooladdressCurve twocrypto-ng pool address.
_oracleaddressBasketOracle address (Chainlink AggregatorV3Interface).
_sequencerUptimeFeedaddressL2 sequencer uptime feed (address(0) on L1).
_crvMinteraddressCurve Minter for CRV emissions (address(0) on L2).

_validateStakingVault

function _validateStakingVault(
    address stakingVault
) private view;

proposeStakedInvarCoin

Propose the sINVAR staking contract. Finalized after STAKED_INVAR_TIMELOCK.

function proposeStakedInvarCoin(
    address _stakedInvarCoin
) external onlyOwner;

Parameters

NameTypeDescription
_stakedInvarCoinaddressAddress of the StakedToken (sINVAR) contract.

finalizeStakedInvarCoin

Finalize the proposed sINVAR staking contract after the timelock.

function finalizeStakedInvarCoin() external onlyOwner;

proposeGaugeRewardsReceiver

Propose the receiver for protected gauge reward tokens.

function proposeGaugeRewardsReceiver(
    address receiver
) external onlyOwner;

finalizeGaugeRewardsReceiver

Finalize the protected reward receiver after the timelock.

function finalizeGaugeRewardsReceiver() external onlyOwner;

protectRewardToken

Irreversibly marks a token as a protected gauge reward token.

function protectRewardToken(
    address token
) external onlyOwner;

sweepGaugeRewards

Sweeps a protected gauge reward token to the configured receiver.

function sweepGaugeRewards(
    address token
) external onlyOwner;

totalAssets

Total assets backing INVAR (USDC, 6 decimals).

Uses pessimistic LP pricing: min(Curve EMA, oracle-derived) to prevent stale-EMA exploitation.

function totalAssets() public view returns (uint256);

totalAssetsValidated

Total assets backing INVAR with strict oracle validation (USDC, 6 decimals).

Reverts if sequencer/oracle checks fail (stale, invalid, or within sequencer grace period).

function totalAssetsValidated() external view returns (uint256);

_totalAssetsWithPrice

Total assets using pre-fetched LP balance and validated oracle price.

function _totalAssetsWithPrice(
    uint256 lpBal,
    uint256 oraclePrice
) private view returns (uint256);

getBufferMetrics

Buffer health metrics for keeper bots and frontends.

Uses permissive totalAssets() (best-effort oracle read). For strict oracle-validated NAV, use totalAssetsValidated().

function getBufferMetrics()
    external
    view
    returns (uint256 currentBuffer, uint256 targetBuffer, uint256 deployable, uint256 replenishable);

Returns

NameTypeDescription
currentBufferuint256USDC held locally (6 decimals).
targetBufferuint256Target USDC buffer based on total assets (6 decimals).
deployableuint256Excess USDC deployable to Curve (0 if below threshold).
replenishableuint256USDC deficit that needs replenishing from Curve LP.

getHarvestableYield

Estimated harvestable Curve fee yield (USDC, 6 decimals).

Read-only estimator mirroring _harvest math. Uses permissive oracle reads and returns 0 if no staking contract or no VP growth.

function getHarvestableYield() external view returns (uint256 yieldUsdc);

getSpotDeviation

Spot-vs-EMA deviation for a 1 USDC deposit (basis points).

Returns 0 if spot >= EMA (no discount). Used by keepers to check if deploy/replenish is safe.

function getSpotDeviation() external view returns (uint256 deviationBps);

_totalAssetsOptimistic

Total assets using optimistic LP pricing — max(EMA, oracle) to prevent deposit dilution.

function _totalAssetsOptimistic(
    uint256 oraclePrice
) private view returns (uint256);

_oracleLpPrice

Oracle-derived LP price: mirrors twocrypto-ng formula 2 * vp * sqrt(bearPrice_18dec).

function _oracleLpPrice(
    uint256 oraclePrice
) private view returns (uint256);

_pessimisticLpPrice

function _pessimisticLpPrice(
    uint256 oraclePrice
) private view returns (uint256);

_optimisticLpPrice

function _optimisticLpPrice(
    uint256 oraclePrice
) private view returns (uint256);

_validatedOraclePrice

function _validatedOraclePrice() private view returns (uint256);

_lpBalance

Total LP held: local + gauge-staked (internally tracked to avoid external call dependency).

function _lpBalance() private view returns (uint256);

_ensureUnstakedLp

Unstakes LP from gauge if local balance is insufficient for the requested amount.

function _ensureUnstakedLp(
    uint256 amount
) private;

_reduceLpAccounting

function _reduceLpAccounting(
    uint256 lpReduced,
    uint256 totalLp
) private;

_recordLpDeployment

function _recordLpDeployment(
    uint256 lpMinted
) private;

_stakeLpToGauge

function _stakeLpToGauge(
    uint256 amount
) private;

_validateGaugeAddress

function _validateGaugeAddress(
    address gauge
) private view;

_validateGauge

function _validateGauge(
    address gauge
) private view;

deposit

Deposit USDC to mint INVAR shares. USDC stays in the local buffer until deployed to Curve.

Uses optimistic LP pricing for NAV to prevent deposit dilution. Harvests yield before minting. Reverts while emergencyActive is true.

function deposit(
    uint256 usdcAmount,
    address receiver,
    uint256 minSharesOut
) public nonReentrant whenNotPaused returns (uint256 glUsdMinted);

Parameters

NameTypeDescription
usdcAmountuint256Amount of USDC to deposit (6 decimals).
receiveraddressAddress that receives the minted INVAR shares.
minSharesOutuint256Minimum INVAR shares to receive (0 = no minimum).

Returns

NameTypeDescription
glUsdMinteduint256Number of INVAR shares minted.

depositWithPermit

Gasless deposit using ERC-2612 permit. Falls back to existing allowance if permit fails (e.g., front-run griefing) and the allowance is sufficient.

function depositWithPermit(
    uint256 usdcAmount,
    address receiver,
    uint256 minSharesOut,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
) external returns (uint256);

Parameters

NameTypeDescription
usdcAmountuint256Amount of USDC to deposit (6 decimals).
receiveraddressAddress that receives the minted INVAR shares.
minSharesOutuint256Minimum INVAR shares to receive (0 = no minimum).
deadlineuint256Permit signature expiry timestamp.
vuint8ECDSA recovery byte.
rbytes32ECDSA r component.
sbytes32ECDSA s component.

Returns

NameTypeDescription
<none>uint256Number of INVAR shares minted.

withdraw

USDC-only withdrawal via pro-rata buffer + JIT Curve LP burn.

Burns the user’s pro-rata share of local USDC and Curve LP (single-sided to USDC). Does not distribute raw BEAR balances — if the contract holds material BEAR, use lpWithdraw() or set minUsdcOut to enforce fair value. Blocked during emergencyActive since single-sided LP exit may be unavailable.

function withdraw(
    uint256 glUsdAmount,
    address receiver,
    uint256 minUsdcOut
) external nonReentrant whenNotPaused returns (uint256 usdcOut);

Parameters

NameTypeDescription
glUsdAmountuint256Amount of INVAR shares to burn.
receiveraddressAddress that receives the withdrawn USDC.
minUsdcOutuint256Minimum USDC to receive (slippage protection).

Returns

NameTypeDescription
usdcOutuint256Total USDC returned (buffer + Curve LP proceeds).

lpWithdraw

Balanced withdrawal: returns pro-rata USDC + BEAR from Curve LP (remove_liquidity).

Intentionally lacks whenNotPaused — serves as the emergency exit when the contract is paused. Emergency mode still honors pro-rata LP claims by redeeming any remaining LP before paying out.

function lpWithdraw(
    uint256 glUsdAmount,
    uint256 minUsdcOut,
    uint256 minBearOut
) external nonReentrant returns (uint256 usdcReturned, uint256 bearReturned);

Parameters

NameTypeDescription
glUsdAmountuint256Amount of INVAR shares to burn.
minUsdcOutuint256Minimum USDC to receive (slippage protection).
minBearOutuint256Minimum plDXY-BEAR to receive (slippage protection).

Returns

NameTypeDescription
usdcReturneduint256Total USDC returned.
bearReturneduint256Total plDXY-BEAR returned.

_lpWithdraw

function _lpWithdraw(
    uint256 glUsdAmount,
    uint256 minUsdcOut,
    uint256 minBearOut
) internal returns (uint256 usdcReturned, uint256 bearReturned);

lpDeposit

Direct LP deposit: provide USDC and/or plDXY-BEAR, deploy to Curve, mint INVAR.

Inverse of lpWithdraw. Curve slippage is borne by the depositor, not existing holders. Shares are priced using pessimistic LP valuation so the depositor cannot extract value from a stale-high EMA. Spot deviation is checked against EMA to block sandwich attacks. Reverts while emergencyActive is true.

function lpDeposit(
    uint256 usdcAmount,
    uint256 bearAmount,
    address receiver,
    uint256 minSharesOut
) external nonReentrant whenNotPaused returns (uint256 glUsdMinted);

Parameters

NameTypeDescription
usdcAmountuint256Amount of USDC to deposit (6 decimals, can be 0 if bearAmount > 0).
bearAmountuint256Amount of plDXY-BEAR to deposit (18 decimals, can be 0 if usdcAmount > 0).
receiveraddressAddress that receives the minted INVAR shares.
minSharesOutuint256Minimum INVAR shares to receive (slippage protection).

Returns

NameTypeDescription
glUsdMinteduint256Number of INVAR shares minted.

harvest

Permissionless keeper harvest for Curve LP fee yield.

Measures fee yield as virtual price growth above the cost basis (curveLpCostVp). Mints INVAR proportional to the USDC value of yield and donates it to sINVAR stakers. Only tracks VP growth on vault-deployed LP (trackedLpBalance), not donated LP. Reverts if no yield is available — use as a heartbeat signal for keepers.

function harvest() external nonReentrant whenNotPaused returns (uint256 donated);

Returns

NameTypeDescription
donateduint256Amount of INVAR minted and donated to sINVAR.

_harvestSafe

Harvest yield before withdrawals. Best-effort: skips when no yield is pending, Curve is down, or oracle is unavailable. Withdrawals must never be blocked by oracle outages.

function _harvestSafe() internal;

_harvest

Uses trackedLpBalance (not _lpBalance()) so donated LP cannot inflate harvestable yield. Divergence from actual LP is prevented by internal gaugeStakedLp tracking and forceRemoveGauge() which writes off stuck LP from both trackedLpBalance and curveLpCostVp.

function _harvest() internal returns (uint256 donated);

_mintAndDonate

function _mintAndDonate(
    uint256 amount
) private;

_harvestWithPrice

function _harvestWithPrice(
    uint256 lpBal,
    uint256 currentVpValue,
    uint256 oraclePrice
) private returns (uint256 donated);

donateUsdc

Accepts USDC donations from RewardDistributor, mints proportional INVAR, and donates to sINVAR.

function donateUsdc(
    uint256 usdcAmount
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
usdcAmountuint256Amount of USDC to donate (6 decimals).

deployToCurve

Permissionless keeper function: deploys excess USDC buffer into Curve as single-sided liquidity.

Maintains a 2% USDC buffer (BUFFER_TARGET_BPS). Only deploys if excess exceeds DEPLOY_THRESHOLD ($1000). Spot-vs-EMA deviation check (MAX_SPOT_DEVIATION_BPS = 0.5%) blocks deployment during pool manipulation.

function deployToCurve(
    uint256 maxUsdc
) external nonReentrant whenNotPaused returns (uint256 lpMinted);

Parameters

NameTypeDescription
maxUsdcuint256Cap on USDC to deploy (0 = no cap, deploy entire excess).

Returns

NameTypeDescription
lpMinteduint256Amount of Curve LP tokens minted.

replenishBuffer

Permissionless keeper function: restores USDC buffer by burning Curve LP (single-sided to USDC).

Inverse of deployToCurve. Uses same spot-vs-EMA deviation check for sandwich protection. The maxLpToBurn parameter allows chunked replenishment when the full withdrawal would exceed the 0.5% spot deviation limit due to price impact.

function replenishBuffer(
    uint256 maxLpToBurn
) external nonReentrant whenNotPaused returns (uint256 usdcRecovered);

Parameters

NameTypeDescription
maxLpToBurnuint256Cap on LP tokens to burn (0 = no cap, burn entire deficit).

redeployToCurve

Re-deploys recovered BEAR + excess USDC to Curve after emergency recovery.

Clears emergencyActive flag. Should only be called after emergencyWithdrawFromCurve() has recovered the BEAR tokens from the pool.

function redeployToCurve(
    uint256 minLpOut
) external onlyOwner nonReentrant;

Parameters

NameTypeDescription
minLpOutuint256Minimum LP tokens to mint (slippage protection for the two-sided deposit).

setEmergencyMode

Activates emergency mode without touching Curve.

Pauses the contract and blocks deposits plus single-sided withdrawals. LP accounting is left intact so users retain their pro-rata claim once balanced exits recover.

function setEmergencyMode() external onlyOwner;

forceRemoveGauge

Write off a bricked gauge and its stuck LP from accounting.

Only callable during emergencyActive. Clears curveGauge, proportionally reduces trackedLpBalance and curveLpCostVp for the lost LP, and zeros gaugeStakedLp. After this, emergencyWithdrawFromCurve() or lpWithdraw() can proceed with remaining local LP.

function forceRemoveGauge() external onlyOwner;

emergencyWithdrawFromCurve

Attempts to recover LP tokens from Curve via balanced remove_liquidity.

Also callable as a standalone emergency — sets emergencyActive, pauses, and only zeroes tracked LP accounting after the LP has actually been recovered. If Curve is bricked, the remove_liquidity call reverts and the entire tx rolls back, leaving state unchanged. Use setEmergencyMode() first in that case.

function emergencyWithdrawFromCurve() external onlyOwner nonReentrant;

setGaugeApproval

function setGaugeApproval(
    address gauge,
    bool approved
) external onlyOwner;

pause

function pause() external onlyOwner;

unpause

function unpause() external onlyOwner;

rescueToken

Rescue accidentally sent ERC20 tokens. Cannot rescue USDC, BEAR, or Curve LP.

function rescueToken(
    address token,
    address to
) external onlyOwner;

Parameters

NameTypeDescription
tokenaddressAddress of the token to rescue.
toaddressDestination address for the rescued tokens.

proposeGauge

Propose a new Curve gauge for LP staking. Subject to GAUGE_TIMELOCK delay.

function proposeGauge(
    address _gauge
) external onlyOwner;

Parameters

NameTypeDescription
_gaugeaddressAddress of the new gauge (address(0) to remove gauge).

finalizeGauge

Finalize a pending gauge change after the timelock expires.

This MUST revert if oldGauge.withdraw() fails. Do NOT wrap in try/catch: silent failure would update curveGauge to newGauge while LP stays locked in oldGauge, causing _lpBalance() to forget the stuck LP and collapsing totalAssets(). If the old gauge is permanently bricked, use setEmergencyMode() instead.

function finalizeGauge() external onlyOwner;

stakeToGauge

Stake LP tokens to the active Curve gauge.

function stakeToGauge(
    uint256 amount
) external onlyOwner;

Parameters

NameTypeDescription
amountuint256Amount of LP to stake (0 = all unstaked LP).

unstakeFromGauge

Unstake LP tokens from the active Curve gauge.

function unstakeFromGauge(
    uint256 amount
) external onlyOwner;

Parameters

NameTypeDescription
amountuint256Amount of LP to unstake (0 = all staked LP).

claimGaugeRewards

Claim CRV + extra rewards from the gauge. Use rescueToken() to sweep reward tokens.

On L1, CRV is minted via the Curve Minter (not claim_rewards). On L2, claim_rewards handles CRV.

function claimGaugeRewards() external onlyOwner;

Events

Deposited

event Deposited(address indexed user, address indexed receiver, uint256 usdcIn, uint256 glUsdOut);

Withdrawn

event Withdrawn(address indexed user, address indexed receiver, uint256 glUsdIn, uint256 usdcOut);

LpWithdrawn

event LpWithdrawn(address indexed user, uint256 sharesBurned, uint256 usdcReturned, uint256 bearReturned);

LpDeposited

event LpDeposited(address indexed user, address indexed receiver, uint256 usdcIn, uint256 bearIn, uint256 glUsdOut);

DeployedToCurve

event DeployedToCurve(address indexed caller, uint256 usdcDeployed, uint256 bearDeployed, uint256 lpMinted);

BufferReplenished

event BufferReplenished(uint256 lpBurned, uint256 usdcRecovered);

YieldHarvested

event YieldHarvested(uint256 glUsdMinted, uint256 callerReward, uint256 donated);

TokenRescued

event TokenRescued(address indexed token, address indexed to, uint256 amount);

EmergencyWithdrawCurve

event EmergencyWithdrawCurve(uint256 lpBurned, uint256 usdcReceived, uint256 bearReceived);

StakedInvarCoinProposed

event StakedInvarCoinProposed(address indexed stakedInvarCoin, uint256 activationTime);

StakedInvarCoinSet

event StakedInvarCoinSet(address indexed stakedInvarCoin);

GaugeProposed

event GaugeProposed(address indexed gauge, uint256 activationTime);

GaugeUpdated

event GaugeUpdated(address indexed oldGauge, address indexed newGauge);

GaugeRewardsReceiverProposed

event GaugeRewardsReceiverProposed(address indexed receiver, uint256 activationTime);

GaugeRewardsReceiverSet

event GaugeRewardsReceiverSet(address indexed receiver);

RewardTokenProtected

event RewardTokenProtected(address indexed token);

GaugeStaked

event GaugeStaked(uint256 amount);

GaugeUnstaked

event GaugeUnstaked(uint256 amount);

GaugeRewardsClaimed

event GaugeRewardsClaimed();

GaugeRewardsSwept

event GaugeRewardsSwept(address indexed token, address indexed receiver, uint256 amount);

UsdcDonated

event UsdcDonated(address indexed donor, uint256 usdcAmount, uint256 invarMinted);

GaugeForceRemoved

event GaugeForceRemoved(address indexed gauge, uint256 lpLost);

Errors

InvarCoin__ZeroAmount

error InvarCoin__ZeroAmount();

InvarCoin__StakingNotSet

error InvarCoin__StakingNotSet();

InvarCoin__ZeroAddress

error InvarCoin__ZeroAddress();

InvarCoin__SlippageExceeded

error InvarCoin__SlippageExceeded();

InvarCoin__NothingToDeploy

error InvarCoin__NothingToDeploy();

InvarCoin__NoYield

error InvarCoin__NoYield();

InvarCoin__CannotRescueCoreAsset

error InvarCoin__CannotRescueCoreAsset();

InvarCoin__PermitFailed

error InvarCoin__PermitFailed();

InvarCoin__AlreadySet

error InvarCoin__AlreadySet();

InvarCoin__SpotDeviationTooHigh

error InvarCoin__SpotDeviationTooHigh();

InvarCoin__UseLpWithdraw

error InvarCoin__UseLpWithdraw();

InvarCoin__Unauthorized

error InvarCoin__Unauthorized();

InvarCoin__GaugeTimelockActive

error InvarCoin__GaugeTimelockActive();

InvarCoin__StakingTimelockActive

error InvarCoin__StakingTimelockActive();

InvarCoin__GaugeRewardsTimelockActive

error InvarCoin__GaugeRewardsTimelockActive();

InvarCoin__InvalidProposal

error InvarCoin__InvalidProposal();

InvarCoin__NoGauge

error InvarCoin__NoGauge();

InvarCoin__EmergencyActive

error InvarCoin__EmergencyActive();

InvarCoin__InvalidGauge

error InvarCoin__InvalidGauge();

InvarCoin__InvalidStakingVault

error InvarCoin__InvalidStakingVault();

InvarCoin__GaugeRewardsReceiverNotSet

error InvarCoin__GaugeRewardsReceiverNotSet();

InvarCoin__NotEmergency

error InvarCoin__NotEmergency();

LeverageRouter

Git Source

Inherits: LeverageRouterBase

Title: LeverageRouter

Leverage router for plDXY-BEAR positions via Morpho Blue.

Flash loans USDC from Morpho → swaps to plDXY-BEAR on Curve → stakes → deposits to Morpho as collateral. Requires user to authorize this contract in Morpho before use. Uses Morpho’s fee-free flash loans for capital efficiency.

Note: security-contact: contact@plether.com

Constants

STAKED_PLDXY_BEAR

StakedToken vault for plDXY-BEAR (used as Morpho collateral).

IERC4626 public immutable STAKED_PLDXY_BEAR

Functions

constructor

Deploys LeverageRouter with Morpho market configuration.

constructor(
    address _morpho,
    address _curvePool,
    address _usdc,
    address _plDxyBear,
    address _stakedPlDxyBear,
    MarketParams memory _marketParams
) LeverageRouterBase(_morpho, _curvePool, _usdc, _plDxyBear);

Parameters

NameTypeDescription
_morphoaddressMorpho Blue protocol address.
_curvePooladdressCurve USDC/plDXY-BEAR pool address.
_usdcaddressUSDC token address.
_plDxyBearaddressplDXY-BEAR token address.
_stakedPlDxyBearaddresssplDXY-BEAR staking vault address.
_marketParamsMarketParamsMorpho market parameters for splDXY-BEAR/USDC.

openLeverage

Open a Leveraged Position in one transaction.

function openLeverage(
    uint256 principal,
    uint256 leverage,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
principaluint256Amount of USDC user sends.
leverageuint256Multiplier (e.g. 3x = 3e18).
maxSlippageBpsuint256Maximum slippage tolerance in basis points (e.g., 50 = 0.5%). Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction.
minAmountOutuint256
deadlineuint256Unix timestamp after which the transaction reverts.

openLeverageWithPermit

Open a leveraged position with a USDC permit signature (gasless approval).

function openLeverageWithPermit(
    uint256 principal,
    uint256 leverage,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
principaluint256Amount of USDC user sends.
leverageuint256Multiplier (e.g. 3x = 3e18).
maxSlippageBpsuint256Maximum slippage tolerance in basis points.
minAmountOutuint256
deadlineuint256Unix timestamp after which the permit and transaction revert.
vuint8Signature recovery byte.
rbytes32Signature r component.
sbytes32Signature s component.

_openLeverageCore

function _openLeverageCore(
    uint256 principal,
    uint256 leverage,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline
) internal;

closeLeverage

Close a Leveraged Position in one transaction.

Queries actual debt from Morpho to ensure full repayment even if interest accrued.

function closeLeverage(
    uint256 collateralToWithdraw,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
collateralToWithdrawuint256Amount of splDXY-BEAR shares to withdraw from Morpho. NOTE: This is staked token shares, not underlying plDXY-BEAR amount. Use STAKED_PLDXY_BEAR.previewRedeem() to convert shares to underlying.
maxSlippageBpsuint256Maximum slippage tolerance in basis points (e.g., 50 = 0.5%). Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction.
minAmountOutuint256
deadlineuint256Unix timestamp after which the transaction reverts.

addCollateral

Add collateral to an existing leveraged position.

Swaps USDC to plDXY-BEAR on Curve, stakes, and deposits to Morpho.

function addCollateral(
    uint256 usdcAmount,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
usdcAmountuint256Amount of USDC to add as collateral.
maxSlippageBpsuint256Maximum slippage tolerance in basis points. Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction.
minAmountOutuint256
deadlineuint256Unix timestamp after which the transaction reverts.

addCollateralWithPermit

Add collateral with a USDC permit signature (gasless approval).

function addCollateralWithPermit(
    uint256 usdcAmount,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
usdcAmountuint256Amount of USDC to add as collateral.
maxSlippageBpsuint256Maximum slippage tolerance in basis points.
minAmountOutuint256
deadlineuint256Unix timestamp after which the permit and transaction revert.
vuint8Signature recovery byte.
rbytes32Signature r component.
sbytes32Signature s component.

_addCollateralCore

function _addCollateralCore(
    uint256 usdcAmount,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline
) internal;

removeCollateral

Remove collateral from an existing leveraged position.

Withdraws from Morpho, unstakes, and swaps to USDC. Reverts if the resulting position would be unhealthy.

function removeCollateral(
    uint256 collateralToWithdraw,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
collateralToWithdrawuint256Amount of splDXY-BEAR shares to withdraw. NOTE: This is staked token shares, not underlying plDXY-BEAR amount.
maxSlippageBpsuint256Maximum slippage tolerance in basis points. Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction.
minAmountOutuint256
deadlineuint256Unix timestamp after which the transaction reverts.

onMorphoFlashLoan

Morpho flash loan callback. Routes to open or close handler.

function onMorphoFlashLoan(
    uint256 amount,
    bytes calldata data
) external override;

Parameters

NameTypeDescription
amountuint256Amount of USDC borrowed.
databytesEncoded operation parameters.

onFlashLoan

ERC-3156 flash loan callback - not used by LeverageRouter.

Always reverts as LeverageRouter only uses Morpho flash loans.

function onFlashLoan(
    address,
    address,
    uint256,
    uint256,
    bytes calldata
) external pure override returns (bytes32);

_executeOpen

Executes open leverage operation within Morpho flash loan callback.

function _executeOpen(
    uint256 loanAmount,
    bytes calldata data
) private;

Parameters

NameTypeDescription
loanAmountuint256Amount of USDC borrowed from Morpho.
databytesEncoded parameters (op, user, deadline, principal, leverage, maxSlippageBps, minPlDxyBear, minAmountOut).

_executeClose

Executes close leverage operation within Morpho flash loan callback.

function _executeClose(
    uint256 loanAmount,
    bytes calldata data
) private;

Parameters

NameTypeDescription
loanAmountuint256Amount of USDC borrowed from Morpho to repay debt.
databytesEncoded parameters (op, user, deadline, collateralToWithdraw, borrowShares, maxSlippageBps, minUsdcOut, minAmountOut).

_executeCloseNoDebt

Closes position without flash loan when user has no Morpho debt.

function _executeCloseNoDebt(
    address user,
    uint256 collateralToWithdraw,
    uint256 maxSlippageBps,
    uint256 minUsdcOut,
    uint256 minAmountOut
) private;

Parameters

NameTypeDescription
useraddressPosition owner receiving USDC.
collateralToWithdrawuint256Amount of splDXY-BEAR shares to withdraw.
maxSlippageBpsuint256Maximum slippage for Curve swap.
minUsdcOutuint256Minimum USDC to receive after swap.
minAmountOutuint256User-provided minimum USDC to receive (MEV protection).

previewOpenLeverage

Preview the result of opening a leveraged position.

function previewOpenLeverage(
    uint256 principal,
    uint256 leverage
) external view returns (uint256 loanAmount, uint256 totalUSDC, uint256 expectedPlDxyBear, uint256 expectedDebt);

Parameters

NameTypeDescription
principaluint256Amount of USDC user will send.
leverageuint256Multiplier (e.g. 3x = 3e18).

Returns

NameTypeDescription
loanAmountuint256Amount of USDC to flash loan.
totalUSDCuint256Total USDC to swap (principal + loan).
expectedPlDxyBearuint256Expected plDXY-BEAR (based on current curve price).
expectedDebtuint256Expected debt incurred (equals loan amount, no flash fee with Morpho).

previewCloseLeverage

Preview the result of closing a leveraged position.

function previewCloseLeverage(
    uint256 debtToRepay,
    uint256 collateralToWithdraw
) external view returns (uint256 expectedUSDC, uint256 flashFee, uint256 expectedReturn);

Parameters

NameTypeDescription
debtToRepayuint256Amount of USDC debt to repay.
collateralToWithdrawuint256Amount of plDXY-BEAR collateral to withdraw.

Returns

NameTypeDescription
expectedUSDCuint256Expected USDC from swap (based on current curve price).
flashFeeuint256Flash loan fee (always 0 with Morpho).
expectedReturnuint256Expected USDC returned to user after repaying flash loan.

previewAddCollateral

Preview the result of adding collateral.

function previewAddCollateral(
    uint256 usdcAmount
) external view returns (uint256 expectedPlDxyBear, uint256 expectedStakedShares);

Parameters

NameTypeDescription
usdcAmountuint256Amount of USDC to add as collateral.

Returns

NameTypeDescription
expectedPlDxyBearuint256Expected plDXY-BEAR from Curve swap.
expectedStakedSharesuint256Expected splDXY-BEAR shares to receive.

previewRemoveCollateral

Preview the result of removing collateral.

function previewRemoveCollateral(
    uint256 collateralToWithdraw
) external view returns (uint256 expectedPlDxyBear, uint256 expectedUSDC);

Parameters

NameTypeDescription
collateralToWithdrawuint256Amount of splDXY-BEAR shares to withdraw.

Returns

NameTypeDescription
expectedPlDxyBearuint256Expected plDXY-BEAR from unstaking.
expectedUSDCuint256Expected USDC from Curve swap.

Events

LeverageOpened

Emitted when a leveraged plDXY-BEAR position is opened.

event LeverageOpened(
    address indexed user,
    uint256 principal,
    uint256 leverage,
    uint256 loanAmount,
    uint256 plDxyBearReceived,
    uint256 debtIncurred,
    uint256 maxSlippageBps
);

LeverageClosed

Emitted when a leveraged plDXY-BEAR position is closed.

event LeverageClosed(
    address indexed user,
    uint256 debtRepaid,
    uint256 collateralWithdrawn,
    uint256 usdcReturned,
    uint256 maxSlippageBps
);

CollateralAdded

Emitted when collateral is added to a position.

usdcReturned is always 0 for BEAR router (full amount swapped to BEAR).

event CollateralAdded(
    address indexed user, uint256 usdcAmount, uint256 usdcReturned, uint256 collateralAdded, uint256 maxSlippageBps
);

CollateralRemoved

Emitted when collateral is removed from a position.

event CollateralRemoved(
    address indexed user, uint256 collateralWithdrawn, uint256 usdcReturned, uint256 maxSlippageBps
);

RewardDistributor

Git Source

Inherits: IRewardDistributor, ReentrancyGuard

Title: RewardDistributor

Distributes staking rewards based on price discrepancy between oracle and Curve EMA.

Receives USDC from SyntheticSplitter.harvestYield() and allocates to StakedToken vaults proportionally based on which token is underperforming relative to theoretical price.

Note: security-contact: contact@plether.com

Constants

DISCREPANCY_THRESHOLD_BPS

Discrepancy threshold for 100% allocation (2% = 200 bps).

uint256 public constant DISCREPANCY_THRESHOLD_BPS = 200

MIN_DISTRIBUTION_INTERVAL

Minimum time between distributions (1 hour).

uint256 public constant MIN_DISTRIBUTION_INTERVAL = 1 hours

CALLER_REWARD_BPS

Reward for calling distributeRewards (0.1% = 10 bps).

uint256 public constant CALLER_REWARD_BPS = 10

USDC_INDEX

USDC index in Curve pool.

uint256 public constant USDC_INDEX = 0

PLDXY_BEAR_INDEX

plDXY-BEAR index in Curve pool.

uint256 public constant PLDXY_BEAR_INDEX = 1

MAX_SWAP_SLIPPAGE_BPS

Maximum slippage for Curve swaps (1% = 100 bps).

uint256 public constant MAX_SWAP_SLIPPAGE_BPS = 100

MAX_ORACLE_ZAP_SLIPPAGE_BPS

Maximum slippage for oracle-based zap estimates (3% = 300 bps).

Wider than MAX_SWAP_SLIPPAGE_BPS because ZapRouter’s flash mint loop adds fees.

uint256 public constant MAX_ORACLE_ZAP_SLIPPAGE_BPS = 300

ORACLE_TIMEOUT

Maximum age for oracle price data (24 hours to match Chainlink CHF/CAD heartbeat).

uint256 public constant ORACLE_TIMEOUT = 24 hours

SPLITTER

SyntheticSplitter contract.

ISyntheticSplitter public immutable SPLITTER

USDC

USDC stablecoin.

IERC20 public immutable USDC

PLDXY_BEAR

plDXY-BEAR token.

IERC20 public immutable PLDXY_BEAR

PLDXY_BULL

plDXY-BULL token.

IERC20 public immutable PLDXY_BULL

STAKED_BEAR

Staked plDXY-BEAR vault.

StakedToken public immutable STAKED_BEAR

STAKED_BULL

Staked plDXY-BULL vault.

StakedToken public immutable STAKED_BULL

CURVE_POOL

Curve USDC/plDXY-BEAR pool.

ICurvePool public immutable CURVE_POOL

ZAP_ROUTER

ZapRouter for acquiring plDXY-BULL.

ZapRouter public immutable ZAP_ROUTER

ORACLE

BasketOracle for theoretical price.

AggregatorV3Interface public immutable ORACLE

PYTH_ADAPTER

Optional PythAdapter for SEK/USD price updates (address(0) if not used).

PythAdapter public immutable PYTH_ADAPTER

INVAR_COIN

Optional InvarCoin vault that receives a share of BEAR rewards (address(0) if not used).

IInvarCoin public immutable INVAR_COIN

CAP

Protocol CAP price (8 decimals).

uint256 public immutable CAP

State Variables

lastDistributionTime

Timestamp of last distribution.

uint256 public lastDistributionTime

Functions

constructor

Deploys RewardDistributor with all required dependencies.

constructor(
    address _splitter,
    address _usdc,
    address _plDxyBear,
    address _plDxyBull,
    address _stakedBear,
    address _stakedBull,
    address _curvePool,
    address _zapRouter,
    address _oracle,
    address _pythAdapter,
    address _invarCoin
) ;

Parameters

NameTypeDescription
_splitteraddressSyntheticSplitter contract address.
_usdcaddressUSDC token address.
_plDxyBearaddressplDXY-BEAR token address.
_plDxyBulladdressplDXY-BULL token address.
_stakedBearaddressStakedToken vault for BEAR.
_stakedBulladdressStakedToken vault for BULL.
_curvePooladdressCurve USDC/plDXY-BEAR pool.
_zapRouteraddressZapRouter for BULL acquisition.
_oracleaddressBasketOracle for price data.
_pythAdapteraddressOptional PythAdapter for SEK/USD updates (address(0) if not used).
_invarCoinaddressOptional InvarCoin vault for BEAR reward split (address(0) if not used).

receive

receive() external payable;

distributeRewards

Permissionless function to distribute accumulated USDC rewards.

Calculates price discrepancy, acquires tokens, and donates to vaults.

function distributeRewards() external nonReentrant returns (uint256 callerReward);

Returns

NameTypeDescription
callerRewarduint256Amount of USDC sent to caller as incentive.

_distributeRewardsInternal

Internal implementation of reward distribution.

function _distributeRewardsInternal() internal returns (uint256 callerReward);

distributeRewardsWithPriceUpdate

Distributes rewards after updating the Pyth oracle price.

Bundles Pyth price update with reward distribution to save gas. Caller receives the same reward as distributeRewards().

function distributeRewardsWithPriceUpdate(
    bytes[] calldata pythUpdateData
) external payable nonReentrant returns (uint256 callerReward);

Parameters

NameTypeDescription
pythUpdateDatabytes[]Price update data from Pyth Hermes API.

Returns

NameTypeDescription
callerRewarduint256Amount of USDC sent to caller as incentive.

previewDistribution

Preview the distribution without executing.

function previewDistribution()
    external
    view
    returns (uint256 bearPct, uint256 bullPct, uint256 usdcBalance, uint256 callerReward);

Returns

NameTypeDescription
bearPctuint256Expected percentage to BEAR stakers (basis points).
bullPctuint256Expected percentage to BULL stakers (basis points).
usdcBalanceuint256Current USDC balance available for distribution.
callerRewarduint256Expected caller reward.

_calculateSplit

Calculates reward split based on price discrepancy.

function _calculateSplit(
    uint256 absBasketPrice
) internal view returns (uint256 bearPct, uint256 bullPct);

Parameters

NameTypeDescription
absBasketPriceuint256Validated basket price (8 decimals, positive).

Returns

NameTypeDescription
bearPctuint256Percentage for BEAR stakers (basis points).
bullPctuint256Percentage for BULL stakers (basis points).

_acquireTokens

Acquires tokens using optimal combination of minting and swapping/zapping.

function _acquireTokens(
    uint256 bearUsdc,
    uint256 bullUsdc,
    uint256 absBasketPrice
) internal returns (uint256 bearAmount, uint256 bullAmount);

Parameters

NameTypeDescription
bearUsdcuint256USDC allocated to BEAR acquisition.
bullUsdcuint256USDC allocated to BULL acquisition.
absBasketPriceuint256Validated basket price (8 decimals, positive).

Returns

NameTypeDescription
bearAmountuint256Amount of plDXY-BEAR acquired.
bullAmountuint256Amount of plDXY-BULL acquired.

rescueUsdc

Rescues USDC trapped after protocol liquidation.

Only callable when Splitter is SETTLED. Sends full USDC balance to Splitter treasury.

function rescueUsdc() external;

_splitBearAllocation

Splits BEAR-side USDC allocation between StakedBear and InvarCoin proportional to BEAR exposure.

function _splitBearAllocation(
    uint256 bearUsdc,
    uint256 absBasketPrice
) internal view returns (uint256 stakedUsdc, uint256 invarUsdc);

Parameters

NameTypeDescription
bearUsdcuint256Total USDC allocated to the BEAR side.
absBasketPriceuint256Validated basket price (8 decimals, positive).

_calculateMintAmount

Converts USDC amount to 18-decimal mint amount.

function _calculateMintAmount(
    uint256 usdcAmount
) internal view returns (uint256 mintAmount);

Parameters

NameTypeDescription
usdcAmountuint256USDC amount (6 decimals).

Returns

NameTypeDescription
mintAmountuint256Token amount to mint (18 decimals).

StakedToken

Git Source

Inherits: ERC4626

Title: StakedToken

ERC4626 vault for staking plDXY-BEAR or plDXY-BULL tokens.

Used as Morpho collateral. Exchange rate increases via yield donations. Implements 1000x virtual share offset to prevent inflation attacks. Implements streaming rewards (1-hour linear vest) to prevent reward sniping.

Note: security-contact: contact@plether.com

Constants

STREAM_DURATION

Duration over which donated rewards are streamed.

uint256 public constant STREAM_DURATION = 1 hours

State Variables

_trackedBalance

uint256 private _trackedBalance

rewardRate

Current reward streaming rate (tokens per second, scaled by 1e18).

uint256 public rewardRate

streamEndTime

Timestamp when current reward stream ends.

uint256 public streamEndTime

Functions

constructor

Creates a new staking vault for a synthetic token.

constructor(
    IERC20 _asset,
    string memory _name,
    string memory _symbol
) ERC4626(_asset) ERC20(_name, _symbol);

Parameters

NameTypeDescription
_assetIERC20The underlying plDXY token to stake (plDXY-BEAR or plDXY-BULL).
_namestringVault share name (e.g., “Staked plDXY-BEAR”).
_symbolstringVault share symbol (e.g., “splDXY-BEAR”).

totalAssets

Returns total assets including only vested streamed rewards.

Overrides ERC4626 to exclude unvested rewards from share price calculation.

function totalAssets() public view override returns (uint256);

donateYield

Donates yield that streams to stakers over STREAM_DURATION.

Rewards vest linearly. New donations extend the stream proportionally to the donation size, preventing griefing via zero-amount timer resets.

function donateYield(
    uint256 amount
) external;

Parameters

NameTypeDescription
amountuint256The amount of underlying tokens to donate.

depositWithPermit

Deposit assets with a permit signature (gasless approval).

Combines EIP-2612 permit with ERC-4626 deposit in a single transaction.

function depositWithPermit(
    uint256 assets,
    address receiver,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
) external returns (uint256 shares);

Parameters

NameTypeDescription
assetsuint256Amount of underlying tokens to deposit
receiveraddressAddress to receive the vault shares
deadlineuint256Permit signature expiration timestamp
vuint8Signature recovery byte
rbytes32Signature r component
sbytes32Signature s component

Returns

NameTypeDescription
sharesuint256Amount of vault shares minted

_deposit

function _deposit(
    address caller,
    address receiver,
    uint256 assets,
    uint256 shares
) internal override;

_withdraw

function _withdraw(
    address caller,
    address receiver,
    address owner,
    uint256 assets,
    uint256 shares
) internal override;

_unvestedRewards

Calculates unvested rewards from the current stream.

function _unvestedRewards() internal view returns (uint256);

_decimalsOffset

Virtual share offset (10^3 = 1000x) to prevent inflation attacks.

function _decimalsOffset() internal pure override returns (uint8);

Events

YieldDonated

Emitted when yield is donated and streaming begins/extends.

event YieldDonated(address indexed donor, uint256 amount, uint256 newStreamEndTime);

Errors

StakedToken__PermitFailed

error StakedToken__PermitFailed();

SyntheticSplitter

Git Source

Inherits: ISyntheticSplitter, Ownable2Step, Pausable, ReentrancyGuard

Title: SyntheticSplitter

Core protocol contract for minting/burning synthetic plDXY tokens.

Accepts USDC collateral to mint equal amounts of plDXY-BEAR + plDXY-BULL tokens. Minted USDC stays local; a permissionless deployToAdapter() pushes excess above the 10% buffer into the yield adapter. Three lifecycle states: ACTIVE → PAUSED → SETTLED.

Note: security-contact: contact@plether.com

Constants

BEAR

SyntheticToken public immutable BEAR

BULL

SyntheticToken public immutable BULL

USDC

IERC20 public immutable USDC

ORACLE

AggregatorV3Interface public immutable ORACLE

CAP

uint256 public immutable CAP

USDC_DECIMALS

uint256 private constant USDC_DECIMALS = 6

USDC_MULTIPLIER

uint256 public constant USDC_MULTIPLIER = 10 ** (18 + 8 - USDC_DECIMALS)

BUFFER_PERCENT

uint256 public constant BUFFER_PERCENT = 10

ORACLE_TIMEOUT

uint256 public constant ORACLE_TIMEOUT = 24 hours

TIMELOCK_DELAY

uint256 public constant TIMELOCK_DELAY = 7 days

HARVEST_REWARD_BPS

uint256 public constant HARVEST_REWARD_BPS = 10

MIN_SURPLUS_THRESHOLD

uint256 public constant MIN_SURPLUS_THRESHOLD = 50 * 10 ** USDC_DECIMALS

MIN_DEPLOY_AMOUNT

uint256 public constant MIN_DEPLOY_AMOUNT = 100 * 10 ** USDC_DECIMALS

SEQUENCER_UPTIME_FEED

AggregatorV3Interface public immutable SEQUENCER_UPTIME_FEED

SEQUENCER_GRACE_PERIOD

uint256 public constant SEQUENCER_GRACE_PERIOD = 1 hours

State Variables

yieldAdapter

IERC4626 public yieldAdapter

pendingAdapter

address public pendingAdapter

adapterActivationTime

uint256 public adapterActivationTime

treasury

address public treasury

staking

address public staking

pendingFees

FeeConfig public pendingFees

feesActivationTime

uint256 public feesActivationTime

lastUnpauseTime

uint256 public lastUnpauseTime

isLiquidated

bool public isLiquidated

liquidationTimestamp

uint256 public liquidationTimestamp

Functions

constructor

Deploys the SyntheticSplitter and creates plDXY-BEAR and plDXY-BULL tokens.

constructor(
    address _oracle,
    address _usdc,
    address _yieldAdapter,
    uint256 _cap,
    address _treasury,
    address _sequencerUptimeFeed
) Ownable(msg.sender);

Parameters

NameTypeDescription
_oracleaddressChainlink-compatible price feed for plDXY basket.
_usdcaddressUSDC token address (6 decimals).
_yieldAdapteraddressERC4626-compliant yield adapter for USDC deposits.
_capuint256Maximum plDXY price (8 decimals). Triggers liquidation when breached.
_treasuryaddressTreasury address for fee distribution.
_sequencerUptimeFeedaddressL2 sequencer uptime feed (address(0) for L1/testnets).

previewMint

Simulates a mint to see required USDC input

function previewMint(
    uint256 mintAmount
) external view returns (uint256 usdcRequired, uint256 depositToAdapter, uint256 keptInBuffer);

Parameters

NameTypeDescription
mintAmountuint256The amount of TokenA/B the user wants to mint

Returns

NameTypeDescription
usdcRequireduint256Total USDC needed from user
depositToAdapteruint256Always 0 (deployment is separate via deployToAdapter())
keptInBufferuint256Amount that will stay in Splitter contract (equals usdcRequired)

mint

Mint plDXY-BEAR and plDXY-BULL tokens by depositing USDC collateral.

function mint(
    uint256 amount
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
amountuint256The amount of token pairs to mint (18 decimals).

mintWithPermit

Mint plDXY-BEAR and plDXY-BULL tokens with a USDC permit signature (gasless approval).

function mintWithPermit(
    uint256 amount,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
amountuint256The amount of token pairs to mint (18 decimals).
deadlineuint256Unix timestamp after which the permit and transaction revert.
vuint8Signature recovery byte.
rbytes32Signature r component.
sbytes32Signature s component.

_mintCore

function _mintCore(
    uint256 amount
) internal;

previewBurn

Simulates a burn to see USDC return

function previewBurn(
    uint256 burnAmount
) external view returns (uint256 usdcRefund, uint256 withdrawnFromAdapter);

Parameters

NameTypeDescription
burnAmountuint256The amount of TokenA/B the user wants to burn

Returns

NameTypeDescription
usdcRefunduint256Total USDC user will receive
withdrawnFromAdapteruint256Amount pulled from Yield Source to cover shortage

burn

Burn plDXY-BEAR and plDXY-BULL tokens to redeem USDC collateral.

function burn(
    uint256 amount
) external nonReentrant;

Parameters

NameTypeDescription
amountuint256The amount of token pairs to burn (18 decimals).

_withdrawFromAdapter

Withdraws USDC from yield adapter with redeem fallback.

function _withdrawFromAdapter(
    uint256 amount
) internal;

Parameters

NameTypeDescription
amountuint256USDC amount to withdraw (6 decimals).

triggerLiquidation

Locks the protocol into liquidated state when price >= CAP.

Permissionless. Prevents system revival if price drops after breach.

function triggerLiquidation() external nonReentrant;

emergencyRedeem

Emergency redemption when protocol is liquidated (price >= CAP).

Only burns plDXY-BEAR tokens at CAP price. plDXY-BULL becomes worthless.

function emergencyRedeem(
    uint256 amount
) external nonReentrant;

Parameters

NameTypeDescription
amountuint256The amount of plDXY-BEAR tokens to redeem (18 decimals).

ejectLiquidity

Emergency exit: withdraws all funds from yield adapter.

Bypasses timelock. Auto-pauses protocol. Use if adapter is compromised.

function ejectLiquidity() external onlyOwner;

withdrawFromAdapter

Withdraws a specific amount from yield adapter while paused.

Requires protocol to be paused. Use for gradual liquidity extraction when full ejectLiquidity() fails due to adapter liquidity constraints.

function withdrawFromAdapter(
    uint256 amount
) external nonReentrant onlyOwner;

Parameters

NameTypeDescription
amountuint256Desired USDC amount to withdraw. Capped by adapter’s maxWithdraw.

deployToAdapter

Deploys excess local USDC to the yield adapter.

Permissionless keeper function. Pushes USDC above the 10% buffer target into the adapter. Returns 0 silently when nothing to deploy (keeper-friendly).

function deployToAdapter() external nonReentrant whenNotPaused returns (uint256 deployed);

Returns

NameTypeDescription
deployeduint256Amount of USDC deployed to the adapter.

_deployExcess

Pushes local USDC above the 10% buffer target into the yield adapter.

function _deployExcess() internal;

previewHarvest

Previews yield harvest amounts and eligibility.

function previewHarvest()
    external
    view
    returns (
        bool canHarvest,
        uint256 totalSurplus,
        uint256 callerReward,
        uint256 treasuryShare,
        uint256 stakingShare
    );

Returns

NameTypeDescription
canHarvestboolTrue if surplus exceeds MIN_SURPLUS_THRESHOLD.
totalSurplusuint256Available surplus (total assets - liabilities).
callerRewarduint256Caller incentive (0.1% of harvest).
treasuryShareuint256Treasury allocation (20% of remaining).
stakingShareuint256Staking allocation (80% of remaining).

harvestYield

Permissionless yield harvesting with automatic redeployment.

Pays surplus from local buffer first, only hits adapter for the remainder. After distribution, deploys any remaining excess to the adapter. Distributes: 0.1% to caller, 20% of remaining to treasury, 80% of remaining to staking.

function harvestYield() external nonReentrant whenNotPaused;

_checkLiveness

Enforces 7-day cooldown after unpause for governance actions.

function _checkLiveness() internal view;

proposeFeeReceivers

Propose new fee receiver addresses (7-day timelock).

function proposeFeeReceivers(
    address _treasury,
    address _staking
) external onlyOwner;

Parameters

NameTypeDescription
_treasuryaddressNew treasury address.
_stakingaddressNew staking address (can be zero to send all to treasury).

finalizeFeeReceivers

Finalize pending fee receiver change after timelock expires.

function finalizeFeeReceivers() external onlyOwner;

proposeAdapter

Propose a new yield adapter (7-day timelock).

function proposeAdapter(
    address _newAdapter
) external onlyOwner;

Parameters

NameTypeDescription
_newAdapteraddressAddress of the new ERC4626-compliant adapter.

finalizeAdapter

Finalize adapter migration after timelock. Migrates all funds atomically.

function finalizeAdapter() external nonReentrant onlyOwner;

pause

Pause the protocol. Blocks minting and harvesting.

function pause() external onlyOwner;

unpause

Unpause the protocol. Starts 7-day governance cooldown.

function unpause() external onlyOwner;

rescueToken

Rescue accidentally sent tokens. Cannot rescue core assets.

function rescueToken(
    address token,
    address to
) external onlyOwner;

Parameters

NameTypeDescription
tokenaddressThe ERC20 token to rescue.
toaddressThe recipient address.

currentStatus

Returns the current protocol lifecycle status.

function currentStatus() external view override returns (Status);

Returns

NameTypeDescription
<none>StatusThe current Status enum value (ACTIVE, PAUSED, or SETTLED).

getSystemStatus

Returns comprehensive system metrics for dashboards.

function getSystemStatus() external view returns (SystemStatus memory status);

Returns

NameTypeDescription
statusSystemStatusStruct containing price, collateral ratio, and liquidity data.

_getTotalLiabilities

Calculates total liabilities based on BEAR supply at CAP price.

function _getTotalLiabilities() internal view returns (uint256);

_getTotalAssets

Calculates total assets (local USDC + adapter value).

function _getTotalAssets() internal view returns (uint256);

_requireSolventIfPaused

Reverts if paused and insolvent (assets < liabilities).

function _requireSolventIfPaused() internal view;

_getOraclePrice

Oracle price validation using OracleLib.

function _getOraclePrice() internal view returns (uint256);

Events

Minted

event Minted(address indexed user, uint256 amount);

Burned

event Burned(address indexed user, uint256 amount);

AdapterProposed

event AdapterProposed(address indexed newAdapter, uint256 activationTime);

AdapterMigrated

event AdapterMigrated(address indexed oldAdapter, address indexed newAdapter, uint256 transferredAmount);

LiquidationTriggered

event LiquidationTriggered(uint256 price);

EmergencyRedeemed

event EmergencyRedeemed(address indexed user, uint256 amount);

YieldHarvested

event YieldHarvested(uint256 totalSurplus, uint256 treasuryAmt, uint256 stakingAmt);

FeesProposed

event FeesProposed(address indexed treasury, address indexed staking, uint256 activationTime);

FeesUpdated

event FeesUpdated(address indexed treasury, address indexed staking);

EmergencyEjected

event EmergencyEjected(uint256 amountRecovered);

DeployedToAdapter

event DeployedToAdapter(address indexed caller, uint256 amount);

AdapterWithdrawn

event AdapterWithdrawn(uint256 requested, uint256 withdrawn);

TokenRescued

event TokenRescued(address indexed token, address indexed to, uint256 amount);

Errors

Splitter__ZeroAddress

error Splitter__ZeroAddress();

Splitter__InvalidCap

error Splitter__InvalidCap();

Splitter__ZeroAmount

error Splitter__ZeroAmount();

Splitter__ZeroRefund

error Splitter__ZeroRefund();

Splitter__AdapterNotSet

error Splitter__AdapterNotSet();

Splitter__LiquidationActive

error Splitter__LiquidationActive();

Splitter__NotLiquidated

error Splitter__NotLiquidated();

Splitter__TimelockActive

error Splitter__TimelockActive();

Splitter__InvalidProposal

error Splitter__InvalidProposal();

Splitter__NoSurplus

error Splitter__NoSurplus();

Splitter__GovernanceLocked

error Splitter__GovernanceLocked();

Splitter__InsufficientHarvest

error Splitter__InsufficientHarvest();

Splitter__AdapterWithdrawFailed

error Splitter__AdapterWithdrawFailed();

Splitter__Insolvent

error Splitter__Insolvent();

Splitter__NotPaused

error Splitter__NotPaused();

Splitter__CannotRescueCoreAsset

error Splitter__CannotRescueCoreAsset();

Splitter__MigrationLostFunds

error Splitter__MigrationLostFunds();

Splitter__InvalidAdapter

error Splitter__InvalidAdapter();

Splitter__PermitFailed

error Splitter__PermitFailed();

Structs

FeeConfig

struct FeeConfig {
    address treasuryAddr;
    address stakingAddr;
}

SystemStatus

struct SystemStatus {
    uint256 currentPrice;
    uint256 capPrice;
    bool liquidated;
    bool isPaused;
    uint256 totalAssets; // Local + Adapter
    uint256 totalLiabilities; // Bear Supply * CAP
    uint256 collateralRatio; // Basis points
    uint256 adapterAssets; // USDC value held in yield adapter
}

SyntheticToken

Git Source

Inherits: ERC20, ERC20Permit, ERC20FlashMint

Title: SyntheticToken

ERC20 token with flash mint and permit capability, controlled by SyntheticSplitter.

Used for plDXY-BEAR and plDXY-BULL tokens. Only the Splitter can mint/burn. Inherits ERC20FlashMint for fee-free flash loans used by routers.

Note: security-contact: contact@plether.com

Constants

SPLITTER

The SyntheticSplitter contract that controls minting and burning.

address public immutable SPLITTER

Functions

onlySplitter

Restricts function access to the Splitter contract only.

modifier onlySplitter() ;

constructor

Creates a new SyntheticToken.

constructor(
    string memory _name,
    string memory _symbol,
    address _splitter
) ERC20(_name, _symbol) ERC20Permit(_name);

Parameters

NameTypeDescription
_namestringToken name (e.g., “Plether Dollar Index Bear”).
_symbolstringToken symbol (e.g., “plDXY-BEAR”).
_splitteraddressAddress of the SyntheticSplitter contract.

mint

Mint tokens to an address. Only callable by Splitter.

function mint(
    address to,
    uint256 amount
) external onlySplitter;

Parameters

NameTypeDescription
toaddressRecipient address.
amountuint256Amount to mint.

burn

Burn tokens from an address. Only callable by Splitter.

function burn(
    address from,
    uint256 amount
) external onlySplitter;

Parameters

NameTypeDescription
fromaddressAddress to burn from.
amountuint256Amount to burn.

Errors

SyntheticToken__Unauthorized

Thrown when a non-Splitter address attempts to mint or burn.

error SyntheticToken__Unauthorized();

SyntheticToken__ZeroAddress

Thrown when zero address provided for splitter.

error SyntheticToken__ZeroAddress();

VaultAdapter

Git Source

Inherits: ERC4626, Ownable2Step, IYieldAdapter

Title: VaultAdapter

ERC4626-compliant wrapper that deposits into a Morpho vault for yield.

Interchangeable with other yield adapters. Only accepts deposits from SyntheticSplitter.

Note: security-contact: contact@plether.com

Constants

VAULT

Morpho vault (ERC4626) that generates yield.

IERC4626 public immutable VAULT

SPLITTER

SyntheticSplitter authorized to deposit.

address public immutable SPLITTER

Functions

constructor

Deploys adapter targeting a Morpho vault.

constructor(
    IERC20 _asset,
    address _vault,
    address _owner,
    address _splitter
) ERC4626(_asset) ERC20("Vault Yield Wrapper", "vyUSDC") Ownable(_owner);

Parameters

NameTypeDescription
_assetIERC20Underlying asset (USDC).
_vaultaddressMorpho vault address (must have same underlying asset).
_owneraddressAdmin address for rescue operations.
_splitteraddressSyntheticSplitter authorized to deposit.

maxWithdraw

Maximum USDC withdrawable by owner.

Does not cap by VAULT.maxWithdraw() — Morpho Vault V2 returns 0 for all max* functions due to its gate system. Actual liquidity is enforced at withdrawal time.

function maxWithdraw(
    address owner
) public view override returns (uint256);

maxRedeem

Maximum adapter shares redeemable by owner.

See maxWithdraw for rationale on not delegating to vault.

function maxRedeem(
    address owner
) public view override returns (uint256);

maxDeposit

Maximum USDC depositable.

See maxWithdraw for rationale on not delegating to vault.

function maxDeposit(
    address
) public view override returns (uint256);

maxMint

Maximum adapter shares mintable.

See maxWithdraw for rationale on not delegating to vault.

function maxMint(
    address
) public view override returns (uint256);

totalAssets

Returns total USDC value of this adapter’s vault position.

function totalAssets() public view override returns (uint256);

Returns

NameTypeDescription
<none>uint256Total assets held in the Morpho vault, converted from vault shares.

_deposit

Deposits assets to Morpho vault after ERC4626 share minting.

function _deposit(
    address caller,
    address receiver,
    uint256 assets,
    uint256 shares
) internal override;

Parameters

NameTypeDescription
calleraddressMust be SPLITTER.
receiveraddressReceiver of adapter shares.
assetsuint256Amount of USDC to deposit.
sharesuint256Amount of adapter shares minted.

_withdraw

Withdraws assets from Morpho vault before ERC4626 share burning.

function _withdraw(
    address caller,
    address receiver,
    address owner,
    uint256 assets,
    uint256 shares
) internal override;

Parameters

NameTypeDescription
calleraddressCaller requesting withdrawal.
receiveraddressReceiver of withdrawn USDC.
owneraddressOwner of adapter shares being burned.
assetsuint256Amount of USDC to withdraw.
sharesuint256Amount of adapter shares burned.

accrueInterest

No-op — Morpho vault accrues interest on underlying markets during deposit/withdraw.

View functions (totalAssets, convertToAssets) may lag by a few blocks of unaccrued interest across the vault’s markets. This is negligible for an actively-used vault and self-corrects on the next state-changing interaction.

function accrueInterest() external;

rescueToken

Recovers stuck tokens (excluding the underlying asset and vault shares).

function rescueToken(
    address token,
    address to
) external onlyOwner;

Parameters

NameTypeDescription
tokenaddressToken to rescue.
toaddressRecipient address.

claimRewards

Claims rewards from an external distributor (Merkl, URD, etc.).

Reward tokens land in this contract; use rescueToken() to extract them.

function claimRewards(
    address target,
    bytes calldata data
) external onlyOwner;

Parameters

NameTypeDescription
targetaddressDistributor contract to call.
databytesABI-encoded call data for the claim function.

Errors

VaultAdapter__OnlySplitter

Thrown when caller is not the SyntheticSplitter.

error VaultAdapter__OnlySplitter();

VaultAdapter__InvalidAddress

Thrown when a zero address is provided.

error VaultAdapter__InvalidAddress();

VaultAdapter__InvalidVault

Thrown when vault’s underlying asset doesn’t match this adapter’s asset.

error VaultAdapter__InvalidVault();

VaultAdapter__CannotRescueUnderlying

Thrown when attempting to rescue the underlying asset.

error VaultAdapter__CannotRescueUnderlying();

VaultAdapter__CannotRescueVaultShares

Thrown when attempting to rescue vault share tokens.

error VaultAdapter__CannotRescueVaultShares();

VaultAdapter__CallFailed

Thrown when a reward claim call fails.

error VaultAdapter__CallFailed();

VaultAdapter__ForbiddenTarget

Thrown when claimRewards targets a forbidden address.

error VaultAdapter__ForbiddenTarget();

ZapRouter

Git Source

Inherits: FlashLoanBase, Ownable2Step, Pausable, ReentrancyGuard

Title: ZapRouter

Efficient router for acquiring plDXY-BULL tokens using flash mints.

Primary path: flash mints plDXY-BEAR → swaps to USDC via Curve → mints pairs → keeps plDXY-BULL. Fallback (direct) path: when BEAR is overpriced on Curve and the flash path can’t close, mints pairs with user USDC → sells all BEAR on Curve → sends BULL + USDC refund to user. For plDXY-BEAR, users should swap directly on Curve instead.

Note: security-contact: contact@plether.com

Constants

MAX_SLIPPAGE_BPS

Maximum allowed slippage in basis points (1% = 100 bps).

uint256 public constant MAX_SLIPPAGE_BPS = 100

SAFETY_BUFFER_BPS

Safety buffer for flash loan repayment calculations (0.5% = 50 bps).

uint256 public constant SAFETY_BUFFER_BPS = 50

USDC_INDEX

USDC index in the Curve USDC/plDXY-BEAR pool.

uint256 public constant USDC_INDEX = 0

PLDXY_BEAR_INDEX

plDXY-BEAR index in the Curve USDC/plDXY-BEAR pool.

uint256 public constant PLDXY_BEAR_INDEX = 1

SPLITTER

SyntheticSplitter contract for minting/burning pairs.

ISyntheticSplitter public immutable SPLITTER

PLDXY_BEAR

plDXY-BEAR token (flash minted for swaps).

IERC20 public immutable PLDXY_BEAR

PLDXY_BULL

plDXY-BULL token (output of zap operations).

IERC20 public immutable PLDXY_BULL

USDC

USDC stablecoin.

IERC20 public immutable USDC

CURVE_POOL

Curve pool for USDC/plDXY-BEAR swaps.

ICurvePool public immutable CURVE_POOL

CAP

Protocol CAP price (8 decimals, oracle format).

uint256 public immutable CAP

CAP_PRICE

CAP price scaled for Curve comparison (6 decimals).

uint256 public immutable CAP_PRICE

ACTION_MINT

Flash loan action: mint plDXY-BULL.

uint256 private constant ACTION_MINT = 0

ACTION_BURN

Flash loan action: burn plDXY-BULL.

uint256 private constant ACTION_BURN = 1

Functions

constructor

Deploys ZapRouter with required protocol dependencies.

constructor(
    address _splitter,
    address _plDxyBear,
    address _plDxyBull,
    address _usdc,
    address _curvePool
) Ownable(msg.sender);

Parameters

NameTypeDescription
_splitteraddressSyntheticSplitter contract address.
_plDxyBearaddressplDXY-BEAR token address.
_plDxyBulladdressplDXY-BULL token address.
_usdcaddressUSDC token address.
_curvePooladdressCurve USDC/plDXY-BEAR pool address.

zapMint

Buy plDXY-BULL using USDC with flash mint efficiency.

For plDXY-BEAR, swap directly on Curve instead.

function zapMint(
    uint256 usdcAmount,
    uint256 minAmountOut,
    uint256 maxSlippageBps,
    uint256 deadline
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
usdcAmountuint256The amount of USDC the user is sending.
minAmountOutuint256Minimum amount of plDXY-BULL tokens to receive.
maxSlippageBpsuint256Maximum slippage tolerance in basis points (e.g., 100 = 1%). Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction.
deadlineuint256Unix timestamp after which the transaction reverts.

zapMintWithPermit

Buy plDXY-BULL using USDC with a permit signature (gasless approval).

function zapMintWithPermit(
    uint256 usdcAmount,
    uint256 minAmountOut,
    uint256 maxSlippageBps,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
usdcAmountuint256The amount of USDC the user is sending.
minAmountOutuint256Minimum amount of plDXY-BULL tokens to receive.
maxSlippageBpsuint256Maximum slippage tolerance in basis points.
deadlineuint256Unix timestamp after which the permit and transaction revert.
vuint8Signature recovery byte.
rbytes32Signature r component.
sbytes32Signature s component.

_zapMintCore

function _zapMintCore(
    uint256 usdcAmount,
    uint256 minAmountOut,
    uint256 maxSlippageBps,
    uint256 deadline
) internal;

zapBurn

Sell plDXY-BULL tokens for USDC using flash mint efficiency.

function zapBurn(
    uint256 bullAmount,
    uint256 minUsdcOut,
    uint256 deadline
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
bullAmountuint256Amount of plDXY-BULL to sell.
minUsdcOutuint256Minimum USDC to receive (slippage protection).
deadlineuint256Unix timestamp after which the transaction reverts.

zapBurnWithPermit

Sell plDXY-BULL tokens for USDC with a permit signature (gasless approval).

function zapBurnWithPermit(
    uint256 bullAmount,
    uint256 minUsdcOut,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
bullAmountuint256Amount of plDXY-BULL to sell.
minUsdcOutuint256Minimum USDC to receive (slippage protection).
deadlineuint256Unix timestamp after which the transaction reverts.
vuint8Signature recovery byte.
rbytes32Signature r component.
sbytes32Signature s component.

_zapBurnCore

function _zapBurnCore(
    uint256 bullAmount,
    uint256 minUsdcOut,
    uint256 deadline
) internal;

onFlashLoan

ERC-3156 flash loan callback. Routes to mint or burn handler.

function onFlashLoan(
    address initiator,
    address,
    uint256 amount,
    uint256 fee,
    bytes calldata data
) external override returns (bytes32);

Parameters

NameTypeDescription
initiatoraddressAddress that initiated the flash loan (must be this contract).
<none>address
amountuint256Amount of plDXY-BEAR borrowed.
feeuint256Flash loan fee (always 0 for SyntheticToken).
databytesEncoded operation parameters.

Returns

NameTypeDescription
<none>bytes32CALLBACK_SUCCESS on successful execution.

onMorphoFlashLoan

Morpho flash loan callback - not used by ZapRouter.

Always reverts as ZapRouter only uses ERC-3156 flash mints.

function onMorphoFlashLoan(
    uint256,
    bytes calldata
) external pure override;

_handleMint

Executes mint operation within flash loan callback.

function _handleMint(
    uint256 loanAmount,
    uint256 fee,
    bytes calldata data
) internal;

Parameters

NameTypeDescription
loanAmountuint256Amount of plDXY-BEAR borrowed.
feeuint256Flash loan fee (always 0).
databytesEncoded mint parameters (action, user, usdcAmount, minSwapOut, minAmountOut, maxSlippageBps).

_handleBurn

Executes burn operation within flash loan callback.

function _handleBurn(
    uint256 loanAmount,
    uint256 fee,
    bytes calldata data
) internal;

Parameters

NameTypeDescription
loanAmountuint256Amount of plDXY-BEAR borrowed.
feeuint256Flash loan fee (always 0).
databytesEncoded burn parameters (action, user, bullAmount, minUsdcOut).

_zapMintDirect

Mints pairs, sells BEAR on Curve, sends BULL + USDC refund to user.

Used when the flash path can’t close (BEAR overpriced or high price impact).

function _zapMintDirect(
    uint256 usdcAmount,
    uint256 minAmountOut,
    uint256 maxSlippageBps
) private;

previewZapMint

Preview the result of a zapMint operation.

When flashAmount == 0, the direct path is used: expectedSwapOut is the USDC refund from selling minted BEAR, and totalUSDC equals usdcAmount (no flash leverage).

function previewZapMint(
    uint256 usdcAmount
)
    external
    view
    returns (
        uint256 flashAmount,
        uint256 expectedSwapOut,
        uint256 totalUSDC,
        uint256 expectedTokensOut,
        uint256 flashFee
    );

Parameters

NameTypeDescription
usdcAmountuint256The amount of USDC the user will send.

Returns

NameTypeDescription
flashAmountuint256Amount of plDXY-BEAR to flash mint (0 signals direct path).
expectedSwapOutuint256Expected USDC from swap (flash: contributes to minting; direct: refund to user).
totalUSDCuint256Total USDC for minting pairs (flash: user + swap; direct: user only).
expectedTokensOutuint256Expected plDXY-BULL tokens to receive.
flashFeeuint256Flash mint fee (0 for direct path).

previewZapBurn

Preview the result of a zapBurn operation.

function previewZapBurn(
    uint256 bullAmount
)
    external
    view
    returns (uint256 expectedUsdcFromBurn, uint256 usdcForBearBuyback, uint256 expectedUsdcOut, uint256 flashFee);

Parameters

NameTypeDescription
bullAmountuint256The amount of plDXY-BULL tokens to sell.

Returns

NameTypeDescription
expectedUsdcFromBurnuint256USDC received from burning pairs via Splitter.
usdcForBearBuybackuint256USDC needed to buy back plDXY-BEAR for flash loan repayment.
expectedUsdcOutuint256Net USDC the user will receive.
flashFeeuint256Flash mint fee (if any).

_estimateUsdcForBearBuyback

function _estimateUsdcForBearBuyback(
    uint256 bearAmount
) private view returns (uint256);

pause

Pause the router. Blocks zapMint and zapBurn.

function pause() external onlyOwner;

unpause

Unpause the router.

function unpause() external onlyOwner;

Events

ZapMint

Emitted when user acquires plDXY-BULL via zapMint.

event ZapMint(
    address indexed user,
    uint256 usdcIn,
    uint256 tokensOut,
    uint256 maxSlippageBps,
    uint256 actualSwapOut,
    uint256 usdcRefund
);

ZapBurn

Emitted when user sells plDXY-BULL via zapBurn.

event ZapBurn(address indexed user, uint256 tokensIn, uint256 usdcOut);

Errors

ZapRouter__ZeroAddress

error ZapRouter__ZeroAddress();

ZapRouter__ZeroAmount

error ZapRouter__ZeroAmount();

ZapRouter__Expired

error ZapRouter__Expired();

ZapRouter__SlippageExceedsMax

error ZapRouter__SlippageExceedsMax();

ZapRouter__SplitterNotActive

error ZapRouter__SplitterNotActive();

ZapRouter__InsufficientOutput

error ZapRouter__InsufficientOutput();

ZapRouter__SolvencyBreach

error ZapRouter__SolvencyBreach();

ZapRouter__PermitFailed

error ZapRouter__PermitFailed();