Skip to main content

xTokens

Mint

The mint function transfers an asset into the protocol, which begins accumulating interest based on the current Supply Rate for the asset. The user receives a quantity of xTokens equal to the underlying tokens supplied, divided by the current Exchange Rate.

XErc20

function mint(uint mintAmount) returns (uint)

  1. msg.sender: The account which shall supply the asset, and own the minted xTokens.
  2. mintAmount: The amount of the asset to be supplied, in units of the underlying asset.
  3. RETURN: 0 on success, otherwise an Error code Before supplying an asset, users must first approve the xToken to access their token balance.

XEther

function mint() payable

  1. msg.value: The amount of ether to be supplied, in wei.
  2. msg.sender: The account which shall supply the ether, and own the minted xTokens.
  3. RETURN: No return, reverts on error.

Solidity

Erc20 underlying = Erc20(0xToken...); // get a handle for the underlying asset contract

XErc20 xToken = XErc20(0x3FDA...); // get a handle for the corresponding xToken contract

underlying.approve(address(xToken), 100); // approve the transfer

assert(xToken.mint(100) == 0); // mint the xTokens and assert there is no error

Web3 1.0

const xToken = XEther.at(0x3FDB...);

await xToken.methods.mint().send({from: myAccount, value: 50});

Redeem

The redeem function converts a specified quantity of xTokens into the underlying asset, and returns them to the user. The amount of underlying tokens received is equal to the quantity of xTokens redeemed, multiplied by the current Exchange Rate. The amount redeemed must be less than the user’s Account Liquidity and the market’s available liquidity.

XErc20 / XEther

function redeem(uint redeemTokens) returns (uint)

  1. msg.sender: The account to which redeemed funds shall be transferred.
  2. redeemTokens: The number of xTokens to be redeemed.
  3. RETURN: 0 on success, otherwise an Error code

Solidity

XEther xToken = XEther(0x3FDB...);

require(xToken.redeem(7) == 0, "something went wrong");

Web3 1.0

const xToken = XErc20.at(0x3FDA...);

xToken.methods.redeem(1).send({from: ...});

Redeem Underlying

The redeem underlying function converts xTokens into a specified quantity of the underlying asset, and returns them to the user. The amount of xTokens redeemed is equal to the quantity of underlying tokens received, divided by the current Exchange Rate. The amount redeemed must be less than the user’s Account Liquidity and the market’s available liquidity.

XErc20 / XEther

function redeemUnderlying(uint redeemAmount) returns (uint)

  1. msg.sender: The account to which redeemed funds shall be transferred.
  2. redeemAmount: The amount of underlying to be redeemed.
  3. RETURN: 0 on success, otherwise an Error code

Solidity


XEther xToken = XEther(0x3FDB...);

require(xToken.redeemUnderlying(50) == 0, "something went wrong");

Web3 1.0


const xToken = XErc20.at(0x3FDA...);

xToken.methods.redeemUnderlying(10).send({from: ...});

Borrow

The borrow function transfers an asset from the protocol to the user, and creates a borrow balance which begins accumulating interest based on the Borrow Rate for the asset. The amount borrowed must be less than the user’s Account Liquidity and the market’s available liquidity. To borrow Ether, the borrower must be ‘payable’ (solidity).

XErc20 / XEther

function borrow(uint borrowAmount) returns (uint)

  1. msg.sender: The account to which borrowed funds shall be transferred.
  2. borrowAmount : The amount of the underlying asset to be borrowed.
  3. RETURN: 0 on success, otherwise an Error code

Solidity


XErc20 xToken = XErc20(0x3FDA...);

require(xToken.borrow(100) == 0, "got collateral?");

Web3 1.0


const xToken = XEther.at(0x3FDB...);

await xToken.methods.borrow(50).send({from: 0xMyAccount});

Repay Borrow

The repay function transfers an asset into the protocol, reducing the user’s borrow balance.

XErc20

function repayBorrow(uint repayAmount) returns (uint)

  1. msg.sender: The account which borrowed the asset, and shall repay the borrow.
  2. repayAmount: The amount of the underlying borrowed asset to be repaid. A value of -1 (i.e. 2^256 - 1) can be used to repay the full amount.
  3. RETURN: 0 on success, otherwise an Error code Before repaying an asset, users must first approve the xToken to access their token balance.

