Plether Protocol
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.
Architecture
Core Contracts
| Contract | Description |
|---|---|
SyntheticSplitter | Central protocol contract. Accepts USDC, mints/burns token pairs. Permissionless deployToAdapter() pushes idle USDC to yield. EIP-2612 permit support on mint. |
SyntheticToken | ERC20 + ERC20FlashMint implementation for plDXY-BEAR and plDXY-BULL |
Staking Layer
| Contract | Description |
|---|---|
StakedToken | ERC-4626 vault wrapper (splDXY-BEAR, splDXY-BULL) with streaming rewards to prevent reward sniping |
RewardDistributor | Distributes USDC yield to StakedToken vaults, favoring the underperforming token |
Oracle Layer
| Contract | Description |
|---|---|
BasketOracle | Computes plDXY as weighted basket of 6 price feeds, with bound validation against Curve EMA price |
PythAdapter | Adapts Pyth Network feeds to Chainlink’s AggregatorV3Interface (used for SEK/USD) |
MorphoOracle | Adapts BasketOracle to Morpho Blue’s oracle scale (24 decimals for USDC/plDXY) |
StakedOracle | Wraps 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):
| Currency | Weight | Base Price (USD) |
|---|---|---|
| EUR | 57.6% | 1.1750 |
| JPY | 13.6% | 0.00638 |
| GBP | 11.9% | 1.3448 |
| CAD | 9.1% | 0.7288 |
| SEK | 4.2% | 0.1086 |
| CHF | 3.6% | 1.2610 |
Both weights and base prices are permanently fixed and cannot be changed after deployment.
Routing Layer
| Contract | Description |
|---|---|
ZapRouter | Single-sided plDXY-BULL minting and burning using flash mints. Permit support. |
LeverageRouter | Leveraged plDXY-BEAR positions via Morpho Blue flash loans. Open/close/add/remove collateral. Permit support. |
BullLeverageRouter | Leveraged plDXY-BULL positions via Morpho + plDXY-BEAR flash mints. Open/close/add/remove collateral. Permit support. |
Yield Adapters (ERC-4626)
| Contract | Description |
|---|---|
VaultAdapter | ERC-4626 wrapper for Morpho Vault vault yield. Owner can claimRewards() from external distributors (Merkl, URD). |
InvarCoin (INVAR)
| Contract | Description |
|---|---|
InvarCoin | Global 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).
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.
LP deposit: Advanced path for depositing USDC + BEAR directly into Curve LP.
LP withdraw: Balanced exit returning pro-rata USDC + BEAR. lpWithdraw intentionally works when paused, serving as the emergency exit.
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
InvarCoinandStakedToken, then callproposeStakedInvarCoin(sINVAR) - Wait
STAKED_INVAR_TIMELOCK(7 days), then callfinalizeStakedInvarCoin()before relying on harvest/donation flows - Propose the reward sink with
proposeGaugeRewardsReceiver(receiver) - Wait
GAUGE_REWARDS_TIMELOCK(7 days), then callfinalizeGaugeRewardsReceiver() - Mark CRV and any other gauge incentives with
protectRewardToken(token)so they cannot be swept withrescueToken() - After claiming rewards, route protected balances only through
sweepGaugeRewards(token)
Keeper operations:
deployToCurve()— pushes excess USDC buffer (>2% target) into single-sided Curve LPreplenishBuffer()— burns Curve LP to restore the 2% USDC bufferharvest()— 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; usetotalAssetsValidated()for strict oracle-validated accounting reads_harvestSafe()gracefully skips when Curve VP reads fail; if yield is pending, strict oracle validation is still enforcedsetEmergencyMode()pauses deposits and single-sided withdrawals without discarding LP accounting;emergencyWithdrawFromCurve()only zeroes LP tracking after assets are actually recoveredstakedInvarCoinandgaugeRewardsReceiverboth 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
- 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
Flash loan USDC from Morpho → swap to plDXY-BEAR on Curve → stake → deposit splDXY-BEAR as Morpho collateral.
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
- 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:
- LeverageRouter (Bear): Morpho flash loan USDC → Swap to plDXY-BEAR → Stake → Deposit to Morpho as collateral → Borrow USDC to repay flash loan
- 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:
- 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.
- PAUSED - Emergency pause (minting and reward distribution blocked, burning allowed so users can exit, gradual adapter withdrawal enabled)
- 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:
| File | Description |
|---|---|
BaseForkTest.sol | Shared base contract, constants, and test helpers |
ZapRouterFork.t.sol | ZapRouter integration with real Curve swaps |
FullCycleFork.t.sol | Complete mint → yield → burn lifecycle |
LeverageRouterFork.t.sol | Bear and Bull leverage via real Morpho |
SlippageProtectionFork.t.sol | MEV protection and slippage scenarios |
LiquidationFork.t.sol | Interest accrual and liquidation mechanics |
BasketOracleFork.t.sol | Full 6-feed plDXY basket oracle validation |
RewardDistributorFork.t.sol | Reward distribution with real oracle prices |
YieldIntegrationFork.t.sol | E2E yield pipeline: Morpho vault → harvest → distribute → staker share price |
PermitFork.t.sol | EIP-2612 permit-based deposits |
SlippageReport.t.sol | Slippage 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):
| Account | Address | Private Key |
|---|---|---|
| #0 | 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 | 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 |
| #1 | 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 | 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d |
MetaMask Setup:
- Import a test private key (Settings → Import Account)
- Add network: RPC
http://127.0.0.1:8545, Chain ID31337
Format
forge fmt # Format code
forge fmt --check # Check formatting
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
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
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
| Name | Type | Description |
|---|---|---|
lender | address | Actual msg.sender. |
expectedLender | address | Expected flash lender address. |
initiator | address | Initiator 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
| Name | Type | Description |
|---|---|---|
lender | address | Actual msg.sender. |
expectedLender | address | Expected 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
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
| Name | Type | Description |
|---|---|---|
_morpho | address | Morpho Blue protocol address. |
_curvePool | address | Curve USDC/plDXY-BEAR pool address. |
_usdc | address | USDC token address. |
_plDxyBear | address | plDXY-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
| Name | Type | Description |
|---|---|---|
user | address | The address to query debt for. |
Returns
| Name | Type | Description |
|---|---|---|
debt | uint256 | The 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
| Name | Type | Description |
|---|---|---|
user | address | The address to query collateral for. |
Returns
| Name | Type | Description |
|---|---|---|
collateral | uint256 | The 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
- ICurveGauge
- ICurveMinter
- ICurvePool
- ICurveTwocrypto
- IInvarCoin
- MarketParams
- IMorpho
- IMorphoFlashLoanCallback
- PythStructs
- IPyth
- IRewardDistributor
- ISyntheticSplitter
- IYieldAdapter
AggregatorV3Interface
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
| Name | Type | Description |
|---|---|---|
_roundId | uint80 | The round ID to query. |
Returns
| Name | Type | Description |
|---|---|---|
roundId | uint80 | The round ID. |
answer | int256 | The price answer. |
startedAt | uint256 | Timestamp when round started. |
updatedAt | uint256 | Timestamp of last update. |
answeredInRound | uint80 | The 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
| Name | Type | Description |
|---|---|---|
roundId | uint80 | The current round ID. |
answer | int256 | The latest price. |
startedAt | uint256 | Timestamp when round started. |
updatedAt | uint256 | Timestamp of last update. |
answeredInRound | uint80 | The round in which answer was computed. |
ICurveGauge
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
Functions
mint
function mint(
address gauge
) external;
ICurvePool
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
| Name | Type | Description |
|---|---|---|
i | uint256 | Input token index. |
j | uint256 | Output token index. |
dx | uint256 | Input amount. |
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | Expected output amount. |
exchange
Executes a token swap.
function exchange(
uint256 i,
uint256 j,
uint256 dx,
uint256 min_dy
) external payable returns (uint256);
Parameters
| Name | Type | Description |
|---|---|---|
i | uint256 | Input token index. |
j | uint256 | Output token index. |
dx | uint256 | Input amount. |
min_dy | uint256 | Minimum output (slippage protection). |
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | Actual output amount. |
price_oracle
Returns EMA oracle price (18 decimals).
function price_oracle() external view returns (uint256);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | Price of token1 in terms of token0. |
ICurveTwocrypto
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
Functions
donateUsdc
function donateUsdc(
uint256 usdcAmount
) external;
totalAssets
function totalAssets() external view returns (uint256);
MarketParams
Morpho Blue market configuration.
struct MarketParams {
address loanToken;
address collateralToken;
address oracle;
address irm;
uint256 lltv;
}
Properties
| Name | Type | Description |
|---|---|---|
loanToken | address | Asset being borrowed. |
collateralToken | address | Asset used as collateral. |
oracle | address | Price oracle for collateral valuation. |
irm | address | Interest rate model contract. |
lltv | uint256 | Liquidation loan-to-value ratio. |
IMorpho
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
| Name | Type | Description |
|---|---|---|
marketParams | MarketParams | The market parameters |
borrower | address | The address of the borrower to liquidate |
seizedAssets | uint256 | The amount of collateral to seize |
repaidShares | uint256 | The amount of debt shares to repay (alternative to seizedAssets) |
data | bytes | Callback 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
| Name | Type | Description |
|---|---|---|
token | address | The token to flash loan |
assets | uint256 | The amount of tokens to flash loan |
data | bytes | Arbitrary 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
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
| Name | Type | Description |
|---|---|---|
assets | uint256 | Amount of tokens borrowed. |
data | bytes | Arbitrary data passed through from flashLoan call. |
PythStructs
Title: Pyth Price Structs
Structs
Price
struct Price {
int64 price;
uint64 conf;
int32 expo;
uint256 publishTime;
}
IPyth
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
| Name | Type | Description |
|---|---|---|
id | bytes32 | The Pyth price feed ID. |
Returns
| Name | Type | Description |
|---|---|---|
price | PythStructs.Price | The 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
| Name | Type | Description |
|---|---|---|
id | bytes32 | The Pyth price feed ID. |
age | uint256 | Maximum acceptable age in seconds. |
Returns
| Name | Type | Description |
|---|---|---|
price | PythStructs.Price | The price data. |
updatePriceFeeds
Updates price feeds with signed data from Pyth.
function updatePriceFeeds(
bytes[] calldata updateData
) external payable;
Parameters
| Name | Type | Description |
|---|---|---|
updateData | bytes[] | 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
| Name | Type | Description |
|---|---|---|
updateData | bytes[] | Array of price update data. |
Returns
| Name | Type | Description |
|---|---|---|
feeAmount | uint256 | The required fee in wei. |
IRewardDistributor
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
| Name | Type | Description |
|---|---|---|
callerReward | uint256 | Amount 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
| Name | Type | Description |
|---|---|---|
pythUpdateData | bytes[] | Price update data from Pyth Hermes API. |
Returns
| Name | Type | Description |
|---|---|---|
callerReward | uint256 | Amount 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
| Name | Type | Description |
|---|---|---|
bearPct | uint256 | Expected percentage to BEAR stakers (basis points). |
bullPct | uint256 | Expected percentage to BULL stakers (basis points). |
usdcBalance | uint256 | Current USDC balance available for distribution. |
callerReward | uint256 | Expected 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
| Name | Type | Description |
|---|---|---|
bearAmount | uint256 | Amount of plDXY-BEAR donated to StakedBear. |
bullAmount | uint256 | Amount of plDXY-BULL donated to StakedBull. |
invarUsdcAmount | uint256 | Amount of USDC donated to InvarCoin. |
bearPct | uint256 | Percentage of rewards allocated to BEAR stakers (basis points). |
bullPct | uint256 | Percentage 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
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
| Name | Type | Description |
|---|---|---|
amount | uint256 | The 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
| Name | Type | Description |
|---|---|---|
amount | uint256 | The amount of token pairs to mint. |
deadline | uint256 | Unix timestamp after which the permit and transaction revert. |
v | uint8 | Signature recovery byte. |
r | bytes32 | Signature r component. |
s | bytes32 | Signature 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
| Name | Type | Description |
|---|---|---|
amount | uint256 | The 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
| Name | Type | Description |
|---|---|---|
amount | uint256 | The amount of plDXY-BEAR tokens to burn. |
currentStatus
Returns the current protocol lifecycle status.
function currentStatus() external view returns (Status);
Returns
| Name | Type | Description |
|---|---|---|
<none> | Status | The current Status enum value. |
CAP
Returns the protocol CAP price (8 decimals, oracle format).
function CAP() external view returns (uint256);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | The 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
| Name | Type | Description |
|---|---|---|
<none> | uint256 | The liquidation timestamp (0 if not liquidated). |
treasury
Returns the treasury address.
function treasury() external view returns (address);
Returns
| Name | Type | Description |
|---|---|---|
<none> | address | The treasury address. |
Enums
Status
Defines the current lifecycle state of the protocol.
enum Status {
ACTIVE,
PAUSED,
SETTLED
}
Variants
| Name | Description |
|---|---|
ACTIVE | Normal operations. Minting and burning enabled. |
PAUSED | Security pause. Minting disabled, burn may be restricted if insolvent. |
SETTLED | End of life. Cap breached. Only emergencyRedeem enabled. |
IYieldAdapter
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
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_TO_MORPHO_SCALE
Chainlink (8 dec) -> Morpho (36 + loanDec - collateralDec = 24 dec): 10^16.
uint256 internal constant CHAINLINK_TO_MORPHO_SCALE = 1e16;
CHAINLINK_TO_TOKEN_SCALE
Chainlink (8 dec) -> Token (18 dec): 10^10.
uint256 internal constant CHAINLINK_TO_TOKEN_SCALE = 1e10;
IIrm
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
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
| Name | Type | Description |
|---|---|---|
morpho | IMorpho | Morpho Blue contract. |
marketParams | MarketParams | Market parameters. |
Returns
| Name | Type | Description |
|---|---|---|
expectedSupplyAssets | uint256 | Total 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
| Name | Type | Description |
|---|---|---|
morpho | IMorpho | Morpho Blue contract. |
marketParams | MarketParams | Market parameters. |
shares | uint256 | Supply shares to convert. |
Returns
| Name | Type | Description |
|---|---|---|
assets | uint256 | Expected asset amount. |
OracleLib
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
| Name | Type | Description |
|---|---|---|
sequencerFeed | AggregatorV3Interface | The Chainlink sequencer uptime feed. |
gracePeriod | uint256 | The 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
| Name | Type | Description |
|---|---|---|
updatedAt | uint256 | The timestamp when the price was last updated. |
timeout | uint256 | The 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
| Name | Type | Description |
|---|---|---|
updatedAt | uint256 | The timestamp when the price was last updated. |
timeout | uint256 | The maximum age in seconds for a valid price. |
referenceTime | uint256 | The 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
| Name | Type | Description |
|---|---|---|
feed | AggregatorV3Interface | The Chainlink price feed. |
targetTimestamp | uint256 | The timestamp to look up the price for. |
hintRoundId | uint80 | The round ID that the caller claims was active at targetTimestamp. |
Returns
| Name | Type | Description |
|---|---|---|
price | int256 | The price at the target timestamp. |
updatedAt | uint256 | The 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
| Name | Type | Description |
|---|---|---|
oracle | AggregatorV3Interface | The price oracle. |
sequencerFeed | AggregatorV3Interface | The sequencer uptime feed (can be address(0) to skip). |
gracePeriod | uint256 | The sequencer grace period in seconds. |
timeout | uint256 | The staleness timeout in seconds. |
Returns
| Name | Type | Description |
|---|---|---|
price | uint256 | The 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
| Name | Type | Description |
|---|---|---|
success | bool | True if the price passed all validation checks. |
price | uint256 | The 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
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
Functions
getSettlementPrices
function getSettlementPrices(
uint256 expiry,
uint80[] calldata roundHints
) external view returns (uint256 bearPrice, uint256 bullPrice);
IOptionToken
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
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
| Name | Type | Description |
|---|---|---|
seriesId | uint256 | |
roundHints | uint80[] | 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
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
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
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
| Name | Type | Description |
|---|---|---|
roundHints | uint80[] | 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
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
| Name | Type | Description |
|---|---|---|
_feeds | address[] | Array of Chainlink feed addresses. |
_quantities | uint256[] | Array of basket weights (1e18 precision). |
_basePrices | uint256[] | Array of base prices for normalization (8 decimals). |
_maxDeviationBps | uint256 | Maximum deviation from Curve (e.g., 200 = 2%). |
_cap | uint256 | Protocol CAP price (8 decimals). Clamps theoretical price in deviation check. |
_owner | address | Admin address for Curve pool management. |
setCurvePool
Sets the Curve pool for deviation validation (initial setup only).
function setCurvePool(
address _curvePool
) external onlyOwner;
Parameters
| Name | Type | Description |
|---|---|---|
_curvePool | address | Curve USDC/plDXY-BEAR pool address. |
proposeCurvePool
Proposes a new Curve pool (requires 7-day timelock).
function proposeCurvePool(
address _newPool
) external onlyOwner;
Parameters
| Name | Type | Description |
|---|---|---|
_newPool | address | New 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
| Name | Type | Description |
|---|---|---|
<none> | uint80 | roundId Mock round ID (always 1). |
<none> | int256 | answer The calculated basket price in 8 decimals. |
<none> | uint256 | startedAt Oldest component updatedAt (no separate round start; same as updatedAt). |
<none> | uint256 | updatedAt Oldest component updatedAt (weakest link for staleness checks). |
<none> | uint80 | answeredInRound 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
| Name | Type | Description |
|---|---|---|
theoreticalDxy8Dec | uint256 | Computed 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
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
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
| Name | Type | Description |
|---|---|---|
_basketOracle | address | BasketOracle address. |
_cap | uint256 | Protocol CAP (8 decimals, e.g., 2e8 = $2.00). |
_isInverse | bool | True 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
| Name | Type | Description |
|---|---|---|
<none> | uint256 | Price 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
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
| Name | Type | Description |
|---|---|---|
pyth_ | address | Pyth contract address on this chain. |
priceId_ | bytes32 | Pyth price feed ID (e.g., USD/SEK). |
maxStaleness_ | uint256 | Maximum age of price in seconds before considered stale. |
description_ | string | Human-readable description (e.g., “SEK / USD”). |
inverse_ | bool | If true, inverts the price (e.g., USD/SEK → SEK/USD). |
maxConfidenceBps_ | uint256 | Maximum 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
| Name | Type | Description |
|---|---|---|
<none> | uint80 | roundId Always returns 1 (Pyth doesn’t use rounds). |
<none> | int256 | answer Price in 8 decimals. |
<none> | uint256 | startedAt Current block timestamp (adapter attestation time). |
<none> | uint256 | updatedAt Current block timestamp (adapter attestation time). |
<none> | uint80 | answeredInRound 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
| Name | Type | Description |
|---|---|---|
updateData | bytes[] | 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
| Name | Type | Description |
|---|---|---|
updateData | bytes[] | Price update data to calculate fee for. |
Returns
| Name | Type | Description |
|---|---|---|
fee | uint256 | Fee 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
| Name | Type | Description |
|---|---|---|
price | int64 | Pyth price value. |
expo | int32 | Pyth exponent (negative for decimal places). |
Returns
| Name | Type | Description |
|---|---|---|
<none> | int256 | Normalized 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
| Name | Type | Description |
|---|---|---|
price | int64 | Pyth price value. |
expo | int32 | Pyth exponent (negative for decimal places). |
Returns
| Name | Type | Description |
|---|---|---|
<none> | int256 | Inverted 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
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
| Name | Type | Description |
|---|---|---|
expiry | uint256 | The timestamp at which to look up prices. |
roundHints | uint80[] | Caller-provided Chainlink round IDs (one per component) active at expiry. |
Returns
| Name | Type | Description |
|---|---|---|
bearPrice | uint256 | min(BasketPrice, CAP) in 8 decimals |
bullPrice | uint256 | CAP - 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
Interface for price oracles.
Functions
price
Returns price of 1 collateral unit in loan asset terms.
function price() external view returns (uint256);
StakedOracle
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
| Name | Type | Description |
|---|---|---|
_vault | address | ERC4626 staking vault address. |
_underlyingOracle | address | Price oracle for the underlying plDXY token. |
price
Returns price of 1 vault share including accrued yield.
function price() external view override returns (uint256);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | Price 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
- interfaces
- libraries
- modules
- CfdEngine
- CfdEngineAccountLens
- CfdEngineAdmin
- CfdEngineLens
- CfdEnginePlanTypes
- CfdEnginePlanner
- CfdEngineProtocolLens
- CfdEngineSettlementModule
- CfdMath
- CfdTypes
- HousePool
- MarginClearinghouse
- OrderRouter
- OrderRouterAdmin
- PerpsPublicLens
- TrancheVault
Contents
- AccountLensViewTypes
- CfdEngineSettlementTypes
- DeferredEngineViewTypes
- EngineStatusViewTypes
- HousePoolEngineViewTypes
- ICfdEngine
- ICfdEngineAccountLens
- ICfdEngineAdminHost
- ICfdEngineCore
- ICfdEngineLens
- ICfdEnginePlanner
- ICfdEngineProtocolLens
- ICfdEngineSettlementHost
- ICfdEngineSettlementModule
- ICfdVault
- IHousePool
- IMarginAccount
- IMarginClearinghouse
- IOrderRouterAccounting
- IOrderRouterAdminHost
- IPerpsAdmin
- IPerpsKeeper
- IPerpsLP
- IPerpsLPActions
- IPerpsLPViews
- IPerpsTrader
- IPerpsTraderActions
- IPerpsTraderViews
- IProtocolViews
- ITrancheVaultBootstrap
- IWithdrawGuard
- PerpsViewTypes
- ProtocolLensViewTypes
AccountLensViewTypes
Structs
AccountLedgerView
struct AccountLedgerView {
uint256 settlementBalanceUsdc;
uint256 freeSettlementUsdc;
uint256 activePositionMarginUsdc;
uint256 otherLockedMarginUsdc;
uint256 executionEscrowUsdc;
uint256 committedMarginUsdc;
uint256 deferredTraderCreditUsdc;
uint256 pendingOrderCount;
}
AccountLedgerSnapshot
struct AccountLedgerSnapshot {
uint256 settlementBalanceUsdc;
uint256 freeSettlementUsdc;
uint256 activePositionMarginUsdc;
uint256 otherLockedMarginUsdc;
uint256 positionMarginBucketUsdc;
uint256 committedOrderMarginBucketUsdc;
uint256 reservedSettlementBucketUsdc;
uint256 executionEscrowUsdc;
uint256 committedMarginUsdc;
uint256 deferredTraderCreditUsdc;
uint256 pendingOrderCount;
uint256 closeReachableUsdc;
uint256 terminalReachableUsdc;
uint256 accountEquityUsdc;
uint256 freeBuyingPowerUsdc;
bool hasPosition;
CfdTypes.Side side;
uint256 size;
uint256 margin;
uint256 entryPrice;
int256 unrealizedPnlUsdc;
int256 netEquityUsdc;
bool liquidatable;
}
CfdEngineSettlementTypes
Structs
PositionState
struct PositionState {
bool deletePosition;
uint256 size;
uint256 entryPrice;
uint256 maxProfitUsdc;
uint64 lastUpdateTime;
uint64 lastCarryTimestamp;
int256 vpiAccrued;
CfdTypes.Side side;
}
DeferredEngineViewTypes
Structs
DeferredCreditStatus
Aggregate deferred-credit status under the current beneficiary-balance model.
struct DeferredCreditStatus {
uint256 deferredTraderCreditUsdc;
bool traderPayoutClaimableNow;
uint256 deferredKeeperCreditUsdc;
bool keeperCreditClaimableNow;
}
EngineStatusViewTypes
Structs
ProtocolStatus
struct ProtocolStatus {
uint8 phase;
uint256 lastMarkPrice;
uint64 lastMarkTime;
bool oracleFrozen;
bool fadWindow;
uint256 fadMaxStaleness;
}
HousePoolEngineViewTypes
Structs
HousePoolInputSnapshot
struct HousePoolInputSnapshot {
uint256 physicalAssetsUsdc;
uint256 netPhysicalAssetsUsdc;
uint256 maxLiabilityUsdc;
uint256 supplementalReservedUsdc;
uint256 unrealizedMtmLiabilityUsdc;
uint256 deferredTraderCreditUsdc;
uint256 deferredKeeperCreditUsdc;
uint256 protocolFeesUsdc;
bool markFreshnessRequired;
uint256 maxMarkStaleness;
}
HousePoolStatusSnapshot
struct HousePoolStatusSnapshot {
uint64 lastMarkTime;
bool oracleFrozen;
bool degradedMode;
}
ICfdEngine
Stateful CFD trading engine: processes orders and liquidates positions.
This remains a rich internal/admin integration interface.
Product-facing consumers should prefer the slim public surfaces in
IPerpsTraderActions, IPerpsTraderViews, IPerpsLPActions, IPerpsLPViews,
IPerpsKeeper, IProtocolViews, and IMarginAccount.
Live protocol contracts should prefer smaller role-specific interfaces like ICfdEngineCore.
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);
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;
recordDeferredKeeperCredit
Records deferred keeper credit when immediate clearinghouse settlement is unavailable.
Deferred keeper value is always later claimed as clearinghouse credit.
function recordDeferredKeeperCredit(
address keeper,
uint256 amountUsdc
) external;
reserveCloseOrderExecutionBounty
Reserves close-order execution bounty from free settlement first, then active position margin.
function reserveCloseOrderExecutionBounty(
bytes32 accountId,
uint256 sizeDelta,
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;
creditKeeperExecutionBounty
Credits a keeper execution bounty into the beneficiary’s clearinghouse account.
Realizes carry first when the beneficiary account currently has an open position so the settlement-balance credit cannot retroactively dilute carry owed over the elapsed interval.
function creditKeeperExecutionBounty(
address beneficiary,
uint256 amountUsdc,
uint256 price,
uint64 publishTime
) 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
| Name | Type | Description |
|---|---|---|
accountId | bytes32 | Account holding the position to liquidate |
currentOraclePrice | uint256 | Mark price from the oracle (8 decimals) |
vaultDepthUsdc | uint256 | Available vault liquidity (6 decimals) |
publishTime | uint64 | Oracle publish timestamp |
Returns
| Name | Type | Description |
|---|---|---|
keeperBountyUsdc | uint256 | Bounty paid to the liquidation keeper (6 decimals) |
realizeCarryBeforeMarginChange
Realizes accrued carry against the current reachable collateral before a user-level settlement balance mutation changes the carry basis.
function realizeCarryBeforeMarginChange(
bytes32 accountId,
uint256 reachableCollateralBasisUsdc
) external;
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);
accumulatedFeesUsdc
Accumulated execution fees awaiting withdrawal (6 decimals)
function accumulatedFeesUsdc() external view returns (uint256);
totalDeferredTraderCreditUsdc
Deferred trader credit still owed to beneficiaries.
function totalDeferredTraderCreditUsdc() external view returns (uint256);
totalDeferredKeeperCreditUsdc
Deferred keeper credit still owed after failed immediate settlement.
function totalDeferredKeeperCreditUsdc() external view returns (uint256);
lastMarkTime
Timestamp of the last mark price update
function lastMarkTime() external view returns (uint64);
updateMarkPrice
Pushes a fresh mark price without processing an order.
This updates the cached mark only; carry is realized on execution and margin-mutating paths.
function updateMarkPrice(
uint256 price,
uint64 publishTime
) external;
Parameters
| Name | Type | Description |
|---|---|---|
price | uint256 | New mark price (8 decimals) |
publishTime | uint64 | Oracle 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);
positions
Returns the current position tuple for an account.
function positions(
bytes32 accountId
)
external
view
returns (
uint256 size,
uint256 margin,
uint256 entryPrice,
uint256 maxProfitUsdc,
CfdTypes.Side side,
uint64 lastUpdateTime,
int256 vpiAccrued
);
getPositionLastCarryTimestamp
Returns the timestamp through which carry has been realized for the position.
function getPositionLastCarryTimestamp(
bytes32 accountId
) external view returns (uint64);
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);
getProtocolStatus
function getProtocolStatus() external view returns (EngineStatusViewTypes.ProtocolStatus memory);
Errors
CfdEngine__TypedOrderFailure
error CfdEngine__TypedOrderFailure(
CfdEnginePlanTypes.ExecutionFailurePolicyCategory failureCategory, uint8 failureCode, bool isClose
);
CfdEngine__MarkPriceOutOfOrder
error CfdEngine__MarkPriceOutOfOrder();
Structs
SideState
struct SideState {
uint256 maxProfitUsdc;
uint256 openInterest;
uint256 entryNotional;
uint256 totalMargin;
}
LiquidationPreview
struct LiquidationPreview {
bool liquidatable;
uint256 oraclePrice;
int256 equityUsdc;
int256 pnlUsdc;
uint256 reachableCollateralUsdc;
uint256 keeperBountyUsdc;
uint256 seizedCollateralUsdc;
uint256 settlementRetainedUsdc;
uint256 freshTraderPayoutUsdc;
uint256 existingDeferredConsumedUsdc;
uint256 existingDeferredRemainingUsdc;
uint256 immediatePayoutUsdc;
uint256 deferredTraderCreditUsdc;
uint256 badDebtUsdc;
bool triggersDegradedMode;
bool postOpDegradedMode;
uint256 effectiveAssetsAfterUsdc;
uint256 maxLiabilityAfterUsdc;
}
Enums
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
}
ICfdEngineAccountLens
Functions
getAccountCollateralView
Legacy detailed account lens kept for internal tooling, tests, and migration.
Product-facing consumers should prefer IPerpsTraderViews via PerpsPublicLens.
function getAccountCollateralView(
bytes32 accountId
) external view returns (CfdEngine.AccountCollateralView memory viewData);
getWithdrawableUsdc
function getWithdrawableUsdc(
bytes32 accountId
) external view returns (uint256 withdrawableUsdc);
getAccountLedgerView
function getAccountLedgerView(
bytes32 accountId
) external view returns (AccountLensViewTypes.AccountLedgerView memory viewData);
getAccountLedgerSnapshot
function getAccountLedgerSnapshot(
bytes32 accountId
) external view returns (AccountLensViewTypes.AccountLedgerSnapshot memory snapshot);
ICfdEngineAdminHost
Functions
applyRiskConfig
function applyRiskConfig(
EngineRiskConfig calldata config
) external;
applyCalendarConfig
function applyCalendarConfig(
EngineCalendarConfig calldata config
) external;
applyFreshnessConfig
function applyFreshnessConfig(
EngineFreshnessConfig calldata config
) external;
Structs
EngineRiskConfig
struct EngineRiskConfig {
CfdTypes.RiskParams riskParams;
uint256 executionFeeBps;
}
EngineCalendarConfig
struct EngineCalendarConfig {
uint256[] fadDayTimestamps;
uint256 fadRunwaySeconds;
}
EngineFreshnessConfig
struct EngineFreshnessConfig {
uint256 fadMaxStaleness;
uint256 engineMarkStalenessLimit;
}
ICfdEngineCore
Core/operator-facing engine surface used by live perps contracts.
Functions
clearinghouse
function clearinghouse() external view returns (address);
orderRouter
function orderRouter() external view returns (address);
settlementModule
function settlementModule() external view returns (address);
USDC
function USDC() external view returns (IERC20);
lastMarkPrice
function lastMarkPrice() external view returns (uint256);
riskParams
function riskParams()
external
view
returns (
uint256 vpiFactor,
uint256 maxSkewRatio,
uint256 maintMarginBps,
uint256 initMarginBps,
uint256 fadMarginBps,
uint256 baseCarryBps,
uint256 minBountyUsdc,
uint256 bountyBps
);
processOrderTyped
function processOrderTyped(
CfdTypes.Order memory order,
uint256 currentOraclePrice,
uint256 vaultDepthUsdc,
uint64 publishTime
) external;
recordDeferredKeeperCredit
function recordDeferredKeeperCredit(
address keeper,
uint256 amountUsdc
) external;
reserveCloseOrderExecutionBounty
function reserveCloseOrderExecutionBounty(
bytes32 accountId,
uint256 sizeDelta,
uint256 amountUsdc,
address recipient
) external;
absorbRouterCancellationFee
function absorbRouterCancellationFee(
uint256 amountUsdc
) external;
recordRouterProtocolFee
function recordRouterProtocolFee(
uint256 amountUsdc
) external;
creditKeeperExecutionBounty
function creditKeeperExecutionBounty(
address beneficiary,
uint256 amountUsdc,
uint256 price,
uint64 publishTime
) external;
accumulatedFeesUsdc
function accumulatedFeesUsdc() external view returns (uint256);
totalDeferredTraderCreditUsdc
function totalDeferredTraderCreditUsdc() external view returns (uint256);
totalDeferredKeeperCreditUsdc
function totalDeferredKeeperCreditUsdc() external view returns (uint256);
liquidatePosition
function liquidatePosition(
bytes32 accountId,
uint256 currentOraclePrice,
uint256 vaultDepthUsdc,
uint64 publishTime
) external returns (uint256 keeperBountyUsdc);
lastMarkTime
function lastMarkTime() external view returns (uint64);
updateMarkPrice
function updateMarkPrice(
uint256 price,
uint64 publishTime
) external;
CAP_PRICE
function CAP_PRICE() external view returns (uint256);
realizeCarryBeforeMarginChange
function realizeCarryBeforeMarginChange(
bytes32 accountId,
uint256 reachableCollateralBasisUsdc
) external;
checkpointCarryUsingStoredMark
function checkpointCarryUsingStoredMark(
bytes32 accountId,
uint256 reachableCollateralBasisUsdc
) external;
isFadWindow
function isFadWindow() external view returns (bool);
fadMaxStaleness
function fadMaxStaleness() external view returns (uint256);
engineMarkStalenessLimit
function engineMarkStalenessLimit() external view returns (uint256);
fadDayOverrides
function fadDayOverrides(
uint256 dayNumber
) external view returns (bool);
isOracleFrozen
function isOracleFrozen() external view returns (bool);
positions
function positions(
bytes32 accountId
)
external
view
returns (
uint256 size,
uint256 margin,
uint256 entryPrice,
uint256 maxProfitUsdc,
CfdTypes.Side side,
uint64 lastUpdateTime,
int256 vpiAccrued
);
degradedMode
function degradedMode() external view returns (bool);
getProtocolStatus
function getProtocolStatus() external view returns (EngineStatusViewTypes.ProtocolStatus memory status);
Errors
CfdEngine__TypedOrderFailure
error CfdEngine__TypedOrderFailure(
CfdEnginePlanTypes.ExecutionFailurePolicyCategory failureCategory, uint8 failureCode, bool isClose
);
CfdEngine__MarkPriceOutOfOrder
error CfdEngine__MarkPriceOutOfOrder();
ICfdEngineLens
Functions
engine
function engine() external view returns (address);
previewClose
function previewClose(
bytes32 accountId,
uint256 sizeDelta,
uint256 oraclePrice
) external view returns (CfdEngine.ClosePreview memory preview);
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);
simulateClose
function simulateClose(
bytes32 accountId,
uint256 sizeDelta,
uint256 oraclePrice,
uint256 vaultDepthUsdc
) external view returns (CfdEngine.ClosePreview memory preview);
previewLiquidation
function previewLiquidation(
bytes32 accountId,
uint256 oraclePrice
) external view returns (CfdEngine.LiquidationPreview memory preview);
simulateLiquidation
function simulateLiquidation(
bytes32 accountId,
uint256 oraclePrice,
uint256 vaultDepthUsdc
) external view returns (CfdEngine.LiquidationPreview memory preview);
ICfdEnginePlanner
Functions
computeOpenMarginAfter
function computeOpenMarginAfter(
uint256 marginAfterFunding,
int256 netMarginChange
) external pure returns (bool drained, uint256 marginAfter);
planOpen
function planOpen(
CfdEnginePlanTypes.RawSnapshot memory snap,
CfdTypes.Order memory order,
uint256 executionPrice,
uint64 publishTime
) external pure returns (CfdEnginePlanTypes.OpenDelta memory delta);
planClose
function planClose(
CfdEnginePlanTypes.RawSnapshot memory snap,
CfdTypes.Order memory order,
uint256 executionPrice,
uint64 publishTime
) external pure returns (CfdEnginePlanTypes.CloseDelta memory delta);
planLiquidation
function planLiquidation(
CfdEnginePlanTypes.RawSnapshot memory snap,
uint256 executionPrice,
uint64 publishTime
) external pure returns (CfdEnginePlanTypes.LiquidationDelta memory delta);
getOpenFailurePolicyCategory
function getOpenFailurePolicyCategory(
CfdEnginePlanTypes.OpenRevertCode code
) external pure returns (CfdEnginePlanTypes.OpenFailurePolicyCategory);
getExecutionFailurePolicyCategory
function getExecutionFailurePolicyCategory(
CfdEnginePlanTypes.OpenRevertCode code
) external pure returns (CfdEnginePlanTypes.ExecutionFailurePolicyCategory);
getCloseExecutionFailurePolicyCategory
function getCloseExecutionFailurePolicyCategory(
CfdEnginePlanTypes.CloseRevertCode code
) external pure returns (CfdEnginePlanTypes.ExecutionFailurePolicyCategory);
ICfdEngineProtocolLens
Functions
getProtocolAccountingSnapshot
Legacy detailed protocol lens kept for internal tooling, tests, and migration.
Product-facing consumers should prefer IPerpsTraderViews, IPerpsLPViews, and
IProtocolViews via PerpsPublicLens.
function getProtocolAccountingSnapshot()
external
view
returns (ProtocolLensViewTypes.ProtocolAccountingSnapshot memory snapshot);
getHousePoolInputSnapshot
function getHousePoolInputSnapshot(
uint256 markStalenessLimit
) external view returns (HousePoolEngineViewTypes.HousePoolInputSnapshot memory snapshot);
getHousePoolStatusSnapshot
function getHousePoolStatusSnapshot()
external
view
returns (HousePoolEngineViewTypes.HousePoolStatusSnapshot memory snapshot);
ICfdEngineSettlementHost
Functions
clearinghouse
function clearinghouse() external view returns (address);
vault
function vault() external view returns (address);
orderRouter
function orderRouter() external view returns (address);
settlementApplyFundingAndMark
function settlementApplyFundingAndMark(
uint256 newMarkPrice,
uint64 newMarkTime
) external;
settlementSyncTotalSideMargin
function settlementSyncTotalSideMargin(
CfdTypes.Side side,
uint256 marginBefore,
uint256 marginAfter
) external;
settlementApplySideDelta
function settlementApplySideDelta(
CfdTypes.Side side,
int256 maxProfitDelta,
int256 openInterestDelta,
int256 entryNotionalDelta
) external;
settlementConsumeDeferredTraderPayout
function settlementConsumeDeferredTraderPayout(
bytes32 accountId,
uint256 amountUsdc
) external;
settlementRecordDeferredTraderPayout
function settlementRecordDeferredTraderPayout(
bytes32 accountId,
uint256 amountUsdc
) external;
settlementAccumulateFees
function settlementAccumulateFees(
uint256 amountUsdc
) external;
settlementAccumulateBadDebt
function settlementAccumulateBadDebt(
uint256 amountUsdc
) external;
settlementWritePosition
function settlementWritePosition(
bytes32 accountId,
CfdEngineSettlementTypes.PositionState calldata position
) external;
settlementDeletePosition
function settlementDeletePosition(
bytes32 accountId
) external;
ICfdEngineSettlementModule
Functions
executeOpen
function executeOpen(
ICfdEngineSettlementHost host,
CfdEnginePlanTypes.OpenDelta calldata delta,
CfdTypes.Position calldata currentPosition,
uint64 publishTime
) external;
executeClose
function executeClose(
ICfdEngineSettlementHost host,
CfdEnginePlanTypes.CloseDelta calldata delta,
CfdTypes.Position calldata currentPosition,
uint64 publishTime
) external;
executeLiquidation
function executeLiquidation(
ICfdEngineSettlementHost host,
CfdEnginePlanTypes.LiquidationDelta calldata delta,
uint64 publishTime
) external returns (uint256 keeperBountyUsdc);
ICfdVault
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
| Name | Type | Description |
|---|---|---|
recipient | address | Address to receive USDC |
amount | uint256 | USDC 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;
recordClaimantInflow
Records claimant-owned value that should ultimately flow through the tranche waterfall.
CashArrived increments canonical accounted assets because raw USDC arrived in this flow.
AlreadyRetained only routes ownership for value already retained physically by the vault.
function recordClaimantInflow(
uint256 amount,
ClaimantInflowKind kind,
ClaimantInflowCashMode cashMode
) 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);
Enums
ClaimantInflowKind
enum ClaimantInflowKind {
Revenue,
Recapitalization
}
ClaimantInflowCashMode
enum ClaimantInflowCashMode {
CashArrived,
AlreadyRetained
}
IHousePool
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
| Name | Type | Description |
|---|---|---|
seniorPrincipalUsdc | uint256 | Simulated senior principal after reconcile (6 decimals) |
juniorPrincipalUsdc | uint256 | Simulated junior principal after reconcile (6 decimals) |
maxSeniorWithdrawUsdc | uint256 | Simulated senior withdrawal cap after reconcile (6 decimals) |
maxJuniorWithdrawUsdc | uint256 | Simulated 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);
isOracleFrozen
function isOracleFrozen() external view returns (bool);
frozenLpFeeBps
function frozenLpFeeBps(
bool isSenior
) external view returns (uint256);
IMarginAccount
Public trader-facing margin account surface stripped of internal reservation and bucket plumbing.
Functions
depositMargin
function depositMargin(
uint256 amount
) external;
withdrawMargin
function withdrawMargin(
uint256 amount
) external;
getAccountEquityUsdc
function getAccountEquityUsdc(
bytes32 accountId
) external view returns (uint256);
getFreeBuyingPowerUsdc
Returns settlement equity that is not currently locked into margin buckets.
This is a clearinghouse-local view and does not account for engine withdrawal guards.
function getFreeBuyingPowerUsdc(
bytes32 accountId
) external view returns (uint256);
IMarginClearinghouse
USDC-only cross-margin account system that holds settlement balances and settles PnL for CFD positions.
This is the full operator/integration surface.
Product-facing consumers should prefer IMarginAccount and avoid depending on
reservation buckets, internal custody buckets, or settlement-path helpers.
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 settlement USDC for realized PnL, deferred-claim servicing, 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);
consumeSettlementLoss
Consumes a realized settlement loss from free settlement plus the active position margin bucket.
function consumeSettlementLoss(
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;
reserveCloseExecutionBountyFromSettlement
Reserves free-settlement USDC for a close-order execution bounty with carry checkpointing.
Restricted to the engine’s atomic fresh close-bounty path.
function reserveCloseExecutionBountyFromSettlement(
bytes32 accountId,
uint256 amount,
address recipient
) external;
reserveStaleCloseExecutionBountyFromSettlement
Reserves free-settlement USDC for a stale close-order execution bounty without checkpointing carry.
Restricted to the engine’s atomic stale close-bounty path.
function reserveStaleCloseExecutionBountyFromSettlement(
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;
reserveStaleCloseExecutionBountyFromPositionMargin
Reserves active position margin for a stale close-order execution bounty without checkpointing carry.
Restricted to the engine’s bounded stale close-bounty path.
function reserveStaleCloseExecutionBountyFromPositionMargin(
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);
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 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
}
ReservationStatus
enum ReservationStatus {
None,
Active,
Consumed,
Released
}
IOrderRouterAccounting
Shared accounting-facing subset of OrderRouter used by engine views and margin bookkeeping.
This remains an internal/admin integration surface.
Product-facing consumers should prefer IPerpsTraderViews via PerpsPublicLens and
avoid depending on queue-accounting internals directly.
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);
accountHeadOrderId
Returns the current account-queue head id for pending-order traversal.
function accountHeadOrderId(
bytes32 accountId
) external view returns (uint64 headOrderId);
getPendingOrderView
Returns the pending-order view for a specific order plus the next account-queue order id.
function getPendingOrderView(
uint64 orderId
) external view returns (PendingOrderView memory pending, uint64 nextAccountOrderId);
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;
}
PendingOrderView
struct PendingOrderView {
uint64 orderId;
bool isClose;
CfdTypes.Side side;
uint256 sizeDelta;
uint256 marginDelta;
uint256 targetPrice;
uint64 commitTime;
uint64 commitBlock;
uint256 committedMarginUsdc;
uint256 executionBountyUsdc;
}
Enums
OrderStatus
enum OrderStatus {
None,
Pending,
Executed,
Failed
}
IOrderRouterAdminHost
Functions
applyRouterConfig
function applyRouterConfig(
RouterConfig calldata config
) external;
applyOracleConfig
function applyOracleConfig(
OracleConfig calldata config
) external;
Structs
RouterConfig
struct RouterConfig {
uint256 maxOrderAge;
uint256 orderExecutionStalenessLimit;
uint256 liquidationStalenessLimit;
uint256 pythMaxConfidenceRatioBps;
uint256 minOpenNotionalUsdc;
uint256 openOrderExecutionBountyBps;
uint256 minOpenOrderExecutionBountyUsdc;
uint256 maxOpenOrderExecutionBountyUsdc;
uint256 closeOrderExecutionBountyUsdc;
uint256 maxPendingOrders;
uint256 minEngineGas;
uint256 maxPruneOrdersPerCall;
}
OracleConfig
struct OracleConfig {
address pyth;
bytes32[] feedIds;
uint256[] quantities;
uint256[] basePrices;
bool[] inversions;
}
IPerpsAdmin
Administrative surface for perps configuration, emergency controls, and one-time setup.
Functions
setPauser
function setPauser(
address newPauser
) external;
pause
function pause() external;
unpause
function unpause() external;
IPerpsKeeper
Keeper-facing execution and liquidation surface for the simplified product API.
Functions
executeOrder
Executes the next eligible delayed order using fresh oracle data.
function executeOrder(
uint64 orderId,
bytes[] calldata pythUpdateData
) external payable;
executeOrderBatch
Executes a bounded batch of eligible delayed orders using a shared oracle update.
function executeOrderBatch(
uint64 maxOrderId,
bytes[] calldata pythUpdateData
) external payable;
executeLiquidation
Liquidates an unsafe account using fresh oracle data.
function executeLiquidation(
bytes32 accountId,
bytes[] calldata pythUpdateData
) external payable;
IPerpsLP
Inherits: IPerpsLPActions, IPerpsLPViews
Combined LP-facing surface for the simplified perps product API.
IPerpsLPActions
LP-facing senior/junior tranche action surface.
Functions
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;
IPerpsLPViews
Compact LP-facing read surface for senior and junior tranches.
Functions
getSeniorTranche
function getSeniorTranche() external view returns (PerpsViewTypes.TrancheView memory viewData);
getJuniorTranche
function getJuniorTranche() external view returns (PerpsViewTypes.TrancheView memory viewData);
getLpStatus
function getLpStatus() external view returns (PerpsViewTypes.LpStatusView memory viewData);
IPerpsTrader
Inherits: IPerpsTraderActions, IPerpsTraderViews
Combined trader-facing surface for the simplified perps product API.
IPerpsTraderActions
Trader-facing action surface aligned with the current delayed-order router model.
Functions
commitOrder
function commitOrder(
CfdTypes.Side side,
uint256 sizeDelta,
uint256 marginDelta,
uint256 targetPrice,
bool isClose
) external;
IPerpsTraderViews
Compact trader-facing read surface for the simplified perps product API.
Functions
getTraderAccount
function getTraderAccount(
bytes32 accountId
) external view returns (PerpsViewTypes.TraderAccountView memory viewData);
getPosition
function getPosition(
bytes32 accountId
) external view returns (PerpsViewTypes.PositionView memory viewData);
getPendingOrders
function getPendingOrders(
bytes32 accountId
) external view returns (PerpsViewTypes.PendingOrderView[] memory pending);
isLiquidatable
function isLiquidatable(
bytes32 accountId
) external view returns (bool);
IProtocolViews
Compact protocol-wide read surface for product consumers.
Functions
getProtocolStatus
function getProtocolStatus() external view returns (PerpsViewTypes.ProtocolStatusView memory viewData);
ITrancheVaultBootstrap
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
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;
Parameters
| Name | Type | Description |
|---|---|---|
accountId | bytes32 | Cross-margin account to check |
PerpsViewTypes
Canonical public-facing view structs for the simplified perps product surface.
Structs
TraderAccountView
struct TraderAccountView {
uint256 equityUsdc;
uint256 withdrawableUsdc;
uint256 pendingOrderMarginUsdc;
uint256 pendingExecutionBountyUsdc;
bool hasOpenPosition;
bool liquidatable;
}
PositionView
struct PositionView {
bool exists;
CfdTypes.Side side;
uint256 size;
uint256 entryPrice;
uint256 marginUsdc;
int256 unrealizedPnlUsdc;
uint256 maintenanceMarginUsdc;
bool liquidatable;
}
PendingOrderView
struct PendingOrderView {
uint64 orderId;
CfdTypes.Side side;
uint256 sizeDelta;
int256 marginDeltaUsdc;
uint256 acceptablePrice;
bool isReduceOnly;
OrderStatus status;
}
TrancheView
struct TrancheView {
uint256 totalAssetsUsdc;
uint256 totalShares;
uint256 sharePrice;
uint256 maxWithdrawUsdc;
uint256 frozenLpFeeBps;
bool depositEnabled;
bool withdrawEnabled;
bool oracleFrozen;
}
LpStatusView
struct LpStatusView {
bool tradingActive;
bool withdrawalLive;
uint64 lastMarkTime;
bool oracleFresh;
bool oracleFrozen;
}
ProtocolStatusView
struct ProtocolStatusView {
uint8 phase;
uint256 lastMarkPrice;
uint64 lastMarkTime;
bool oracleFrozen;
bool fadWindow;
bool tradingActive;
bool withdrawalLive;
}
Enums
OrderStatus
enum OrderStatus {
None,
Pending,
Executed,
Failed
}
ProtocolLensViewTypes
Structs
ProtocolAccountingSnapshot
struct ProtocolAccountingSnapshot {
uint256 vaultAssetsUsdc;
uint256 netPhysicalAssetsUsdc;
uint256 maxLiabilityUsdc;
uint256 effectiveSolvencyAssetsUsdc;
uint256 withdrawalReservedUsdc;
uint256 freeUsdc;
uint256 accumulatedFeesUsdc;
uint256 accumulatedBadDebtUsdc;
uint256 totalDeferredTraderCreditUsdc;
uint256 totalDeferredKeeperCreditUsdc;
bool degradedMode;
bool hasLiveLiability;
}
Contents
- CashPriorityLib
- CfdEnginePlanLib
- CfdEngineSettlementLib
- CfdEngineSnapshotsLib
- CloseAccountingLib
- HousePoolAccountingLib
- HousePoolFreshnessLib
- HousePoolPendingLivePlanLib
- HousePoolPendingPreviewLib
- HousePoolReconcilePlanLib
- HousePoolSeedLifecycleLib
- HousePoolTrancheGateLib
- HousePoolWaterfallAccountingLib
- HousePoolWithdrawalPreviewLib
- LiquidationAccountingLib
- MarginClearinghouseAccountingLib
- MarketCalendarLib
- OpenAccountingLib
- OracleFreshnessPolicyLib
- OrderFailurePolicyLib
- OrderOraclePolicyLib
- PositionRiskAccountingLib
- SolvencyAccountingLib
CashPriorityLib
Functions
reserveFreshPayouts
function reserveFreshPayouts(
uint256 physicalAssetsUsdc,
uint256 protocolFeesUsdc,
uint256 deferredTraderCreditUsdc,
uint256 deferredKeeperCreditUsdc
) internal pure returns (SeniorCashReservation memory reservation);
reserveDeferredClaim
function reserveDeferredClaim(
uint256 physicalAssetsUsdc,
uint256 protocolFeesUsdc,
uint256 deferredTraderCreditUsdc,
uint256 deferredKeeperCreditUsdc,
uint256 deferredClaimAmountUsdc
) internal pure returns (SeniorCashReservation memory reservation);
reservedSeniorCashUsdc
function reservedSeniorCashUsdc(
uint256 deferredTraderCreditUsdc,
uint256 deferredKeeperCreditUsdc
) internal pure returns (uint256);
availableCashForFreshPayouts
function availableCashForFreshPayouts(
uint256 physicalAssetsUsdc,
uint256 protocolFeesUsdc,
uint256 deferredTraderCreditUsdc,
uint256 deferredKeeperCreditUsdc
) internal pure returns (uint256);
availableCashForDeferredBeneficiaryClaim
function availableCashForDeferredBeneficiaryClaim(
uint256 physicalAssetsUsdc,
uint256 protocolFeesUsdc,
uint256 deferredTraderCreditUsdc,
uint256 deferredKeeperCreditUsdc,
uint256 claimAmountUsdc
) internal pure returns (uint256);
availableCashForProtocolFeeWithdrawal
function availableCashForProtocolFeeWithdrawal(
uint256 physicalAssetsUsdc,
uint256 protocolFeesUsdc,
uint256 deferredTraderCreditUsdc,
uint256 deferredKeeperCreditUsdc
) internal pure returns (uint256);
canPayFreshPayout
function canPayFreshPayout(
uint256 physicalAssetsUsdc,
uint256 protocolFeesUsdc,
uint256 deferredTraderCreditUsdc,
uint256 deferredKeeperCreditUsdc,
uint256 amountUsdc
) internal pure returns (bool);
canPayDeferredBeneficiaryClaim
function canPayDeferredBeneficiaryClaim(
uint256 physicalAssetsUsdc,
uint256 protocolFeesUsdc,
uint256 deferredTraderCreditUsdc,
uint256 deferredKeeperCreditUsdc,
uint256 claimAmountUsdc
) internal pure returns (bool);
canWithdrawProtocolFees
function canWithdrawProtocolFees(
uint256 physicalAssetsUsdc,
uint256 protocolFeesUsdc,
uint256 deferredTraderCreditUsdc,
uint256 deferredKeeperCreditUsdc,
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 deferredTraderCreditUsdc,
uint256 deferredKeeperCreditUsdc
) private pure returns (SeniorCashReservation memory reservation);
Structs
SeniorCashReservation
struct SeniorCashReservation {
uint256 physicalAssetsUsdc;
uint256 protocolFeesUsdc;
uint256 deferredTraderCreditUsdc;
uint256 deferredKeeperCreditUsdc;
uint256 totalSeniorClaimsUsdc;
uint256 reservedSeniorCashUsdc;
uint256 protocolFeeWithdrawalUsdc;
uint256 freeCashUsdc;
uint256 deferredClaimServiceableUsdc;
}
CfdEnginePlanLib
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
_liquidationVpiClawbackUsdc
function _liquidationVpiClawbackUsdc(
int256 vpiAccrued
) private pure returns (uint256);
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);
_planDeferredTraderCreditConsumption
function _planDeferredTraderCreditConsumption(
uint256 deferredTraderCreditUsdc,
uint256 shortfallUsdc,
bool shortfallAlreadyIncludesDeferred
) private pure returns (uint256 consumedUsdc, uint256 remainingUsdc, uint256 badDebtUsdc);
_planCloseDeferredTraderCreditConsumption
function _planCloseDeferredTraderCreditConsumption(
uint256 deferredTraderCreditUsdc,
CfdEngineSettlementLib.CloseSettlementResult memory lossResult
)
private
pure
returns (uint256 consumedUsdc, uint256 remainingUsdc, uint256 feeRecoveredUsdc, uint256 badDebtUsdc);
planOpen
function planOpen(
CfdEnginePlanTypes.RawSnapshot memory snap,
CfdTypes.Order memory order,
uint256 executionPrice,
uint64 publishTime
) internal pure returns (CfdEnginePlanTypes.OpenDelta memory delta);
_applyPendingCarryRealizationToOpenSnapshot
function _applyPendingCarryRealizationToOpenSnapshot(
CfdEnginePlanTypes.RawSnapshot memory snap,
uint256 pendingCarryUsdc
) private pure returns (bool hasShortfall);
_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,
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);
CfdEngineSettlementLib
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
Structs
SolvencySnapshot
struct SolvencySnapshot {
uint256 physicalAssets;
uint256 protocolFees;
uint256 netPhysicalAssets;
uint256 maxLiability;
uint256 effectiveSolvencyAssets;
}
CloseAccountingLib
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
) 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
Functions
buildWithdrawalSnapshot
function buildWithdrawalSnapshot(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory engineSnapshot
) internal pure returns (WithdrawalSnapshot memory snapshot);
buildReconcileSnapshot
function buildReconcileSnapshot(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory engineSnapshot
) internal pure returns (ReconcileSnapshot memory snapshot);
getMarkFreshnessPolicy
function getMarkFreshnessPolicy(
HousePoolEngineViewTypes.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
Functions
markIsFreshForReconcile
function markIsFreshForReconcile(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot,
uint256 currentTimestamp
) internal pure returns (bool);
withdrawalsLive
function withdrawalsLive(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot,
uint256 currentTimestamp
) internal pure returns (bool);
markFresh
function markFresh(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot,
uint256 currentTimestamp
) internal pure returns (bool);
HousePoolPendingLivePlanLib
Functions
planApplyPendingClaimantBuckets
function planApplyPendingClaimantBuckets(
HousePoolPendingPreviewLib.PendingAccountingState memory state,
uint256 currentSeniorPrincipal,
HousePoolPendingPreviewLib.ClaimantPendingBuckets memory claimantBuckets
) internal pure returns (PendingLivePlan memory plan);
Structs
PendingLivePlan
struct PendingLivePlan {
HousePoolPendingPreviewLib.PendingAccountingState state;
bool seniorPrincipalChanged;
}
HousePoolPendingPreviewLib
Functions
applyPendingClaimantBucketsPreview
function applyPendingClaimantBucketsPreview(
PendingAccountingState memory state,
ClaimantPendingBuckets memory claimantBuckets
) internal pure;
applyClaimantRecapitalizationIntent
function applyClaimantRecapitalizationIntent(
PendingAccountingState memory state,
uint256 amount
) internal pure;
applyRevenueIntent
function applyRevenueIntent(
PendingAccountingState memory state,
uint256 amount
) internal pure;
Structs
ClaimantPendingBuckets
struct ClaimantPendingBuckets {
uint256 recapitalizationUsdc;
uint256 revenueUsdc;
}
PendingAccountingState
struct PendingAccountingState {
HousePoolWaterfallAccountingLib.WaterfallState waterfall;
uint256 unassignedAssets;
uint256 seniorSupply;
uint256 juniorSupply;
}
HousePoolReconcilePlanLib
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
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
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
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
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
Functions
buildLiquidationState
function buildLiquidationState(
uint256 size,
uint256 oraclePrice,
uint256 reachableCollateralUsdc,
int256 equityUsdc,
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
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);
getSettlementBalanceUsdc
function getSettlementBalanceUsdc(
IMarginClearinghouse.AccountUsdcBuckets memory buckets
) internal pure returns (uint256);
getFreeSettlementUsdc
function getFreeSettlementUsdc(
IMarginClearinghouse.AccountUsdcBuckets memory buckets
) internal pure returns (uint256);
getPositionMarginUsdc
function getPositionMarginUsdc(
IMarginClearinghouse.AccountUsdcBuckets memory buckets
) internal pure returns (uint256);
getQueuedReservedUsdc
function getQueuedReservedUsdc(
IMarginClearinghouse.AccountUsdcBuckets memory buckets
) internal pure returns (uint256);
getGenericReachableUsdc
function getGenericReachableUsdc(
IMarginClearinghouse.AccountUsdcBuckets memory buckets
) internal pure returns (uint256 reachableUsdc);
planFundingLossConsumption
function planFundingLossConsumption(
IMarginClearinghouse.AccountUsdcBuckets memory buckets,
uint256 lossUsdc
) internal pure returns (SettlementConsumption memory consumption);
planOpenCostApplication
function planOpenCostApplication(
IMarginClearinghouse.AccountUsdcBuckets memory buckets,
uint256 marginDeltaUsdc,
int256 tradeCostUsdc
) internal pure returns (OpenCostPlan memory plan);
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;
}
OpenCostPlan
struct OpenCostPlan {
int256 netMarginChangeUsdc;
uint256 settlementCreditUsdc;
uint256 settlementDebitUsdc;
uint256 positionMarginUnlockedUsdc;
uint256 positionMarginLockedUsdc;
uint256 resultingSettlementBalanceUsdc;
uint256 resultingPositionMarginUsdc;
uint256 resultingFreeSettlementUsdc;
bool insufficientFreeEquity;
bool insufficientPositionMargin;
}
LiquidationResidualPlan
struct LiquidationResidualPlan {
uint256 settlementRetainedUsdc;
uint256 settlementSeizedUsdc;
uint256 freshTraderPayoutUsdc;
uint256 badDebtUsdc;
BucketMutation mutation;
}
MarketCalendarLib
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
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;
CfdTypes.RiskParams riskParams;
}
OpenState
struct OpenState {
uint256 addedMaxProfitUsdc;
uint256 oldEntryNotional;
uint256 newEntryPrice;
uint256 newSize;
uint256 newEntryNotional;
uint256 postSkewUsdc;
int256 vpiUsdc;
uint256 notionalUsdc;
uint256 executionFeeUsdc;
int256 tradeCostUsdc;
uint256 maintenanceMarginUsdc;
uint256 initialMarginRequirementUsdc;
}
OracleFreshnessPolicyLib
Functions
getPolicy
function getPolicy(
Mode mode,
bool oracleFrozen,
bool isFad,
uint256 engineMarkStalenessLimit,
uint256 poolMarkStalenessLimit,
uint256 routerOrderExecutionStalenessLimit,
uint256 routerLiquidationStalenessLimit,
uint256 fadMaxStaleness
) internal pure returns (Policy memory policy);
isStale
function isStale(
uint256 oraclePublishTime,
uint256 maxStaleness,
uint256 currentTimestamp
) internal pure returns (bool);
_effectiveLiveMarkLimit
function _effectiveLiveMarkLimit(
uint256 engineMarkStalenessLimit,
uint256 poolMarkStalenessLimit
) private pure returns (uint256);
Structs
Policy
struct Policy {
bool closeOnly;
bool requireStoredMark;
bool allowAnyStoredMark;
uint256 maxStaleness;
}
Enums
Mode
enum Mode {
OpenExecution,
CloseExecution,
Liquidation,
PoolReconcile,
CloseCommitFallback,
MarkRefresh
}
OrderFailurePolicyLib
Functions
isPredictablyInvalidOpen
function isPredictablyInvalidOpen(
CfdEnginePlanTypes.OpenFailurePolicyCategory category
) internal pure returns (bool);
OrderOraclePolicyLib
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(
uint256 oraclePublishTime,
uint256 maxStaleness,
uint256 currentTimestamp
) internal pure returns (bool);
Structs
OracleExecutionPolicy
struct OracleExecutionPolicy {
bool closeOnly;
uint256 maxStaleness;
}
Enums
OracleAction
enum OracleAction {
OrderExecution,
MarkRefresh,
Liquidation
}
PositionRiskAccountingLib
Functions
_vpiClawbackUsdc
function _vpiClawbackUsdc(
int256 vpiAccrued
) private pure returns (uint256);
computeLpBackedNotionalUsdc
function computeLpBackedNotionalUsdc(
uint256 size,
uint256 price,
uint256 reachableCollateralUsdc
) internal pure returns (uint256 lpBackedNotionalUsdc);
computePendingCarryUsdc
function computePendingCarryUsdc(
uint256 lpBackedNotionalUsdc,
uint256 baseCarryBps,
uint256 timeDelta
) internal pure returns (uint256 carryUsdc);
buildPositionRiskState
function buildPositionRiskState(
CfdTypes.Position memory pos,
uint256 price,
uint256 capPrice,
uint256 reachableCollateralUsdc,
uint256 requiredBps
) internal pure returns (PositionRiskState memory state);
buildPositionRiskStateWithCarry
function buildPositionRiskStateWithCarry(
CfdTypes.Position memory pos,
uint256 price,
uint256 capPrice,
uint256 pendingCarryUsdc,
uint256 reachableCollateralUsdc,
uint256 requiredBps
) internal pure returns (PositionRiskState memory state);
Structs
PositionRiskState
struct PositionRiskState {
int256 unrealizedPnlUsdc;
int256 equityUsdc;
uint256 currentNotionalUsdc;
uint256 maintenanceMarginUsdc;
bool liquidatable;
}
SolvencyAccountingLib
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,
uint256 deferredTraderCreditUsdc,
uint256 deferredKeeperCreditUsdc
) 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 deferredKeeperCreditDeltaUsdc;
uint256 pendingVaultPayoutUsdc;
}
PreviewResult
struct PreviewResult {
uint256 effectiveAssetsAfterUsdc;
uint256 maxLiabilityAfterUsdc;
bool triggersDegradedMode;
bool postOpDegradedMode;
}
SolvencyState
struct SolvencyState {
uint256 physicalAssetsUsdc;
uint256 protocolFeesUsdc;
uint256 netPhysicalAssetsUsdc;
uint256 maxLiabilityUsdc;
uint256 deferredTraderCreditUsdc;
uint256 deferredKeeperCreditUsdc;
uint256 withdrawalReservedUsdc;
uint256 freeWithdrawableUsdc;
uint256 effectiveAssetsUsdc;
}
Contents
OrderEscrowAccounting
Inherits: IOrderRouterAccounting
Constants
engine
ICfdEngineCore 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;
accountHeadOrderId
mapping(bytes32 => uint64) public accountHeadOrderId;
accountTailOrderId
mapping(bytes32 => uint64) internal accountTailOrderId;
marginHeadOrderId
mapping(bytes32 => uint64) public marginHeadOrderId;
marginTailOrderId
mapping(bytes32 => uint64) public marginTailOrderId;
Functions
constructor
constructor(
address _engine
);
getAccountEscrow
function getAccountEscrow(
bytes32 accountId
) public view override returns (IOrderRouterAccounting.AccountEscrowView memory escrow);
_summarizePendingOrders
function _summarizePendingOrders(
bytes32 accountId
)
internal
view
returns (
uint256 pendingOrderCount,
uint256 executionBountyUsdc,
uint256 pendingCloseSize_,
bool hasTerminalCloseQueued
);
_nextCommitId
function _nextCommitId() internal view virtual returns (uint64);
getMarginReservationIds
function getMarginReservationIds(
bytes32 accountId
) public view override returns (uint64[] memory orderIds);
_reserveExecutionBounty
function _reserveExecutionBounty(
bytes32 accountId,
uint64 orderId,
uint256 sizeDelta,
uint256 executionBountyUsdc,
bool isClose
) internal;
_reserveCommittedMargin
function _reserveCommittedMargin(
bytes32 accountId,
uint64 orderId,
bool isClose,
uint256 marginDelta
) internal;
_consumeOrderEscrow
function _consumeOrderEscrow(
uint64 orderId,
bool success,
uint256 executionPrice,
uint64 oraclePublishTime
) internal returns (uint256 executionBountyUsdc);
_collectExecutionBounty
function _collectExecutionBounty(
uint64 orderId,
uint256 executionPrice,
uint64 oraclePublishTime
) internal returns (uint256 executionBountyUsdc);
_releaseCommittedMargin
function _releaseCommittedMargin(
uint64 orderId
) internal;
_linkMarginOrder
function _linkMarginOrder(
bytes32 accountId,
uint64 orderId
) internal;
_linkAccountOrder
function _linkAccountOrder(
bytes32 accountId,
uint64 orderId
) internal;
_unlinkAccountOrder
function _unlinkAccountOrder(
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);
_reserveCloseExecutionBounty
function _reserveCloseExecutionBounty(
bytes32 accountId,
uint256 sizeDelta,
uint256 executionBountyUsdc
) internal virtual;
_revertInsufficientFreeEquity
function _revertInsufficientFreeEquity() internal pure virtual;
_revertMarginOrderLinkCorrupted
function _revertMarginOrderLinkCorrupted() internal pure virtual;
_revertPendingOrderLinkCorrupted
function _revertPendingOrderLinkCorrupted() internal pure virtual;
Structs
OrderRecord
struct OrderRecord {
CfdTypes.Order core;
IOrderRouterAccounting.OrderStatus status;
uint256 executionBountyUsdc;
uint64 nextGlobalOrderId;
uint64 prevGlobalOrderId;
uint64 nextAccountOrderId;
uint64 prevAccountOrderId;
uint64 nextMarginOrderId;
uint64 prevMarginOrderId;
bool inAccountQueue;
bool inMarginQueue;
}
OrderExecutionOrchestrator
Inherits: OrderOracleExecution, OrderQueueBook
Constants
PANIC_SELECTOR
bytes4 internal constant PANIC_SELECTOR = 0x4e487b71;
TYPED_ORDER_FAILURE_SELECTOR
bytes4 internal constant TYPED_ORDER_FAILURE_SELECTOR = ICfdEngineCore.CfdEngine__TypedOrderFailure.selector;
MARK_PRICE_OUT_OF_ORDER_SELECTOR
bytes4 internal constant MARK_PRICE_OUT_OF_ORDER_SELECTOR = ICfdEngineCore.CfdEngine__MarkPriceOutOfOrder.selector;
State Variables
minEngineGas
uint256 public minEngineGas;
maxPruneOrdersPerCall
uint256 public maxPruneOrdersPerCall;
Functions
_maxOrderAge
function _maxOrderAge() internal view virtual returns (uint256);
_queueHeadOrderId
function _queueHeadOrderId() internal view virtual override returns (uint64);
_setQueueHeadOrderId
function _setQueueHeadOrderId(
uint64 orderId
) internal virtual override;
_revertNoOrdersToExecute
function _revertNoOrdersToExecute() internal pure virtual;
_revertInsufficientGas
function _revertInsufficientGas() internal pure virtual;
_revertMevDetected
function _revertMevDetected() internal pure virtual;
_revertCloseOnlyMode
function _revertCloseOnlyMode() internal pure virtual;
_releaseCommittedMarginForExecution
function _releaseCommittedMarginForExecution(
uint64 orderId
) internal virtual;
_deleteOrder
function _deleteOrder(
uint64 orderId,
IOrderRouterAccounting.OrderStatus terminalStatus
) internal virtual;
_skipStaleOrders
function _skipStaleOrders(
uint64 upToId,
uint256 executionPrice,
uint64 oraclePublishTime
) internal returns (uint256 skipped);
_pruneExpiredHeadOrders
function _pruneExpiredHeadOrders(
uint64 upToId,
uint256 maxPrunes,
uint256 executionPrice,
uint64 oraclePublishTime
) internal returns (uint256 pruned);
_processTypedOrderExecution
function _processTypedOrderExecution(
CfdTypes.Order memory order,
uint256 executionPrice,
uint256 vaultDepth,
uint64 oraclePublishTime
) internal returns (bool success, OrderFailReason failureReason, FailedOrderOutcome failureOutcome);
_executePendingOrder
function _executePendingOrder(
uint64 orderId,
CfdTypes.Order memory order,
uint256 executionPrice,
uint64 oraclePublishTime,
RouterExecutionContext memory executionContext,
bool revertOnBlockedExecution,
uint256 pythFee
) internal returns (OrderExecutionStepResult result);
_finalizeOrCleanupOrder
function _finalizeOrCleanupOrder(
uint64 orderId,
uint256 pythFee,
bool success,
FailedOrderOutcome failedOutcome,
bool refundEthNow,
uint256 executionPrice,
uint64 oraclePublishTime
) internal;
_decodeTypedOrderFailure
function _decodeTypedOrderFailure(
bytes memory revertData
)
internal
pure
returns (CfdEnginePlanTypes.ExecutionFailurePolicyCategory failureCategory, uint8 failureCode, bool isClose);
_failedOutcomeFromEngineRevert
function _failedOutcomeFromEngineRevert(
CfdTypes.Order memory order,
bytes memory revertData
) internal pure returns (FailedOrderOutcome outcome);
_failedOutcomeForTerminalFailure
function _failedOutcomeForTerminalFailure(
CfdTypes.Order memory order
) internal pure returns (FailedOrderOutcome outcome);
_failedOutcomeForSlippageFailure
function _failedOutcomeForSlippageFailure(
CfdTypes.Order memory order
) internal pure returns (FailedOrderOutcome outcome);
_cleanupOrder
function _cleanupOrder(
uint64 orderId,
FailedOrderOutcome,
uint256 executionPrice,
uint64 oraclePublishTime
) internal returns (uint256 executionBountyUsdc);
_finalizeExecution
function _finalizeExecution(
uint64 orderId,
uint256 executionPrice,
uint64 oraclePublishTime
) internal;
_sendEth
function _sendEth(
address to,
uint256 amount
) internal virtual;
Events
OrderExecuted
event OrderExecuted(uint64 indexed orderId, uint256 executionPrice);
OrderFailed
event OrderFailed(uint64 indexed orderId, OrderFailReason reason);
Enums
OrderExecutionStepResult
enum OrderExecutionStepResult {
Continue,
Break,
Return
}
FailedOrderOutcome
enum FailedOrderOutcome {
ClearerFull
}
OrderFailReason
enum OrderFailReason {
Expired,
CloseOnly,
SlippageExceeded,
EnginePanic,
AccountLiquidated,
EngineRevert
}
OrderOracleExecution
Inherits: OrderEscrowAccounting
Constants
vault
ICfdVault internal immutable vault;
engineLens
ICfdEngineLens internal immutable engineLens;
State Variables
pyth
IPyth public pyth;
pythFeedIds
bytes32[] public pythFeedIds;
quantities
uint256[] public quantities;
basePrices
uint256[] public basePrices;
inversions
bool[] public inversions;
orderExecutionStalenessLimit
uint256 public orderExecutionStalenessLimit = 60;
liquidationStalenessLimit
uint256 public liquidationStalenessLimit = 15;
pythMaxConfidenceRatioBps
uint256 public pythMaxConfidenceRatioBps = 10_000;
Functions
_revertZeroAddress
function _revertZeroAddress() internal pure virtual;
_revertEmptyFeeds
function _revertEmptyFeeds() internal pure virtual;
_revertLengthMismatch
function _revertLengthMismatch() internal pure virtual;
_revertInvalidBasePrice
function _revertInvalidBasePrice() internal pure virtual;
_revertInvalidWeights
function _revertInvalidWeights() internal pure virtual;
_revertMissingPythUpdateData
function _revertMissingPythUpdateData() internal pure virtual;
_revertInsufficientPythFee
function _revertInsufficientPythFee() internal pure virtual;
_revertMockModeDisabled
function _revertMockModeDisabled() internal pure virtual;
_revertOraclePriceTooStale
function _revertOraclePriceTooStale() internal pure virtual;
_revertOracleConfidenceTooWide
function _revertOracleConfidenceTooWide() internal pure virtual;
_revertOraclePublishTimeOutOfOrder
function _revertOraclePublishTimeOutOfOrder() internal pure virtual;
_revertMevOraclePriceTooStale
function _revertMevOraclePriceTooStale() internal pure virtual;
_revertOraclePriceNegative
function _revertOraclePriceNegative() internal pure virtual;
constructor
constructor(
address _engine,
address _engineLens,
address _vault,
address _pyth,
bytes32[] memory _feedIds,
uint256[] memory _quantities,
uint256[] memory _basePrices,
bool[] memory _inversions
) OrderEscrowAccounting(_engine);
_currentRouterExecutionContext
function _currentRouterExecutionContext() internal view returns (RouterExecutionContext memory context);
_prepareOrderExecutionOracle
function _prepareOrderExecutionOracle(
bytes[] calldata pythUpdateData,
uint256 mockFallbackPrice
) internal returns (OracleUpdateResult memory update, RouterExecutionContext memory executionContext);
_prepareMarkRefreshOracle
function _prepareMarkRefreshOracle(
bytes[] calldata pythUpdateData
) internal returns (OracleUpdateResult memory update);
_prepareLiquidationOracle
function _prepareLiquidationOracle(
bytes[] calldata pythUpdateData
) internal returns (OracleUpdateResult memory update);
_executionPolicyForOrder
function _executionPolicyForOrder(
bool isClose,
bool oracleFrozen,
bool isFadWindow
) internal view returns (OracleFreshnessPolicyLib.Policy memory);
_resolveOraclePrice
function _resolveOraclePrice(
bytes[] calldata pythUpdateData,
uint256 mockFallbackPrice,
uint256 maxStaleness,
uint256 maxPublishTimeDivergence
) internal returns (uint256 price, uint64 publishTime, uint256 pythFee);
_setOracleConfig
function _setOracleConfig(
address newPyth,
bytes32[] memory newFeedIds,
uint256[] memory newQuantities,
uint256[] memory newBasePrices,
bool[] memory newInversions
) internal;
_validateOracleConfig
function _validateOracleConfig(
address newPyth,
bytes32[] memory newFeedIds,
uint256[] memory newQuantities,
uint256[] memory newBasePrices,
bool[] memory newInversions
) internal pure;
_computeBasketPrice
function _computeBasketPrice(
uint256 maxStaleness,
uint256 maxPublishTimeDivergence
) internal view returns (uint256 basketPrice, uint256 minPublishTime);
_checkSlippage
function _checkSlippage(
CfdTypes.Order memory order,
uint256 executionPrice
) internal pure returns (bool);
_commitReferencePrice
function _commitReferencePrice() internal view returns (uint256 price);
_canUseCommitMarkForOpenPrefilter
function _canUseCommitMarkForOpenPrefilter() internal view returns (bool);
_isOracleFrozen
function _isOracleFrozen() internal view returns (bool);
_isCloseOnlyWindow
function _isCloseOnlyWindow() internal view returns (bool);
_invertPythPrice
function _invertPythPrice(
int64 price,
int32 expo
) internal pure returns (uint256);
_normalizePythPrice
function _normalizePythPrice(
int64 price,
int32 expo
) internal pure returns (uint256);
Structs
RouterExecutionContext
struct RouterExecutionContext {
bool oracleFrozen;
bool isFadWindow;
OracleFreshnessPolicyLib.Policy policy;
}
OracleUpdateResult
struct OracleUpdateResult {
uint256 executionPrice;
uint64 oraclePublishTime;
uint256 pythFee;
}
OrderQueueBook
Inherits: OrderEscrowAccounting
Functions
_queueHeadOrderId
function _queueHeadOrderId() internal view virtual returns (uint64);
_setQueueHeadOrderId
function _setQueueHeadOrderId(
uint64 orderId
) internal virtual;
_queueTailOrderId
function _queueTailOrderId() internal view virtual returns (uint64);
_setQueueTailOrderId
function _setQueueTailOrderId(
uint64 orderId
) internal virtual;
_revertOrderNotPending
function _revertOrderNotPending() internal pure virtual;
_linkGlobalOrder
function _linkGlobalOrder(
uint64 orderId
) internal;
_unlinkGlobalOrder
function _unlinkGlobalOrder(
uint64 orderId
) 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);
Structs
QueuedPositionView
struct QueuedPositionView {
bool exists;
CfdTypes.Side side;
uint256 size;
}
CfdEngine
Inherits: IWithdrawGuard, ICfdEngineAdminHost, 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;
State Variables
vault
ICfdVault public vault;
planner
ICfdEnginePlanner public planner;
settlementModule
ICfdEngineSettlementModule public settlementModule;
admin
address public admin;
sides
SideState[2] public sides;
lastMarkPrice
uint256 public lastMarkPrice;
lastMarkTime
uint64 public lastMarkTime;
accumulatedFeesUsdc
uint256 public accumulatedFeesUsdc;
accumulatedBadDebtUsdc
uint256 public accumulatedBadDebtUsdc;
unsettledCarryUsdc
mapping(bytes32 => uint256) public unsettledCarryUsdc;
degradedMode
bool public degradedMode;
riskParams
CfdTypes.RiskParams public riskParams;
_positions
mapping(bytes32 => StoredPosition) internal _positions;
deferredTraderCreditUsdc
mapping(bytes32 => uint256) public deferredTraderCreditUsdc;
totalDeferredTraderCreditUsdc
uint256 public totalDeferredTraderCreditUsdc;
deferredKeeperCreditUsdc
mapping(address => uint256) public deferredKeeperCreditUsdc;
totalDeferredKeeperCreditUsdc
uint256 public totalDeferredKeeperCreditUsdc;
orderRouter
address public orderRouter;
fadDayOverrides
mapping(uint256 => bool) public fadDayOverrides;
_fadOverrideDays
uint256[] private _fadOverrideDays;
fadMaxStaleness
uint256 public fadMaxStaleness = 3 days;
fadRunwaySeconds
uint256 public fadRunwaySeconds = 3 hours;
engineMarkStalenessLimit
uint256 public engineMarkStalenessLimit = 60;
executionFeeBps
uint256 public executionFeeBps = 4;
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);
_checkpointDeferredClaimCarryIfPossible
function _checkpointDeferredClaimCarryIfPossible(
bytes32 accountId,
StoredPosition storage pos
) internal;
_claimDeferredBalance
function _claimDeferredBalance(
uint256 amount,
bytes32 accountId
) internal returns (uint256 claimAmountUsdc);
_increaseDeferredLiability
function _increaseDeferredLiability(
uint256 currentAmountUsdc,
uint256 currentTotalUsdc,
uint256 amountUsdc
) internal pure returns (uint256 updatedAmountUsdc, uint256 updatedTotalUsdc);
_decreaseDeferredLiability
function _decreaseDeferredLiability(
uint256 currentAmountUsdc,
uint256 currentTotalUsdc,
uint256 amountUsdc
) internal pure returns (uint256 updatedAmountUsdc, uint256 updatedTotalUsdc);
onlyRouter
modifier onlyRouter();
onlySettlementModule
modifier onlySettlementModule();
onlyAdmin
modifier onlyAdmin();
constructor
constructor(
address _usdc,
address _clearinghouse,
uint256 _capPrice,
CfdTypes.RiskParams memory _riskParams
) Ownable(msg.sender);
Parameters
| Name | Type | Description |
|---|---|---|
_usdc | address | USDC token used as margin and settlement currency |
_clearinghouse | address | Margin clearinghouse that custodies trader balances |
_capPrice | uint256 | Maximum oracle price — positions are clamped here (also determines BULL max profit) |
_riskParams | CfdTypes.RiskParams | Initial risk parameters (margin requirements, carry rate, bounty config) |
setDependencies
One-time setter for planner, settlement module, and admin sidecars.
function setDependencies(
address planner_,
address settlementModule_,
address admin_
) external onlyOwner;
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;
withdrawFees
Withdraws accumulated execution fees from the vault to a recipient.
function withdrawFees(
address recipient
) external onlyOwner;
withdrawFees
Withdraws up to amountUsdc of accumulated execution fees from the vault to a recipient.
function withdrawFees(
address recipient,
uint256 amountUsdc
) public 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 funded the vault.
function recordRouterProtocolFee(
uint256 amountUsdc
) external onlyRouter;
creditKeeperExecutionBounty
Credits a router-collected execution bounty into the beneficiary’s clearinghouse account.
Realizes carry first when the beneficiary currently has an open position because the clearinghouse settlement credit changes the carry basis. Router execution already validates the oracle publish time, so this helper only enforces monotonic publish ordering before checkpointing against the validated cached mark.
function creditKeeperExecutionBounty(
address beneficiary,
uint256 amountUsdc,
uint256 price,
uint64 publishTime
) external onlyRouter nonReentrant;
addMargin
Adds isolated margin to an existing open position without changing size.
function addMargin(
bytes32 accountId,
uint256 amount
) external nonReentrant;
realizeCarryBeforeMarginChange
Realizes accrued carry before a user-level clearinghouse balance mutation changes the carry basis.
Called only by the clearinghouse before user deposits and withdrawals.
function realizeCarryBeforeMarginChange(
bytes32 accountId,
uint256 reachableCollateralBasisUsdc
) external nonReentrant;
checkpointCarryUsingStoredMark
Checkpoints carry against the cached stored mark when fresh-mark liveness is unavailable.
Restricted to the clearinghouse stale-deposit path so deposits preserve pre-mutation carry basis.
function checkpointCarryUsingStoredMark(
bytes32 accountId,
uint256 reachableCollateralBasisUsdc
) external nonReentrant;
claimDeferredTraderCredit
Claims deferred trader credit balance into the clearinghouse.
The claim can be partial if current vault cash is insufficient. Funds are credited to the clearinghouse first, so beneficiaries access them through the normal account-balance path. Carry is checkpointed before the settlement-basis change using a fresh mark when available, otherwise the cached stored mark is used.
function claimDeferredTraderCredit(
bytes32 accountId
) external nonReentrant;
claimDeferredKeeperCredit
Claims previously deferred keeper credit when the vault has replenished cash.
Deferred keeper value always settles to clearinghouse credit for the recorded keeper address-derived account.
function claimDeferredKeeperCredit() external nonReentrant;
recordDeferredKeeperCredit
Records keeper credit that could not be serviced immediately because vault cash was unavailable.
function recordDeferredKeeperCredit(
address keeper,
uint256 amountUsdc
) external onlyRouter;
reserveCloseOrderExecutionBounty
function reserveCloseOrderExecutionBounty(
bytes32 accountId,
uint256 sizeDelta,
uint256 amountUsdc,
address recipient
) external onlyRouter;
clearBadDebt
Reduces accumulated bad debt after governance-confirmed recapitalization
function clearBadDebt(
uint256 amount
) external onlyOwner;
Parameters
| Name | Type | Description |
|---|---|---|
amount | uint256 | USDC amount of bad debt to clear (6 decimals) |
sweepToken
function sweepToken(
address token,
address to,
uint256 amount
) external onlyOwner;
clearDegradedMode
function clearDegradedMode() external onlyOwner;
applyRiskConfig
function applyRiskConfig(
ICfdEngineAdminHost.EngineRiskConfig calldata config
) external onlyAdmin;
applyCalendarConfig
function applyCalendarConfig(
ICfdEngineAdminHost.EngineCalendarConfig calldata config
) external onlyAdmin;
applyFreshnessConfig
function applyFreshnessConfig(
ICfdEngineAdminHost.EngineFreshnessConfig calldata config
) external onlyAdmin;
checkWithdraw
Reverts if the account has an open position that would be undercollateralized after withdrawal
function checkWithdraw(
bytes32 accountId
) external override nonReentrant;
Parameters
| Name | Type | Description |
|---|---|---|
accountId | bytes32 | Clearinghouse account to check |
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
) 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;
_enqueueOrAccrueDeferredKeeperCredit
function _enqueueOrAccrueDeferredKeeperCredit(
address keeper,
uint256 amountUsdc
) 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);
_freshVaultReservation
function _freshVaultReservation() internal view returns (CashPriorityLib.SeniorCashReservation memory reservation);
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);
positions
function positions(
bytes32 accountId
)
external
view
returns (
uint256 size,
uint256 margin,
uint256 entryPrice,
uint256 maxProfitUsdc,
CfdTypes.Side side,
uint64 lastUpdateTime,
int256 vpiAccrued
);
getPositionLastCarryTimestamp
function getPositionLastCarryTimestamp(
bytes32 accountId
) external view returns (uint64);
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
| Name | Type | Description |
|---|---|---|
accountId | bytes32 | Clearinghouse account that owns the position |
currentOraclePrice | uint256 | Pyth oracle price (8 decimals), clamped to CAP_PRICE |
vaultDepthUsdc | uint256 | HousePool total assets used for post-op solvency checks and payout affordability |
publishTime | uint64 | Pyth publish timestamp, stored as lastMarkTime |
Returns
| Name | Type | Description |
|---|---|---|
keeperBountyUsdc | uint256 | Bounty 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);
_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);
_tryGetFreshLiveMarkPrice
function _tryGetFreshLiveMarkPrice() internal view returns (bool fresh, uint256 price);
_revertIfOpenInvalidTyped
function _revertIfOpenInvalidTyped(
CfdEnginePlanTypes.OpenRevertCode code
) internal view;
_revertIfCloseInvalidTyped
function _revertIfCloseInvalidTyped(
CfdEnginePlanTypes.CloseRevertCode code
) internal view;
_applyFundingAndMark
function _applyFundingAndMark(
uint256 newMarkPrice,
uint64 newMarkTime
) internal;
settlementApplyFundingAndMark
function settlementApplyFundingAndMark(
uint256 newMarkPrice,
uint64 newMarkTime
) external onlySettlementModule;
settlementSyncTotalSideMargin
function settlementSyncTotalSideMargin(
CfdTypes.Side side,
uint256 marginBefore,
uint256 marginAfter
) external onlySettlementModule;
settlementApplySideDelta
function settlementApplySideDelta(
CfdTypes.Side side,
int256 maxProfitDelta,
int256 openInterestDelta,
int256 entryNotionalDelta
) external onlySettlementModule;
settlementConsumeDeferredTraderPayout
function settlementConsumeDeferredTraderPayout(
bytes32 accountId,
uint256 amountUsdc
) external onlySettlementModule;
settlementRecordDeferredTraderPayout
function settlementRecordDeferredTraderPayout(
bytes32 accountId,
uint256 amountUsdc
) external onlySettlementModule;
settlementAccumulateFees
function settlementAccumulateFees(
uint256 amountUsdc
) external onlySettlementModule;
settlementAccumulateBadDebt
function settlementAccumulateBadDebt(
uint256 amountUsdc
) external onlySettlementModule;
settlementWritePosition
function settlementWritePosition(
bytes32 accountId,
CfdEngineSettlementTypes.PositionState calldata position
) external onlySettlementModule;
settlementDeletePosition
function settlementDeletePosition(
bytes32 accountId
) external onlySettlementModule;
_applyOpen
function _applyOpen(
CfdEnginePlanTypes.OpenDelta memory delta,
uint64 publishTime
) internal;
_applyClose
function _applyClose(
CfdEnginePlanTypes.CloseDelta memory delta,
uint64 publishTime
) internal;
_applyLiquidation
function _applyLiquidation(
CfdEnginePlanTypes.LiquidationDelta memory delta,
uint64 publishTime
) internal returns (uint256 keeperBountyUsdc);
_enterDegradedModeIfInsolvent
function _enterDegradedModeIfInsolvent(
bytes32 accountId,
uint256 pendingVaultPayoutUsdc
) internal;
_genericReachableCollateralUsdc
function _genericReachableCollateralUsdc(
bytes32 accountId
) internal view returns (uint256);
_terminalReachableCollateralUsdc
function _terminalReachableCollateralUsdc(
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);
_elapsedCarryUsdc
function _elapsedCarryUsdc(
CfdTypes.Position memory pos,
uint256 price,
uint256 reachableCollateralUsdc,
uint256 timestampNow
) internal view returns (uint256);
_totalPendingCarryUsdc
function _totalPendingCarryUsdc(
bytes32 accountId,
CfdTypes.Position memory pos,
uint256 price,
uint256 reachableCollateralUsdc,
uint256 timestampNow
) internal view returns (uint256);
_canFullyRealizeCarryFromSettlement
function _canFullyRealizeCarryFromSettlement(
bytes32 accountId,
CfdTypes.Position memory pos,
uint256 price
) internal view returns (bool);
_checkpointCarryBeforeBasisChange
function _checkpointCarryBeforeBasisChange(
bytes32 accountId,
StoredPosition storage pos,
uint256 price,
uint256 reachableCollateralUsdc
) internal;
_realizeCarryFromSettlement
function _realizeCarryFromSettlement(
bytes32 accountId,
StoredPosition storage pos,
uint256 price,
uint256 reachableCollateralUsdc
) internal returns (uint256 realizedCarryUsdc);
_liveMarkStalenessLimit
function _liveMarkStalenessLimit() internal view returns (uint256);
_consumeDeferredTraderPayout
function _consumeDeferredTraderPayout(
bytes32 accountId,
uint256 amountUsdc
) internal;
_validateRiskParams
function _validateRiskParams(
CfdTypes.RiskParams memory _riskParams
) internal pure;
updateMarkPrice
Updates the cached mark price without processing a trade or liquidation.
This does not itself realize carry; carry realization happens on execution and margin-mutating paths.
function updateMarkPrice(
uint256 price,
uint64 publishTime
) external onlyRouter;
Parameters
| Name | Type | Description |
|---|---|---|
price | uint256 | Oracle price (8 decimals), clamped to CAP_PRICE |
publishTime | uint64 | Pyth publish timestamp |
_getVaultMtmLiability
function _getVaultMtmLiability() internal view returns (uint256);
_getProtocolPhase
function _getProtocolPhase() internal view returns (ICfdEngine.ProtocolPhase);
getProtocolStatus
function getProtocolStatus() external view returns (EngineStatusViewTypes.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);
EngineMarkStalenessLimitUpdated
event EngineMarkStalenessLimitUpdated(uint256 newStaleness);
BadDebtCleared
event BadDebtCleared(uint256 amount, uint256 remaining);
DegradedModeEntered
event DegradedModeEntered(uint256 effectiveAssets, uint256 maxLiability, bytes32 indexed triggeringAccount);
DegradedModeCleared
event DegradedModeCleared();
DeferredTraderCreditRecorded
event DeferredTraderCreditRecorded(bytes32 indexed accountId, uint256 amountUsdc);
DeferredTraderCreditClaimed
event DeferredTraderCreditClaimed(bytes32 indexed accountId, uint256 amountUsdc);
DeferredKeeperCreditRecorded
event DeferredKeeperCreditRecorded(address indexed keeper, uint256 amountUsdc);
DeferredKeeperCreditClaimed
event DeferredKeeperCreditClaimed(address indexed keeper, uint256 amountUsdc);
CarryCheckpointed
event CarryCheckpointed(
bytes32 indexed accountId, uint256 addedUnsettledCarryUsdc, uint256 totalUnsettledCarryUsdc
);
CarryRealized
event CarryRealized(
bytes32 indexed accountId,
uint256 realizedCarryUsdc,
uint256 freeSettlementConsumedUsdc,
uint256 marginConsumedUsdc,
uint256 remainingUnsettledCarryUsdc
);
TokenSwept
event TokenSwept(address indexed token, address indexed to, uint256 amount);
Errors
CfdEngine__Unauthorized
error CfdEngine__Unauthorized();
CfdEngine__VaultAlreadySet
error CfdEngine__VaultAlreadySet();
CfdEngine__RouterAlreadySet
error CfdEngine__RouterAlreadySet();
CfdEngine__DependenciesAlreadySet
error CfdEngine__DependenciesAlreadySet();
CfdEngine__NoFeesToWithdraw
error CfdEngine__NoFeesToWithdraw();
CfdEngine__NoDeferredTraderCredit
error CfdEngine__NoDeferredTraderCredit();
CfdEngine__InsufficientVaultLiquidity
error CfdEngine__InsufficientVaultLiquidity();
CfdEngine__NoDeferredKeeperCredit
error CfdEngine__NoDeferredKeeperCredit();
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__ZeroAmount
error CfdEngine__ZeroAmount();
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__NotClearinghouse
error CfdEngine__NotClearinghouse();
CfdEngine__NotAccountOwner
error CfdEngine__NotAccountOwner();
CfdEngine__NoOpenPosition
error CfdEngine__NoOpenPosition();
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();
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 deferredTraderCreditUsdc;
}
PositionView
struct PositionView {
bool exists;
CfdTypes.Side side;
uint256 size;
uint256 margin;
uint256 entryPrice;
uint256 entryNotionalUsdc;
uint256 physicalReachableCollateralUsdc;
uint256 nettableDeferredTraderCreditUsdc;
int256 unrealizedPnlUsdc;
int256 netEquityUsdc;
uint256 maxProfitUsdc;
bool liquidatable;
}
ProtocolAccountingView
struct ProtocolAccountingView {
uint256 vaultAssetsUsdc;
uint256 maxLiabilityUsdc;
uint256 withdrawalReservedUsdc;
uint256 freeUsdc;
uint256 accumulatedFeesUsdc;
uint256 totalDeferredTraderCreditUsdc;
uint256 totalDeferredKeeperCreditUsdc;
bool degradedMode;
bool hasLiveLiability;
}
ClosePreview
struct ClosePreview {
bool valid;
CfdTypes.CloseInvalidReason invalidReason;
uint256 executionPrice;
uint256 sizeDelta;
int256 realizedPnlUsdc;
int256 vpiDeltaUsdc;
uint256 vpiUsdc;
uint256 executionFeeUsdc;
uint256 freshTraderPayoutUsdc;
uint256 existingDeferredConsumedUsdc;
uint256 existingDeferredRemainingUsdc;
uint256 immediatePayoutUsdc;
uint256 deferredTraderCreditUsdc;
uint256 seizedCollateralUsdc;
uint256 badDebtUsdc;
uint256 remainingSize;
uint256 remainingMargin;
bool triggersDegradedMode;
bool postOpDegradedMode;
uint256 effectiveAssetsAfterUsdc;
uint256 maxLiabilityAfterUsdc;
}
LiquidationPreview
struct LiquidationPreview {
bool liquidatable;
uint256 oraclePrice;
int256 equityUsdc;
int256 pnlUsdc;
uint256 reachableCollateralUsdc;
uint256 keeperBountyUsdc;
uint256 seizedCollateralUsdc;
uint256 settlementRetainedUsdc;
uint256 freshTraderPayoutUsdc;
uint256 existingDeferredConsumedUsdc;
uint256 existingDeferredRemainingUsdc;
uint256 immediatePayoutUsdc;
uint256 deferredTraderCreditUsdc;
uint256 badDebtUsdc;
bool triggersDegradedMode;
bool postOpDegradedMode;
uint256 effectiveAssetsAfterUsdc;
uint256 maxLiabilityAfterUsdc;
}
DeferredCreditStatus
struct DeferredCreditStatus {
uint256 deferredTraderCreditUsdc;
bool traderPayoutClaimableNow;
uint256 deferredKeeperCreditUsdc;
bool keeperCreditClaimableNow;
}
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;
}
StoredPosition
struct StoredPosition {
uint256 size;
uint256 entryPrice;
uint256 maxProfitUsdc;
CfdTypes.Side side;
uint64 lastUpdateTime;
uint64 lastCarryTimestamp;
int256 vpiAccrued;
}
CfdEngineAccountLens
Inherits: ICfdEngineAccountLens
Title: CfdEngineAccountLens
Rich per-account diagnostic lens for audits, tests, and operator tooling.
This is intentionally wider than the product-facing PerpsPublicLens surface.
Constants
engineContract
CfdEngine public immutable engineContract;
Functions
constructor
constructor(
address engine_
);
Parameters
| Name | Type | Description |
|---|---|---|
engine_ | address | Deployed CfdEngine instance to inspect. |
getAccountCollateralView
Returns detailed clearinghouse bucket and reachability state for an account.
function getAccountCollateralView(
bytes32 accountId
) external view returns (CfdEngine.AccountCollateralView memory viewData);
getWithdrawableUsdc
Returns the current withdrawable USDC for an account under engine-side guards.
Open-position withdrawals are limited by free buying power, degraded mode, mark freshness, pending carry, and the post-withdraw initial margin requirement.
function getWithdrawableUsdc(
bytes32 accountId
) external view returns (uint256 withdrawableUsdc);
getAccountLedgerView
Returns a compact accounting split for account custody, escrow, and deferred balances.
function getAccountLedgerView(
bytes32 accountId
) external view returns (AccountLensViewTypes.AccountLedgerView memory viewData);
getAccountLedgerSnapshot
Returns the full account ledger snapshot used by tests and richer read paths.
function getAccountLedgerSnapshot(
bytes32 accountId
) external view returns (AccountLensViewTypes.AccountLedgerSnapshot memory snapshot);
_buildAccountLedgerSnapshot
function _buildAccountLedgerSnapshot(
bytes32 accountId
) internal view returns (AccountLensViewTypes.AccountLedgerSnapshot memory snapshot);
_position
function _position(
bytes32 accountId
) internal view returns (CfdTypes.Position memory pos);
_riskParams
function _riskParams() internal view returns (CfdTypes.RiskParams memory params);
CfdEngineAdmin
Inherits: Ownable
Constants
TIMELOCK_DELAY
uint256 public constant TIMELOCK_DELAY = 48 hours;
engine
ICfdEngineAdminHost public immutable engine;
State Variables
pendingRiskConfig
ICfdEngineAdminHost.EngineRiskConfig public pendingRiskConfig;
riskConfigActivationTime
uint256 public riskConfigActivationTime;
_pendingCalendarConfig
ICfdEngineAdminHost.EngineCalendarConfig private _pendingCalendarConfig;
calendarConfigActivationTime
uint256 public calendarConfigActivationTime;
pendingFreshnessConfig
ICfdEngineAdminHost.EngineFreshnessConfig public pendingFreshnessConfig;
freshnessConfigActivationTime
uint256 public freshnessConfigActivationTime;
Functions
constructor
constructor(
address engine_,
address initialOwner
) Ownable(initialOwner);
proposeRiskConfig
function proposeRiskConfig(
ICfdEngineAdminHost.EngineRiskConfig calldata config
) external onlyOwner;
finalizeRiskConfig
function finalizeRiskConfig() external onlyOwner;
cancelRiskConfig
function cancelRiskConfig() external onlyOwner;
proposeCalendarConfig
function proposeCalendarConfig(
ICfdEngineAdminHost.EngineCalendarConfig calldata config
) external onlyOwner;
finalizeCalendarConfig
function finalizeCalendarConfig() external onlyOwner;
cancelCalendarConfig
function cancelCalendarConfig() external onlyOwner;
getPendingCalendarConfig
function getPendingCalendarConfig() external view returns (ICfdEngineAdminHost.EngineCalendarConfig memory config);
proposeFreshnessConfig
function proposeFreshnessConfig(
ICfdEngineAdminHost.EngineFreshnessConfig calldata config
) external onlyOwner;
finalizeFreshnessConfig
function finalizeFreshnessConfig() external onlyOwner;
cancelFreshnessConfig
function cancelFreshnessConfig() external onlyOwner;
_requireTimelockReady
function _requireTimelockReady(
uint256 activationTime
) internal view;
_validateRiskParams
function _validateRiskParams(
CfdTypes.RiskParams memory riskParams_
) internal pure;
Events
RiskConfigProposed
event RiskConfigProposed(ICfdEngineAdminHost.EngineRiskConfig config, uint256 activationTime);
RiskConfigFinalized
event RiskConfigFinalized(ICfdEngineAdminHost.EngineRiskConfig config);
RiskConfigCancelled
event RiskConfigCancelled();
CalendarConfigProposed
event CalendarConfigProposed(ICfdEngineAdminHost.EngineCalendarConfig config, uint256 activationTime);
CalendarConfigFinalized
event CalendarConfigFinalized(ICfdEngineAdminHost.EngineCalendarConfig config);
CalendarConfigCancelled
event CalendarConfigCancelled();
FreshnessConfigProposed
event FreshnessConfigProposed(ICfdEngineAdminHost.EngineFreshnessConfig config, uint256 activationTime);
FreshnessConfigFinalized
event FreshnessConfigFinalized(ICfdEngineAdminHost.EngineFreshnessConfig config);
FreshnessConfigCancelled
event FreshnessConfigCancelled();
Errors
CfdEngineAdmin__NoProposal
error CfdEngineAdmin__NoProposal();
CfdEngineAdmin__TimelockNotReady
error CfdEngineAdmin__TimelockNotReady();
CfdEngineAdmin__ZeroStaleness
error CfdEngineAdmin__ZeroStaleness();
CfdEngineAdmin__RunwayTooLong
error CfdEngineAdmin__RunwayTooLong();
CfdEngineAdmin__InvalidRiskParams
error CfdEngineAdmin__InvalidRiskParams();
CfdEngineAdmin__InvalidExecutionFee
error CfdEngineAdmin__InvalidExecutionFee();
CfdEngineLens
Inherits: ICfdEngineLens
Constants
engineContract
CfdEngine public immutable engineContract;
Functions
constructor
constructor(
address engine_
);
engine
function engine() external view returns (address);
previewClose
function previewClose(
bytes32 accountId,
uint256 sizeDelta,
uint256 oraclePrice
) external view returns (CfdEngine.ClosePreview memory preview);
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);
simulateClose
function simulateClose(
bytes32 accountId,
uint256 sizeDelta,
uint256 oraclePrice,
uint256 vaultDepthUsdc
) external view returns (CfdEngine.ClosePreview memory preview);
previewLiquidation
function previewLiquidation(
bytes32 accountId,
uint256 oraclePrice
) external view returns (CfdEngine.LiquidationPreview memory preview);
simulateLiquidation
function simulateLiquidation(
bytes32 accountId,
uint256 oraclePrice,
uint256 vaultDepthUsdc
) external view returns (CfdEngine.LiquidationPreview memory preview);
_previewClose
function _previewClose(
bytes32 accountId,
uint256 sizeDelta,
uint256 oraclePrice,
uint256 vaultDepthUsdc
) internal view returns (CfdEngine.ClosePreview memory preview);
_previewLiquidation
function _previewLiquidation(
bytes32 accountId,
uint256 oraclePrice,
uint256 vaultDepthUsdc
) internal view returns (CfdEngine.LiquidationPreview memory preview);
_buildRawSnapshot
function _buildRawSnapshot(
bytes32 accountId,
uint256 oraclePrice,
uint256 vaultDepthUsdc,
uint64 publishTime
) internal view returns (CfdEnginePlanTypes.RawSnapshot memory snap);
_applyLiquidationPreviewForfeiture
function _applyLiquidationPreviewForfeiture(
bytes32 accountId,
CfdEnginePlanTypes.RawSnapshot memory snap
) internal view;
_position
function _position(
bytes32 accountId
) internal view returns (CfdTypes.Position memory pos);
_sideSnapshot
function _sideSnapshot(
ICfdEngine.SideState memory side
) internal pure returns (CfdEnginePlanTypes.SideSnapshot memory snap);
_riskParams
function _riskParams() internal view returns (CfdTypes.RiskParams memory params);
CfdEnginePlanTypes
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;
}
RawSnapshot
struct RawSnapshot {
CfdTypes.Position position;
bytes32 accountId;
uint256 currentTimestamp;
uint256 lastMarkPrice;
uint64 lastMarkTime;
SideSnapshot bullSide;
SideSnapshot bearSide;
uint256 vaultAssetsUsdc;
uint256 vaultCashUsdc;
IMarginClearinghouse.AccountUsdcBuckets accountBuckets;
IMarginClearinghouse.LockedMarginBuckets lockedBuckets;
uint64[] marginReservationIds;
uint256 accumulatedFeesUsdc;
uint256 accumulatedBadDebtUsdc;
uint256 unsettledCarryUsdc;
uint256 totalDeferredTraderCreditUsdc;
uint256 totalDeferredKeeperCreditUsdc;
uint256 deferredTraderCreditForAccount;
bool degradedMode;
uint256 capPrice;
CfdTypes.RiskParams riskParams;
uint256 executionFeeBps;
bool isFadWindow;
}
SolvencyPreview
struct SolvencyPreview {
uint256 effectiveAssetsAfterUsdc;
uint256 maxLiabilityAfterUsdc;
bool triggersDegradedMode;
bool postOpDegradedMode;
}
OpenDelta
struct OpenDelta {
bool valid;
OpenRevertCode revertCode;
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 pendingCarryUsdc;
uint256 sideTotalMarginBefore;
uint256 sideTotalMarginAfterOpen;
bytes32 accountId;
uint256 sizeDelta;
uint256 price;
}
CloseDelta
struct CloseDelta {
bool valid;
CloseRevertCode revertCode;
CloseAccountingLib.CloseState closeState;
uint256 postBullOi;
uint256 postBearOi;
uint256 posMarginAfter;
uint256 posSizeDelta;
uint256 posMaxProfitReduction;
int256 posVpiAccruedReduction;
bool deletePosition;
CfdTypes.Side side;
uint256 sideOiDecrease;
uint256 sideEntryNotionalReduction;
uint256 sideMaxProfitReduction;
uint256 unlockMarginUsdc;
SettlementType settlementType;
uint256 lossUsdc;
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 pendingCarryUsdc;
uint256 totalMarginBefore;
uint256 totalMarginAfterClose;
SolvencyPreview solvency;
bytes32 accountId;
uint256 sizeDelta;
uint256 price;
int256 realizedPnlUsdc;
}
LiquidationDelta
struct LiquidationDelta {
bool liquidatable;
PositionRiskAccountingLib.PositionRiskState riskState;
LiquidationAccountingLib.LiquidationState liquidationState;
CfdTypes.Side side;
uint256 posSize;
uint256 posMargin;
uint256 posMaxProfit;
uint256 posEntryPrice;
uint256 sideOiDecrease;
uint256 sideMaxProfitDecrease;
uint256 sideEntryNotionalReduction;
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;
uint256 pendingCarryUsdc;
SolvencyPreview solvency;
bytes32 accountId;
uint256 price;
}
Enums
OpenFailurePolicyCategory
enum OpenFailurePolicyCategory {
None,
CommitTimeRejectable,
ExecutionTimeUserInvalid,
ExecutionTimeProtocolStateInvalidated
}
ExecutionFailurePolicyCategory
enum ExecutionFailurePolicyCategory {
None,
UserInvalid,
ProtocolStateInvalidated
}
OpenRevertCode
enum OpenRevertCode {
OK,
MUST_CLOSE_OPPOSING,
DEGRADED_MODE,
POSITION_TOO_SMALL,
SKEW_TOO_HIGH,
MARGIN_DRAINED_BY_FEES,
INSUFFICIENT_INITIAL_MARGIN,
SOLVENCY_EXCEEDED
}
CloseRevertCode
enum CloseRevertCode {
OK,
CLOSE_SIZE_EXCEEDS,
DUST_POSITION,
PARTIAL_CLOSE_UNDERWATER
}
SettlementType
enum SettlementType {
ZERO,
GAIN,
LOSS
}
CfdEnginePlanner
Inherits: ICfdEnginePlanner
Functions
computeOpenMarginAfter
function computeOpenMarginAfter(
uint256 marginAfterFunding,
int256 netMarginChange
) external pure returns (bool drained, uint256 marginAfter);
planOpen
function planOpen(
CfdEnginePlanTypes.RawSnapshot memory snap,
CfdTypes.Order memory order,
uint256 executionPrice,
uint64 publishTime
) external pure returns (CfdEnginePlanTypes.OpenDelta memory delta);
planClose
function planClose(
CfdEnginePlanTypes.RawSnapshot memory snap,
CfdTypes.Order memory order,
uint256 executionPrice,
uint64 publishTime
) external pure returns (CfdEnginePlanTypes.CloseDelta memory delta);
planLiquidation
function planLiquidation(
CfdEnginePlanTypes.RawSnapshot memory snap,
uint256 executionPrice,
uint64 publishTime
) external pure returns (CfdEnginePlanTypes.LiquidationDelta memory delta);
getOpenFailurePolicyCategory
function getOpenFailurePolicyCategory(
CfdEnginePlanTypes.OpenRevertCode code
) external pure returns (CfdEnginePlanTypes.OpenFailurePolicyCategory);
getExecutionFailurePolicyCategory
function getExecutionFailurePolicyCategory(
CfdEnginePlanTypes.OpenRevertCode code
) external pure returns (CfdEnginePlanTypes.ExecutionFailurePolicyCategory);
getCloseExecutionFailurePolicyCategory
function getCloseExecutionFailurePolicyCategory(
CfdEnginePlanTypes.CloseRevertCode code
) external pure returns (CfdEnginePlanTypes.ExecutionFailurePolicyCategory);
CfdEngineProtocolLens
Inherits: ICfdEngineProtocolLens
Title: CfdEngineProtocolLens
Rich protocol-accounting lens for audits, tests, and HousePool integration.
Exposes conservative solvency and liability views rather than product-level summaries.
Constants
engineContract
CfdEngine public immutable engineContract;
Functions
constructor
constructor(
address engine_
);
Parameters
| Name | Type | Description |
|---|---|---|
engine_ | address | Deployed CfdEngine instance to inspect. |
getProtocolAccountingSnapshot
Returns the canonical protocol-accounting snapshot used by diagnostics and audits.
function getProtocolAccountingSnapshot()
external
view
returns (ProtocolLensViewTypes.ProtocolAccountingSnapshot memory snapshot);
getHousePoolInputSnapshot
Builds the HousePool accounting snapshot against a caller-supplied freshness limit.
This packages the engine-side values HousePool needs for reconcile and withdrawal logic.
function getHousePoolInputSnapshot(
uint256 markStalenessLimit
) external view returns (HousePoolEngineViewTypes.HousePoolInputSnapshot memory snapshot);
getHousePoolStatusSnapshot
Returns the current HousePool status flags sourced from engine runtime state.
function getHousePoolStatusSnapshot()
external
view
returns (HousePoolEngineViewTypes.HousePoolStatusSnapshot memory snapshot);
_getVaultMtmLiability
function _getVaultMtmLiability() internal view returns (uint256);
_buildProtocolAccountingSnapshot
function _buildProtocolAccountingSnapshot()
internal
view
returns (ProtocolLensViewTypes.ProtocolAccountingSnapshot memory snapshot);
_buildAdjustedSolvencyState
function _buildAdjustedSolvencyState() internal view returns (SolvencyAccountingLib.SolvencyState memory);
_sideState
function _sideState(
CfdTypes.Side side
) internal view returns (ICfdEngine.SideState memory state);
_riskParams
function _riskParams() internal view returns (CfdTypes.RiskParams memory params);
CfdEngineSettlementModule
Inherits: ICfdEngineSettlementModule
Title: CfdEngineSettlementModule
Externalized settlement executor for CfdEngine close and liquidation flows.
CfdEngine remains the storage owner and grants this module access only through narrow
settlement-host hooks. The module does not own independent protocol state.
Constants
ENGINE
address public immutable ENGINE;
Functions
constructor
constructor(
address engine_
);
onlyEngine
modifier onlyEngine();
executeOpen
Applies the live open/increase settlement plan produced by the planner.
Realizes carry, fee, and vault-flow side effects through the settlement host while keeping the engine as the canonical state owner.
function executeOpen(
ICfdEngineSettlementHost host,
CfdEnginePlanTypes.OpenDelta calldata delta,
CfdTypes.Position calldata currentPosition,
uint64 publishTime
) external onlyEngine;
executeClose
Applies the live close/decrease settlement plan produced by the planner.
Can record deferred trader credit, bad debt, and realized carry depending on the close result.
function executeClose(
ICfdEngineSettlementHost host,
CfdEnginePlanTypes.CloseDelta calldata delta,
CfdTypes.Position calldata currentPosition,
uint64 publishTime
) external onlyEngine;
executeLiquidation
Applies the live liquidation settlement plan produced by the planner.
function executeLiquidation(
ICfdEngineSettlementHost host,
CfdEnginePlanTypes.LiquidationDelta calldata delta,
uint64 publishTime
) external onlyEngine returns (uint256 keeperBountyUsdc);
Returns
| Name | Type | Description |
|---|---|---|
keeperBountyUsdc | uint256 | Liquidation bounty owed to the keeper after the state transition. |
Errors
CfdEngineSettlementModule__Unauthorized
error CfdEngineSettlementModule__Unauthorized();
CfdMath
Title: CfdMath
Pure stateless math library for PnL and price impact
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;
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
| Name | Type | Description |
|---|---|---|
pos | CfdTypes.Position | The position to evaluate |
currentOraclePrice | uint256 | Current oracle price (8 decimals) |
capPrice | uint256 | Protocol cap price (8 decimals) |
Returns
| Name | Type | Description |
|---|---|---|
isProfit | bool | True if the position is in profit |
pnlUsdc | uint256 | Absolute 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
| Name | Type | Description |
|---|---|---|
size | uint256 | Notional size (18 decimals) |
entryPrice | uint256 | Entry oracle price (8 decimals) |
side | CfdTypes.Side | BULL or BEAR |
capPrice | uint256 | Protocol cap price (8 decimals) |
Returns
| Name | Type | Description |
|---|---|---|
maxProfitUsdc | uint256 | Maximum possible profit in USDC (6 decimals) |
conservativeMtmLiability
Conservative upper bound for a side’s current gross winning-trader MtM liability.
Uses each position’s max-profit envelope so same-side losing positions cannot net down winning positions before their losses are physically realized.
function conservativeMtmLiability(
uint256 maxProfitUsdc,
CfdTypes.Side side,
uint256 price,
uint256 capPrice
) internal pure returns (uint256);
_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
| Name | Type | Description |
|---|---|---|
skewUsdc | uint256 | The absolute directional imbalance in USDC (6 decimals) |
depthUsdc | uint256 | The total free USDC in the House Pool (6 decimals) |
vpiFactorWad | uint256 | The ‘k’ impact parameter (18 decimals) |
Returns
| Name | Type | Description |
|---|---|---|
costUsdc | uint256 | The 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);
CfdTypes
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
Side side; // [uint8] Trade direction
uint64 lastUpdateTime; // [uint64] Timestamp of last modification
uint64 lastCarryTimestamp; // [uint64] Timestamp through which carry has been realized
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 carry engines
struct RiskParams {
uint256 vpiFactor; // [18 dec WAD] Impact severity 'k'
uint256 maxSkewRatio; // [18 dec WAD] Hard cliff e.g., 40% (0.40e18)
uint256 maintMarginBps; // e.g., 100 (1%)
uint256 initMarginBps; // e.g., 150 (1.5%)
uint256 fadMarginBps; // e.g., 300 (3%)
uint256 baseCarryBps; // e.g., 500 (5% annualized carry on LP-backed notional)
uint256 minBountyUsdc; // e.g., 1_000_000 ($1 USDC floor)
uint256 bountyBps; // e.g., 10 (0.10% 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
Inherits: ICfdVault, IHousePool, IPerpsLPActions, Ownable2Step, Pausable
Title: HousePool
Tranched house pool. Senior tranche gets fixed-rate yield with last-loss protection. Junior tranche absorbs first loss but captures surplus revenue.
Note: security-contact: contact@plether.com
Constants
USDC
IERC20 public immutable USDC;
ENGINE
ICfdEngineCore public immutable ENGINE;
ENGINE_PROTOCOL_LENS
ICfdEngineProtocolLens public immutable ENGINE_PROTOCOL_LENS;
MAX_FROZEN_LP_FEE_BPS
uint256 public constant MAX_FROZEN_LP_FEE_BPS = 1000;
TIMELOCK_DELAY
uint256 public constant TIMELOCK_DELAY = 48 hours;
State Variables
orderRouter
address public orderRouter;
seniorVault
address public seniorVault;
juniorVault
address public juniorVault;
pauser
address public pauser;
seniorPrincipal
uint256 public seniorPrincipal;
juniorPrincipal
uint256 public juniorPrincipal;
unpaidSeniorYield
uint256 public unpaidSeniorYield;
seniorHighWaterMark
uint256 public seniorHighWaterMark;
accountedAssets
uint256 public accountedAssets;
unassignedAssets
uint256 public unassignedAssets;
pendingRecapitalizationUsdc
uint256 public pendingRecapitalizationUsdc;
pendingTradingRevenueUsdc
uint256 public pendingTradingRevenueUsdc;
lastReconcileTime
uint256 public lastReconcileTime;
lastSeniorYieldCheckpointTime
uint256 public lastSeniorYieldCheckpointTime;
poolConfig
PoolConfig internal poolConfig;
isTradingActive
bool public override(ICfdVault, IHousePool) isTradingActive;
seniorSeedInitialized
bool public seniorSeedInitialized;
juniorSeedInitialized
bool public juniorSeedInitialized;
pendingPoolConfig
PoolConfig public pendingPoolConfig;
poolConfigActivationTime
uint256 public poolConfigActivationTime;
Functions
onlyPauserOrOwner
modifier onlyPauserOrOwner();
onlyVault
modifier onlyVault();
constructor
constructor(
address _usdc,
address _engine
) Ownable(msg.sender);
Parameters
| Name | Type | Description |
|---|---|---|
_usdc | address | USDC token address used as collateral |
_engine | address | CfdEngine that manages positions and PnL |
setOrderRouter
Set the OrderRouter address (one-time, immutable after set)
function setOrderRouter(
address _router
) external onlyOwner;
setSeniorVault
Set the senior tranche vault address (one-time, immutable after set)
function setSeniorVault(
address _vault
) external onlyOwner;
setJuniorVault
Set the junior tranche vault address (one-time, immutable after set)
function setJuniorVault(
address _vault
) external onlyOwner;
proposePoolConfig
Propose a new pool config, subject to a 48h timelock.
function proposePoolConfig(
PoolConfig calldata newConfig
) external onlyOwner;
finalizePoolConfig
Finalizes the proposed pool config after the timelock expires.
Senior-rate changes require a fresh mark so yield accrual cannot be rerated across a stale interval.
function finalizePoolConfig() external onlyOwner;
cancelPoolConfigProposal
Cancel the pending pool config proposal.
function cancelPoolConfigProposal() external onlyOwner;
setPauser
Updates the dedicated emergency pauser.
The owner retains unpause authority and may still pause directly.
function setPauser(
address newPauser
) external onlyOwner;
pause
Pause deposits into both tranches
function pause() external onlyPauserOrOwner;
unpause
Unpause deposits into both tranches
function unpause() external onlyOwner;
totalAssets
Canonical economic USDC backing recognized by the pool. Unsolicited positive transfers are ignored until explicitly accounted, while raw-balance shortfalls still reduce the effective backing.
function totalAssets() public view returns (uint256);
isSeedLifecycleComplete
function isSeedLifecycleComplete() public view returns (bool);
hasSeedLifecycleStarted
function hasSeedLifecycleStarted() public view override(ICfdVault, IHousePool) returns (bool);
canAcceptOrdinaryDeposits
function canAcceptOrdinaryDeposits() public view override(ICfdVault, IHousePool) returns (bool);
canAcceptTrancheDeposits
function canAcceptTrancheDeposits(
bool isSenior
) public view override returns (bool);
canIncreaseRisk
function canIncreaseRisk() public view override(ICfdVault, IHousePool) returns (bool);
activateTrading
function activateTrading() external onlyOwner;
rawAssets
Raw USDC balance currently held by the pool, including unsolicited transfers.
function rawAssets() public view returns (uint256);
excessAssets
Raw USDC held above canonical accounted assets.
function excessAssets() public view returns (uint256);
accountExcess
Explicitly converts unsolicited USDC into accounted protocol assets.
This admits previously quarantined excess into canonical pool accounting going forward.
function accountExcess() external onlyOwner;
sweepExcess
Sweeps unsolicited USDC that has not been accounted into protocol economics.
function sweepExcess(
address recipient,
uint256 amount
) external onlyOwner;
payOut
Transfers USDC from the pool for protocol-authorized settlement or keeper payments.
function payOut(
address recipient,
uint256 amount
) external;
Parameters
| Name | Type | Description |
|---|---|---|
recipient | address | Address to receive USDC |
amount | uint256 | USDC amount to transfer (6 decimals) |
recordProtocolInflow
Accounts a legitimate protocol-owned inflow into canonical vault assets.
Only the engine or order router may use this path. Unlike accountExcess(), this does
not require raw excess to exist: it is the explicit accounting hook for endogenous
protocol gains and may also be used to restore canonical accounting after a raw-balance
shortfall has already reduced effective assets through totalAssets() = min(raw, accounted).
function recordProtocolInflow(
uint256 amount
) external;
recordClaimantInflow
Records claimant-owned value into the tranche claimant path.
Revenue and recapitalization remain distinct economic buckets, but share one API.
function recordClaimantInflow(
uint256 amount,
ICfdVault.ClaimantInflowKind kind,
ICfdVault.ClaimantInflowCashMode cashMode
) external;
assignUnassignedAssets
Explicitly bootstraps quarantined LP assets into a tranche by minting matching shares.
Prevents later LPs from implicitly capturing value that arrived while no claimant shares existed.
function assignUnassignedAssets(
bool toSenior,
address receiver
) external onlyOwner;
initializeSeedPosition
Seeds a tranche with a permanent minimum share supply backed by real USDC.
Mints bootstrap shares so a tranche never becomes ownerless in steady state.
function initializeSeedPosition(
bool toSenior,
uint256 amount,
address receiver
) external onlyOwner;
depositSenior
Deposit USDC into the senior tranche. Reverts if senior is impaired (below high-water mark).
function depositSenior(
uint256 amount
) external override(IHousePool, IPerpsLPActions) onlyVault whenNotPaused;
Parameters
| Name | Type | Description |
|---|---|---|
amount | uint256 | USDC to deposit (6 decimals) |
withdrawSenior
Withdraw USDC from the senior tranche. Scales high-water mark and unpaid yield proportionally.
function withdrawSenior(
uint256 amount,
address receiver
) external override(IHousePool, IPerpsLPActions) onlyVault;
Parameters
| Name | Type | Description |
|---|---|---|
amount | uint256 | USDC to withdraw (6 decimals) |
receiver | address | Address to receive USDC |
depositJunior
Deposit USDC into the junior tranche.
function depositJunior(
uint256 amount
) external override(IHousePool, IPerpsLPActions) onlyVault whenNotPaused;
Parameters
| Name | Type | Description |
|---|---|---|
amount | uint256 | USDC to deposit (6 decimals) |
withdrawJunior
Withdraw USDC from the junior tranche. Limited to free USDC above senior’s claim.
function withdrawJunior(
uint256 amount,
address receiver
) external override(IHousePool, IPerpsLPActions) onlyVault;
Parameters
| Name | Type | Description |
|---|---|---|
amount | uint256 | USDC to withdraw (6 decimals) |
receiver | address | Address to receive USDC |
getFreeUSDC
Returns USDC not reserved for worst-case position payouts (max of bull/bear liability)
function getFreeUSDC() public view returns (uint256);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | Free USDC available for withdrawals (6 decimals) |
getMaxSeniorWithdraw
Max USDC the senior tranche can withdraw (limited by free USDC)
function getMaxSeniorWithdraw() public view returns (uint256);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | Withdrawable senior USDC, capped at seniorPrincipal (6 decimals) |
getMaxJuniorWithdraw
Max USDC the junior tranche can withdraw (subordinated behind senior)
function getMaxJuniorWithdraw() public view returns (uint256);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | Withdrawable junior USDC, capped at juniorPrincipal (6 decimals) |
getPendingTrancheState
Returns tranche principals and withdrawal caps as if reconcile ran right now.
Read-only preview for ERC4626 consumers that need same-tx parity with reconcile-first vault flows.
function getPendingTrancheState()
external
view
returns (
uint256 seniorPrincipalUsdc,
uint256 juniorPrincipalUsdc,
uint256 maxSeniorWithdrawUsdc,
uint256 maxJuniorWithdrawUsdc
);
isWithdrawalLive
function isWithdrawalLive() external view returns (bool);
seniorRateBps
function seniorRateBps() public view returns (uint256);
markStalenessLimit
function markStalenessLimit() public view returns (uint256);
seniorFrozenLpFeeBps
function seniorFrozenLpFeeBps() public view returns (uint256);
juniorFrozenLpFeeBps
function juniorFrozenLpFeeBps() public view returns (uint256);
isOracleFrozen
function isOracleFrozen() public view override returns (bool);
frozenLpFeeBps
function frozenLpFeeBps(
bool isSenior
) public view override returns (uint256);
getVaultLiquidityView
Snapshot of pool liquidity, tranche principals, and oracle health for frontend consumption
function getVaultLiquidityView() external view returns (VaultLiquidityView memory viewData);
Returns
| Name | Type | Description |
|---|---|---|
viewData | VaultLiquidityView | Struct containing balances, reserves, and status flags |
reconcile
Distributes revenue (senior yield first, junior gets surplus) or absorbs losses (junior first-loss, senior last-loss). Called before any deposit/withdrawal.
function reconcile() external onlyVault;
_requireFreshMark
function _requireFreshMark(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
) internal view;
_requireRateChangeMarkFresh
function _requireRateChangeMarkFresh(
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
) internal view;
_requireBootstrapOracleLive
function _requireBootstrapOracleLive(
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
) internal pure;
_reconcile
function _reconcile(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot
) internal;
_getWithdrawalSnapshot
function _getWithdrawalSnapshot()
internal
view
returns (HousePoolAccountingLib.WithdrawalSnapshot memory snapshot);
_buildHousePoolContext
function _buildHousePoolContext(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
) internal view returns (HousePoolContext memory ctx);
_buildCurrentHousePoolContext
function _buildCurrentHousePoolContext() internal view returns (HousePoolContext memory ctx);
_previewPendingAccountingState
function _previewPendingAccountingState(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
) internal view returns (PendingAccountingState memory pendingState);
_markIsFreshForReconcile
function _markIsFreshForReconcile(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
) internal view returns (bool);
_withdrawalsLive
function _withdrawalsLive(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
) internal view returns (bool);
_validatePoolConfig
function _validatePoolConfig(
PoolConfig memory config
) internal pure;
_checkpointSeniorYieldBeforeRateChange
function _checkpointSeniorYieldBeforeRateChange() internal;
_normalizeUnassignedAssets
function _normalizeUnassignedAssets(
uint256 distributableUsdc
) internal view returns (uint256 normalized);
_juniorShareSupply
function _juniorShareSupply() internal view returns (uint256);
_seniorShareSupply
function _seniorShareSupply() internal view returns (uint256);
_requireNoPendingBootstrap
function _requireNoPendingBootstrap() internal view;
_buildWithdrawalSnapshot
function _buildWithdrawalSnapshot(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
uint256 reservedUnassignedAssets,
bool isProjected
) internal view returns (HousePoolAccountingLib.WithdrawalSnapshot memory snapshot);
_checkpointSeniorYieldBeforePrincipalMutation
function _checkpointSeniorYieldBeforePrincipalMutation(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
) internal;
_applyPendingClaimantBucketsLive
function _applyPendingClaimantBucketsLive(
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
) internal;
_applyPendingClaimantBucketsPreview
function _applyPendingClaimantBucketsPreview(
PendingAccountingState memory state
) internal view;
_getPendingClaimantBuckets
function _getPendingClaimantBuckets()
internal
view
returns (HousePoolPendingPreviewLib.ClaimantPendingBuckets memory buckets);
_clearPendingClaimantBuckets
function _clearPendingClaimantBuckets() internal;
_recordPendingClaimantInflow
function _recordPendingClaimantInflow(
ICfdVault.ClaimantInflowKind kind,
uint256 amount
) internal;
_copyPendingAccountingState
function _copyPendingAccountingState(
PendingAccountingState memory state
) internal pure returns (HousePoolPendingPreviewLib.PendingAccountingState memory copiedState);
_pendingClaimantBucketAssets
function _pendingClaimantBucketAssets() internal view returns (uint256);
_getHousePoolInputSnapshot
function _getHousePoolInputSnapshot()
internal
view
returns (HousePoolEngineViewTypes.HousePoolInputSnapshot memory snapshot);
_getHousePoolStatusSnapshot
function _getHousePoolStatusSnapshot()
internal
view
returns (HousePoolEngineViewTypes.HousePoolStatusSnapshot memory snapshot);
_getHousePoolSnapshots
function _getHousePoolSnapshots()
internal
view
returns (
HousePoolEngineViewTypes.HousePoolInputSnapshot memory accountingSnapshot,
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
);
_requireWithdrawalsLive
function _requireWithdrawalsLive(
HousePoolEngineViewTypes.HousePoolStatusSnapshot memory statusSnapshot
) internal pure;
_distributeRevenue
function _distributeRevenue(
uint256 revenue
) internal;
_absorbLoss
function _absorbLoss(
uint256 loss
) internal;
_getWaterfallState
function _getWaterfallState() internal view returns (HousePoolWaterfallAccountingLib.WaterfallState memory state);
_setWaterfallState
function _setWaterfallState(
HousePoolWaterfallAccountingLib.WaterfallState memory state
) internal;
Events
Reconciled
event Reconciled(uint256 seniorPrincipal, uint256 juniorPrincipal, int256 delta);
SeniorRateUpdated
event SeniorRateUpdated(uint256 newRateBps);
MarkStalenessLimitUpdated
event MarkStalenessLimitUpdated(uint256 newLimit);
PoolConfigProposed
event PoolConfigProposed(
uint256 seniorRateBps,
uint256 markStalenessLimit,
uint256 seniorFrozenLpFeeBps,
uint256 juniorFrozenLpFeeBps,
uint256 activationTime
);
PoolConfigFinalized
event PoolConfigFinalized();
FrozenLpFeesUpdated
event FrozenLpFeesUpdated(uint256 seniorFeeBps, uint256 juniorFeeBps);
ExcessAccounted
event ExcessAccounted(uint256 amountUsdc, uint256 accountedAssetsUsdc);
ExcessSwept
event ExcessSwept(address indexed recipient, uint256 amountUsdc);
ProtocolInflowAccounted
event ProtocolInflowAccounted(address indexed caller, uint256 amountUsdc, uint256 accountedAssetsUsdc);
ClaimantInflowAccounted
event ClaimantInflowAccounted(
address indexed caller,
ICfdVault.ClaimantInflowKind kind,
ICfdVault.ClaimantInflowCashMode cashMode,
uint256 amountUsdc
);
UnassignedAssetsAssigned
event UnassignedAssetsAssigned(
bool indexed toSenior, address indexed receiver, uint256 amountUsdc, uint256 sharesMinted
);
SeedPositionInitialized
event SeedPositionInitialized(
bool indexed toSenior, address indexed receiver, uint256 amountUsdc, uint256 sharesMinted
);
TradingActivated
event TradingActivated();
PauserUpdated
event PauserUpdated(address indexed previousPauser, address indexed newPauser);
Errors
HousePool__NotAVault
error HousePool__NotAVault();
HousePool__RouterAlreadySet
error HousePool__RouterAlreadySet();
HousePool__SeniorVaultAlreadySet
error HousePool__SeniorVaultAlreadySet();
HousePool__JuniorVaultAlreadySet
error HousePool__JuniorVaultAlreadySet();
HousePool__Unauthorized
error HousePool__Unauthorized();
HousePool__ExceedsMaxSeniorWithdraw
error HousePool__ExceedsMaxSeniorWithdraw();
HousePool__ExceedsMaxJuniorWithdraw
error HousePool__ExceedsMaxJuniorWithdraw();
HousePool__MarkPriceStale
error HousePool__MarkPriceStale();
HousePool__TimelockNotReady
error HousePool__TimelockNotReady();
HousePool__NoProposal
error HousePool__NoProposal();
HousePool__SeniorImpaired
error HousePool__SeniorImpaired();
HousePool__DegradedMode
error HousePool__DegradedMode();
HousePool__ZeroAddress
error HousePool__ZeroAddress();
HousePool__ZeroStaleness
error HousePool__ZeroStaleness();
HousePool__InvalidSeniorRate
error HousePool__InvalidSeniorRate();
HousePool__InvalidFrozenLpFee
error HousePool__InvalidFrozenLpFee();
HousePool__NoExcessAssets
error HousePool__NoExcessAssets();
HousePool__ExcessAmountTooHigh
error HousePool__ExcessAmountTooHigh();
HousePool__PendingBootstrap
error HousePool__PendingBootstrap();
HousePool__NoUnassignedAssets
error HousePool__NoUnassignedAssets();
HousePool__BootstrapSharesZero
error HousePool__BootstrapSharesZero();
HousePool__SeedAlreadyInitialized
error HousePool__SeedAlreadyInitialized();
HousePool__TradingActivationNotReady
error HousePool__TradingActivationNotReady();
HousePool__UnauthorizedPauser
error HousePool__UnauthorizedPauser();
HousePool__OracleFrozen
error HousePool__OracleFrozen();
Structs
VaultLiquidityView
struct VaultLiquidityView {
uint256 totalAssetsUsdc;
uint256 freeUsdc;
uint256 withdrawalReservedUsdc;
uint256 pendingRecapitalizationUsdc;
uint256 pendingTradingRevenueUsdc;
uint256 seniorPrincipalUsdc;
uint256 juniorPrincipalUsdc;
uint256 unpaidSeniorYieldUsdc;
uint256 seniorHighWaterMarkUsdc;
bool markFresh;
bool oracleFrozen;
bool degradedMode;
}
PendingAccountingState
struct PendingAccountingState {
HousePoolWaterfallAccountingLib.WaterfallState waterfall;
uint256 unassignedAssets;
uint256 seniorSupply;
uint256 juniorSupply;
}
HousePoolContext
struct HousePoolContext {
HousePoolEngineViewTypes.HousePoolInputSnapshot accountingSnapshot;
HousePoolEngineViewTypes.HousePoolStatusSnapshot statusSnapshot;
PendingAccountingState pendingState;
}
PoolConfig
struct PoolConfig {
uint256 seniorRateBps;
uint256 markStalenessLimit;
uint256 seniorFrozenLpFeeBps;
uint256 juniorFrozenLpFeeBps;
}
MarginClearinghouse
Inherits: IMarginAccount, Ownable2Step, ReentrancyGuardTransient
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
MARK_PRICE_STALE_SELECTOR
bytes4 internal constant MARK_PRICE_STALE_SELECTOR = bytes4(keccak256("CfdEngine__MarkPriceStale()"));
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;
activeCommittedOrderReservationUsdc
mapping(bytes32 => uint256) internal activeCommittedOrderReservationUsdc;
activeReservationCount
mapping(bytes32 => uint256) internal activeReservationCount;
engine
address public engine;
Functions
onlyOperator
modifier onlyOperator();
onlyOrderRouter
modifier onlyOrderRouter();
onlyEngine
modifier onlyEngine();
constructor
constructor(
address _settlementAsset
) Ownable(msg.sender);
Parameters
| Name | Type | Description |
|---|---|---|
_settlementAsset | address | USDC 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
| Name | Type | Description |
|---|---|---|
accountId | bytes32 | Deterministic account ID derived from msg.sender address |
amount | uint256 | Token amount to transfer in |
depositMargin
Trader-facing wrapper that deposits into the caller’s canonical account id.
function depositMargin(
uint256 amount
) external nonReentrant;
withdraw
Withdraws settlement USDC from a margin account.
function withdraw(
bytes32 accountId,
uint256 amount
) external nonReentrant;
Parameters
| Name | Type | Description |
|---|---|---|
accountId | bytes32 | Deterministic account ID derived from msg.sender address |
amount | uint256 | USDC amount to withdraw |
withdrawMargin
Trader-facing wrapper that withdraws from the caller’s canonical account id.
function withdrawMargin(
uint256 amount
) external nonReentrant;
_deposit
function _deposit(
bytes32 accountId,
address owner,
uint256 amount
) internal;
_withdraw
function _withdraw(
bytes32 accountId,
address owner,
uint256 amount
) internal;
getAccountEquityUsdc
Returns the total USD buying power of the account (6 decimals).
function getAccountEquityUsdc(
bytes32 accountId
) public view returns (uint256 totalEquityUsdc);
Parameters
| Name | Type | Description |
|---|---|---|
accountId | bytes32 | Account to value |
Returns
| Name | Type | Description |
|---|---|---|
totalEquityUsdc | uint256 | Settlement balance in USDC (6 decimals) |
getFreeBuyingPowerUsdc
Returns strictly unencumbered purchasing power
function getFreeBuyingPowerUsdc(
bytes32 accountId
) public view returns (uint256);
Parameters
| Name | Type | Description |
|---|---|---|
accountId | bytes32 | Account to query |
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | Equity 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);
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
| Name | Type | Description |
|---|---|---|
accountId | bytes32 | Account to lock margin on |
amountUsdc | uint256 | USDC amount to lock (6 decimals) |
unlockPositionMargin
Unlocks active position margin when a CFD trade closes
function unlockPositionMargin(
bytes32 accountId,
uint256 amountUsdc
) external onlyOperator;
Parameters
| Name | Type | Description |
|---|---|---|
accountId | bytes32 | Account to unlock margin on |
amountUsdc | uint256 | USDC 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
| Name | Type | Description |
|---|---|---|
accountId | bytes32 | Account to lock margin on |
amountUsdc | uint256 | USDC 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
| Name | Type | Description |
|---|---|---|
accountId | bytes32 | Account to unlock margin on |
amountUsdc | uint256 | USDC 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,
uint256 amountUsdc
) internal;
lockReservedSettlement
function lockReservedSettlement(
bytes32 accountId,
uint256 amountUsdc
) external onlyOperator;
unlockReservedSettlement
function unlockReservedSettlement(
bytes32 accountId,
uint256 amountUsdc
) external onlyOperator;
settleUsdc
Adjusts settlement USDC for realized PnL, deferred servicing, and rebates. Positive amounts credit the account; negative amounts debit it.
function settleUsdc(
bytes32 accountId,
int256 amount
) external onlyOperator;
Parameters
| Name | Type | Description |
|---|---|---|
accountId | bytes32 | Account to settle |
amount | int256 | Signed 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);
consumeSettlementLoss
Consumes a realized settlement loss from free settlement first, then from active position margin.
Unrelated locked margin remains protected.
function consumeSettlementLoss(
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;
_checkpointCarryBeforeMarginChange
function _checkpointCarryBeforeMarginChange(
bytes32 accountId
) internal;
_checkpointCarryBeforeMarginChange
function _checkpointCarryBeforeMarginChange(
bytes32 accountId,
uint256 reachableCollateralBasisUsdc
) internal;
_requireNoActiveReservations
function _requireNoActiveReservations(
bytes32 accountId
) internal view;
_realizeOrCheckpointCarryBeforeMarginChange
function _realizeOrCheckpointCarryBeforeMarginChange(
bytes32 accountId,
uint256 reachableCollateralBasisUsdc
) 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;
_activeMarginReservationIds
The router already maintains the active reservation FIFO for each account, so the clearinghouse no longer needs an append-only historical reservation index.
function _activeMarginReservationIds(
bytes32 accountId
) internal view returns (uint64[] memory reservationIds);
_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
| Name | Type | Description |
|---|---|---|
accountId | bytes32 | Account to seize from |
amount | uint256 | USDC amount to seize |
recipient | address | Recipient of seized tokens (must equal msg.sender) |
reserveCloseExecutionBountyFromSettlement
Reserves free settlement for the engine’s fresh close-bounty path with carry checkpointing.
function reserveCloseExecutionBountyFromSettlement(
bytes32 accountId,
uint256 amount,
address recipient
) external onlyEngine;
reserveStaleCloseExecutionBountyFromSettlement
Reserves free settlement for the engine’s stale close-bounty path without checkpointing carry.
function reserveStaleCloseExecutionBountyFromSettlement(
bytes32 accountId,
uint256 amount,
address recipient
) external onlyEngine;
seizePositionMarginUsdc
function seizePositionMarginUsdc(
bytes32 accountId,
uint256 amount,
address recipient
) external onlyOperator;
reserveStaleCloseExecutionBountyFromPositionMargin
Reserves active position margin for the engine’s stale close-bounty path without checkpointing carry.
function reserveStaleCloseExecutionBountyFromPositionMargin(
bytes32 accountId,
uint256 amount,
address recipient
) external onlyEngine;
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);
_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__ReservationLedgerActive
error MarginClearinghouse__ReservationLedgerActive();
MarginClearinghouse__EngineAlreadySet
error MarginClearinghouse__EngineAlreadySet();
MarginClearinghouse__ZeroAddress
error MarginClearinghouse__ZeroAddress();
MarginClearinghouse__InsufficientBucketMargin
error MarginClearinghouse__InsufficientBucketMargin();
MarginClearinghouse__AmountOverflow
error MarginClearinghouse__AmountOverflow();
OrderRouter
Inherits: IPerpsKeeper, IPerpsTraderActions, IOrderRouterAdminHost, OrderExecutionOrchestrator
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
admin
address public immutable admin;
DEFAULT_MAX_ORDER_AGE
uint256 internal constant DEFAULT_MAX_ORDER_AGE = 60;
State Variables
nextCommitId
uint64 public nextCommitId = 1;
nextExecuteId
uint64 public nextExecuteId = 1;
maxOrderAge
uint256 public maxOrderAge;
minOpenNotionalUsdc
uint256 public minOpenNotionalUsdc;
openOrderExecutionBountyBps
uint256 public openOrderExecutionBountyBps;
minOpenOrderExecutionBountyUsdc
uint256 public minOpenOrderExecutionBountyUsdc;
maxOpenOrderExecutionBountyUsdc
uint256 public maxOpenOrderExecutionBountyUsdc;
closeOrderExecutionBountyUsdc
uint256 public closeOrderExecutionBountyUsdc;
maxPendingOrders
uint256 public maxPendingOrders;
globalTailOrderId
uint64 public globalTailOrderId;
Functions
_onlyEngine
function _onlyEngine() internal view;
_onlyAdmin
function _onlyAdmin() internal view;
constructor
constructor(
address _engine,
address _engineLens,
address _vault,
address _pyth,
bytes32[] memory _feedIds,
uint256[] memory _quantities,
uint256[] memory _basePrices,
bool[] memory _inversions
) OrderOracleExecution(_engine, _engineLens, _vault, _pyth, _feedIds, _quantities, _basePrices, _inversions);
Parameters
| Name | Type | Description |
|---|---|---|
_engine | address | CfdEngine that processes trades and liquidations |
_engineLens | address | |
_vault | address | CfdVault used for vault depth queries and liquidation bounty payouts |
_pyth | address | Pyth oracle contract (address(0) enables mock mode on Anvil) |
_feedIds | bytes32[] | Pyth price feed IDs for each basket component |
_quantities | uint256[] | Weight of each component (must sum to 1e18) |
_basePrices | uint256[] | Base price per component for normalization (8 decimals) |
_inversions | bool[] | Whether to invert each feed (e.g. USD/JPY -> JPY/USD) |
_revertZeroAddress
function _revertZeroAddress() internal pure override;
_revertOracleValidation
function _revertOracleValidation(
uint8 code
) internal pure;
_revertQueueState
function _revertQueueState(
uint8 code
) internal pure;
_revertCommitValidation
function _revertCommitValidation(
uint8 code
) internal pure;
_revertEmptyFeeds
function _revertEmptyFeeds() internal pure override;
_revertLengthMismatch
function _revertLengthMismatch() internal pure override;
_revertInvalidBasePrice
function _revertInvalidBasePrice() internal pure override;
_revertInvalidWeights
function _revertInvalidWeights() internal pure override;
_revertMissingPythUpdateData
function _revertMissingPythUpdateData() internal pure override;
_revertInsufficientPythFee
function _revertInsufficientPythFee() internal pure override;
_revertMockModeDisabled
function _revertMockModeDisabled() internal pure override;
_revertOraclePriceTooStale
function _revertOraclePriceTooStale() internal pure override;
_revertOracleConfidenceTooWide
function _revertOracleConfidenceTooWide() internal pure override;
_revertOraclePublishTimeOutOfOrder
function _revertOraclePublishTimeOutOfOrder() internal pure override;
_revertMevOraclePriceTooStale
function _revertMevOraclePriceTooStale() internal pure override;
_revertOraclePriceNegative
function _revertOraclePriceNegative() internal pure override;
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
| Name | Type | Description |
|---|---|---|
side | CfdTypes.Side | BULL or BEAR |
sizeDelta | uint256 | Position size change (18 decimals) |
marginDelta | uint256 | Margin to add or remove (6 decimals, USDC) |
targetPrice | uint256 | Slippage limit price (8 decimals, 0 = market order) |
isClose | bool | True to allow execution even when paused or in FAD close-only mode |
syncMarginQueue
Returns the total queued escrow state for an account across all pending orders.
function syncMarginQueue(
bytes32 accountId
) external;
getPendingOrderView
function getPendingOrderView(
uint64 orderId
) external view returns (IOrderRouterAccounting.PendingOrderView memory pending, uint64 nextAccountOrderId);
executeOrder
Keeper executes the current global queue head.
Validates oracle freshness, publish-time ordering, and slippage, then delegates to the engine. Invalid, expired, or out-of-slippage orders are finalized from router-custodied execution bounty escrow; the router does not maintain a retry/requeue lane.
function executeOrder(
uint64 orderId,
bytes[] calldata pythUpdateData
) external payable;
Parameters
| Name | Type | Description |
|---|---|---|
orderId | uint64 | Must equal the current global queue head (expired orders are auto-skipped) |
pythUpdateData | bytes[] | 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
| Name | Type | Description |
|---|---|---|
maxOrderId | uint64 | Inclusive upper bound on committed order ids the batch may begin processing from |
pythUpdateData | bytes[] | Pyth price update blobs; attach ETH to cover the Pyth fee |
_queueHeadOrderId
function _queueHeadOrderId() internal view override returns (uint64);
_setQueueHeadOrderId
function _setQueueHeadOrderId(
uint64 orderId
) internal override;
_queueTailOrderId
function _queueTailOrderId() internal view override returns (uint64);
_setQueueTailOrderId
function _setQueueTailOrderId(
uint64 orderId
) internal override;
_revertOrderNotPending
function _revertOrderNotPending() internal pure override;
_maxOrderAge
function _maxOrderAge() internal view override returns (uint256);
_revertNoOrdersToExecute
function _revertNoOrdersToExecute() internal pure override;
_revertInsufficientGas
function _revertInsufficientGas() internal pure override;
_revertMevDetected
function _revertMevDetected() internal pure override;
_revertCloseOnlyMode
function _revertCloseOnlyMode() internal pure override;
_sendEth
function _sendEth(
address to,
uint256 amount
) internal override;
_creditOrDeferLiquidationBounty
Liquidation keeper value follows the same default custody path as other keeper flows: credit the beneficiary’s clearinghouse account when cash is available, otherwise defer the claim for later clearinghouse settlement.
function _creditOrDeferLiquidationBounty(
uint256 liquidationBountyUsdc,
uint256 executionPrice,
uint64 oraclePublishTime
) internal;
_forfeitEscrowedOrderBountiesOnLiquidation
function _forfeitEscrowedOrderBountiesOnLiquidation(
bytes32 accountId
) internal;
_clearLiquidatedAccountOrders
function _clearLiquidatedAccountOrders(
bytes32 accountId
) internal;
_quoteOpenOrderExecutionBountyUsdc
function _quoteOpenOrderExecutionBountyUsdc(
uint256 sizeDelta,
uint256 price
) internal view returns (uint256);
_reserveCloseExecutionBounty
function _reserveCloseExecutionBounty(
bytes32 accountId,
uint256 sizeDelta,
uint256 executionBountyUsdc
) internal override;
_hasFreshCarryCheckpointMark
function _hasFreshCarryCheckpointMark() internal view returns (bool);
_deleteOrder
function _deleteOrder(
uint64 orderId,
IOrderRouterAccounting.OrderStatus terminalStatus
) internal override;
applyRouterConfig
function applyRouterConfig(
IOrderRouterAdminHost.RouterConfig calldata config
) external;
applyOracleConfig
function applyOracleConfig(
IOrderRouterAdminHost.OracleConfig calldata config
) external;
_nextCommitId
function _nextCommitId() internal view override returns (uint64);
_releaseCommittedMarginForExecution
function _releaseCommittedMarginForExecution(
uint64 orderId
) internal override;
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
| Name | Type | Description |
|---|---|---|
pythUpdateData | bytes[] | 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 credits the liquidation keeper through the clearinghouse when cash is available.
function executeLiquidation(
bytes32 accountId,
bytes[] calldata pythUpdateData
) external payable;
Parameters
| Name | Type | Description |
|---|---|---|
accountId | bytes32 | The account to liquidate (bytes32-encoded address) |
pythUpdateData | bytes[] | Pyth price update blobs; attach ETH to cover the Pyth fee |
_revertInsufficientFreeEquity
function _revertInsufficientFreeEquity() internal pure override;
_revertMarginOrderLinkCorrupted
function _revertMarginOrderLinkCorrupted() internal pure override;
_revertPendingOrderLinkCorrupted
function _revertPendingOrderLinkCorrupted() internal pure override;
Events
OrderCommitted
event OrderCommitted(uint64 indexed orderId, bytes32 indexed accountId, CfdTypes.Side side);
Errors
OrderRouter__ZeroSize
error OrderRouter__ZeroSize();
OrderRouter__OracleValidation
error OrderRouter__OracleValidation(uint8 code);
OrderRouter__QueueState
error OrderRouter__QueueState(uint8 code);
OrderRouter__CommitValidation
error OrderRouter__CommitValidation(uint8 code);
OrderRouter__InsufficientGas
error OrderRouter__InsufficientGas();
OrderRouter__PredictableOpenInvalid
error OrderRouter__PredictableOpenInvalid(uint8 code);
OrderRouterAdmin
Inherits: Ownable, Pausable
Constants
TIMELOCK_DELAY
uint256 public constant TIMELOCK_DELAY = 48 hours;
MAX_PENDING_ORDERS_LIMIT
uint256 internal constant MAX_PENDING_ORDERS_LIMIT = 32;
MAX_CLOSE_ORDER_EXECUTION_BOUNTY_USDC
uint256 internal constant MAX_CLOSE_ORDER_EXECUTION_BOUNTY_USDC = 1_000_000;
MIN_ENGINE_GAS_FLOOR
uint256 internal constant MIN_ENGINE_GAS_FLOOR = 100_000;
MIN_ENGINE_GAS_CAP
uint256 internal constant MIN_ENGINE_GAS_CAP = 5_000_000;
MAX_PRUNE_ORDERS_PER_CALL_LIMIT
uint256 internal constant MAX_PRUNE_ORDERS_PER_CALL_LIMIT = 256;
MAX_ORDER_AGE_LIMIT
uint256 internal constant MAX_ORDER_AGE_LIMIT = 1 hours;
router
IOrderRouterAdminHost public immutable router;
State Variables
claimableEth
mapping(address => uint256) public claimableEth;
pauser
address public pauser;
pendingRouterConfig
IOrderRouterAdminHost.RouterConfig public pendingRouterConfig;
routerConfigActivationTime
uint256 public routerConfigActivationTime;
_pendingOracleConfig
IOrderRouterAdminHost.OracleConfig private _pendingOracleConfig;
oracleConfigActivationTime
uint256 public oracleConfigActivationTime;
Functions
constructor
constructor(
address router_,
address initialOwner
) Ownable(initialOwner);
onlyRouterHost
modifier onlyRouterHost();
onlyPauserOrOwner
modifier onlyPauserOrOwner();
proposeRouterConfig
function proposeRouterConfig(
IOrderRouterAdminHost.RouterConfig calldata config
) external onlyOwner;
finalizeRouterConfig
function finalizeRouterConfig() external onlyOwner;
cancelRouterConfig
function cancelRouterConfig() external onlyOwner;
proposeOracleConfig
function proposeOracleConfig(
IOrderRouterAdminHost.OracleConfig calldata config
) external onlyOwner;
finalizeOracleConfig
function finalizeOracleConfig() external onlyOwner;
cancelOracleConfig
function cancelOracleConfig() external onlyOwner;
getPendingOracleConfig
function getPendingOracleConfig() external view returns (IOrderRouterAdminHost.OracleConfig memory config);
setPauser
function setPauser(
address newPauser
) external onlyOwner;
pause
function pause() external onlyPauserOrOwner;
unpause
function unpause() external onlyOwner;
creditClaimableEth
function creditClaimableEth(
address beneficiary,
uint256 amount
) external payable onlyRouterHost;
claimBalance
function claimBalance(
bool ethBalance
) external;
_requireTimelockReady
function _requireTimelockReady(
uint256 activationTime
) internal view;
_validateRouterConfig
function _validateRouterConfig(
IOrderRouterAdminHost.RouterConfig memory config
) internal pure;
_validateOracleConfig
function _validateOracleConfig(
IOrderRouterAdminHost.OracleConfig calldata config
) internal pure;
Events
RouterConfigProposed
event RouterConfigProposed(IOrderRouterAdminHost.RouterConfig config, uint256 activationTime);
RouterConfigFinalized
event RouterConfigFinalized(IOrderRouterAdminHost.RouterConfig config);
RouterConfigCancelled
event RouterConfigCancelled();
OracleConfigProposed
event OracleConfigProposed(IOrderRouterAdminHost.OracleConfig config, uint256 activationTime);
OracleConfigFinalized
event OracleConfigFinalized(IOrderRouterAdminHost.OracleConfig config);
OracleConfigCancelled
event OracleConfigCancelled();
PauserUpdated
event PauserUpdated(address indexed previousPauser, address indexed newPauser);
Errors
OrderRouterAdmin__TimelockNotReady
error OrderRouterAdmin__TimelockNotReady();
OrderRouterAdmin__NoProposal
error OrderRouterAdmin__NoProposal();
OrderRouterAdmin__InvalidMaxOrderAge
error OrderRouterAdmin__InvalidMaxOrderAge();
OrderRouterAdmin__InvalidStalenessLimit
error OrderRouterAdmin__InvalidStalenessLimit();
OrderRouterAdmin__InvalidConfidenceRatio
error OrderRouterAdmin__InvalidConfidenceRatio();
OrderRouterAdmin__InvalidExecutionBounty
error OrderRouterAdmin__InvalidExecutionBounty();
OrderRouterAdmin__InvalidPendingOrderLimit
error OrderRouterAdmin__InvalidPendingOrderLimit();
OrderRouterAdmin__InvalidGasLimit
error OrderRouterAdmin__InvalidGasLimit();
OrderRouterAdmin__InvalidOracleConfig
error OrderRouterAdmin__InvalidOracleConfig();
OrderRouterAdmin__Unauthorized
error OrderRouterAdmin__Unauthorized();
OrderRouterAdmin__UnauthorizedPauser
error OrderRouterAdmin__UnauthorizedPauser();
OrderRouterAdmin__NothingToClaim
error OrderRouterAdmin__NothingToClaim();
OrderRouterAdmin__EthTransferFailed
error OrderRouterAdmin__EthTransferFailed();
OrderRouterAdmin__EthAmountMismatch
error OrderRouterAdmin__EthAmountMismatch();
PerpsPublicLens
Inherits: IPerpsTraderViews, IPerpsLPViews, IProtocolViews
Title: PerpsPublicLens
Compact read facade for the simplified product-facing perps surface.
This intentionally presents a narrower, easier-to-consume view than the rich engine and accounting lenses used by tests, audits, and operator tooling.
Constants
ACCOUNT_LENS
ICfdEngineAccountLens public immutable ACCOUNT_LENS;
ENGINE
ICfdEngineCore public immutable ENGINE;
ORDER_ROUTER
IOrderRouterAccounting public immutable ORDER_ROUTER;
HOUSE_POOL
HousePool public immutable HOUSE_POOL;
Functions
constructor
constructor(
address accountLens_,
address engine_,
address orderRouter_,
address housePool_
);
Parameters
| Name | Type | Description |
|---|---|---|
accountLens_ | address | Rich account lens used to derive compact trader views. |
engine_ | address | Core engine used for runtime status and risk params. |
orderRouter_ | address | Router accounting surface used for pending-order summaries. |
housePool_ | address | HousePool used for tranche and protocol status views. |
getTraderAccount
Returns the compact trader account summary for a canonical perps account.
function getTraderAccount(
bytes32 accountId
) external view returns (PerpsViewTypes.TraderAccountView memory viewData);
getPosition
Returns the compact current-position view for an account.
function getPosition(
bytes32 accountId
) external view returns (PerpsViewTypes.PositionView memory viewData);
getPendingOrders
Returns all currently pending orders for an account.
The public surface only returns pending orders because executed and failed orders are not part of the compact product-facing queue summary.
function getPendingOrders(
bytes32 accountId
) external view returns (PerpsViewTypes.PendingOrderView[] memory pending);
isLiquidatable
Returns whether the account’s current live position is liquidatable.
function isLiquidatable(
bytes32 accountId
) external view returns (bool);
getSeniorTranche
Returns the compact senior tranche view.
function getSeniorTranche() external view returns (PerpsViewTypes.TrancheView memory viewData);
getJuniorTranche
Returns the compact junior tranche view.
function getJuniorTranche() external view returns (PerpsViewTypes.TrancheView memory viewData);
getLpStatus
Returns high-level LP status flags.
function getLpStatus() external view returns (PerpsViewTypes.LpStatusView memory viewData);
getProtocolStatus
Returns high-level protocol runtime status flags.
function getProtocolStatus() external view returns (PerpsViewTypes.ProtocolStatusView memory viewData);
_getPositionView
function _getPositionView(
bytes32 accountId
) internal view returns (PerpsViewTypes.PositionView memory viewData);
_getTrancheView
function _getTrancheView(
address vault,
bool isSenior
) internal view returns (PerpsViewTypes.TrancheView memory viewData);
_getProtocolStatusView
function _getProtocolStatusView() internal view returns (PerpsViewTypes.ProtocolStatusView memory viewData);
TrancheVault
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
| Name | Type | Description |
|---|---|---|
_usdc | IERC20 | Underlying USDC token used as the vault asset |
_pool | address | HousePool that holds USDC and manages the tranche waterfall |
_isSenior | bool | True for the senior tranche, false for junior |
_name | string | ERC20 share token name |
_symbol | string | ERC20 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
Returns the tranche assets from the pending post-reconcile HousePool state.
function totalAssets() public view override returns (uint256);
deposit
Deposits assets into the tranche after reconciling pool accounting and lifecycle gates.
function deposit(
uint256 assets,
address receiver
) public override returns (uint256);
mint
Mints tranche shares after reconciling pool accounting and lifecycle gates.
function mint(
uint256 shares,
address receiver
) public override returns (uint256);
previewDeposit
function previewDeposit(
uint256 assets
) public view override returns (uint256);
previewMint
function previewMint(
uint256 shares
) public view override returns (uint256);
maxDeposit
Returns the current max deposit if lifecycle, freshness, and impairment gates allow deposits.
function maxDeposit(
address receiver
) public view override returns (uint256);
maxMint
Returns the current max mint if lifecycle, freshness, and impairment gates allow deposits.
function maxMint(
address receiver
) public view override returns (uint256);
withdraw
Withdraws tranche assets after reconciling pool accounting.
function withdraw(
uint256 assets,
address receiver,
address _owner
) public override returns (uint256);
redeem
Redeems tranche shares after reconciling pool accounting.
function redeem(
uint256 shares,
address receiver,
address _owner
) public override returns (uint256);
previewWithdraw
function previewWithdraw(
uint256 assets
) public view override returns (uint256);
previewRedeem
function previewRedeem(
uint256 shares
) public view override returns (uint256);
maxWithdraw
Returns the withdrawable asset amount after cooldown and pool-level withdrawal gates.
function maxWithdraw(
address _owner
) public view override returns (uint256);
maxRedeem
Returns the redeemable share amount after cooldown and pool-level withdrawal gates.
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);
_frozenLpFeeBps
function _frozenLpFeeBps() internal view returns (uint256);
_applyFee
function _applyFee(
uint256 grossAssets,
uint256 feeBps
) internal pure returns (uint256);
_grossUpForFee
function _grossUpForFee(
uint256 netAssets,
uint256 feeBps
) internal pure returns (uint256);
_applyFeeToShares
function _applyFeeToShares(
uint256 grossShares,
uint256 feeBps
) internal pure returns (uint256);
_grossUpSharesForFee
function _grossUpSharesForFee(
uint256 netShares,
uint256 feeBps
) internal pure returns (uint256);
_previewFrozenDepositShares
function _previewFrozenDepositShares(
uint256 assets,
uint256 feeBps
) internal view returns (uint256);
_previewFrozenMintAssets
function _previewFrozenMintAssets(
uint256 shares,
uint256 feeBps
) internal view returns (uint256);
_maxFrozenMintShares
function _maxFrozenMintShares(
uint256 feeBps
) internal view returns (uint256);
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
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
| Name | Type | Description |
|---|---|---|
_morpho | address | Morpho Blue protocol address. |
_splitter | address | SyntheticSplitter contract address. |
_curvePool | address | Curve USDC/plDXY-BEAR pool address. |
_usdc | address | USDC token address. |
_plDxyBear | address | plDXY-BEAR token address. |
_plDxyBull | address | plDXY-BULL token address. |
_stakedPlDxyBull | address | splDXY-BULL staking vault address. |
_marketParams | MarketParams | Morpho market parameters for splDXY-BULL/USDC. |
_sequencerUptimeFeed | address | Chainlink 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
| Name | Type | Description |
|---|---|---|
principal | uint256 | Amount of USDC user sends. |
leverage | uint256 | Multiplier (e.g. 3x = 3e18). |
maxSlippageBps | uint256 | Maximum slippage tolerance in basis points (e.g., 50 = 0.5%). Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction. |
minAmountOut | uint256 | |
deadline | uint256 | Unix 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
| Name | Type | Description |
|---|---|---|
principal | uint256 | Amount of USDC user sends. |
leverage | uint256 | Multiplier (e.g. 3x = 3e18). |
maxSlippageBps | uint256 | Maximum slippage tolerance in basis points. |
minAmountOut | uint256 | |
deadline | uint256 | Unix timestamp after which the permit and transaction revert. |
v | uint8 | Signature recovery byte. |
r | bytes32 | Signature r component. |
s | bytes32 | Signature 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
| Name | Type | Description |
|---|---|---|
collateralToWithdraw | uint256 | Amount 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. |
maxSlippageBps | uint256 | Maximum slippage tolerance in basis points. Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction. |
minAmountOut | uint256 | |
deadline | uint256 | Unix 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
| Name | Type | Description |
|---|---|---|
usdcAmount | uint256 | Amount of USDC representing desired collateral value. |
maxSlippageBps | uint256 | Maximum slippage tolerance in basis points. Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction. |
minAmountOut | uint256 | |
deadline | uint256 | Unix 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
| Name | Type | Description |
|---|---|---|
usdcAmount | uint256 | Amount of USDC representing desired collateral value. |
maxSlippageBps | uint256 | Maximum slippage tolerance in basis points. |
minAmountOut | uint256 | |
deadline | uint256 | Unix timestamp after which the permit and transaction revert. |
v | uint8 | Signature recovery byte. |
r | bytes32 | Signature r component. |
s | bytes32 | Signature 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
| Name | Type | Description |
|---|---|---|
collateralToWithdraw | uint256 | Amount of splDXY-BULL shares to withdraw. NOTE: This is staked token shares, not underlying plDXY-BULL amount. |
maxSlippageBps | uint256 | Maximum slippage tolerance in basis points. Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction. |
minAmountOut | uint256 | |
deadline | uint256 | Unix 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
| Name | Type | Description |
|---|---|---|
amount | uint256 | Amount of USDC borrowed. |
data | bytes | Encoded 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
| Name | Type | Description |
|---|---|---|
initiator | address | Address that initiated the flash loan (must be this contract). |
<none> | address | |
amount | uint256 | Amount of plDXY-BEAR borrowed. |
fee | uint256 | Flash loan fee (always 0 for SyntheticToken). |
data | bytes | Encoded operation parameters. |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bytes32 | CALLBACK_SUCCESS on successful execution. |
_executeOpen
Executes open leverage operation within Morpho flash loan callback.
function _executeOpen(
uint256 loanAmount,
bytes calldata data
) private;
Parameters
| Name | Type | Description |
|---|---|---|
loanAmount | uint256 | Amount of USDC borrowed from Morpho. |
data | bytes | Encoded 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
| Name | Type | Description |
|---|---|---|
flashLoanAmount | uint256 | Amount of USDC flash loaned. |
data | bytes | Encoded 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
| Name | Type | Description |
|---|---|---|
flashAmount | uint256 | Amount of plDXY-BEAR flash minted. |
flashFee | uint256 | Flash mint fee (always 0). |
data | bytes | Encoded 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
| Name | Type | Description |
|---|---|---|
flashAmount | uint256 | Amount of plDXY-BEAR flash minted. |
flashFee | uint256 | Flash mint fee (always 0). |
data | bytes | Encoded 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
| Name | Type | Description |
|---|---|---|
principal | uint256 | Amount of USDC user will send. |
leverage | uint256 | Multiplier (e.g. 2x = 2e18). |
Returns
| Name | Type | Description |
|---|---|---|
loanAmount | uint256 | Amount of USDC to flash loan. |
totalUSDC | uint256 | Total USDC for minting pairs (principal + loan). |
expectedPlDxyBull | uint256 | Expected plDXY-BULL tokens received. |
expectedDebt | uint256 | Expected 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
| Name | Type | Description |
|---|---|---|
debtToRepay | uint256 | Amount of USDC debt to repay. |
collateralToWithdraw | uint256 | Amount of plDXY-BULL collateral to withdraw. |
Returns
| Name | Type | Description |
|---|---|---|
expectedUSDC | uint256 | Expected USDC from redeeming pairs. |
usdcForBearBuyback | uint256 | Expected USDC needed to buy back plDXY-BEAR. |
expectedReturn | uint256 | Expected 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
| Name | Type | Description |
|---|---|---|
usdcAmount | uint256 | Amount of USDC representing desired collateral value. |
Returns
| Name | Type | Description |
|---|---|---|
flashLoanAmount | uint256 | Amount of USDC to flash loan. |
totalUSDC | uint256 | Total USDC for minting pairs. |
expectedPlDxyBull | uint256 | Expected plDXY-BULL tokens to receive. |
expectedStakedShares | uint256 | Expected 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
| Name | Type | Description |
|---|---|---|
collateralToWithdraw | uint256 | Amount of splDXY-BULL shares to withdraw. |
Returns
| Name | Type | Description |
|---|---|---|
expectedPlDxyBull | uint256 | Expected plDXY-BULL from unstaking. |
expectedUsdcFromBurn | uint256 | Expected USDC from burning pairs. |
usdcForBearBuyback | uint256 | Expected USDC needed to buy back flash-minted BEAR. |
expectedReturn | uint256 | Expected 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
| Name | Type | Description |
|---|---|---|
i | uint256 | Curve pool input index. |
j | uint256 | Curve pool output index. |
oneUnit | uint256 | One unit of the input token (1e18 for BEAR, 1e6 for USDC). |
targetOut | uint256 | Desired minimum output from the swap. |
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | Minimum 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
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. Permissionless solvers can rebalance USDC/Curve LP inventory against conservative reserve prices. 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;
SOLVER_PRICE_SPREAD_BPS
uint256 private constant SOLVER_PRICE_SPREAD_BPS = 10;
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
| Name | Type | Description |
|---|---|---|
_usdc | address | USDC token address. |
_bear | address | plDXY-BEAR token address. |
_curveLpToken | address | Curve USDC/plDXY-BEAR LP token address. |
_curvePool | address | Curve twocrypto-ng pool address. |
_oracle | address | BasketOracle address (Chainlink AggregatorV3Interface). |
_sequencerUptimeFeed | address | L2 sequencer uptime feed (address(0) on L1). |
_crvMinter | address | Curve 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
| Name | Type | Description |
|---|---|---|
_stakedInvarCoin | address | Address 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;
_isCoreRewardProtectedAsset
function _isCoreRewardProtectedAsset(
address token
) private view returns (bool);
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
| Name | Type | Description |
|---|---|---|
currentBuffer | uint256 | USDC held locally (6 decimals). |
targetBuffer | uint256 | Target USDC buffer based on total assets (6 decimals). |
deployable | uint256 | Excess USDC deployable to Curve (0 if below threshold). |
replenishable | uint256 | USDC 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, no sINVAR stakers, 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);
_hasStakedInvarSupply
function _hasStakedInvarSupply() private view returns (bool);
_checkpointIfNoStakers
function _checkpointIfNoStakers(
uint256 currentVpValue
) private returns (bool checkpointed);
_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;
_outsideSpotDeviationBounds
function _outsideSpotDeviationBounds(
uint256 spotValue,
uint256 emaValue
) private pure returns (bool);
_reduceLpAccounting
function _reduceLpAccounting(
uint256 lpReduced,
uint256 totalLp
) private;
_recordLpDeployment
function _recordLpDeployment(
uint256 lpMinted
) private;
_depositToCurve
function _depositToCurve(
uint256 usdcAmount,
uint256 bearAmount,
uint256 oraclePrice
) private returns (uint256 lpMinted);
_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
| Name | Type | Description |
|---|---|---|
usdcAmount | uint256 | Amount of USDC to deposit (6 decimals). |
receiver | address | Address that receives the minted INVAR shares. |
minSharesOut | uint256 | Minimum INVAR shares to receive (0 = no minimum). |
Returns
| Name | Type | Description |
|---|---|---|
glUsdMinted | uint256 | Number 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
| Name | Type | Description |
|---|---|---|
usdcAmount | uint256 | Amount of USDC to deposit (6 decimals). |
receiver | address | Address that receives the minted INVAR shares. |
minSharesOut | uint256 | Minimum INVAR shares to receive (0 = no minimum). |
deadline | uint256 | Permit signature expiry timestamp. |
v | uint8 | ECDSA recovery byte. |
r | bytes32 | ECDSA r component. |
s | bytes32 | ECDSA s component. |
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | Number 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
| Name | Type | Description |
|---|---|---|
glUsdAmount | uint256 | Amount of INVAR shares to burn. |
receiver | address | Address that receives the withdrawn USDC. |
minUsdcOut | uint256 | Minimum USDC to receive (slippage protection). |
Returns
| Name | Type | Description |
|---|---|---|
usdcOut | uint256 | Total 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,
address receiver
) external nonReentrant returns (uint256 usdcReturned, uint256 bearReturned);
Parameters
| Name | Type | Description |
|---|---|---|
glUsdAmount | uint256 | Amount of INVAR shares to burn. |
minUsdcOut | uint256 | Minimum USDC to receive (slippage protection). |
minBearOut | uint256 | Minimum plDXY-BEAR to receive (slippage protection). |
receiver | address | Address receiving the withdrawn assets. |
Returns
| Name | Type | Description |
|---|---|---|
usdcReturned | uint256 | Total USDC returned. |
bearReturned | uint256 | Total plDXY-BEAR returned. |
_lpWithdraw
function _lpWithdraw(
uint256 glUsdAmount,
uint256 minUsdcOut,
uint256 minBearOut,
address receiver
) 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
| Name | Type | Description |
|---|---|---|
usdcAmount | uint256 | Amount of USDC to deposit (6 decimals, can be 0 if bearAmount > 0). |
bearAmount | uint256 | Amount of plDXY-BEAR to deposit (18 decimals, can be 0 if usdcAmount > 0). |
receiver | address | Address that receives the minted INVAR shares. |
minSharesOut | uint256 | Minimum INVAR shares to receive (slippage protection). |
Returns
| Name | Type | Description |
|---|---|---|
glUsdMinted | uint256 | Number 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 to donate or checkpoint — use as a heartbeat signal for keepers.
function harvest() external nonReentrant whenNotPaused returns (uint256 donated);
Returns
| Name | Type | Description |
|---|---|---|
donated | uint256 | Amount 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. If no sINVAR recipients exist, checkpoints VP growth as INVAR NAV. Withdrawals must never be blocked.
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, bool accounted);
_mintAndDonate
function _mintAndDonate(
uint256 amount
) private;
_harvestWithPrice
function _harvestWithPrice(
uint256 lpBal,
uint256 currentVpValue,
uint256 oraclePrice
) private returns (uint256 donated, bool accounted);
donateUsdc
Accepts USDC donations from RewardDistributor, mints proportional INVAR, and donates to sINVAR.
function donateUsdc(
uint256 usdcAmount
) external nonReentrant whenNotPaused;
Parameters
| Name | Type | Description |
|---|---|---|
usdcAmount | uint256 | Amount of USDC to donate (6 decimals). |
previewSellLpToVault
Preview USDC paid when a solver sells Curve LP to the vault.
Uses the pessimistic fair LP price less SOLVER_PRICE_SPREAD_BPS as the vault bid.
function previewSellLpToVault(
uint256 lpAmount
) external view returns (uint256 usdcOut);
previewBuyLpFromVault
Preview USDC required when a solver buys Curve LP from the vault.
Uses the optimistic fair LP price plus SOLVER_PRICE_SPREAD_BPS as the vault ask.
function previewBuyLpFromVault(
uint256 lpAmount
) external view returns (uint256 usdcIn);
sellLpToVault
Permissionless solver fill: solver sells Curve LP to the vault for excess USDC buffer.
The vault never trades on Curve; the solver owns sourcing/slippage risk.
function sellLpToVault(
uint256 lpAmount,
uint256 minUsdcOut
) external nonReentrant whenNotPaused returns (uint256 usdcOut);
Parameters
| Name | Type | Description |
|---|---|---|
lpAmount | uint256 | Amount of Curve LP transferred from the solver. |
minUsdcOut | uint256 | Minimum USDC the solver is willing to receive. |
Returns
| Name | Type | Description |
|---|---|---|
usdcOut | uint256 | USDC paid to the solver. |
buyLpFromVault
Permissionless solver fill: solver buys Curve LP from the vault and restores USDC buffer.
The vault never trades on Curve; the solver owns exit/slippage risk.
function buyLpFromVault(
uint256 lpAmount,
uint256 maxUsdcIn
) external nonReentrant whenNotPaused returns (uint256 usdcIn);
Parameters
| Name | Type | Description |
|---|---|---|
lpAmount | uint256 | Amount of Curve LP bought from the vault. |
maxUsdcIn | uint256 | Maximum USDC the solver is willing to pay. |
Returns
| Name | Type | Description |
|---|---|---|
usdcIn | uint256 | USDC paid by the solver. |
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
| Name | Type | Description |
|---|---|---|
minLpOut | uint256 | Minimum 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
| Name | Type | Description |
|---|---|---|
token | address | Address of the token to rescue. |
to | address | Destination 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
| Name | Type | Description |
|---|---|---|
_gauge | address | Address 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
| Name | Type | Description |
|---|---|---|
amount | uint256 | Amount of LP to stake (0 = all unstaked LP). |
unstakeFromGauge
Unstake LP tokens from the active Curve gauge.
function unstakeFromGauge(
uint256 amount
) external onlyOwner;
Parameters
| Name | Type | Description |
|---|---|---|
amount | uint256 | Amount 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, address indexed receiver, 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);
SolverLpPurchased
event SolverLpPurchased(address indexed solver, uint256 lpIn, uint256 usdcOut);
SolverLpSold
event SolverLpSold(address indexed solver, uint256 lpOut, uint256 usdcIn);
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__NoStakers
error InvarCoin__NoStakers();
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
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
| Name | Type | Description |
|---|---|---|
_morpho | address | Morpho Blue protocol address. |
_curvePool | address | Curve USDC/plDXY-BEAR pool address. |
_usdc | address | USDC token address. |
_plDxyBear | address | plDXY-BEAR token address. |
_stakedPlDxyBear | address | splDXY-BEAR staking vault address. |
_marketParams | MarketParams | Morpho 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
| Name | Type | Description |
|---|---|---|
principal | uint256 | Amount of USDC user sends. |
leverage | uint256 | Multiplier (e.g. 3x = 3e18). |
maxSlippageBps | uint256 | Maximum slippage tolerance in basis points (e.g., 50 = 0.5%). Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction. |
minAmountOut | uint256 | |
deadline | uint256 | Unix 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
| Name | Type | Description |
|---|---|---|
principal | uint256 | Amount of USDC user sends. |
leverage | uint256 | Multiplier (e.g. 3x = 3e18). |
maxSlippageBps | uint256 | Maximum slippage tolerance in basis points. |
minAmountOut | uint256 | |
deadline | uint256 | Unix timestamp after which the permit and transaction revert. |
v | uint8 | Signature recovery byte. |
r | bytes32 | Signature r component. |
s | bytes32 | Signature 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
| Name | Type | Description |
|---|---|---|
collateralToWithdraw | uint256 | Amount 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. |
maxSlippageBps | uint256 | Maximum slippage tolerance in basis points (e.g., 50 = 0.5%). Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction. |
minAmountOut | uint256 | |
deadline | uint256 | Unix 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
| Name | Type | Description |
|---|---|---|
usdcAmount | uint256 | Amount of USDC to add as collateral. |
maxSlippageBps | uint256 | Maximum slippage tolerance in basis points. Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction. |
minAmountOut | uint256 | |
deadline | uint256 | Unix 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
| Name | Type | Description |
|---|---|---|
usdcAmount | uint256 | Amount of USDC to add as collateral. |
maxSlippageBps | uint256 | Maximum slippage tolerance in basis points. |
minAmountOut | uint256 | |
deadline | uint256 | Unix timestamp after which the permit and transaction revert. |
v | uint8 | Signature recovery byte. |
r | bytes32 | Signature r component. |
s | bytes32 | Signature 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
| Name | Type | Description |
|---|---|---|
collateralToWithdraw | uint256 | Amount of splDXY-BEAR shares to withdraw. NOTE: This is staked token shares, not underlying plDXY-BEAR amount. |
maxSlippageBps | uint256 | Maximum slippage tolerance in basis points. Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction. |
minAmountOut | uint256 | |
deadline | uint256 | Unix 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
| Name | Type | Description |
|---|---|---|
amount | uint256 | Amount of USDC borrowed. |
data | bytes | Encoded 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
| Name | Type | Description |
|---|---|---|
loanAmount | uint256 | Amount of USDC borrowed from Morpho. |
data | bytes | Encoded 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
| Name | Type | Description |
|---|---|---|
loanAmount | uint256 | Amount of USDC borrowed from Morpho to repay debt. |
data | bytes | Encoded 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
| Name | Type | Description |
|---|---|---|
user | address | Position owner receiving USDC. |
collateralToWithdraw | uint256 | Amount of splDXY-BEAR shares to withdraw. |
maxSlippageBps | uint256 | Maximum slippage for Curve swap. |
minUsdcOut | uint256 | Minimum USDC to receive after swap. |
minAmountOut | uint256 | User-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
| Name | Type | Description |
|---|---|---|
principal | uint256 | Amount of USDC user will send. |
leverage | uint256 | Multiplier (e.g. 3x = 3e18). |
Returns
| Name | Type | Description |
|---|---|---|
loanAmount | uint256 | Amount of USDC to flash loan. |
totalUSDC | uint256 | Total USDC to swap (principal + loan). |
expectedPlDxyBear | uint256 | Expected plDXY-BEAR (based on current curve price). |
expectedDebt | uint256 | Expected 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
| Name | Type | Description |
|---|---|---|
debtToRepay | uint256 | Amount of USDC debt to repay. |
collateralToWithdraw | uint256 | Amount of plDXY-BEAR collateral to withdraw. |
Returns
| Name | Type | Description |
|---|---|---|
expectedUSDC | uint256 | Expected USDC from swap (based on current curve price). |
flashFee | uint256 | Flash loan fee (always 0 with Morpho). |
expectedReturn | uint256 | Expected 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
| Name | Type | Description |
|---|---|---|
usdcAmount | uint256 | Amount of USDC to add as collateral. |
Returns
| Name | Type | Description |
|---|---|---|
expectedPlDxyBear | uint256 | Expected plDXY-BEAR from Curve swap. |
expectedStakedShares | uint256 | Expected splDXY-BEAR shares to receive. |
previewRemoveCollateral
Preview the result of removing collateral.
function previewRemoveCollateral(
uint256 collateralToWithdraw
) external view returns (uint256 expectedPlDxyBear, uint256 expectedUSDC);
Parameters
| Name | Type | Description |
|---|---|---|
collateralToWithdraw | uint256 | Amount of splDXY-BEAR shares to withdraw. |
Returns
| Name | Type | Description |
|---|---|---|
expectedPlDxyBear | uint256 | Expected plDXY-BEAR from unstaking. |
expectedUSDC | uint256 | Expected 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
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
| Name | Type | Description |
|---|---|---|
_splitter | address | SyntheticSplitter contract address. |
_usdc | address | USDC token address. |
_plDxyBear | address | plDXY-BEAR token address. |
_plDxyBull | address | plDXY-BULL token address. |
_stakedBear | address | StakedToken vault for BEAR. |
_stakedBull | address | StakedToken vault for BULL. |
_curvePool | address | Curve USDC/plDXY-BEAR pool. |
_zapRouter | address | ZapRouter for BULL acquisition. |
_oracle | address | BasketOracle for price data. |
_pythAdapter | address | Optional PythAdapter for SEK/USD updates (address(0) if not used). |
_invarCoin | address | Optional 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
| Name | Type | Description |
|---|---|---|
callerReward | uint256 | Amount of USDC sent to caller as incentive. |
_distributeRewardsInternal
Internal implementation of reward distribution.
function _distributeRewardsInternal() internal returns (uint256 callerReward);
_allocateRewards
function _allocateRewards(
uint256 distributableUsdc,
uint256 bearPct,
uint256 bullPct
) internal pure returns (uint256 bearUsdc, uint256 bullUsdc);
_prepareBearAllocation
function _prepareBearAllocation(
uint256 bearUsdc,
uint256 absBasketPrice
) internal returns (uint256 stakedBearUsdc, uint256 invarUsdcAmount);
_distributeAcquiredTokens
function _distributeAcquiredTokens(
uint256 bearAmount,
uint256 bullAmount
) internal;
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
| Name | Type | Description |
|---|---|---|
pythUpdateData | bytes[] | Price update data from Pyth Hermes API. |
Returns
| Name | Type | Description |
|---|---|---|
callerReward | uint256 | Amount 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
| Name | Type | Description |
|---|---|---|
bearPct | uint256 | Expected percentage to BEAR stakers (basis points). |
bullPct | uint256 | Expected percentage to BULL stakers (basis points). |
usdcBalance | uint256 | Current USDC balance available for distribution. |
callerReward | uint256 | Expected caller reward. |
_calculateSplit
Calculates reward split based on price discrepancy.
function _calculateSplit(
uint256 absBasketPrice
) internal view returns (uint256 bearPct, uint256 bullPct);
Parameters
| Name | Type | Description |
|---|---|---|
absBasketPrice | uint256 | Validated basket price (8 decimals, positive). |
Returns
| Name | Type | Description |
|---|---|---|
bearPct | uint256 | Percentage for BEAR stakers (basis points). |
bullPct | uint256 | Percentage 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
| Name | Type | Description |
|---|---|---|
bearUsdc | uint256 | USDC allocated to BEAR acquisition. |
bullUsdc | uint256 | USDC allocated to BULL acquisition. |
absBasketPrice | uint256 | Validated basket price (8 decimals, positive). |
Returns
| Name | Type | Description |
|---|---|---|
bearAmount | uint256 | Amount of plDXY-BEAR acquired. |
bullAmount | uint256 | Amount 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
| Name | Type | Description |
|---|---|---|
bearUsdc | uint256 | Total USDC allocated to the BEAR side. |
absBasketPrice | uint256 | Validated basket price (8 decimals, positive). |
_calculateMintAmount
Converts USDC amount to 18-decimal mint amount.
function _calculateMintAmount(
uint256 usdcAmount
) internal view returns (uint256 mintAmount);
Parameters
| Name | Type | Description |
|---|---|---|
usdcAmount | uint256 | USDC amount (6 decimals). |
Returns
| Name | Type | Description |
|---|---|---|
mintAmount | uint256 | Token amount to mint (18 decimals). |
StakedToken
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
| Name | Type | Description |
|---|---|---|
_asset | IERC20 | The underlying plDXY token to stake (plDXY-BEAR or plDXY-BULL). |
_name | string | Vault share name (e.g., “Staked plDXY-BEAR”). |
_symbol | string | Vault 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
| Name | Type | Description |
|---|---|---|
amount | uint256 | The 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
| Name | Type | Description |
|---|---|---|
assets | uint256 | Amount of underlying tokens to deposit |
receiver | address | Address to receive the vault shares |
deadline | uint256 | Permit signature expiration timestamp |
v | uint8 | Signature recovery byte |
r | bytes32 | Signature r component |
s | bytes32 | Signature s component |
Returns
| Name | Type | Description |
|---|---|---|
shares | uint256 | Amount 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__NoStakers
error StakedToken__NoStakers();
StakedToken__PermitFailed
error StakedToken__PermitFailed();
SyntheticSplitter
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
| Name | Type | Description |
|---|---|---|
_oracle | address | Chainlink-compatible price feed for plDXY basket. |
_usdc | address | USDC token address (6 decimals). |
_yieldAdapter | address | ERC4626-compliant yield adapter for USDC deposits. |
_cap | uint256 | Maximum plDXY price (8 decimals). Triggers liquidation when breached. |
_treasury | address | Treasury address for fee distribution. |
_sequencerUptimeFeed | address | L2 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
| Name | Type | Description |
|---|---|---|
mintAmount | uint256 | The amount of TokenA/B the user wants to mint |
Returns
| Name | Type | Description |
|---|---|---|
usdcRequired | uint256 | Total USDC needed from user |
depositToAdapter | uint256 | Always 0 (deployment is separate via deployToAdapter()) |
keptInBuffer | uint256 | Amount 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
| Name | Type | Description |
|---|---|---|
amount | uint256 | The 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
| Name | Type | Description |
|---|---|---|
amount | uint256 | The amount of token pairs to mint (18 decimals). |
deadline | uint256 | Unix timestamp after which the permit and transaction revert. |
v | uint8 | Signature recovery byte. |
r | bytes32 | Signature r component. |
s | bytes32 | Signature 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
| Name | Type | Description |
|---|---|---|
burnAmount | uint256 | The amount of TokenA/B the user wants to burn |
Returns
| Name | Type | Description |
|---|---|---|
usdcRefund | uint256 | Total USDC user will receive |
withdrawnFromAdapter | uint256 | Amount 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
| Name | Type | Description |
|---|---|---|
amount | uint256 | The amount of token pairs to burn (18 decimals). |
_withdrawFromAdapter
Withdraws USDC from yield adapter with redeem fallback.
function _withdrawFromAdapter(
uint256 amount
) internal;
Parameters
| Name | Type | Description |
|---|---|---|
amount | uint256 | USDC 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
| Name | Type | Description |
|---|---|---|
amount | uint256 | The 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
| Name | Type | Description |
|---|---|---|
amount | uint256 | Desired 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
| Name | Type | Description |
|---|---|---|
deployed | uint256 | Amount 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
| Name | Type | Description |
|---|---|---|
canHarvest | bool | True if surplus exceeds MIN_SURPLUS_THRESHOLD. |
totalSurplus | uint256 | Available surplus (total assets - liabilities). |
callerReward | uint256 | Caller incentive (0.1% of harvest). |
treasuryShare | uint256 | Treasury allocation (20% of remaining). |
stakingShare | uint256 | Staking 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
| Name | Type | Description |
|---|---|---|
_treasury | address | New treasury address. |
_staking | address | New 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
| Name | Type | Description |
|---|---|---|
_newAdapter | address | Address 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
| Name | Type | Description |
|---|---|---|
token | address | The ERC20 token to rescue. |
to | address | The recipient address. |
currentStatus
Returns the current protocol lifecycle status.
function currentStatus() external view override returns (Status);
Returns
| Name | Type | Description |
|---|---|---|
<none> | Status | The current Status enum value (ACTIVE, PAUSED, or SETTLED). |
getSystemStatus
Returns comprehensive system metrics for dashboards.
function getSystemStatus() external view returns (SystemStatus memory status);
Returns
| Name | Type | Description |
|---|---|---|
status | SystemStatus | Struct 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
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
| Name | Type | Description |
|---|---|---|
_name | string | Token name (e.g., “Plether Dollar Index Bear”). |
_symbol | string | Token symbol (e.g., “plDXY-BEAR”). |
_splitter | address | Address of the SyntheticSplitter contract. |
mint
Mint tokens to an address. Only callable by Splitter.
function mint(
address to,
uint256 amount
) external onlySplitter;
Parameters
| Name | Type | Description |
|---|---|---|
to | address | Recipient address. |
amount | uint256 | Amount to mint. |
burn
Burn tokens from an address. Only callable by Splitter.
function burn(
address from,
uint256 amount
) external onlySplitter;
Parameters
| Name | Type | Description |
|---|---|---|
from | address | Address to burn from. |
amount | uint256 | Amount 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
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
| Name | Type | Description |
|---|---|---|
_asset | IERC20 | Underlying asset (USDC). |
_vault | address | Morpho vault address (must have same underlying asset). |
_owner | address | Admin address for rescue operations. |
_splitter | address | SyntheticSplitter 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
| Name | Type | Description |
|---|---|---|
<none> | uint256 | Total 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
| Name | Type | Description |
|---|---|---|
caller | address | Must be SPLITTER. |
receiver | address | Receiver of adapter shares. |
assets | uint256 | Amount of USDC to deposit. |
shares | uint256 | Amount 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
| Name | Type | Description |
|---|---|---|
caller | address | Caller requesting withdrawal. |
receiver | address | Receiver of withdrawn USDC. |
owner | address | Owner of adapter shares being burned. |
assets | uint256 | Amount of USDC to withdraw. |
shares | uint256 | Amount 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
| Name | Type | Description |
|---|---|---|
token | address | Token to rescue. |
to | address | Recipient 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
| Name | Type | Description |
|---|---|---|
target | address | Distributor contract to call. |
data | bytes | ABI-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
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
| Name | Type | Description |
|---|---|---|
_splitter | address | SyntheticSplitter contract address. |
_plDxyBear | address | plDXY-BEAR token address. |
_plDxyBull | address | plDXY-BULL token address. |
_usdc | address | USDC token address. |
_curvePool | address | Curve 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
| Name | Type | Description |
|---|---|---|
usdcAmount | uint256 | The amount of USDC the user is sending. |
minAmountOut | uint256 | Minimum amount of plDXY-BULL tokens to receive. |
maxSlippageBps | uint256 | Maximum slippage tolerance in basis points (e.g., 100 = 1%). Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction. |
deadline | uint256 | Unix 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
| Name | Type | Description |
|---|---|---|
usdcAmount | uint256 | The amount of USDC the user is sending. |
minAmountOut | uint256 | Minimum amount of plDXY-BULL tokens to receive. |
maxSlippageBps | uint256 | Maximum slippage tolerance in basis points. |
deadline | uint256 | Unix timestamp after which the permit and transaction revert. |
v | uint8 | Signature recovery byte. |
r | bytes32 | Signature r component. |
s | bytes32 | Signature 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
| Name | Type | Description |
|---|---|---|
bullAmount | uint256 | Amount of plDXY-BULL to sell. |
minUsdcOut | uint256 | Minimum USDC to receive (slippage protection). |
deadline | uint256 | Unix 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
| Name | Type | Description |
|---|---|---|
bullAmount | uint256 | Amount of plDXY-BULL to sell. |
minUsdcOut | uint256 | Minimum USDC to receive (slippage protection). |
deadline | uint256 | Unix timestamp after which the transaction reverts. |
v | uint8 | Signature recovery byte. |
r | bytes32 | Signature r component. |
s | bytes32 | Signature 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
| Name | Type | Description |
|---|---|---|
initiator | address | Address that initiated the flash loan (must be this contract). |
<none> | address | |
amount | uint256 | Amount of plDXY-BEAR borrowed. |
fee | uint256 | Flash loan fee (always 0 for SyntheticToken). |
data | bytes | Encoded operation parameters. |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bytes32 | CALLBACK_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
| Name | Type | Description |
|---|---|---|
loanAmount | uint256 | Amount of plDXY-BEAR borrowed. |
fee | uint256 | Flash loan fee (always 0). |
data | bytes | Encoded 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
| Name | Type | Description |
|---|---|---|
loanAmount | uint256 | Amount of plDXY-BEAR borrowed. |
fee | uint256 | Flash loan fee (always 0). |
data | bytes | Encoded 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
| Name | Type | Description |
|---|---|---|
usdcAmount | uint256 | The amount of USDC the user will send. |
Returns
| Name | Type | Description |
|---|---|---|
flashAmount | uint256 | Amount of plDXY-BEAR to flash mint (0 signals direct path). |
expectedSwapOut | uint256 | Expected USDC from swap (flash: contributes to minting; direct: refund to user). |
totalUSDC | uint256 | Total USDC for minting pairs (flash: user + swap; direct: user only). |
expectedTokensOut | uint256 | Expected plDXY-BULL tokens to receive. |
flashFee | uint256 | Flash 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
| Name | Type | Description |
|---|---|---|
bullAmount | uint256 | The amount of plDXY-BULL tokens to sell. |
Returns
| Name | Type | Description |
|---|---|---|
expectedUsdcFromBurn | uint256 | USDC received from burning pairs via Splitter. |
usdcForBearBuyback | uint256 | USDC needed to buy back plDXY-BEAR for flash loan repayment. |
expectedUsdcOut | uint256 | Net USDC the user will receive. |
flashFee | uint256 | Flash 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();