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 Variables
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
EXCHANGE_RATE_BUFFER_BPS
Buffer for exchange rate drift between previewRedeem and redeem (1%).
Protects against DoS attacks via yield donation front-running.
uint256 public constant EXCHANGE_RATE_BUFFER_BPS = 100
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
) 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. |
openLeverage
Open a Leveraged plDXY-BULL Position in one transaction.
Mints pairs via Splitter, sells plDXY-BEAR on Curve, deposits plDXY-BULL to Morpho.
function openLeverage(
uint256 principal,
uint256 leverage,
uint256 maxSlippageBps,
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. |
deadline | uint256 | Unix timestamp after which the transaction reverts. |
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 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. |
deadline | uint256 | Unix timestamp after which the transaction reverts. |
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). |
_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.
Used for shares-based repayment to avoid Morpho edge case when repaying exact debt.
function _getBorrowShares(
address user
) internal view returns (uint256);
_marketId
Computes market ID from marketParams.
function _marketId() internal view returns (bytes32);
onMorphoFlashLoan
Morpho flash loan callback for USDC flash loans (OP_OPEN only).
function onMorphoFlashLoan(
uint256 amount,
bytes calldata data
) external override;
Parameters
| Name | Type | Description |
|---|---|---|
amount | uint256 | Amount of USDC borrowed. |
data | bytes | Encoded open operation parameters. |
onFlashLoan
ERC-3156 flash loan callback for plDXY-BEAR flash mints (OP_CLOSE only).
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 close 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, maxSlippageBps, minSwapOut). |
_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). |
previewOpenLeverage
Preview the result of opening a leveraged plDXY-BULL position.
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. 3x = 3e18). |
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 (flash repayment - USDC from plDXY-BEAR sale). |
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. |
_estimateUsdcForBearBuyback
Estimates USDC needed to buy BEAR using binary search on Curve.
function _estimateUsdcForBearBuyback(
uint256 bearAmount
) private view returns (uint256);
Parameters
| Name | Type | Description |
|---|---|---|
bearAmount | uint256 | Target plDXY-BEAR amount to acquire. |
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | Estimated USDC needed (with slippage margin). |
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
);