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
  • Overview
  • Core Architecture
  • State and Data Model
  • Data Flow
  • Interest Accrual Mechanism
  • Exchange Rate Calculation
  • Integration with Market Manager
  • Safety Features
  • Protocol Revenue
  • User Interaction Functions
  • Share/Assets
  • Mint Functions (Depositing Assets)
  • Redeem Functions (Withdrawing Assets)
  • Borrow Functions
  • Repay Functions
  • Interest Accrual Mechanism
  • Exchange Rate Calculation
  • Safe Functions for External Integration
  • Debt Tracking
  • Market Utilization and Rates
Export as PDF
  1. Developer Docs
  2. Lending Protocol

Earn Tokens (eTokens)

Overview

Earn Tokens (eTokens) are Curvance's lending market tokens that enable users to earn interest on deposited assets. eTokens function similarly to interest-bearing tokens in other lending protocols but with a focus on enhanced security and flexibility. Users who deposit underlying assets receive eTokens representing their share of the lending pool, which increase in value as borrowers pay interest.

Core Architecture

eTokens operate within a network of contracts:

  • EToken: The core implementation of the Earn Token functionality.

  • ETokenWithGauge: Extension that integrates with Curvance's Gauge system for additional rewards.

  • MarketManager: Manages risk parameters, collateral requirements, and market health.

  • CentralRegistry: Provides protocol-wide configuration and permissions.

  • InterestRateModel: Determines interest rates based on market utilization.

State and Data Model

eTokens maintain several key state variables:

// User balances
mapping(address => uint256) public balanceOf;

// Debt tracking
mapping(address => DebtData) internal _debtOf;

// Market state
MarketData public marketData; 
uint256 public totalBorrows; 
uint256 public totalReserves; 
uint256 public totalSupply;

// Structures

// Data for a market. 
struct MarketData {
    uint40 lastTimestampUpdated;
    uint216 exchangeRate;
    uint256 compoundRate;
}

// Data for a user's debt. 
struct DebtData {
    uint256 principal;
    uint256 accountExchangeRate;
}

The exchangeRate is a critical parameter that determines the conversion between eTokens (shares) and underlying assets. It increases over time as interest accrues, allowing eToken holders to claim more underlying assets for the same number of tokens.

Data Flow

Deposit Flow

  1. User calls mint() with underlying assets.

  2. Contract accrues any pending interest.

  3. Contract calculates shares based on current exchange rate.

  4. Underlying tokens are transferred from the user to the contract.

  5. eTokens are minted to the user.

  6. MarketManager is notified of the deposit (if needed).

Withdrawal Flow

  1. User calls redeem() with eTokens.

  2. Contract accrues any pending interest.

  3. Contract calculates assets based on current exchange rate.

  4. Underlying tokens are transferred from the contract to the user.

  5. eTokens are burned.

  6. MarketManager is notified of the withdrawal.

Borrowing Flow

  1. User must first deposit collateral into a pToken.

  2. User calls borrow() on an eToken.

  3. Contract accrues any pending interest.

  4. MarketManager checks if user has sufficient collateral.

  5. Debt is recorded for the user.

  6. Underlying tokens are transferred to the user.

Repayment Flow

  1. User calls repay() or repayFor() .

  2. Contract accrues any pending interest.

  3. Current debt is calculated.

  4. Underlying tokens are transferred from the user to the contract.

  5. User's debt is reduced or eliminated.

  6. MarketManager is updated regarding the user's position.

Interest Accrual Mechanism

Interest accrual is a key feature of eTokens, handled through the accrueInterest() function:

  • Time elapsed since last update is calculated.

  • InterestRateModel determines appropriate interest rate based on market utilization.

  • Interest is applied to total borrows.

  • A portion of interest (determined by interestFactor) is allocated to protocol reserves.

  • Exchange rate is updated, increasing the value of all eTokens.

This process occurs automatically when users interact with any of the main functions, ensuring up-to-date state before transactions execute.

Exchange Rate Calculation

The exchange rate is calculated by:

exchangeRate = (marketUnderlyingHeld + totalBorrows) * WAD / (totalSupply + totalReserves)

This rate determines how many underlying tokens each eToken is worth and increases over time as interest accrues.

Integration with Market Manager

eTokens work closely with the MarketManager, which:

  1. Defines which assets can be used as collateral (pTokens).

  2. Sets borrowing parameters like collateral factor and liquidation threshold.

  3. Authorizes borrowing based on user's collateral.

  4. Manages the liquidation process for underwater positions.

  5. Enforces market-wide caps and security measures.

