Protocol Core

caTokens

Each asset supported by the CapyFi Protocol is integrated through a caToken contract, which is an EIP-20 compliant representation of balances supplied to the protocol.

Introduction

Understanding caTokens

By minting caTokens, users (1) earn interest through the caToken's exchange rate, which increases in value relative to the underlying asset, and (2) gain the ability to use caTokens as collateral.

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

There are currently two types of caTokens: CErc20 and CEther. Though both types expose the EIP-20 interface, CErc20 wraps an underlying ERC-20 asset, while CEther simply wraps Ether itself.

How Do caTokens earn interest?

Interest mechanism explained

Each market has its own Supply interest rate (APR). Interest isn't distributed; instead, simply by holding caTokens, you'll earn interest.

caTokens accumulates interest through their exchange rate — over time, each caToken becomes convertible into an increasing amount of it's underlying asset, even while the number of caTokens in your wallet stays the same.

Example:

Let's say you supply 1,000 DAI to the CapyFi protocol, when the exchange rate is 0.020070; you would receive 49,825.61 cDAI (1,000/0.020070).

A few months later, the exchange rate is now 0.021591: Your 49,825.61 cDAI is now equal to 1,075.78 DAI (49,825.61 × 0.021591).

MINT

Mint

Supply assets to the protocol

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 caTokens equal to the underlying tokens supplied, divided by the current Exchange Rate.

CErc20

function mint(uint mintAmount) returns (uint)

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

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

RETURN: 0 on success, otherwise an Error code

CEther

function mint() payable

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

msg.sender: The account which shall supply the ether, and own the minted caTokens.

RETURN: No return, reverts on error.

Solidity Example

Erc20 underlying = Erc20(0xToken...);     // get a handle for the underlying asset contract
CErc20 cToken = CErc20(0x3FDA...);        // get a handle for the corresponding cToken contract
underlying.approve(address(cToken), 100); // approve the transfer
assert(cToken.mint(100) == 0);            // mint the caTokens and assert there is no error

Web3 1.0 Example

const cToken = CEther.at(0x3FDB...);
await cToken.methods.mint().send({from: myAccount, value: 50});
REDEEM

Redeem

Convert caTokens to underlying assets

The redeem function converts a specified quantity of caTokens into the underlying asset, and returns them to the user. The amount of underlying tokens received is equal to the quantity of caTokens redeemed, multiplied by the current Exchange Rate.

CErc20 / CEther

function redeem(uint redeemTokens) returns (uint)

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

redeemTokens: The number of caTokens to be redeemed.

RETURN: 0 on success, otherwise an Error code

Solidity Example

CEther cToken = CEther(0x3FDB...);
require(cToken.redeem(7) == 0, "something went wrong");

Web3 1.0 Example

const cToken = CErc20.at(0x3FDA...);
cToken.methods.redeem(1).send({from: ...});
REDEEM

Redeem Underlying

Convert caTokens to a specific amount of underlying assets

The redeem underlying function converts caTokens into a specified quantity of the underlying asset, and returns them to the user. The amount of caTokens redeemed is equal to the quantity of underlying tokens received, divided by the current Exchange Rate.

CErc20 / CEther

function redeemUnderlying(uint redeemAmount) returns (uint)

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 Example

CEther cToken = CEther(0x3FDB...);
require(cToken.redeemUnderlying(50) == 0, "something went wrong");

Web3 1.0 Example

const cToken = CErc20.at(0x3FDA...);
cToken.methods.redeemUnderlying(10).send({from: ...});
BORROW

Borrow

Borrow assets from the protocol

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.

CErc20 / CEther

function borrow(uint borrowAmount) returns (uint)

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

borrowAmount: The amount of the underlying asset to be borrowed.

RETURN: 0 on success, otherwise an Error code

Solidity Example

CErc20 cToken = CErc20(0x3FDA...);
require(cToken.borrow(100) == 0, "borrow failed");

Web3 1.0 Example

const cToken = CErc20.at(0x3FDA...);
cToken.methods.borrow(50).send({from: myAccount});
REPAY

Repay Borrow

Repay borrowed assets

The repay borrow function transfers an asset into the protocol, reducing the user's borrow balance. The amount repaid must be less than or equal to the user's current borrow balance.

CErc20 / CEther

function repayBorrow(uint repayAmount) returns (uint)

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

repayAmount: The amount of the underlying asset to be repaid.

RETURN: 0 on success, otherwise an Error code