XEther

function repayBorrow() payable

  1. msg.value: The amount of ether to be repaid, in wei.
  2. msg.sender: The account which borrowed the asset, and shall repay the borrow.
  3. RETURN: No return, reverts on error.

Solidity


XEther xToken = XEther(0x3FDB...);

require(xToken.repayBorrow.value(100)() == 0, "transfer approved?");

Web3 1.0


const xToken = XErc20.at(0x3FDA...);

xToken.methods.repayBorrow(10000).send({from: ...});

Repay Borrow Behalf

The repay function transfers an asset into the protocol, reducing the target user’s borrow balance.

XErc20

function repayBorrowBehalf(address borrower, uint repayAmount) returns (uint)

  1. msg.sender: The account which shall repay the borrow.
  2. borrower: The account which borrowed the asset to be repaid.
  3. repayAmount: The amount of the underlying borrowed asset to be repaid. A value of -1 (i.e. 2^256 - 1) can be used to repay the full amount.
  4. RETURN: 0 on success, otherwise an Error code Before repaying an asset, users must first approve the xToken to access their token balance.

XEther

function repayBorrowBehalf(address borrower) payable

  1. msg.value: The amount of ether to be repaid, in wei.
  2. msg.sender: The account which shall repay the borrow.
  3. borrower: The account which borrowed the asset to be repaid.
  4. RETURN: No return, reverts on error.

Solidity


XEther xToken = XEther(0x3FDB...);

require(xToken.repayBorrowBehalf.value(100)(0xBorrower) == 0, "transfer approved?");

Web3 1.0


const xToken = XErc20.at(0x3FDA...);

await xToken.methods.repayBorrowBehalf(0xBorrower, 10000).send({from: 0xPayer});

Transfer

Transfer is an ERC-20 method that allows accounts to send tokens to other Ethereum addresses. A xToken transfer will fail if the account has entered that xToken market and the transfer would have put the account into a state of negative liquidity.

XErc20 / XEther

function transfer(address recipient, uint256 amount) returns (bool)

  1. recipient: The transfer recipient address.
  2. amount: The amount of xTokens to transfer.
  3. RETURN: Returns a boolean value indicating whether or not the operation succeeded.

Solidity


XEther xToken = XEther(0x3FDB...);

xToken.transfer(0xABCD..., 100000000000);

Web3 1.0


const xToken = XErc20.at(0x3FDA...);

await xToken.methods.transfer(0xABCD..., 100000000000).send({from: 0xSender});

Liquidate Borrow

A user who has negative account liquidity is subject to liquidation by other users of the protocol to return his/her account liquidity back to positive (i.e. above the collateral requirement). When a liquidation occurs, a liquidator may repay some or all of an outstanding borrow on behalf of a borrower and in return receive a discounted amount of collateral held by the borrower; this discount is defined as the liquidation incentive. A liquidator may close up to a certain fixed percentage (i.e. close factor) of any individual outstanding borrow of the underwater account. Unlike in v1, liquidators must interact with each xToken contract in which they wish to repay a borrow and seize another asset as collateral. When collateral is seized, the liquidator is transferred xTokens, which they may redeem the same as if they had supplied the asset themselves. Users must approve each xToken contract before calling liquidate (i.e. on the borrowed asset which they are repaying), as they are transferring funds into the contract.

XErc20

function liquidateBorrow(address borrower, uint amount, address collateral) returns (uint)

  1. msg.sender: The account which shall liquidate the borrower by repaying their debt and seizing their collateral.
  2. borrower: The account with negative account liquidity that shall be liquidated.
  3. repayAmount: The amount of the borrowed asset to be repaid and converted into collateral, specified in units of the underlying borrowed asset.
  4. xTokenCollateral: The address of the xToken currently held as collateral by a borrower, that the liquidator shall seize.
  5. RETURN: 0 on success, otherwise an Error code Before supplying an asset, users must first approve the xToken to access their token balance.

XEther

