Introduction

vTokens.c3b8cf11.png

Each asset supported by the Venus Protocol is integrated through a vToken contract, which is an EIP-20 compliant representation of balances supplied to the protocol. By minting vTokens, users (1) earn interest through the vToken's exchange rate, which increases in value relative to the underlying asset, and (2) gain the ability to use vTokens as collateral.

 

vTokens are the primary means of interacting with the Venus Protocol; when a user mints, redeems, borrows, repays a borrow, liquidates a borrow, or transfers vTokens, she will do so using the vToken contract.

 

There are currently two types of vTokens: VBep20 and VBnb. Though both types expose the EIP-20 interface, VBep20 wraps an underlying BEP-20 asset, while VBnb simply wraps BNB itself. As such, the core functions which involve transferring an asset into the protocol have slightly different interfaces depending on the type, each of which is shown below.

Mint

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

VBep20

1   function mint(uint mintAmount) returns (uint)

  • msg.sender: The account which shall supply the asset, and own the minted vTokens.

  • mintAmount: The amount of the asset to be supplied, in units of the underlying asset.

  • RETURN: 0 on success, otherwise an Error code

Before supplying an asset, users must first approve the vToken to access their token balance.

VBnb

  • msg.value: payable The amount of ether to be supplied, in wei.

  • msg.sender: The account which shall supply the bnb, and own the minted vTokens.

  • RETURN: No return, reverts on error.

Solidity

 

 

 

 

 

 

Web3 1.0

1   function mint() payable

1   Bep20 underlying = Bep20(0xToken...); // get a handle for the underlying      asset

2   VBep20 vToken = VBep20(0x3FDA...); // get a handle for the corresponding      vToken Contract

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

4   assert(vToken.mint(100) == 0); // mint the vTokens and assert there is no      error

1   const vToken = VBep20.at(0x3FDB...);

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

Redeem

The redeem function converts a specified quantity of vTokens into the underlying asset, and returns them to the user. The amount of underlying tokens received is equal to the quantity of vTokens 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.

VBep20 / VBnb

  • msg.value: The account to which redeemed funds shall be transferred.

  • redeemTokens: The number of vTokens to be redeemed.

  • RETURN: 0 on success, otherwise an Error code

Solidity

Web3 1.0

1   function redeem(uint redeemTokens) returns (uint)

1   VBnb vToken = VBnb(0x3FDB...);

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

1   const vToken = VBep20.at(0x3FDB...);

2   await vToken.methods.redeem(1).send({from: ...});

Redeem Underlying

The redeem underlying function converts vTokens into a specified quantity of the underlying asset, and returns them to the user. The amount of vTokens 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.

VBep20 / VBnb

  • msg.sender: The account to which redeemed funds shall be transferred.

  • redeemAmount: The amount of underlying to be redeemed.

  • RETURN: 0 on success, otherwise an Error code

Solidity

Web3 1.0

1   function redeemUnderlying(uint redeemAmount) returns (uint)

1   VBnb vToken = VBnb(0x3FDB...);

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

1   const vToken = VBep20.at(0x3FDB...);

2   await vToken.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).

VBep20 / VBnb

  • msg.sender: The account to which redeemed funds shall be transferred.

  • redeemAmount: The amount of underlying to be redeemed.

  • RETURN: 0 on success, otherwise an Error code

Solidity

Web3 1.0

1   function borrow(uint borrowAmount) returns (uint)

1   VBnb vToken = VBnb(0x3FDB...);

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

1   const vToken = VBep20.at(0x3FDA...);

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

Repay Borrow

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

VBep20

  • msg.sender: The account which borrowed the asset, and shall repay the borrow.

  • borrowAmount: 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.

  • RETURN: 0 on success, otherwise an Error code

VBnb

  • msg.value: payable The amount of ether to be repaid, in wei.

  • msg.sender: The amount which borrowed the asset, and shall repay the borrow

  • RETURN: No return, reverts on error

Solidity

Web3 1.0

1   function repayBorrow(uint repayAmount) returns (uint)

1   VBnb vToken = VBnb(0x3FDB...);

2   require(vToken.repayBorrow(100) == 0, "transfer approved?");

1   function repayBorrow() payable

1   const vToken = VBep20.at(0x3FDA...);

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

