Curvance
  • Protocol Overview
    • Click Less, Earn More
    • Protocol Architecture
    • Asset Types
    • Liquidity Markets
      • Borrowing
      • Liquidations
      • Interest Rates
      • Oracles
      • Collateral Caps
      • Bad Debt Socialization
    • Application Specific Sequencing
    • New Age Liquidity Mining
      • Protocols
    • How Are New Assets Integrated
    • Plugin System
    • Universal Account Balance
    • Token Approval Management
    • Lending Risks
  • Security
    • Security and Audits
  • Miscellaneous
    • RPCs and Testnet Stability
    • Glossary
    • TL;DR
      • Customer Types and Benefits
    • Brand Assets
    • Weblinks
    • Disclaimer
    • Frequently Asked Questions
  • Developer Docs
    • Overview
    • Quick Start Guides
      • Atlas Fastlane Auctions (coming soon)
      • Plugin Integration
        • List of Delegable Actions
      • Loans & Collateral
        • Lend Assets
        • Deposit into pTokens
        • Withdraw Loans
        • Withdraw pTokens
      • Borrowing & Repayment
        • Borrow
        • Repaying Debt
      • Leverage
        • Leveraging
        • Deleveraging
    • Lending Protocol
      • Market Manager
      • Position Tokens (pToken)
      • Earn Tokens (eTokens)
      • Dynamic Interest Rate Model
      • Universal Balance
    • Position Management
      • Leverage
      • Deleverage / Fold
    • Dynamic Liquidation Engine (DLE)
      • Orderflow Auction System
      • Bad Debt Socialization
    • Plugin & Delegation System
      • Transfer Lock Mechanism
      • Delegable Actions
    • Cross-Chain Functionality
      • Messaging Hub
      • Fee Manager
      • Reward Manager
    • Auxiliary Functionality
Powered by GitBook
On this page
  • Core Structures for Leveraging
  • Pre, Post, and Auxiliary Swap Operations
  • Setting Up Your Environment
  • Monitoring Position Health
Export as PDF
  1. Developer Docs
  2. Quick Start Guides

Leverage

PreviousRepaying DebtNextLeveraging

Last updated 9 days ago

Leveraging in Curvance allows users to amplify their position by borrowing assets against their collateral and reinvesting them. This creates a more capital-efficient position with greater exposure to underlying assets. Curvance's leveraging system is built on its powerful Position Management framework, which simplifies complex DeFi operations into single, atomic transactions. This eliminates the manual loop of borrowing, swapping, and depositing that would otherwise be required to build leveraged positions.

For those that want to dive deep into the inner workings of our leverage system, check out our Position Management page here:

Core Structures for Leveraging

To understand leveraging in Curvance, you need to be familiar with two key data structures that control the leverage and deleverage operations:

LeverageStruct

struct LeverageStruct {
    IEToken borrowToken;       // The eToken you want to borrow from
    uint256 borrowAmount;      // Amount of underlying tokens to borrow
    IPToken positionToken;     // The pToken to deposit borrowed funds into
    SwapperLib.Swap swapData;  // Instructions for swapping borrowed tokens
    bytes auxData;             // Optional protocol-specific data
}

DeleverageStruct

struct DeleverageStruct {
    IPToken positionToken;       // The pToken you're unwinding
    uint256 collateralAmount;    // Amount of pTokens to redeem
    IEToken borrowToken;         // The eToken debt to repay
    SwapperLib.Swap[] swapData;  // Array of swaps to execute
    uint256 repayAmount;         // Amount of debt to repay
    bytes auxData;               // Optional protocol-specific data
}

SwapperLib.Swap

Both structures use the SwapperLib.Swap structure to handle token swaps:

struct Swap {
    address target;        // Swap router address
    address inputToken;    // Token being swapped from
    address outputToken;   // Token being swapped to
    uint256 inputAmount;   // Amount to swap
    bytes call;            // Encoded swap call data
}

Important Note: LeverageStruct takes a single Swap while DeleverageStruct takes an array of Swap operations, allowing for multi-hop swaps when deleveraging.

Pre, Post, and Auxiliary Swap Operations

Pre-Swap when Leveraging

When leveraging, a swap is executed to obtain the collateral asset using the borrowed asset. You must provide the appropriate calldata hex string in the Swap.call struct member. Additionally, ensure the swap's receiver is set to the corresponding PositionManager contract.

Post-Swap when Deleveraging

During deleveraging, a swap is performed to exchange the collateral asset for the borrowed asset. You need to supply the correct calldata hex string in the Swap.call struct member. Also, make sure the swap's receiver is configured as the relevant PositionManager contract.

Auxiliary Swap for Complex Assets

When leveraging or deleveraging exotic assets, you may need to include auxiliary data to initiate the position. For instance, to enter a Pendle PT position, you must provide swap data to exchange the borrowed asset for Pendle PT via Pendle’s internal exchange.

