Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

BullLeverageRouter

Git Source

Inherits: LeverageRouterBase

Title: BullLeverageRouter

Leverage router for plDXY-BULL positions via Morpho Blue.

Uses Morpho flash loans + Splitter minting to acquire plDXY-BULL, then deposits as Morpho collateral. Close operation uses a single plDXY-BEAR flash mint for simplicity and gas efficiency. Uses Morpho’s fee-free flash loans for capital efficiency.

STATE MACHINE - OPEN LEVERAGE: ┌─────────────────────────────────────────────────────────────────────────┐ │ openLeverage(principal, leverage) │ │ 1. Pull USDC from user │ │ 2. Flash loan additional USDC from Morpho (fee-free) │ │ └──► onMorphoFlashLoan(OP_OPEN) │ │ └──► _executeOpen() │ │ 1. Mint plDXY-BEAR + plDXY-BULL pairs via Splitter │ │ 2. Sell plDXY-BEAR on Curve → USDC │ │ 3. Stake plDXY-BULL → splDXY-BULL │ │ 4. Deposit splDXY-BULL to Morpho (user’s collateral) │ │ 5. Borrow USDC from Morpho to cover flash repayment │ │ 6. Emit LeverageOpened event │ └─────────────────────────────────────────────────────────────────────────┘

STATE MACHINE - CLOSE LEVERAGE (Single Flash Mint): ┌─────────────────────────────────────────────────────────────────────────┐ │ closeLeverage(debtToRepay, collateralToWithdraw) │ │ 1. Flash mint plDXY-BEAR (collateral + extra for debt repayment) │ │ └──► onFlashLoan(OP_CLOSE) │ │ └──► _executeClose() │ │ 1. Sell extra plDXY-BEAR on Curve → USDC │ │ 2. Repay user’s Morpho debt with USDC from sale │ │ 3. Withdraw user’s splDXY-BULL from Morpho │ │ 4. Unstake splDXY-BULL → plDXY-BULL │ │ 5. Redeem plDXY-BEAR + plDXY-BULL → USDC │ │ 6. Buy plDXY-BEAR on Curve to repay flash mint │ │ 7. Transfer remaining USDC to user │ │ 8. Emit LeverageClosed event │ └─────────────────────────────────────────────────────────────────────────┘

STATE MACHINE - ADD COLLATERAL (Morpho Flash Loan): ┌─────────────────────────────────────────────────────────────────────────┐ │ addCollateral(usdcAmount) │ │ 1. Pull USDC from user │ │ 2. Flash loan USDC from Morpho (F = U × bearPrice / bullPrice) │ │ └──► onMorphoFlashLoan(OP_ADD_COLLATERAL) │ │ └──► _executeAddCollateral() │ │ 1. Mint plDXY-BEAR + plDXY-BULL pairs via Splitter │ │ 2. Sell ALL plDXY-BEAR on Curve → USDC │ │ 3. Stake plDXY-BULL → splDXY-BULL │ │ 4. Deposit splDXY-BULL to Morpho (user’s collateral) │ │ 5. Repay flash loan from BEAR sale proceeds │ │ 6. Emit CollateralAdded event │ └─────────────────────────────────────────────────────────────────────────┘

Note: security-contact: contact@plether.com

Constants

SPLITTER

SyntheticSplitter for minting/burning token pairs.

ISyntheticSplitter public immutable SPLITTER

PLDXY_BULL

plDXY-BULL token (collateral for bull positions).

IERC20 public immutable PLDXY_BULL

STAKED_PLDXY_BULL

StakedToken vault for plDXY-BULL (used as Morpho collateral).

IERC4626 public immutable STAKED_PLDXY_BULL

CAP

Protocol CAP price (8 decimals, oracle format).

uint256 public immutable CAP

ORACLE

Oracle for plDXY basket price (returns BEAR price in 8 decimals).

AggregatorV3Interface public immutable ORACLE

SEQUENCER_UPTIME_FEED

Chainlink L2 sequencer uptime feed (address(0) on L1).

AggregatorV3Interface public immutable SEQUENCER_UPTIME_FEED

ORACLE_TIMEOUT

Maximum age for a valid oracle price.

uint256 public constant ORACLE_TIMEOUT = 24 hours

SEQUENCER_GRACE_PERIOD

Grace period after L2 sequencer restarts before accepting prices.

uint256 public constant SEQUENCER_GRACE_PERIOD = 1 hours

OP_REMOVE_COLLATERAL

Operation type: remove collateral (flash mint).

uint8 internal constant OP_REMOVE_COLLATERAL = 3

OP_ADD_COLLATERAL