Solidity Example

CErc20 cToken = CErc20(0x3FDA...);
require(cToken.repayBorrow(100) == 0, "repay failed");

Web3 1.0 Example

const cToken = CErc20.at(0x3FDA...);
cToken.methods.repayBorrow(50).send({from: myAccount});
REPAY

Repay Borrow Behalf

Repay borrowed assets on behalf of another user

The repay borrow behalf function transfers an asset into the protocol, reducing the target user's borrow balance. The amount repaid must be less than or equal to the target user's current borrow balance.

CErc20 / CEther

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

borrower: The account which borrowed the assets.

repayAmount: The amount of the underlying asset to be repaid.

RETURN: 0 on success, otherwise an Error code

Solidity Example

CErc20 cToken = CErc20(0x3FDA...);
require(cToken.repayBorrowBehalf(borrower, 100) == 0, "repay behalf failed");

Web3 1.0 Example

const cToken = CErc20.at(0x3FDA...);
cToken.methods.repayBorrowBehalf(borrower, 50).send({from: myAccount});
TRANSFER

Transfer

Transfer caTokens between accounts

caTokens can be transferred between accounts, but exercise caution! By transferring caTokens, you're transferring your balance of the underlying asset inside the CapyFi protocol. A caToken transfer will fail if the account has entered that caToken market and the transfer would have put the account into a state of negative liquidity.

EIP-20 Standard

function transfer(address to, uint amount) returns (bool)

to: The account to receive the caTokens.

amount: The number of caTokens to transfer.

RETURN: true on success, false otherwise

Solidity Example

CErc20 cToken = CErc20(0x3FDA...);
require(cToken.transfer(recipient, 100), "transfer failed");

Web3 1.0 Example

const cToken = CErc20.at(0x3FDA...);
cToken.methods.transfer(recipient, 50).send({from: myAccount});
LIQUIDATE

Liquidate Borrow

Liquidate undercollateralized positions

The liquidate borrow function allows users to repay a borrower's debt on behalf of that borrower and in return receive a discounted amount of collateral held by the borrower. This function is used to liquidate undercollateralized accounts.

CErc20 / CEther

function liquidateBorrow(address borrower, uint repayAmount, CTokenInterface cTokenCollateral) returns (uint)

borrower: The account with the borrow to be liquidated.

repayAmount: The amount of the underlying borrowed asset to repay.

cTokenCollateral: The market in which to seize collateral from the borrower.

RETURN: 0 on success, otherwise an Error code

Solidity Example

CErc20 cToken = CErc20(0x3FDA...);
CErc20 collateral = CErc20(0x3FDB...);
require(cToken.liquidateBorrow(borrower, 100, collateral) == 0, "liquidation failed");

Web3 1.0 Example

const cToken = CErc20.at(0x3FDA...);
const collateral = CErc20.at(0x3FDB...);
cToken.methods.liquidateBorrow(borrower, 50, collateral.address).send({from: myAccount});
EVENTS

Key Events

Important events emitted by cToken contracts

Mint

event Mint(address minter, uint mintAmount, uint mintTokens)

Emitted when tokens are minted

Redeem

event Redeem(address redeemer, uint redeemAmount, uint redeemTokens)

Emitted when tokens are redeemed

Borrow

event Borrow(address borrower, uint borrowAmount, uint accountBorrows, uint totalBorrows)

Emitted when assets are borrowed

RepayBorrow

event RepayBorrow(address payer, address borrower, uint repayAmount, uint accountBorrows, uint totalBorrows)

Emitted when borrows are repaid

LiquidateBorrow

event LiquidateBorrow(address liquidator, address borrower, uint repayAmount, address cTokenCollateral, uint seizeTokens)

Emitted when borrows are liquidated

ERRORS

Error Codes

Common error codes returned by cToken functions

CodeError
0NO_ERROR
1UNAUTHORIZED
2BAD_INPUT
3COMPTROLLER_REJECTION
4COMPTROLLER_CALCULATION_ERROR
5INTEREST_RATE_MODEL_ERROR
6INVALID_ACCOUNT_PAIR
7INVALID_CLOSE_AMOUNT_REQUESTED
8INVALID_COLLATERAL_FACTOR
9MATH_ERROR
10MARKET_NOT_FRESH
11MARKET_NOT_LISTED
12TOKEN_INSUFFICIENT_ALLOWANCE
13TOKEN_INSUFFICIENT_BALANCE
14TOKEN_INSUFFICIENT_CASH
15TOKEN_TRANSFER_IN_FAILED
16TOKEN_TRANSFER_OUT_FAILED
RATE

