Cozy tokens
API reference for Cozy tokens. Cozy tokens are a core contract in the Cozy protocol and each market is a unique instance of a Cozy token.

Core methods

This section contains the primary methods for interacting with the Cozy protocol. Most methods in this section return a uint256 value of zero (0) for a successful call, or return an error code on a unsuccessful call. The main exceptions to this general rule are the methods that are part of the standard ERC-20 specification, such as the transfer and balanceOf methods.

Mint

You use the mint function to transfer assets from your wallet to any Cozy market. You can use the mint function when you want to do the following:
  • supply funds to use as collateral for protected borrowing.
  • deposit funds to provide protection and earn interest.
Depending on whether you are minting tokens or ETH, use one of the following function signatures:
// For markets with tokens as underlying
function mint(uint256 amount) external returns (uint256);
// For markets with ETH as underlying
function mint() external payable;
For tokens, the amount is the number of tokens to supply, denominated in units of the underlying token. For ETH, instead of specifying an amount, you send ETH along with the transaction and msg.value is used in place of amount.
Before supplying a token, remember to approve the Cozy market. A successful mint call returns a value of zero and transfers Cozy tokens to the caller's wallet. The number of Cozy tokens the user receives is equal to the supplied amount divided by the exchange rate.

Redeem

You use the redeem method to redeem Cozy tokens for the underlying supplying funds. The amount of underlying received is equal to the number of Cozy tokens redeemed multiplied by the exchange rate. There are two methods you can use to redeem tokens:
// Specify amount to redeem denominated in amount of Cozy tokens
function redeem(uint256 redeemTokens) external returns (uint256);
// Specify amount to redeem denominated in amount of underlying
function redeemUnderlying(uint256 redeemAmount) external returns (uint256);
A successful redeem burns the caller's Cozy tokens, transfers a proportional amount of the underlying asset, and returns a value of zero.

Borrow

After supplying collateral with the mint method, you can use the borrow method to borrow funds from the Cozy protocol. Borrowed funds accrue interest at the current borrow rate. If a borrower has insufficient account liquidity, however, the borrowed funds can be liquidated.
The method for borrowing funds from a market is:
function borrow(uint256 borrowAmount) external returns (uint256);
where borrowAmount is specified in units of the token to borrow.

Repay debt

You can use either the repayBorrow or repayBorrowBehalf function to repay borrowed funds as follows:
// --- For markets with tokens as underlying ---
// Repays `repayAmount` of the underlying for `msg.sender`
function repayBorrow(uint256 repayAmount) external returns (uint256);
// Repays `repayAmount` of the underlying for `borrower`
function repayBorrowBehalf(address borrower, uint256 repayAmount) external returns (uint256);
// --- For markets with ETH as underlying ---
// Repays `msg.value` ETH for `msg.sender`
function repayBorrow() external payable;
// Repays `msg.value` ETH for `borrower`
function repayBorrowBehalf(address borrower) external payable;
To repay all token debt without leaving any dust, you can specify a repayAmount ofMAX_UINT256 = 2^256 - 1.
To repay all ETH debt without leaving any dust, it is recommended to use a special helper contract called Maximillion and call the following method:
function repayBehalfExplicit(address borrower, CEther cEther_) external payable;
where borrower is the address of the user to pay back debt for, and cEther_ is the address of the market to pay back debt in (for example, the Cozy Ether money market, or a protection market with ETH as the underlying). When calling this method, send along more ETH than the debt amount, and after paying off the full debt, the excess ETH will be refunded.
The Maximillion contract is deployed on mainnet at 0xf859A1AD94BcF445A406B892eF0d3082f4174088.

Liquidate