Operation type: add collateral (Morpho flash loan).

uint8 internal constant OP_ADD_COLLATERAL = 4

Functions

constructor

Deploys BullLeverageRouter with Morpho market configuration.

constructor(
    address _morpho,
    address _splitter,
    address _curvePool,
    address _usdc,
    address _plDxyBear,
    address _plDxyBull,
    address _stakedPlDxyBull,
    MarketParams memory _marketParams,
    address _sequencerUptimeFeed
) LeverageRouterBase(_morpho, _curvePool, _usdc, _plDxyBear);

Parameters

NameTypeDescription
_morphoaddressMorpho Blue protocol address.
_splitteraddressSyntheticSplitter contract address.
_curvePooladdressCurve USDC/plDXY-BEAR pool address.
_usdcaddressUSDC token address.
_plDxyBearaddressplDXY-BEAR token address.
_plDxyBulladdressplDXY-BULL token address.
_stakedPlDxyBulladdresssplDXY-BULL staking vault address.
_marketParamsMarketParamsMorpho market parameters for splDXY-BULL/USDC.
_sequencerUptimeFeedaddressChainlink L2 sequencer feed (address(0) on L1/testnet).

openLeverage

Open a Leveraged plDXY-BULL Position in one transaction.

Mints pairs via Splitter, sells plDXY-BEAR on Curve, deposits plDXY-BULL to Morpho. Uses fixed debt model (same as BEAR router) - Morpho debt equals principal * (leverage - 1).