Repay Borrow Behalf

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

VBep20

  • msg.sender: The account which shall repay the borrow.

  • borrower: The account which borrowed the asset to be repaid.

  • 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.

  • RETURN: 0 on success, otherwise an Error code

Before repaying an asset, users must first approve the vToken to access their token balance.

VBnb

  • msg.value: payable The amount of ether to be repaid, in wei.

  • msg.sender: The amount which shall repay the borrow

  • borrower: The account which borrowed the asset to be repaid

  • RETURN: No return, reverts on error

Solidity

Web3 1.0

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

1   VBnb vToken = VBnb(0x3FDB...);

2   require(vToken.repayBorrowBehalf(100)(0xBorrower) == 0, "transfer
    approved?
");

1   function repayBorrowBehalf(address borrower) payable

1   const vToken = VBep20.at(0x3FDA...);

2   await vToken.methods.repayBorrowBehalf(10000).send({from: 0xPayer});

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 vToken contract in which they wish to repay a borrow and seize another asset as collateral. When collateral is seized, the liquidator is transferred vTokens, which they may redeem the same as if they had supplied the asset themselves. Users must approve each vToken contract before calling liquidate (i.e. on the borrowed asset which they are repaying), as they are transferring funds into the contract.

 

VBep20

  • msg.sender: The account which shall liquidate the borrower by repaying their debt and seizing their collateral.

  • borrower: The account with negative account liquidity that shall be liquidated.

  • repayAmount: The amount of the borrowed asset to be repaid and converted into collateral, specified in units of the underlying borrowed asset.

  • vTokenCollateral: The address of the vToken currently held as collateral by a borrower, that the liquidator shall seize.

  • RETURN: 0 on success, otherwise an Error code

Before repaying an asset, users must first approve the vToken to access their token balance.

VBnb

  • msg.value: payable The amount of ether to be repaid and converted into collateral, in wei.

  • msg.sender: The account which shall liquidate the borrower by repaying their debt and seizing their collateral.

  • borrower: The account with negative account liquidity that shall be liquidated.

  • vTokenCollateral: The address of the vToken currently held as collateral by a borrower, that the liquidator shall seize.

  • RETURN: No return, reverts on error

Solidity

Web3 1.0

1   function liquidateBorrow(address borrower, uint Amount, address,
    collateral
) returns (uint)

1   VBnb vToken = VBnb(0x3FDB...);

2   VBep20 vTokenCollateral = VBep20(0x3FDA...); 3

3   require(vToken.liquidateBorrow.value(100)(0xBorrower, vTokenCollateral) ==
    0, "borrower underwater??");

1   function liquidateBorrowBehalf(address borrower, address vTokenCollateral)
    
payable

1   const vToken = VBep20.at(0x3FDA...);

2   const vTokenCollateral = VBnb.at(0x3FDB...);

3   await vToken.methods.liquidateBorrow(0xBorrower, 33,
    vCollateral
).send({from: 0xLiquidator});

Key Events

Function

Description

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 vTokenCollateral, uint seizeTokens)

Emitted upon a successful Liquidate Borrow.

Error Codes

Code

Name

Description

0

NO_ERROR

Not a failure.

1

UNAUTHORIZED

The sender is not authorized to perform this action.

2

BAD_INPUT

An invalid argument was supplied by the caller.

3

SXPTROLLER_REJECTION

The action would violate the SXPtroller policy.

4

SXPTROLLER_CALCULATION_ERROR

An internal calculation has failed in the SXPtroller.

5

INTEREST_RATE_MODEL_ERROR

The interest rate model returned an invalid value.

6

INVALID_ACCOUNT_PAIR

The specified combination of accounts is invalid.

7

INVALID_CLOSE_AMOUNT_REQUESTED

The amount to liquidate is invalid.

8

INVALID_COLLATERAL_FACTOR

The collateral factor is invalid.

9

MATH_ERROR

A math calculation error occurred.

10

MARKET_NOT_FRESH

Interest has not been properly accrued.

11

MARKET_NOT_LISTED

The market is not currently listed by its unitroller.

12

TOKEN_INSUFICIENT_ALLOWANCE

BEP-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.

13

TOKEN_INSUFFICIENT_BALANCE