You use the liquidateBorrow function to liquidate a user's assets when their account liquidity is negative. This action brings the user back to a solvent state. During a liquidation, the liquidator repays some or all of the user's borrow and, in return, receives a portion of their collateral, as Cozy tokens, at a discount.
The maximum portion of the borrow that can be liquidated is specified by the close factor in the Comptroller. As with mints and repays, liquidating pulls tokens from the caller, so the liquidator must approve the Cozy token contract before liquidating.
Liquidations can be executed with the following methods:
// For markets with tokens as underlying
function liquidateBorrow(
address borrower,
uint256 repayAmount,
CTokenInterface cTokenCollateral
) external returns (uint256);
// For markets with ETH as underlying
function liquidateBorrow(
address borrower,
CToken cTokenCollateral
) external payable;
where borrower is the account with a shortfall to liquidate and cTokenCollateral is the token being used by the borrower as collateral that the liquidator will receive. For token-based markets, repayAmount specifies how much of the borrowed asset to repay, and for ETH-based markets that amount is specified by msg.value.

Transfer

All Cozy tokens are ERC-20 compliant and can be transferred with both the transfer and transferFrom functions. They also implement ERC-2612 permit function to improve the approval flow.
Token transfers fail if the transfer would put the account into an under-collateralized position.

View methods

This section contains the primary methods for viewing information about Cozy markets.

Exchange rate

Every Cozy token has it's own exchange rate, which is a function of the market's cash, borrows, reserves, and supply. This value is initialized to 0.02 when a market is created, and increases as the accrues interest. The exchange rate for a given market is calculated as:
exchangeRate = ( getCash() + totalBorrows() - totalReserves() ) / totalSupply();
The exchange rate is represented as a mantissa (an 18 decimal number) with a precision of 18 + underlyingDecimals - cozyTokenDecimals. For example, all Cozy tokens have 8 decimals. If the underlying token has 6 decimals, the initial exchange rate for that market would have 18 + 6 - 8 = 16 decimals. Querying the exchange rate of this market immediately after deployment would return 0.02e16 = 200000000000000.

Cash

Cash is the amount of the underlying token held by the Cozy token. You can read the cash held by the contract using the following function:
function getCash() external view returns (uint256);
For markets with tokens as the underlying, this function returns the value of underlyingToken.balanceOf(address(this));. For markets with ETH as the underlying, the function returns address(this).balance - msg.value.

Borrows

A market's total borrows is the amount of the underlying token actively borrowed. This amount is used when computing the accrued interest. It can be queried for a given market with the function below. When a market is triggered, this value is set to zero, so the below methods always returns zero after a trigger event.
// View method which returns the last known borrow amount, `totalBorrows`
function totalBorrows() external view returns (uint256);
// Non-view method which accrues interest before returning `totalBorrows`.
// Because this version accrues interest first, it will be more up to date
function totalBorrowsCurrent() external returns (uint256);
The amount being borrowed by an individual user can be read with the method below. Both methods always returns a borrow balance of zero after a market is triggered.
// View method which returns the last known borrow balance for `account`
function borrowBalanceStored(address account) external view returns (uint256);
// Non-view method which accrues interest before returning `borrowBalanceStored`.
// Because this version accrues interest first, it will be more up to date
function borrowBalanceCurrent(address account) external returns (uint256);

Supply

A market's total supply is the number of Cozy tokens that have been minted and are currently in circulation. You can use the standard ERC-20 totalSupply method to return the number of Cozy tokens in a market as follows:
function totalSupply() external view returns (uint256);

Balances

To read a user's Cozy token balance, you can use the standard ERC-20 balanceOf method as follows:
function balanceOf(address account) external view returns (uint256);
You can also read a user's balance with the balanceOfUnderlying function, which returns the user's Cozy token balance multiplied by the exchange rate.
// Note that `balanceOfUnderlying` is not a view method
function balanceOfUnderlying(address account) external returns (uint256);
For example, if a user supplies 1000 USDC with an exchange rate of 0.02, she receives 1000 / 0.02 = 50,000 Cozy tokens. Calling balanceOf will return 50,000e8, and calling balanceOfUnderlying will return 1000e6, since Cozy tokens have 8 decimals and USDC has 6 decimals).

Interest rates

You can use the borrowRatePerBlock function to read the current interest rate accrued by borrowers every block.
function borrowRatePerBlock() external view returns (uint256);
The supply-rate-per-block is a function of the borrow-rate-per-block, as well the market's reserve factor and the its utilization rate. The utilization rate is the ratio of borrowed funds to supplied funds, calculated as borrows / (cash + borrows - reserves). The supply rate is then calculated as utilizationRate * (borrowRatePerBlock * (1 - reserveFactor)). You can query this value as follows:
function supplyRatePerBlock() external view returns (uint256);
Both the borrow rate and supply rate returned from these methods will always be zero after a market is triggered.