function liquidateBorrow(address borrower, address xTokenCollateral) payable

  1. msg.value: The amount of ether to be repaid and converted into collateral, in wei.
  2. msg.sender: The account which shall liquidate the borrower by repaying their debt and seizing their collateral.
  3. borrower: The account with negative account liquidity that shall be liquidated.
  4. xTokenCollateral: The address of the xToken currently held as collateral by a borrower, that the liquidator shall seize.
  5. RETURN: No return, reverts on error.

Solidity


XEther xToken = XEther(0x3FDB...);

XErc20 xTokenCollateral = XErc20(0x3FDA...);

require(xToken.liquidateBorrow.value(100)(0xBorrower, xTokenCollateral) == 0, "borrower underwater??");

Web3 1.0


const xToken = XErc20.at(0x3FDA...);

const xTokenCollateral = XEther.at(0x3FDB...);

await xToken.methods.liquidateBorrow(0xBorrower, 33, xTokenCollateral).send({from: 0xLiquidator});

Key Events

EventDescription
Mint(address minter, uint mintAmount, uint mintTokens)Emitted upon a successful Mint.
Redeem(address redeemer, uint redeemAmount, uint redeemTokens)Emitted upon a successful Redeem.
Borrow(address borrower, uint borrowAmount, uint accountBorrows, uint totalBorrows)Emitted upon a successful Borrow.
RepayBorrow(address payer, address borrower, uint repayAmount, uint accountBorrows, uint totalBorrows)Emitted upon a successful Repay Borrow.
LiquidateBorrow(address liquidator, address borrower, uint repayAmount, address xTokenCollateral, uint seizeTokens)Emitted upon a successful Liquidate Borrow.

Error Codes

CodeNameDescription
0NO_ERRORNot a failure.
1UNAUTHORIZEDThe sender is not authorized to perform this action.
2BAD_INPUTAn invalid argument was supplied by the caller.
3COMPTROLLER_REJECTIONThe action would violate the comptroller policy.
4COMPTROLLER_CALCULATION_ERRORAn internal calculation has failed in the comptroller.
5INTEREST_RATE_MODEL_ERRORThe interest rate model returned an invalid value.
6INVALID_ACCOUNT_PAIRThe specified combination of accounts is invalid.
7INVALID_CLOSE_AMOUNT_REQUESTEDThe amount to liquidate is invalid.
8INVALID_COLLATERAL_FACTORThe collateral factor is invalid.
9MATH_ERRORA math calculation error occurred.
10MARKET_NOT_FRESHInterest has not been properly accrued.
11MARKET_NOT_LISTEDThe market is not currently listed by its comptroller.
12TOKEN_INSUFFICIENT_ALLOWANCEERC-20 contract must allow Money Market contract to call transferFrom. The current allowance is either 0 or less than the requested supply, repayBorrow or liquidate amount.
13TOKEN_INSUFFICIENT_BALANCECaller does not have sufficient balance in the ERC-20 contract to complete the desired action.
14TOKEN_INSUFFICIENT_CASHThe market does not have a sufficient cash balance to complete the transaction. You may attempt this transaction again later.
15TOKEN_TRANSFER_IN_FAILEDFailure in ERC-20 when transfering token into the market.
16TOKEN_TRANSFER_OUT_FAILEDFailure in ERC-20 when transfering token out of the market.

Failure Info