Safety Features

eTokens incorporate multiple security features:

  1. Reentrancy protection on all critical functions.

  2. Safe variants of functions for external protocol integration.

  3. Accrual of interest before any state-changing operations.

  4. Minimum hold periods to prevent flash loan attacks.

  5. Multiple layer validation for borrowing and collateralization.

Protocol Revenue

The eToken contracts generate protocol revenue through:

  1. Interest Factor: A portion of all interest paid by borrowers goes to protocol reserves.

  2. These reserves can be withdrawn by the DAO using processWithdrawReserves() .

  3. For eTokens with gauges, additional rewards may be distributed to depositors based on their contribution.

User Interaction Functions

Share/Assets

convertToShares()

Contract: eToken

Description: Converts an amount of underlying assets to equivalent eToken shares using the current exchange rate.

Function signature:

function convertToShares(uint256 amount) public view returns (uint256)
Type
Name
Description

uint256

amount

The number of underlying tokens to theoretically convert to eTokens

Return data:

Type
Description

uint256

The number of eTokens a user would receive for the given amount of underlying


convertToAssets()

Contract: eToken

Description: Converts an amount of eToken shares to equivalent underlying assets using the current exchange rate.

Function signature:

function convertToAssets(uint256 tokens) public view returns (uint256) 
Type
Name
Description

uint256

tokens

The number of eToken shares to theoretically convert to underlying assets

Return data:

Type
Description

uint256

The number of underlying assets the user would receive for redeeming shares


Mint Functions (Depositing Assets)

mint()

Contract: eToken

Description: Users deposit underlying assets into the market and receive eTokens in return.

Function signature:

function mint(uint256 amount) external returns (uint256)
Type
Name
Description

uint256

amount

The amount of the underlying asset to deposit

Return Data:

Type
Description

uint256

The amount of eTokens minted

Events:

// From EToken
// Emitted from EToken and underlying asset.
event Transfer(address indexed from, address indexed to, uint256 value);
// Only emitted if interest needs to be approved.
event InterestAccrued(
    uint256 debtAccumulated,
    uint256 exchangeRate,
    uint256 totalBorrows
);

mintfor()

Contract: eToken

Description: Deposits underlying assets into the market, and recipient receives eTokens.

Function signature:

function mintFor(uint256 amount, address recipient) external returns (uint256)
Type
Name
Description

uint256

amount

The amount of the underlying asset to deposit

address

recipient

The account that should receive the eTokens

Return data:

Type
Description

uint256

The amount of eTokens minted

Events:

// From EToken
// Emitted from EToken and underlying asset.
event Transfer(address indexed from, address indexed to, uint256 value);
// Only emitted if interest needs to be approved.
event InterestAccrued(
    uint256 debtAccumulated,
    uint256 exchangeRate,
    uint256 totalBorrows
);

Redeem Functions (Withdrawing Assets)

redeem()

Contract: eToken

Description: Redeems eTokens in exchange for the underlying asset

Function signature:

function redeem(uint256 tokens, address recipient) external returns (uint256)
Type
Name
Description

uint256

tokens

The number of eTokens to redeem for underlying tokens

address

recipient

The account who will receive the underlying assets

Return data:

Type
Description

uint256

The amount of underlying asset redeemed

Events:

// From EToken
// Emitted from EToken and underlying asset.
event Transfer(address indexed from, address indexed to, uint256 value);
// Only emitted if interest needs to be approved.
event InterestAccrued(
    uint256 debtAccumulated,
    uint256 exchangeRate,
    uint256 totalBorrows
);
// From MarketManager
// Only emitted if positions need to be closed
event PositionAdjusted(address mToken, address account, bool open);

redeemFor()

Contract: eToken

Description: Used by a delegated user to redeem eTokens in exchange for the underlying asset, on behalf of account.

Function signature:

function redeemFor(
    uint256 tokens, 
    address recipient, 
    address account) external returns (uint256)

Return data:

Type
Description

uint256

The amount of underlying asset redeemed

Events:

// From EToken
// Emitted from EToken and underlying asset.
event Transfer(address indexed from, address indexed to, uint256 value);
// Only emitted if interest needs to be approved.
event InterestAccrued(
    uint256 debtAccumulated,
    uint256 exchangeRate,
    uint256 totalBorrows
);
// From MarketManager
// Only emitted if positions need to be closed
event PositionAdjusted(address mToken, address account, bool open);

Borrow Functions

borrow()

Contract: eToken

Description: Borrows underlying tokens from lenders, based on collateral posted inside this market.

Function signature:

function borrow(uint256 amount) external
Type
Name
Description

uint256

amount

The amount of the underlying asset to borrow

Event:

// From EToken
event Borrow(address account, uint256 amount);
// Emitted from EToken and underlying ERC20 asset.
event Transfer(address indexed from, address indexed to, uint256 value);
// Only emitted if interest needs to be accrued.
event InterestAccrued(
    uint256 debtAccumulated,
    uint256 exchangeRate,
    uint256 totalBorrows
);
// From MarketManager
// Only emitted if interest needs to be accrued.
event InterestAccrued(
    uint256 debtAccumulated,
    uint256 exchangeRate,
    uint256 totalBorrows
);
// Potentially emitted multiple times, if this is the first time borrowing this eToken,
// and for any positions that need to be closed after borrowing.
event PositionAdjusted(address mToken, address account, bool open);

borrowFor()

Contract: eToken

Description: Used by a delegated user to borrow underlying tokens from lenders, based on collateral posted inside this market by account

Function signature:

function borrowFor(
        address account,
        address recipient,
        uint256 amount
    ) external nonReentrant
Type
Name
Description

address

account

The account who will have their assets borrowed against

address

recipient

The account who will receive the borrowed assets

uint256

amount

The amount of the underlying asset to borrow

Event:

// From EToken
event Borrow(address account, uint256 amount);
// Emitted from EToken and underlying ERC20 asset.
event Transfer(address indexed from, address indexed to, uint256 value);
// Only emitted if interest needs to be accrued.
event InterestAccrued(
    uint256 debtAccumulated,
    uint256 exchangeRate,
    uint256 totalBorrows
);
// From MarketManager
// Only emitted if interest needs to be accrued.
event InterestAccrued(
    uint256 debtAccumulated,
    uint256 exchangeRate,
    uint256 totalBorrows
);
// Potentially emitted multiple times, if this is the first time borrowing this eToken,
// and for any positions that need to be closed after borrowing.
event PositionAdjusted(address mToken, address account, bool open);

Repay Functions

repay()

Contract: eToken

Description: Repays underlying tokens to lenders, freeing up their collateral posted inside this market and updates interest before executing the repayment.

Function signature:

function repay(uint256 amount) external nonReentrant
Type
Name
Description

uint256

amount

The amount of the underlying asset to repay, or 0 for the full outstanding amount

Event:

// From EToken
event Repay(address payer, address account, uint256 amount);
// Only emitted if interest needs to be accrued.
event InterestAccrued(
    uint256 debtAccumulated,
    uint256 exchangeRate,
    uint256 totalBorrows
);
// Emitted from underlying ERC20 asset transfer.
event Transfer(address indexed from, address indexed to, uint256 value);
// From MarketManager
// Potentially emitted if a position is fully closed.
event PositionAdjusted(address mToken, address account, bool open);

repayFor()

Contract: eToken

Description: Repays underlying tokens to lenders, on behalf of account, freeing up their collateral posted inside this market.

Function signature:

function repayFor(address account, uint256 amount) external nonReentrant
Type
Name
Description

address

account

The account address to repay on behalf of.

uint256

amount

The amount to repay, or 0 for the full outstanding amount.

Event:

// From EToken
event Repay(address payer, address account, uint256 amount);
// Only emitted if interest needs to be accrued.
event InterestAccrued(
    uint256 debtAccumulated,
    uint256 exchangeRate,
    uint256 totalBorrows
);
// Emitted from underlying ERC20 asset transfer.
event Transfer(address indexed from, address indexed to, uint256 value);
// From MarketManager
// Potentially emitted if a position is fully closed.
event PositionAdjusted(address mToken, address account, bool open);

Interest Accrual Mechanism

Interest is accrued on borrowed assets and distributed to eToken holders through the increasing exchange rate. The accrual process is managed by the accrueInterest function.

accrueInterest()

Contract: eToken

Function signature:

function accrueInterest() public

This function:

  1. Calculates time elapsed since the last interest accrual.

  2. Fetches the current interest rate from the interest rate model.

  3. Computes the interest amount based on current total borrows.

  4. Updates total borrows with the new interest.

  5. Allocates a portion of interest to protocol reserves based on the interestFactor.

  6. Updates the exchange rate to reflect the new value of each eToken.