Reserves

A portion of interest accrued from borrowers is set aside as cash, and cash from this source is known as reserves. The amount of reserves set aside is determined by the reserve factor. You can use the reserveFactorMantissa method to return the reserve factor. See the Interest Rates section for more information on how the reserve factor is used.
// Returns a mantissa, so it's scaled by 1e18
function reserveFactorMantissa() external view returns (uint256)
The total reserves in a given market can be read with:
function totalReserves() external view returns (uint256)
Reserves can be withdrawn or transferred by the protocol administrator.

Events

This sections contains the core events emitted by Cozy token contracts, and is not a comprehensive list.
// Emitted when interest is accrued
event AccrueInterest(uint256 cashPrior, uint256 interestAccumulated, uint256 borrowIndex, uint256 totalBorrows);
// Emitted when tokens are minted
event Mint(address minter, uint256 mintAmount, uint256 mintTokens);
// Emitted when tokens are redeemed
event Redeem(address redeemer, uint256 redeemAmount, uint256 redeemTokens);
// Emitted when underlying is borrowed
event Borrow(address borrower, uint256 borrowAmount, uint256 accountBorrows, uint256 totalBorrows);
// Emitted when a borrow is repaid
event RepayBorrow(address payer, address borrower, uint256 repayAmount, uint256 accountBorrows, uint256 totalBorrows);
// Emitted when a borrow is liquidated
event LiquidateBorrow(
address liquidator,
address borrower,
uint256 repayAmount,
address cTokenCollateral,
uint256 seizeTokens
);
// Emitted when trigger status is set. This is emitted once at
// construction and one more time when the trigger is toggled
event TriggerSet(bool isTriggered);

Error handling

This section contains information about error codes and failure messages that may be returned when calling methods on a Cozy token contract.

Error codes

The table below contains a list of error codes that may be returned when calling methods on a Cozy token contract.
Code
Name
Description
0
NO_ERROR
Call succeeded
1
UNAUTHORIZED
Caller is not authorized
2
BAD_INPUT
Caller provided bad arguments
3
COMPTROLLER_REJECTION
The Comptroller blocked this action
4
COMPTROLLER_CALCULATION_ERROR
A calculation failed in the Comptroller
5
INTEREST_RATE_MODEL_ERROR
An invalid value was returned from the interest rate model
6
INVALID_ACCOUNT_PAIR
The borrower and liquidator are the same account
7
INVALID_CLOSE_AMOUNT_REQUESTED
The MAX_UINT256 is passed as the repayAmount during liquidation
8
INVALID_COLLATERAL_FACTOR
Provided collateral factor is not allowed
9
MATH_ERROR
An error occurred in a math operation
10
MARKET_NOT_FRESH
The market has not properly accrued interest
11
MARKET_NOT_LISTED
The market is not supported by the Comptroller
12
TOKEN_INSUFFICIENT_ALLOWANCE
Caller has not approved the contract to spend enough tokens
13
TOKEN_INSUFFICIENT_BALANCE
Caller has an insufficient token balance to complete the transaction
14
TOKEN_INSUFFICIENT_CASH
The market does not have enough cash at this time
15
TOKEN_TRANSFER_IN_FAILED
ERC-20 token transfer to the market failed
16
TOKEN_TRANSFER_OUT_FAILED
ERC-20 token transfer from the market failed
17
INVALID_GUARDIAN
Reserve guardian cannot be the zero address

Failure codes and logged messages

The table below contains a list of error codes that may be emitted in Failure logs when calling methods on a Cozy token contract. These codes are descriptive so no additional description is provided.
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_COMPTROLLER_REJECTION
15
LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED
16
LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED
17
LIQUIDATE_COLLATERAL_FRESHNESS_CHECK
18
LIQUIDATE_COMPTROLLER_REJECTION
19
LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED