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:
1
// For markets with tokens as underlying
2
function mint(uint256 amount) external returns (uint256);
3
4
// For markets with ETH as underlying
5
function mint() external payable;
Copied!
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:
1
// Specify amount to redeem denominated in amount of Cozy tokens
2
function redeem(uint256 redeemTokens) external returns (uint256);
3
4
// Specify amount to redeem denominated in amount of underlying
5
function redeemUnderlying(uint256 redeemAmount) external returns (uint256);
Copied!
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:
1
function borrow(uint256 borrowAmount) external returns (uint256);
Copied!
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:
1
// --- For markets with tokens as underlying ---
2
// Repays `repayAmount` of the underlying for `msg.sender`
3
function repayBorrow(uint256 repayAmount) external returns (uint256);
4
5
// Repays `repayAmount` of the underlying for `borrower`
6
function repayBorrowBehalf(address borrower, uint256 repayAmount) external returns (uint256);
7
8
// --- For markets with ETH as underlying ---
9
// Repays `msg.value` ETH for `msg.sender`
10
function repayBorrow() external payable;
11
12
// Repays `msg.value` ETH for `borrower`
13
function repayBorrowBehalf(address borrower) external payable;
Copied!
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:
1
function repayBehalfExplicit(address borrower, CEther cEther_) external payable;
Copied!
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:
1
// For markets with tokens as underlying
2
function liquidateBorrow(
3
address borrower,
4
uint256 repayAmount,
5
CTokenInterface cTokenCollateral
6
) external returns (uint256);
7
8
// For markets with ETH as underlying
9
function liquidateBorrow(
10
address borrower,
11
CToken cTokenCollateral
12
) external payable;
Copied!
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:
1
exchangeRate = ( getCash() + totalBorrows() - totalReserves() ) / totalSupply();
Copied!
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:
1
function getCash() external view returns (uint256);
Copied!
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.
1
// View method which returns the last known borrow amount, `totalBorrows`
2
function totalBorrows() external view returns (uint256);
3
4
// Non-view method which accrues interest before returning `totalBorrows`.
5
// Because this version accrues interest first, it will be more up to date
6
function totalBorrowsCurrent() external returns (uint256);
Copied!
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.
1
// View method which returns the last known borrow balance for `account`
2
function borrowBalanceStored(address account) external view returns (uint256);
3
4
// Non-view method which accrues interest before returning `borrowBalanceStored`.
5
// Because this version accrues interest first, it will be more up to date
6
function borrowBalanceCurrent(address account) external returns (uint256);
Copied!

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:
1
function totalSupply() external view returns (uint256);
Copied!

Balances

To read a user's Cozy token balance, you can use the standard ERC-20 balanceOf method as follows:
1
function balanceOf(address account) external view returns (uint256);
Copied!
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.
1
// Note that `balanceOfUnderlying` is not a view method
2
function balanceOfUnderlying(address account) external returns (uint256);
Copied!
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.
1
function borrowRatePerBlock() external view returns (uint256);
Copied!
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:
1
function supplyRatePerBlock() external view returns (uint256);
Copied!
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.
1
// Returns a mantissa, so it's scaled by 1e18
2
function reserveFactorMantissa() external view returns (uint256)
Copied!
The total reserves in a given market can be read with:
1
function totalReserves() external view returns (uint256)
Copied!
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.
1
// Emitted when interest is accrued
2
event AccrueInterest(uint256 cashPrior, uint256 interestAccumulated, uint256 borrowIndex, uint256 totalBorrows);
3
4
// Emitted when tokens are minted
5
event Mint(address minter, uint256 mintAmount, uint256 mintTokens);
6
7
// Emitted when tokens are redeemed
8
event Redeem(address redeemer, uint256 redeemAmount, uint256 redeemTokens);
9
10
// Emitted when underlying is borrowed
11
event Borrow(address borrower, uint256 borrowAmount, uint256 accountBorrows, uint256 totalBorrows);
12
13
// Emitted when a borrow is repaid
14
event RepayBorrow(address payer, address borrower, uint256 repayAmount, uint256 accountBorrows, uint256 totalBorrows);
15
16
// Emitted when a borrow is liquidated
17
event LiquidateBorrow(
18
address liquidator,
19
address borrower,
20
uint256 repayAmount,
21
address cTokenCollateral,
22
uint256 seizeTokens
23
);
24
25
// Emitted when trigger status is set. This is emitted once at
26
// construction and one more time when the trigger is toggled
27
event TriggerSet(bool isTriggered);
Copied!

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
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_COMPTROLLER_REJECTION
28
LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER
29
LIQUIDATE_SEIZE_TOO_MUCH
30
MINT_ACCRUE_INTEREST_FAILED
31
MINT_COMPTROLLER_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_COMPTROLLER_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_COMPTROLLER_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_COMPTROLLER_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_COMPTROLLER_REJECTION
75
TRANSFER_NOT_ALLOWED
76
TRANSFER_NOT_ENOUGH
77
TRANSFER_TOO_MUCH
78
ADD_RESERVES_ACCRUE_INTEREST_FAILED
79
ADD_RESERVES_FRESH_CHECK
80
ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE
81
REDUCE_RESERVES_GUARDIAN_NOT_SET
82
TRIGGER_ACTIVATED_BEFORE_REDEEM_OR_BORROW
Last modified 4mo ago