Exchange Rate

Current exchange rate between caTokens and underlying assets

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

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

CErc20 / CEther

function exchangeRateCurrent() returns (uint)

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

Solidity Example

CErc20 cToken = CToken(0x3FDA...);
uint exchangeRateMantissa = cToken.exchangeRateCurrent();

Web3 1.0 Example

const cToken = CEther.at(0x3FDB...);
const exchangeRate = (await cToken.methods.exchangeRateCurrent().call()) / 1e18;
CASH

Get Cash

Amount of underlying balance owned by the cToken contract

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

CErc20 / CEther

function getCash() returns (uint)

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

Solidity Example

CErc20 cToken = CToken(0x3FDA...);
uint cash = cToken.getCash();

Web3 1.0 Example

const cToken = CEther.at(0x3FDB...);
const cash = (await cToken.methods.getCash().call());
BORROWS

Total Borrows

Total amount of underlying currently loaned out by the market

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.

CErc20 / CEther

function totalBorrowsCurrent() returns (uint)

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

Solidity Example

CErc20 cToken = CToken(0x3FDA...);
uint borrows = cToken.totalBorrowsCurrent();

Web3 1.0 Example

const cToken = CEther.at(0x3FDB...);
const borrows = (await cToken.methods.totalBorrowsCurrent().call());
BALANCE

Borrow Balance

Current borrow balance of a specific account

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.

CErc20 / CEther

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 Example

CErc20 cToken = CToken(0x3FDA...);
uint borrows = cToken.borrowBalanceCurrent(msg.caller);

Web3 1.0 Example

const cToken = CEther.at(0x3FDB...);
const borrows = await cToken.methods.borrowBalanceCurrent(account).call();
RATE

Borrow Rate

Current borrow rate per block

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

CErc20 / CEther

function borrowRatePerBlock() returns (uint)

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

Solidity Example

CErc20 cToken = CToken(0x3FDA...);
uint borrowRateMantissa = cToken.borrowRatePerBlock();

Web3 1.0 Example

const cToken = CEther.at(0x3FDB...);
const borrowRate = (await cToken.methods.borrowRatePerBlock().call()) / 1e18;
SUPPLY

Total Supply

Number of tokens currently in circulation

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

CErc20 / CEther

function totalSupply() returns (uint)

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

Solidity Example

CErc20 cToken = CToken(0x3FDA...);
uint tokens = cToken.totalSupply();

Web3 1.0 Example

const cToken = CEther.at(0x3FDB...);
const tokens = (await cToken.methods.totalSupply().call());
BALANCE

Underlying Balance

User's underlying balance in the protocol

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

CErc20 / CEther

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 Example

CErc20 cToken = CToken(0x3FDA...);
uint tokens = cToken.balanceOfUnderlying(msg.caller);

Web3 1.0 Example

const cToken = CEther.at(0x3FDB...);
const tokens = await cToken.methods.balanceOfUnderlying(account).call();
RATE

Supply Rate

Current supply rate per block

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.

CErc20 / CEther

function supplyRatePerBlock() returns (uint)

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

Solidity Example

CErc20 cToken = CToken(0x3FDA...);
uint supplyRateMantissa = cToken.supplyRatePerBlock();

Web3 1.0 Example

const cToken = CEther.at(0x3FDB...);
const supplyRate = (await cToken.methods.supplyRatePerBlock().call()) / 1e18;
RESERVES

Total Reserves

Total reserves held in the market

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

CErc20 / CEther

function totalReserves() returns (uint)

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

Solidity Example

CErc20 cToken = CToken(0x3FDA...);
uint reserves = cToken.totalReserves();

Web3 1.0 Example

const cToken = CEther.at(0x3FDB...);
const reserves = (await cToken.methods.totalReserves().call());
RESERVE

Reserve Factor

Portion of borrower interest converted to reserves

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

CErc20 / CEther

function reserveFactorMantissa() returns (uint)

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

Solidity Example

CErc20 cToken = CToken(0x3FDA...);
uint reserveFactorMantissa = cToken.reserveFactorMantissa();

Web3 1.0 Example

const cToken = CEther.at(0x3FDB...);
const reserveFactor = (await cToken.methods.reserveFactorMantissa().call()) / 1e18;