Below is a code snippet demonstrating how to prepare this data:

const PendleData = {
    approx: {
        guessMin: ethers.utils.parseUnits("9.9", 18),
        guessMax: ethers.utils.parseUnits("10.0", 18),
        guessOffchain: ethers.utils.parseUnits("1.0", 18),
        maxIteration: 30,
        eps: ethers.utils.parseUnits("0.001", 18)
    },
    input: {
        tokenIn: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC address
        netTokenIn: ethers.utils.parseUnits(estimatedUniswapOutputAmount.toString(), 18),
        tokenMintSy: "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84", // STETH address
        pendleSwap: "0x1e8b6Ac39f8A33f46a6Eb2D1aCD1047B99180AD1", // PENDLE_SWAP address
        swapData: {
            swapType: 1, // KYBERSWAP enum value
            extRouter: "0x6131B5fae19EA4f9D964eAc0408E4408b66337b5",
            extCalldata: "0xe21fd0e9...", // The calldata hex string
            needScale: false
        }
    }
};

// Create the leverage data object
const leverageData = {
    borrowToken: eDAIAddress,
    borrowAmount: ethers.utils.parseUnits(amountForLeverage.toString(), 18),
    positionToken: pPendlePTAddress,
    auxData: null,
    swapData: swapData
};

// Encode the data
leverageData.auxData = ethers.utils.defaultAbiCoder.encode(
    [
        "tuple(tuple(uint256 guessMin, uint256 guessMax, uint256 guessOffchain, uint256 maxIteration, uint256 eps) approx, tuple(address tokenIn, uint256 netTokenIn, address tokenMintSy, address pendleSwap, tuple(uint8 swapType, address extRouter, bytes extCalldata, bool needScale) swapData) input)",
        "address",
        "uint256"
    ],
    [
        [
            [
                PendleData.approx.guessMin,
                PendleData.approx.guessMax,
                PendleData.approx.guessOffchain,
                PendleData.approx.maxIteration,
                PendleData.approx.eps
            ],
            [
                PendleData.input.tokenIn,
                PendleData.input.netTokenIn,
                PendleData.input.tokenMintSy,
                PendleData.input.pendleSwap,
                [
                    PendleData.input.swapData.swapType,
                    PendleData.input.swapData.extRouter,
                    PendleData.input.swapData.extCalldata,
                    PendleData.input.swapData.needScale
                ]
            ]
        ],
        lpStethAddress,
        1
    ]
);

Setting Up Your Environment

Before interacting with Curvance, set up your development environment:

const { ethers } = require('ethers');

// Initialize provider and signer
const provider = new ethers.providers.JsonRpcProvider('YOUR_RPC_URL');
const signer = new ethers.Wallet('YOUR_PRIVATE_KEY', provider);

// Contract addresses
const MARKET_MANAGER = '0x...';
const POSITION_MANAGEMENT = '0x...';
const P_TOKEN = '0x...'; // Your collateral token
const E_TOKEN = '0x...'; // Your borrow token

// Initialize contracts
const marketManager = new ethers.Contract(
  MARKET_MANAGER,
  ['function statusOf(address) view returns (uint256, uint256, uint256)'],
  provider
);

const positionManagement = new ethers.Contract(
  POSITION_MANAGEMENT,
  [
    'function depositAndLeverage(uint256, tuple(address,uint256,address,tuple(address,address,address,uint256,bytes),bytes), uint256)',
    'function leverage(tuple(address,uint256,address,tuple(address,address,address,uint256,bytes),bytes), uint256)',
    'function deleverage(tuple(address,uint256,address,tuple[](address,address,address,uint256,bytes),uint256,bytes), uint256)'
  ],
  signer
);

Monitoring Position Health

Maintaining a healthy leverage ratio is crucial to avoid liquidation. Regularly check your position's health by using liquidationStatusOf() in the MarketManager contract. The function returns the lFactor and current prices for the specified tokens.

Function arguments:

Type
Name
Description

address

account

The account to check liquidation status for.

address

earnToken

The eToken (debt token) to be repaid during potential liquidation.

address

positionToken

The pToken (collateral token) to be seized during potential liquidation.

Which returns a tuple:

Type
Description

uint256

lFactor - Account's current liquidation factor. A value of 0 indicates a healthy position. A value between 0 and 1e18 (WAD) indicates a soft liquidation state. A value of 1e18 (WAD) indicates a hard liquidation state.

uint256

earnTokenPrice - Current price for the earnToken (debt token).

uint256

positionTokenPrice - Current price for the positionToken (collateral token).

// Get position status
const [lFactor, earnTokenPrice, pTokenPrice] = await marketManager.liquidationStatusOf(wallet.address, eToken_Address, pToken_Address);

// Check if position is at risk 
if (status.gt(ethers.utils.parseUnits('0', 18))) {
  console.log('⚠️ WARNING: Position at risk of liquidation!');
}

Position Management