Leverage
Overview
Leveraged positions in Curvance allow users to increase their exposure to certain assets by borrowing additional capital against their collateral. This documentation explains the core mechanics, data flows, and components involved in creating leveraged positions.
Core Concepts
Position Types
Curvance supports leverage through concrete PositionManager implementations:
SimplePositionManager: generic non-native ERC20 positions, such as major or stablecoin assets.PendlePTPositionManager: Pendle principal-token positions.SingleSidedVaultPositionManager,DualSidedVaultPositionManager,NativeVaultPositionManager:vault and native-vault position paths.
Key Components
The leverage system involves several interconnected components:
BasePositionManager: shared entrypoints, callback handling, delegation checks, reentrancy protection, pre/post account-value slippage checks, and protocol fee handling.Concrete PositionManagers: asset-specific hooks that convert the borrowed asset into the collateral-side asset or protocol receipt token.
MarketManager: market listing, PositionManager authorization, collateral caps, debt caps, account liquidity, borrow pauses, and terminal borrow validation.cTokens and
BorrowableCToken: live cTokens share the same underlying implementation family. A cToken can receive deposits and collateral, and it is borrowable in a market only whenmarketManager.debtCaps(cToken) > 0.SwapperLibandCentralRegistry: approved external swap calldata, swap-level value checks, and protocol configuration such asprotocolLeverageFee().
Leverage Flow

1. Initial Deposit and Request Flow
For a new position, depositAndLeverage(assets, action, slippage) pulls the initial underlying asset from the caller, calls action.cToken.depositAsCollateral(assets, msg.sender), and then executes the leverage leg.
For an existing position, leverage(action, slippage) adds debt and collateral without a fresh initial deposit. The account still needs enough posted collateral in the same isolated market for the terminal borrow check to pass.
For delegated execution, leverageFor(action, account, slippage) requires the account to approve the caller on the PositionManager contract being used.
3. Validation & Maximum Borrowing
There is no public _maxRemainingLeverageOf(account, borrowToken) function in the protocol contracts. For pre-trade sizing, integrators can use ProtocolReader.hypotheticalLeverageOf(account, cToken, borrowableCToken, assets, bufferTime), which returns the current leverage, theoretical max leverage, adjusted max leverage, maximum debt amount, loan-size error flag, and oracle-error flag.
Execution is still enforced by the contracts. BasePositionManager calls borrowForPositionManager, the borrowed cToken checks that the caller is an enabled PositionManager, accrues interest, notifies the hold-period cooldown, borrows to the PositionManager, runs the callback, and then calls marketManager.canBorrow(...) for the terminal position. Debt caps, borrow pauses, account liquidity, and available cToken liquidity can still make the transaction revert.
4. Token Borrowing
The system borrows tokens from the specified BorrowableCToken through a callback pattern:
5. Asset Conversion
Depending on the token type, different specialized swapping mechanisms are used:
Simple Tokens: Direct swaps through external DEXs.
Vault Tokens: If a collateral cToken is a vault, and the borrowed cToken is a simple ERC20, the manager converts the borrowed asset into the vault deposit asset, deposits into the vault, and then deposits the minted vault receipt tokens into
action.cTokenas collateral. If the borrowed asset already matches the vault underlying, the swap is skipped. Native vaults unwrapwrappedNative, or swap into the native token, before depositing.Pendle PT Tokens: validates the supplied Pendle market, optionally pre-swaps the borrowed asset into
pendleAction.input.tokenIn, and uses the Pendle Router to mint PT tokens. The resulting PT balance is deposited intoaction.cTokenas collateral.
Each implementation handles the specific logic required for that token type.
Asset-Specific Flows
Simple Token Leverage
Simple ERC20 leverage uses SimplePositionManager. The borrowed asset and target collateral asset must be different, and the manager requires one external swap whose inputToken is the debt asset, outputToken is action.cToken.asset(), and inputAmount equals the post-fee action.borrowAssets. The resulting collateral asset balance is deposited into action.cToken as collateral for the owner.
Vault Token Leverage
Vault token leverage is handled by vault-specific PositionManagers. The leverage path depends on whether the vault deposit asset is an ERC20 underlying or the chain's native token.
Pendle PT Token Leverage
Pendle PT leverage uses PendlePTPositionManager. auxData decodes as (address lpToken, uint256 minPtAmount, PendleLib.PendleAction pendleAction). If a Curvance external swap is provided, its output must match pendleAction.input.tokenIn, and the manager enters the PT path through PendleLib._enterPendle(..., true, ...).
Protocol Fees
When leveraging, the base callback applies centralRegistry.protocolLeverageFee() to the borrowed amount before the manager-specific conversion path runs:
The fee is BPS-denominated, not WAD-denominated, and it is transferred to centralRegistry.daoAddress(). For the simple ERC20 path, swapAction.inputAmount must match the net post-fee amount, because SimplePositionManager compares swapAction.inputAmount against the mutated action.borrowAssets.
Slippage Protection
Leverage has several slippage and sanity checks:
checkSlippage(account, slippage)compares the account's collateral-minus-debt value before and after the action usingmarketManager.statusOf(account). The contract comments describe this as a sanity check, not the user's only slippage protection.SwapperLib._swapSafevalidates the external swap target through the Central Registry calldata checker, enforces the calldata checker's minimum output, and compares oracle-priced input and output value againstswapAction.slippage.action.expectedSharesis enforced after the converted collateral asset is deposited intoaction.cToken.
Security Considerations
Position Monitoring
Leveraged positions increase risk exposure and should be monitored closely for:
Price movements that could trigger liquidations.
Changes in market conditions affecting collateral value.
Available liquidity for potential deleveraging.
Permission Management
Delegated leverage is checked on the PositionManager being called. leverageFor(action, account, slippage) calls _checkDelegate(account, msg.sender), so the account must approve the caller on that PositionManager with setDelegateApproval(delegate, true).
Users can revoke that PositionManager-specific approval with setDelegateApproval(delegate, false). They can also mass-revoke prior delegate approvals across Curvance contracts by calling centralRegistry.incrementApprovalIndex().
Integration Points
When integrating with the leverage system, consider:
Providing clear slippage parameters to protect users.
Understanding the specific asset type and its leverage implementation.
Ensuring sufficient collateral to avoid immediate liquidation risk.
Monitoring gas costs, which vary based on the complexity of the leverage operation.
By understanding these core mechanics, developers can effectively integrate with and extend Curvance's leveraged position capabilities.
User Interaction Functions
Leverage Functions
depositAndLeverage()
Description: Deposits underlying assets into action.cToken as collateral and then leverages the position to increase both collateral and debt. Includes the checkSlippage sanity check. The caller must ERC20-approve the PositionManager to pull the initial underlying assets; cToken delegate approval is not required for this pre-deposit path because depositAsCollateral explicitly allows enabled PositionManager contracts to deposit for the receiver.
Contract: PositionManagement
Function signature:
uint256
assets
The amount of the underlying assets to deposit.
LeverageStruct
leverageData
Structure containing leverage operation details including borrow token, amount, position token, swap data, and auxiliary data.
uint256
slippage
Slippage accepted by the user for the leverage action, in WAD (1e18).
Events:
leverage()
Description: Leverages an existing Curvance position to increase both collateral and debt. Includes slippage protection through the checkSlippage modifier.
Contract: PositionManagement
Function signature:
LeverageStruct
leverageData
Structure containing leverage operation details including borrow token, amount, position token, swap data, and auxiliary data.
uint256
slippage
Slippage accepted by the user for the leverage action, in WAD (1e18).
Events:
leverageFor()
Description: Leverages an existing Curvance position on behalf of another account via delegation. Includes slippage protection through the checkSlippage modifier. Requires delegation approval from the account being leveraged for.
Contract: PositionManagement
Function signature:
LeverageStruct
leverageData
Structure containing leverage operation details including borrow token, amount, position token, swap data, and auxiliary data.
address
account
The account to leverage an active Curvance position for.
uint256
slippage
Slippage accepted by the user for the leverage action, in WAD (1e18).
Events:
Last updated
Was this helpful?