CodeName
0ACCEPT_ADMIN_PENDING_ADMIN_CHECK
1ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED
2ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED
3ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED
4ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED
5ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED
6ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED
7BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED
8BORROW_ACCRUE_INTEREST_FAILED
9BORROW_CASH_NOT_AVAILABLE
10BORROW_FRESHNESS_CHECK
11BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED
12BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED
13BORROW_MARKET_NOT_LISTED
14BORROW_COMPTROLLER_REJECTION
15LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED
16LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED
17LIQUIDATE_COLLATERAL_FRESHNESS_CHECK
18LIQUIDATE_COMPTROLLER_REJECTION
19LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED
20LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX
21LIQUIDATE_CLOSE_AMOUNT_IS_ZERO
22LIQUIDATE_FRESHNESS_CHECK
23LIQUIDATE_LIQUIDATOR_IS_BORROWER
24LIQUIDATE_REPAY_BORROW_FRESH_FAILED
25LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED
26LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED
27LIQUIDATE_SEIZE_COMPTROLLER_REJECTION
28LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER
29LIQUIDATE_SEIZE_TOO_MUCH
30MINT_ACCRUE_INTEREST_FAILED
31MINT_COMPTROLLER_REJECTION
32MINT_EXCHANGE_CALCULATION_FAILED
33MINT_EXCHANGE_RATE_READ_FAILED
34MINT_FRESHNESS_CHECK
35MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED
36MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED
37MINT_TRANSFER_IN_FAILED
38MINT_TRANSFER_IN_NOT_POSSIBLE
39REDEEM_ACCRUE_INTEREST_FAILED
40REDEEM_COMPTROLLER_REJECTION
41REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED
42REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED
43REDEEM_EXCHANGE_RATE_READ_FAILED
44REDEEM_FRESHNESS_CHECK
45REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED
46REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED
47REDEEM_TRANSFER_OUT_NOT_POSSIBLE
48REDUCE_RESERVES_ACCRUE_INTEREST_FAILED
49REDUCE_RESERVES_ADMIN_CHECK
50REDUCE_RESERVES_CASH_NOT_AVAILABLE
51REDUCE_RESERVES_FRESH_CHECK
52REDUCE_RESERVES_VALIDATION
53REPAY_BEHALF_ACCRUE_INTEREST_FAILED
54REPAY_BORROW_ACCRUE_INTEREST_FAILED
55REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED
56REPAY_BORROW_COMPTROLLER_REJECTION
57REPAY_BORROW_FRESHNESS_CHECK
58REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED
59REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED
60REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE
61SET_COLLATERAL_FACTOR_OWNER_CHECK
62SET_COLLATERAL_FACTOR_VALIDATION
63SET_COMPTROLLER_OWNER_CHECK
64SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED
65SET_INTEREST_RATE_MODEL_FRESH_CHECK
66SET_INTEREST_RATE_MODEL_OWNER_CHECK
67SET_MAX_ASSETS_OWNER_CHECK
68SET_ORACLE_MARKET_NOT_LISTED
69SET_PENDING_ADMIN_OWNER_CHECK
70SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED
71SET_RESERVE_FACTOR_ADMIN_CHECK
72SET_RESERVE_FACTOR_FRESH_CHECK
73SET_RESERVE_FACTOR_BOUNDS_CHECK
74TRANSFER_COMPTROLLER_REJECTION
75TRANSFER_NOT_ALLOWED
76TRANSFER_NOT_ENOUGH
77TRANSFER_TOO_MUCH

Exchange Rate

Each xToken is convertible into an ever increasing quantity of the underlying asset, as interest accrues in the market. The exchange rate between a xToken and the underlying asset is equal to:

exchangeRate = (getCash() + totalBorrows() - totalReserves()) / totalSupply()

XErc20 / XEther

function exchangeRateCurrent() returns (uint)

  1. RETURN: The current exchange rate as an unsigned integer, scaled by 1 * 10^(18 - 8 + Underlying Token Decimals).

Solidity


XErc20 xToken = xToken(0x3FDA...);

uint exchangeRateMantissa = xToken.exchangeRateCurrent();

Web3 1.0


const xToken = XEther.at(0x3FDB...);

const exchangeRate = (await xToken.methods.exchangeRateCurrent().call()) / 1e18;

Tip: note the use of call vs. send to invoke the function from off-chain without incurring gas costs.

Get Cash

Cash is the amount of underlying balance owned by this xToken contract. One may query the total amount of cash currently available to this market.

XErc20 / XEther

function getCash() returns (uint)

  1. RETURN: The quantity of underlying asset owned by the contract.

Solidity


XErc20 xToken = xToken(0x3FDA...);

uint cash = xToken.getCash();

Web3 1.0


const xToken = XEther.at(0x3FDB...);

const cash = (await xToken.methods.getCash().call());

Total Borrows

Total Borrows is the amount of underlying currently loaned out by the market, and the amount upon which interest is accumulated to suppliers of the market.

XErc20 / XEther

function totalBorrowsCurrent() returns (uint)

  1. RETURN: The total amount of borrowed underlying, with interest.

Solidity


XErc20 xToken = xToken(0x3FDA...);

uint borrows = xToken.totalBorrowsCurrent();

Web3 1.0


const xToken = XEther.at(0x3FDB...);

const borrows = (await xToken.methods.totalBorrowsCurrent().call());

Borrow Balance

A user who borrows assets from the protocol is subject to accumulated interest based on the current borrow rate. Interest is accumulated every block and integrations may use this function to obtain the current value of a user’s borrow balance with interest.

XErc20 / XEther

function borrowBalanceCurrent(address account) returns (uint)

  1. account: The account which borrowed the assets.
  2. RETURN: The user’s current borrow balance (with interest) in units of the underlying asset.

Solidity


XErc20 xToken = xToken(0x3FDA...);

uint borrows = xToken.borrowBalanceCurrent(msg.caller);

Web3 1.0


const xToken = XEther.at(0x3FDB...);

const borrows = await xToken.methods.borrowBalanceCurrent(account).call();

Borrow Rate

At any point in time one may query the contract to get the current borrow rate per block.

XErc20 / XEther

function borrowRatePerBlock() returns (uint)

  1. RETURN: The current borrow rate as an unsigned integer, scaled by 1e18.

Solidity


XErc20 xToken = xToken(0x3FDA...);

uint borrowRateMantissa = xToken.borrowRatePerBlock();

Web3 1.0


const xToken = XEther.at(0x3FDB...);

const borrowRate = (await xToken.methods.borrowRatePerBlock().call()) / 1e18;

Total Supply

Total Supply is the number of tokens currently in circulation in this xToken market. It is part of the EIP-20 interface of the xToken contract.

XErc20 / XEther

function totalSupply() returns (uint)

  1. RETURN: The total number of tokens in circulation for the market.

Solidity


XErc20 xToken = xToken(0x3FDA...);

uint tokens = xToken.totalSupply();

Web3 1.0


const xToken = XEther.at(0x3FDB...);

const tokens = (await xToken.methods.totalSupply().call());

Underlying Balance

The user’s underlying balance, representing their assets in the protocol, is equal to the user’s xToken balance multiplied by the Exchange Rate.

XErc20 / XEther

function balanceOfUnderlying(address account) returns (uint)

  1. account: The account to get the underlying balance of.
  2. RETURN: The amount of underlying currently owned by the account.

Solidity


XErc20 xToken = xToken(0x3FDA...);

uint tokens = xToken.balanceOfUnderlying(msg.caller);

Web3 1.0


const xToken = XEther.at(0x3FDB...);

const tokens = await xToken.methods.balanceOfUnderlying(account).call();

Supply Rate

At any point in time one may query the contract to get the current supply rate per block. The supply rate is derived from the borrow rate, reserve factor and the amount of total borrows.

XErc20 / XEther

function supplyRatePerBlock() returns (uint)

  1. RETURN: The current supply rate as an unsigned integer, scaled by 1e18.

Solidity


XErc20 xToken = xToken(0x3FDA...);

uint supplyRateMantissa = xToken.supplyRatePerBlock();

Web3 1.0


const xToken = XEther.at(0x3FDB...);

const supplyRate = (await xToken.methods.supplyRatePerBlock().call()) / 1e18;

Total Reserves

Reserves are an accounting entry in each xToken contract that represents a portion of historical interest set aside as cash which can be withdrawn or transferred through the protocol’s governance. A small portion of borrower interest accrues into the protocol, determined by the reserve factor.

XErc20 / XEther

function totalReserves() returns (uint)

  1. RETURN: The total amount of reserves held in the market.

Solidity


XErc20 xToken = xToken(0x3FDA...);

uint reserves = xToken.totalReserves();

Web3 1.0


const xToken = XEther.at(0x3FDB...);

const reserves = (await xToken.methods.totalReserves().call());

Reserve Factor

The reserve factor defines the portion of borrower interest that is converted into reserves.

XErc20 / XEther

function reserveFactorMantissa() returns (uint)

  1. RETURN: The current reserve factor as an unsigned integer, scaled by 1e18.

Solidity


XErc20 xToken = xToken(0x3FDA...);

uint reserveFactorMantissa = xToken.reserveFactorMantissa();

Web3 1.0


const xToken = XEther.at(0x3FDB...);

const reserveFactor = (await xToken.methods.reserveFactorMantissa().call()) / 1e18;