Caller does not have sufficient balance in the BEP-20 contract to complete the desired action.

14

TOKEN_INSUFFICIENT_CASH

The market does not have a sufficient cash balance to complete the transaction. You may attempt this transaction again later.

15

TOKEN_TRANSFER_IN_FAILED

Failure in BEP-20 when transfering token into the market.

16

TOKEN_TRANSFER_OUT_FAILED

Failure in BEP-20 when transfering token out of the market.

Failure Info

Code

Name

0

ACCEPT_ADMIN_PENDING_ADMIN_CHECK

1

ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED

2

ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED

3

ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED

4

ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED

5

ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED

6

ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED

7

BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED

8

BORROW_ACCRUE_INTEREST_FAILED

9

BORROW_CASH_NOT_AVAILABLE

10

BORROW_FRESHNESS_CHECK

11

BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED

12

BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED

13

BORROW_MARKET_NOT_LISTED

14

BORROW_UNITROLLER_REJECTION

15

LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED

16

LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED

17

LIQUIDATE_COLLATERAL_FRESHNESS_CHECK

18

LIQUIDATE_UNITROLLER_REJECTION

19

LIQUIDATE_UNITROLLER_CALCULATE_AMOUNT_SEIZE_FAILED

20

LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX

21

LIQUIDATE_CLOSE_AMOUNT_IS_ZERO

22

LIQUIDATE_FRESHNESS_CHECK

23

LIQUIDATE_LIQUIDATOR_IS_BORROWER

24

LIQUIDATE_REPAY_BORROW_FRESH_FAILED

25

LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED

26

LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED

27

LIQUIDATE_SEIZE_UNITROLLER_REJECTION

28

LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER

29

LIQUIDATE_SEIZE_TOO_MUCH

30

MINT_ACCRUE_INTEREST_FAILED

31

MINT_UNITROLLER_REJECTION

32

MINT_EXCHANGE_CALCULATION_FAILED

33

MINT_EXCHANGE_RATE_READ_FAILED

34

MINT_FRESHNESS_CHECK

35

MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED

36

MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED

37

MINT_TRANSFER_IN_FAILED

38

MINT_TRANSFER_IN_NOT_POSSIBLE

39

REDEEM_ACCRUE_INTEREST_FAILED

40

REDEEM_UNITROLLER_REJECTION

41

REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED

42

REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED

43

REDEEM_EXCHANGE_RATE_READ_FAILED

44

REDEEM_FRESHNESS_CHECK

45

REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED

46

REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED

47

REDEEM_TRANSFER_OUT_NOT_POSSIBLE

48

REDUCE_RESERVES_ACCRUE_INTEREST_FAILED

49

REDUCE_RESERVES_ADMIN_CHECK

50

REDUCE_RESERVES_CASH_NOT_AVAILABLE

51

REDUCE_RESERVES_FRESH_CHECK

52

REDUCE_RESERVES_VALIDATION

53

REPAY_BEHALF_ACCRUE_INTEREST_FAILED

54

REPAY_BORROW_ACCRUE_INTEREST_FAILED

55

REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED

56

REPAY_BORROW_UNITROLLER_REJECTION

57

REPAY_BORROW_FRESHNESS_CHECK

58

REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED

59

REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED

60

REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE

61

SET_COLLATERAL_FACTOR_OWNER_CHECK

62

SET_COLLATERAL_FACTOR_VALIDATION

63

SET_UNITROLLER_OWNER_CHECK

64

SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED

65

SET_INTEREST_RATE_MODEL_FRESH_CHECK

66

SET_INTEREST_RATE_MODEL_OWNER_CHECK

67

SET_MAX_ASSETS_OWNER_CHECK

68

SET_ORACLE_MARKET_NOT_LISTED

69

SET_PENDING_ADMIN_OWNER_CHECK

70

SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED

71

SET_RESERVE_FACTOR_ADMIN_CHECK

72

SET_RESERVE_FACTOR_FRESH_CHECK

73

SET_RESERVE_FACTOR_BOUNDS_CHECK

74

TRANSFER_UNITROLLER_REJECTION

75

TRANSFER_NOT_ALLOWED

76

TRANSFER_NOT_ENOUGH

77