function openLeverage(
    uint256 principal,
    uint256 leverage,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
principaluint256Amount of USDC user sends.
leverageuint256Multiplier (e.g. 3x = 3e18).
maxSlippageBpsuint256Maximum slippage tolerance in basis points (e.g., 50 = 0.5%). Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction.
minAmountOutuint256
deadlineuint256Unix timestamp after which the transaction reverts.

openLeverageWithPermit

Open a leveraged plDXY-BULL position with a USDC permit signature (gasless approval).

function openLeverageWithPermit(
    uint256 principal,
    uint256 leverage,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
principaluint256Amount of USDC user sends.
leverageuint256Multiplier (e.g. 3x = 3e18).
maxSlippageBpsuint256Maximum slippage tolerance in basis points.
minAmountOutuint256
deadlineuint256Unix timestamp after which the permit and transaction revert.
vuint8Signature recovery byte.
rbytes32Signature r component.
sbytes32Signature s component.

_openLeverageCore

function _openLeverageCore(
    uint256 principal,
    uint256 leverage,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline
) internal;

closeLeverage

Close a Leveraged plDXY-BULL Position in one transaction.

Uses a single plDXY-BEAR flash mint to unwind positions efficiently. Queries actual debt from Morpho to ensure full repayment even if interest accrued.

function closeLeverage(
    uint256 collateralToWithdraw,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
collateralToWithdrawuint256Amount of splDXY-BULL shares to withdraw from Morpho. NOTE: This is staked token shares, not underlying plDXY-BULL amount. Use STAKED_PLDXY_BULL.previewRedeem() to convert shares to underlying.
maxSlippageBpsuint256Maximum slippage tolerance in basis points. Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction.
minAmountOutuint256
deadlineuint256Unix timestamp after which the transaction reverts.

addCollateral

Add collateral to an existing leveraged position.

Uses Morpho flash loan so user’s USDC input ≈ collateral value added. Flow: Flash loan USDC → Mint pairs → Sell ALL BEAR to repay flash loan → Keep BULL as collateral. Formula: flashLoan = userUSDC × bearPrice / bullPrice

function addCollateral(
    uint256 usdcAmount,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
usdcAmountuint256Amount of USDC representing desired collateral value.
maxSlippageBpsuint256Maximum slippage tolerance in basis points. Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction.
minAmountOutuint256
deadlineuint256Unix timestamp after which the transaction reverts.

addCollateralWithPermit

Add collateral with a USDC permit signature (gasless approval).

function addCollateralWithPermit(
    uint256 usdcAmount,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
usdcAmountuint256Amount of USDC representing desired collateral value.
maxSlippageBpsuint256Maximum slippage tolerance in basis points.
minAmountOutuint256
deadlineuint256Unix timestamp after which the permit and transaction revert.
vuint8Signature recovery byte.
rbytes32Signature r component.
sbytes32Signature s component.

_addCollateralCore

function _addCollateralCore(
    uint256 usdcAmount,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline
) internal;

removeCollateral

Remove collateral from an existing leveraged position.

Uses flash mint of BEAR to redeem pairs, then buys back BEAR with USDC. Reverts if the resulting position would be unhealthy.

function removeCollateral(
    uint256 collateralToWithdraw,
    uint256 maxSlippageBps,
    uint256 minAmountOut,
    uint256 deadline
) external nonReentrant whenNotPaused;

Parameters

NameTypeDescription
collateralToWithdrawuint256Amount of splDXY-BULL shares to withdraw. NOTE: This is staked token shares, not underlying plDXY-BULL amount.
maxSlippageBpsuint256Maximum slippage tolerance in basis points. Capped at MAX_SLIPPAGE_BPS (1%) to limit MEV extraction.
minAmountOutuint256
deadlineuint256Unix timestamp after which the transaction reverts.

onMorphoFlashLoan

Morpho flash loan callback for USDC flash loans (OP_OPEN, OP_ADD_COLLATERAL).

function onMorphoFlashLoan(
    uint256 amount,
    bytes calldata data
) external override;

Parameters

NameTypeDescription
amountuint256Amount of USDC borrowed.
databytesEncoded operation parameters.

onFlashLoan

ERC-3156 flash loan callback for plDXY-BEAR flash mints.

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

Parameters

NameTypeDescription
initiatoraddressAddress that initiated the flash loan (must be this contract).
<none>address
amountuint256Amount of plDXY-BEAR borrowed.
feeuint256Flash loan fee (always 0 for SyntheticToken).
databytesEncoded operation parameters.

Returns

NameTypeDescription
<none>bytes32CALLBACK_SUCCESS on successful execution.

_executeOpen

Executes open leverage operation within Morpho flash loan callback.

function _executeOpen(
    uint256 loanAmount,
    bytes calldata data
) private;

Parameters

NameTypeDescription
loanAmountuint256Amount of USDC borrowed from Morpho.
databytesEncoded parameters (op, user, deadline, principal, leverage, targetDebt, maxSlippageBps, minSwapOut, minAmountOut).

_executeAddCollateral

Executes add collateral operation within Morpho flash loan callback.

function _executeAddCollateral(
    uint256 flashLoanAmount,
    bytes calldata data
) private;

Parameters

NameTypeDescription
flashLoanAmountuint256Amount of USDC flash loaned.
databytesEncoded parameters (op, user, deadline, usdcAmount, maxSlippageBps, minSwapOut, minAmountOut).

_executeClose

Executes close leverage operation within plDXY-BEAR flash mint callback.

function _executeClose(
    uint256 flashAmount,
    uint256 flashFee,
    bytes calldata data
) private;

Parameters

NameTypeDescription
flashAmountuint256Amount of plDXY-BEAR flash minted.
flashFeeuint256Flash mint fee (always 0).
databytesEncoded parameters (op, user, deadline, collateralToWithdraw, debtToRepay, borrowShares, extraBearForDebt, maxSlippageBps, minAmountOut).

_executeRemoveCollateral

Executes remove collateral operation within plDXY-BEAR flash mint callback.

function _executeRemoveCollateral(
    uint256 flashAmount,
    uint256 flashFee,
    bytes calldata data
) private;

Parameters

NameTypeDescription
flashAmountuint256Amount of plDXY-BEAR flash minted.
flashFeeuint256Flash mint fee (always 0).
databytesEncoded parameters (op, user, deadline, collateralToWithdraw, maxSlippageBps, minAmountOut).

previewOpenLeverage

Preview the result of opening a leveraged plDXY-BULL position.

BULL leverage requires a larger flash loan than BEAR because minting happens at CAP price, not market price. The flash loan is repaid by: bearSaleProceeds + morphoBorrow. Morpho debt still follows the fixed model: principal * (leverage - 1).

function previewOpenLeverage(
    uint256 principal,
    uint256 leverage
) external view returns (uint256 loanAmount, uint256 totalUSDC, uint256 expectedPlDxyBull, uint256 expectedDebt);

Parameters

NameTypeDescription
principaluint256Amount of USDC user will send.
leverageuint256Multiplier (e.g. 2x = 2e18).

Returns

NameTypeDescription
loanAmountuint256Amount of USDC to flash loan.
totalUSDCuint256Total USDC for minting pairs (principal + loan).
expectedPlDxyBulluint256Expected plDXY-BULL tokens received.
expectedDebtuint256Expected Morpho debt (fixed: principal * (leverage - 1)).

previewCloseLeverage

Preview the result of closing a leveraged plDXY-BULL position.

function previewCloseLeverage(
    uint256 debtToRepay,
    uint256 collateralToWithdraw
) external view returns (uint256 expectedUSDC, uint256 usdcForBearBuyback, uint256 expectedReturn);

Parameters

NameTypeDescription
debtToRepayuint256Amount of USDC debt to repay.
collateralToWithdrawuint256Amount of plDXY-BULL collateral to withdraw.

Returns

NameTypeDescription
expectedUSDCuint256Expected USDC from redeeming pairs.
usdcForBearBuybackuint256Expected USDC needed to buy back plDXY-BEAR.
expectedReturnuint256Expected USDC returned to user after all repayments.

previewAddCollateral

Preview the result of adding collateral.

Uses flash loan so user’s USDC input ≈ collateral value added.

function previewAddCollateral(
    uint256 usdcAmount
)
    external
    view
    returns (uint256 flashLoanAmount, uint256 totalUSDC, uint256 expectedPlDxyBull, uint256 expectedStakedShares);

Parameters

NameTypeDescription
usdcAmountuint256Amount of USDC representing desired collateral value.

Returns

NameTypeDescription
flashLoanAmountuint256Amount of USDC to flash loan.
totalUSDCuint256Total USDC for minting pairs.
expectedPlDxyBulluint256Expected plDXY-BULL tokens to receive.
expectedStakedSharesuint256Expected splDXY-BULL shares to receive.

previewRemoveCollateral

Preview the result of removing collateral.

function previewRemoveCollateral(
    uint256 collateralToWithdraw
)
    external
    view
    returns (
        uint256 expectedPlDxyBull,
        uint256 expectedUsdcFromBurn,
        uint256 usdcForBearBuyback,
        uint256 expectedReturn
    );

Parameters

NameTypeDescription
collateralToWithdrawuint256Amount of splDXY-BULL shares to withdraw.

Returns

NameTypeDescription
expectedPlDxyBulluint256Expected plDXY-BULL from unstaking.
expectedUsdcFromBurnuint256Expected USDC from burning pairs.
usdcForBearBuybackuint256Expected USDC needed to buy back flash-minted BEAR.
expectedReturnuint256Expected USDC returned to user.

_calculateOpenParams

Calculates parameters for opening a leveraged position.

function _calculateOpenParams(
    uint256 principal,
    uint256 leverage
) private view returns (OpenParams memory params);

_getValidatedOraclePrice

Returns validated oracle prices with staleness, sequencer, and CAP checks.

function _getValidatedOraclePrice() private view returns (uint256 bearPrice, uint256 bullPrice);

_estimateBearForUsdcSale

Estimates BEAR needed to sell for a target USDC amount using binary search on Curve.

function _estimateBearForUsdcSale(
    uint256 targetUsdc
) private view returns (uint256);

_estimateUsdcForBearBuyback

Estimates USDC needed to buy BEAR using binary search on Curve.

function _estimateUsdcForBearBuyback(
    uint256 bearAmount
) private view returns (uint256);

_binarySearchCurve

Binary search for minimum input to Curve such that get_dy(i, j, input) >= targetOut.

function _binarySearchCurve(
    uint256 i,
    uint256 j,
    uint256 oneUnit,
    uint256 targetOut
) private view returns (uint256);

Parameters

NameTypeDescription
iuint256Curve pool input index.
juint256Curve pool output index.
oneUnituint256One unit of the input token (1e18 for BEAR, 1e6 for USDC).
targetOutuint256Desired minimum output from the swap.

Returns

NameTypeDescription
<none>uint256Minimum input amount that produces at least targetOut.

Events

LeverageOpened

Emitted when a leveraged plDXY-BULL position is opened.

event LeverageOpened(
    address indexed user,
    uint256 principal,
    uint256 leverage,
    uint256 loanAmount,
    uint256 plDxyBullReceived,
    uint256 debtIncurred,
    uint256 maxSlippageBps
);

LeverageClosed

Emitted when a leveraged plDXY-BULL position is closed.

event LeverageClosed(
    address indexed user,
    uint256 debtRepaid,
    uint256 collateralWithdrawn,
    uint256 usdcReturned,
    uint256 maxSlippageBps
);

CollateralAdded

Emitted when collateral is added to a position.

Net USDC cost = usdcAmount - usdcReturned (BEAR sale proceeds returned to user).

event CollateralAdded(
    address indexed user, uint256 usdcAmount, uint256 usdcReturned, uint256 collateralAdded, uint256 maxSlippageBps
);

CollateralRemoved

Emitted when collateral is removed from a position.

event CollateralRemoved(
    address indexed user, uint256 collateralWithdrawn, uint256 usdcReturned, uint256 maxSlippageBps
);

Structs

OpenParams

struct OpenParams {
    uint256 targetDebt;
    uint256 loanAmount;
    uint256 tokensToMint;
    uint256 expectedBearSale;
}