Interest accrues automaically when users interact with the protocol (mint, redeem, borrow, repay) as these functions call accrueInterest internally.

Events:

// Only emitted if interest needs to be accrued.
event InterestAccrued(
    uint256 debtAccumulated,
    uint256 exchangeRate,
    uint256 totalBorrows
);

Exchange Rate Calculation

exchangeRateWithUpdate()

Contract: eToken

Description: Returns the current exchange rate after updating interest, used to determine how many underlying tokens each eToken is worth:

Function signature:

function exchangeRateWithUpdate() external returns (uint256)

Return data:

Type
Description

uint256

Calculated exchange rate, in WAD.

Events:

// Only emitted if interest needs to be accrued.
event InterestAccrued(
    uint256 debtAccumulated,
    uint256 exchangeRate,
    uint256 totalBorrows
);

Safe Functions for External Integration

Curvance provides safe versions of key functions with additional reentrancy protection. These should be used when integrating with external protocols to minimize security risks.

exchangeRateWithUpdateSafe()

Contract: eToken

Description: Updates pending interest and returns the up-to-date exchange rate from the underlying to the eToken, with inherent reentrancy protection.

Function signature:

function exchangeRateWithUpdateSafe() public nonReentrant returns (uint256)

Return data:

Type
Description

uint256

Calculated exchange rate, in WAD.

Event:

// Only emitted if enough time has passed since the last interest accrual
event InterestAccrued(
    uint256 debtAccumulated,
    uint256 exchangeRate,
    uint256 totalBorrows
);

balanceOfUnderlyingSafe()

Contract: eToken

Description: Updates pending interest and returns the up-to-date balance of account, in underlying assets, with inherent reentrancy protection.

Function signature:

function balanceOfUnderlyingSafe(
    address account
) external returns (uint256) {

Return data:

Type
Description

uint256

The amount of underlying owned by account.

Event:

// Only emitted if enough time has passed since the last interest accrual
event InterestAccrued(
    uint256 debtAccumulated,
    uint256 exchangeRate,
    uint256 totalBorrows
);

debtBalanceWithUpdateSafe()

Contract: eToken

Description: Updates pending interest and returns the current debt balance for account with inherent reentrancy protection.

Function signature:

    function debtBalanceWithUpdateSafe(
        address account
    ) external nonReentrant returns (uint256)

Return data:

Type
Description

uint256

The current balance index of account, with pending interest applied.

Event:

// Only emitted if enough time has passed since the last interest accrual
event InterestAccrued(
    uint256 debtAccumulated,
    uint256 exchangeRate,
    uint256 totalBorrows
);

Debt Tracking

debtBalanceCached()

Contract: eToken

Description: Returns the current debt balance for a given account without accruing interest. This is a gas-efficient view function that uses the cached exchange rate.

Function signature:

function debtBalanceCached(address account) public view returns (uint256)
Type
Name
Description

address

account

The address whose debt balance should be calculated

Return data:

Type
Description

uint256

The current balance of debt for the account


debtBalanceAtTimestamp()

Contract: eToken

Description: Returns the estimated future debt balance for an account at a specific timestamp, assuming interest rates remain constant.

Function signature:

function debtBalanceAtTimestamp(
    address account, 
    uint256 timestamp) public view returns (uint256)
Type
Name
Description

address

account

The address whose debt balance should be calculated

uint256

timestamp

The unix timestamp to calculate the account's debt balance with

Return data:

Type
Description

uint256

The estimated debt balance at the specified timestamp


Market Utilization and Rates

getBorrowRatePerYear()

Contract: eToken

Description: Returns the current yearly borrow interest rate for the market, calculated from the interest rate model.

Function signature:

function getBorrowRatePerYear() public view returns (uint256)

Return data:

Type
Description

uint256

The borrow interest rate per year, in WAD format (1e18)


getSupplyRatePerYear()

Contract: eToken

Description: Returns the current yearly supply interest rate for lenders, derived from the borrow rate and adjusted by the interest factor.

Function signature:

function getSupplyRatePerYear() public view returns (uint256)

Return data:

Type
Description

uint256

The supply interest rate per year, in WAD format (1e18)

PreviousPosition Tokens (pToken)NextDynamic Interest Rate Model

Last updated 14 days ago