TRANSFER_TOO_MUCH

Exchange Rate

 

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

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

 

VBep20 / VBnb

1   function exchangeRateCurrent() returns (uint)

 

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

Solidity

1   VBep20 vToken = VToken(0x3FDA...);

2   uint exchangeRateMantissa = vToken.exchangeRateCurrent();

Web3 1.0

1   const vToken = VBnb.at(0x3FDB...);

2   const exchangeRate = (await vToken.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 vToken contract. One may query the total amount of cash currently available to this market.

 

VBep20 / VBnb

1   function getCash() returns (uint)

 

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

Solidity

1   VBep20 vToken = VToken(0x3FDA...);

2   uint cash = vToken.getCash();

Web3 1.0

1   const vToken = VBnb.at(0x3FDB...);

2   const cash = (await vToken.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.

 

VBep20 / VBnb

1   function totalBorrowsCurrent() returns (uint)

 

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

Solidity

1   VBep20 vToken = VToken(0x3FDA...);

2   uint borrows = vToken.totalBorrowsCurrent();

Web3 1.0

1   const vToken = VBnb.at(0x3FDB...);

2   const cash = (await vToken.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.

 

VBep20 / VBnb

1   function borrowBalanceCurrent(address account) returns (uint)

 

  • account: The account which borrowed the assets.

  • RETURN: The user's current borrow balance (with interest) in units of the underlying asset.

Solidity

1   VBep20 vToken = VToken(0x3FDA...);

2   uint borrows = vToken.borrowBalanceCurrent(msg.caller);

Web3 1.0

1   const vToken = VBnb.at(0x3FDB...);

2   const cash = (await vToken.methods.borrowBalanceCurrent(account).call());

Borrow Rate

 

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

 

VBep20 / VBnb

1   function borrowRatePerBlock() returns (uint)

 

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

Solidity

1   VBep20 vToken = VToken(0x3FDA...);

2   uint borrowRateMantissa = vToken.borrowRatePerBlock();

Web3 1.0

1   const vToken = VBnb.at(0x3FDB...);

2   const borrowrate = (await vToken.methods.borrowRatePerBlock().
    call())/
1e18;

Total Supply

 

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

 

VBep20 / VBnb

1   function totalSupply() returns (uint)

 

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

Solidity

1   VBep20 vToken = VToken(0x3FDA...);

2   uint tokens = vToken.totalSupply();

Web3 1.0

1   const vToken = VBnb.at(0x3FDB...);

2   const tokens = (await vToken.methods.totalSupply().call());

Underlying Balance

 

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

 

VBep20 / VBnb

1   function balanceOfUnderlying(address account) returns (uint)

 

  • account: The account to get the underlying balance of.

  • RETURN: The amount of underlying currently owned by the account.

Solidity

1   VBep20 vToken = VToken(0x3FDA...);

2   uint tokens = vToken.balanceOfUnderlying(msg.caller);

Web3 1.0

1   const vToken = VBnb.at(0x3FDB...);

2   const tokens = (await vToken.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 ratereserve factor and the amount of total borrows.

 

VBep20 / VBnb

1   function supplyRatePerBlock() returns (uint)

 

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

Solidity

1   VBep20 vToken = VToken(0x3FDA...);

2   uint supplyRateMantissa = vToken.supplyRatePerBlock();

Web3 1.0

1   const vToken = VBnb.at(0x3FDB...);

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

Total Reserves

 

Reserves are an accounting entry in each vToken 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.

 

VBep20 / VBnb

1   function totalReserves() returns (uint)

 

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

Solidity

1   VBep20 vToken = VToken(0x3FDA...);

2   uint reserves = vToken.totalReserves();

Web3 1.0

1   const vToken = VBnb.at(0x3FDB...);

2   const reserves = (await vToken.methods.totalReserves().call());

Reserve Factor

 

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

 

VBep20 / VBnb

1   function reserveFactorMantissa() returns (uint)

 

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

Solidity

1   VBep20 vToken = VToken(0x3FDA...);

2   uint reserveFactorMantissa = vToken.reserveFactorMantissa();

Web3 1.0

1   const vToken = VBnb.at(0x3FDB...);

2   const reserveFactor = (await vToken.methods.reserveFactorMantissa().
    call());