# Introduction

DeFiner protocol introduction

## What is DeFiner?

DeFiner is a decentralized finance network for crypto savings, loans, and payments. Powered by blockchain technology, DeFiner enables users to effortlessly lend, borrow, and earn digital assets within a global network. DeFiner removes the friction and costs associated with conventional financial services and instead offers maximum flexibility to set one’s own rates and terms.DeFiner allows those embracing the new, digital economy to unlock instant value from their assets.

The following documentation describes the fundamentals of the protocol and how to interact with it. Please join the #development room in the DeFiner community Discord server; our team and members of the community look forward to helping you build on top of DeFiner.

### Basic overview

The DeFiner protocol codebase is hosted on [Github](https://github.com/DeFinerOrg/Savings).

The protocol is implemented as a set of **smart contracts** on top of the Ethereum blockchain. Smart contracts guarantee safety and do not require a middleman.&#x20;

Users and applications can interact directly with the smart contracts, the blockchain data, or via their favorite web3 providers.

DeFiner Protocol is developed with security as a priority, having been audited by multiple auditors.

For a deeper dive into the protocol, economics, and how it works, refer to the [White Paper](https://github.com/DeFinerOrg/whitepaper/wiki/DeFiner-Whitepaper).

## Network

The DeFiner Protocol is currently deployed on the following networks:

## Gas Costs

![](/files/-MT4NELFmwhbcr0SAc-i)

![](/files/-MT4NJQizknVSQ6GsBYf)


# Protocol Overview

DeFiner Savings protocol aggregates crypto deposits from lenders to the smart contract for users to borrow against the collateral asset that they deposited. The protocol will If there is unused capital in the contract, it will be auto deployed on money market protocol like Compound, AAVE etc.&#x20;

![](/files/-Mi_iBUT2C7aEdL4ovxc)

## Capital Reservation Ratio and Compound Ratio

For current available digital assets on the compound protocol (Ether, USD Coin, Augur, Dai, Sai, Wrapped BTC, Ox, Basic Attention Token), as there is cToken available, this enables DeFiner to supply/withdraw assets to compound to improve the utilization rate of DeFiner. &#x20;

DeFiner auto supplies loan currency to “Compound Network” when capital reserve ratio (R) increases to a certain level, and auto withdraws loan currency from “Compound Network” when capital reservation ratio (R) drops to a range between 0 and 10. Here are the definitions of  Capital Utilization Rate (U ), Capital Compound Ratio (C) and Capital reserve ratio (R).

1. Capital Utilization Rate (U)= total loan outstanding / Total market deposit.
2. Capital Compound Ratio (C) = total capital in Compound / Total market deposit.
3. Capital reserve ratio (R) = 1 - U - C.

DeFiner always keeps the R between 10 and 20.  When R > 20,   it should signal Savings Pool Smart Contract to deposit to compound, which increases the value of C and reduces remaining reserve fund to 15% of total deposit. When R < 10, it should signal Savings Pool Smart Contract to withdraw from the money market, which decreases the value of C and increases the remaining reserve fund to 15% of the total deposit. (This reserve ratio range is globally configurable.)


# Interest Model

### **Interest Rate Calculations**

#### **Definitions:**

* **u** is the capital utilization rate of a certain token
* **Compound Supply Rate**: the real-time supply rate on the money market
* **Compound Borrow Rate**: the real-time borrow rate on the money market
* **Compound Supply Rate Weight**: the weight parameter of the Compound Supply Rate
* **Compound Borrow Rate Weight**: the weight parameter of the Compound Borrow Rate
* **Compound Supply Ratio**: the percentage of capital deployed on money market

#### Borrow Rate Model

$$Borrow APR= Compound Supply Rate Weights  \times Compound Supply Rate + Compound Borrow Rate Weights \times Compound Borrow Rate () + RateCurve Constant\div(1-u)$$&#x20;

When  $$u$$ >0.98,

$$Rate Curve Constant\div(1-u) = Rate Curve Constant \div(1-0.98)= RateCurveConstant\times50$$&#x20;

For assets that are not available on Compound or other money markets, Compound Supply Rate Weights=0, Compound Borrow Rate Weights=0,

In summary, there are two factors that decided the Borrow APR, the prevailing market rate that is available in the market and the capital utilization rate in the DeFiner protocol. Also,  it's a non-linear model. The borrowing interest can adapt quickly if the utilization of the pool approaches a relatively high level.

Based on different parameter sets, we have three different strategies: Conservative Mode, Moderate Model, and Aggressive Model.&#x20;

| Parameters                                | Conservative Model | Moderate Model | Aggressive Model |
| ----------------------------------------- | :----------------: | :------------: | :--------------: |
| <p>Compound Supply </p><p>Rate Weight</p> |         0.1        |       0.3      |        0.9       |
| <p>Compound Borrow </p><p>Rate Weight</p> |         0.9        |       0.7      |        0.1       |
| \_RateCurveConstant                       |          3         |        6       |        10        |

Below is how the borrow interest rate curve varies at different capital utilization levels based on three strategies.&#x20;

![Interest Model](/files/-Mi_XvGXEi1tR-kDte77)

#### Pseudocode:

```
function getBorrowRatePerBlock(address _token) public view returns(uint) {    
    if(isSupportedOnCompound) {
        if (u>0.999) {
            BorrowAPR= compoundSupplyRateWeights*(compoundSupplyRate) + compoundBorrowRateWeights*(compoundBorrowRate) + RateCurveConstant*(1000);
        } else {
            BorrowAPR= compoundSupplyRateWeights*(compoundSupplyRate) + compoundBorrowRateWeights*(compoundBorrowRate) + RateCurveConstant/(1-u);
        } 
    } else {
        if (u>0.999) {
            BorrowAPR = RateCurveConstant*(1000);
        } else {
            BorrowAPR = RateCurveConstant/(1-u);
        }
    }
}
```

#### Code:

```
function getBorrowRatePerBlock(address _token) public view returns(uint) {
    uint256 capitalUtilizationRatio = getCapitalUtilizationRatio(_token);
    // rateCurveConstant = <'3 * (10)^16'_rateCurveConstant_configurable>
    uint256 rateCurveConstant = globalConfig.rateCurveConstant();
    // compoundSupply = Compound Supply Rate * <'0.4'_supplyRateWeights_configurable>
    uint256 compoundSupply = compoundPool[_token].depositRatePerBlock.mul(globalConfig.compoundSupplyRateWeights());
    // compoundBorrow = Compound Borrow Rate * <'0.6'_borrowRateWeights_configurable>
    uint256 compoundBorrow = compoundPool[_token].borrowRatePerBlock.mul(globalConfig.compoundBorrowRateWeights());
    // nonUtilizedCapRatio = (1 - U) // Non utilized capital ratio
    uint256 nonUtilizedCapRatio = INT_UNIT.sub(capitalUtilizationRatio);

    bool isSupportedOnCompound = globalConfig.tokenInfoRegistry().isSupportedOnCompound(_token);
    if(isSupportedOnCompound) {
        uint256 compoundSupplyPlusBorrow = compoundSupply.add(compoundBorrow).div(10);
        uint256 rateConstant;
        // if the token is supported in third party (like Compound), check if U = 1
        if(capitalUtilizationRatio > ((10**18) - (10**15))) { // > 0.999
            // if U = 1, borrowing rate = compoundSupply + compoundBorrow + ((rateCurveConstant * 100) / BLOCKS_PER_YEAR)
            rateConstant = rateCurveConstant.mul(1000).div(BLOCKS_PER_YEAR);
            return compoundSupplyPlusBorrow.add(rateConstant);
        } else {
            // if U != 1, borrowing rate = compoundSupply + compoundBorrow + ((rateCurveConstant / (1 - U)) / BLOCKS_PER_YEAR)
            rateConstant = rateCurveConstant.mul(10**18).div(nonUtilizedCapRatio).div(BLOCKS_PER_YEAR);
            return compoundSupplyPlusBorrow.add(rateConstant);
        }
    } else {
        // If the token is NOT supported by the third party, check if U = 1
        if(capitalUtilizationRatio > ((10**18) - (10**15))) { // > 0.999
            // if U = 1, borrowing rate = rateCurveConstant * 100
            return rateCurveConstant.mul(1000).div(BLOCKS_PER_YEAR);
        } else {
            // if 0 < U < 1, borrowing rate = 3% / (1 - U)
            return rateCurveConstant.mul(10**18).div(nonUtilizedCapRatio).div(BLOCKS_PER_YEAR);
        }
    }
}
```

#### Deposit Rate Model

$$Deposit Rate= CompoundSupplyRatio\times CompoundSupplyRate +BorrowRate\times u$$&#x20;

For assets that are not available on Compound or other money markets, Compound Supply Rate Weights=0, Compound Borrow Rate Weights=0

#### PseudoCode

```
function getDepositRatePerBlock(address _token) public view returns(uint) {    
    uint borrowRatePerBlock = getBorrowRatePerBlock(_token);
    uint capitalUtilRatio = getCapitalUtilizationRatio(_token);
    
    if(!isSupportedOnCompound) {
        DepositAPR = borrowRatePerBlock * capitalUtilRatio;
    } else {
        DepositAPR = borrowRatePerBlock * capitalUtilRatio + CompoundSupplyRate*(u);
    }
}
```

#### Code:

```
function getDepositRatePerBlock(address _token) public view returns(uint) {
    uint256 borrowRatePerBlock = getBorrowRatePerBlock(_token);
    uint256 capitalUtilRatio = getCapitalUtilizationRatio(_token);
    if(!globalConfig.tokenInfoRegistry().isSupportedOnCompound(_token))
        return borrowRatePerBlock.mul(capitalUtilRatio).div(INT_UNIT);
    
    return borrowRatePerBlock.mul(capitalUtilRatio).add(compoundPool[_token].depositRatePerBlock
        .mul(compoundPool[_token].capitalRatio)).div(INT_UNIT);
}
```

### Interest Accounting System

**Definitions:**

* **Deposit principle**: the crypto assets that users deposited
* **Deposit interest**: interest that the depositor earned
* **Deposit storage interest:** the interest that depositor accrued
* **Deposit accrual interest:** the deposit interest that has not accrued
* **Deposit Interest per block:** interest that user earned for every block
* **BlocksPerYear:** annual expected blocks of the blockchain&#x20;

**Formular:**

$$Deposit Interest Rate Per Block = BorrowAPR\div BlocksPerYear$$&#x20;

$$Deposit Interest Per Block = (Deposit Principle+Deposit Storage Interest) \times Deposit Interest Rate Per Block$$&#x20;

$$DepositInterest(block\_t)=DepositInterest(block\_t -\_1))+DepositInterestPerBlock$$&#x20;

**BorrowAPR** will be updated in the contract if there were any users who have deposits of the token performs a transaction

The interest earned between the last transaction block of the user and the latest transaction block will be accrued if the user performed a transaction and will be added to the **Deposit Storage Interest.**&#x20;


# Risks Control Model

Details of how liquidation works in DeFiner

### **Parameters**

1. \_liquidator: address of the liquidator.
2. \_borrower: address of the borrower, also the account which will be liquidated
3. \_borrowedToken:  address of the borrowed token
4. \_collateralToken: address of the collateral token

### Design Overview

By calling this function, the liquidator repays the borrower's loan if the borrower is liquidatable and also ends up buying the borrower's collateral at a 5% discounted price. This also resets the borrower's LTV back to what it was initially. The tokens that the liquidator uses to liquidate the borrower's account should be deposited in DeFiner.

By calling this function, the liquidator repays the borrower's loan if the borrower is liquidatable and also ends up buying the borrower's collateral at a 5% discounted price. This resets the borrower's LTV back to what it was initially. The tokens that the liquidator uses to liquidate the borrower's account should be deposited in DeFiner.

In order to be liquidatable, an account's LTV should be greater than 85%, since there is a high risk that this account will not repay it's debt once the LTV goes above 85%.

In order to be liquidatable, an account's LTV should be greater than 85%, since there is a high risk that this account will not repay it's debt once the LTV goes above 85%.

If all conditions are met, the `liquidate` function majorly executed the following operations:

1. Liquidator deposits collateral tokens equivalent to the `payAmount` calculated
2. Withdraws borrowed tokens equivalent to the `repayAmount` to the liquidator
3. Withdraws collateral tokens equivalent to the `payAmount`.
4. Repays the borrower's loan.

Please refer to the pseudocode given below for more details on how these calculations are performed.

### Examples:

**Terminology used:**

**CBB**: Current borrow balance = principle + accrued interest

**LDR:** Liquidation Discount ratio: The discount ratio the liquidator will get when buying other's assets during the liquidation process.

**CCV**: Current Collateral Value = Collateral price \* Collateral Amount

**UAAL**: User asset at Liquidation: The maximum collateral that can be liquidated or swapped.

**BP**: Borrow Power of borrower

**ILTV**: Initial LTV ratio of collateral token: 0.6 currently for most tokens

We have to make sure that:

$$
UAAL= (CBB – BP) \*100 / (LDR-ILTV)
$$

Before liquidation:

(Assuming 1 DAI = 1 USDT = $1)\
USDT Price drops by 65% after user deposits, setting LTV to 92%

1. **Full liquidation**

(Assuming 1 USDT = 1 DAI = $1)\
Collateral price drops to 65% after User 1 borrows

User1:

$$
UAAL=(60-39)\*100/(95-60)=60
$$

1. Deposits: 100 USDT
2. Loans: 60 DAI
3. Collateral price drops to 65%, new collateral value = $65
4. LTV: 0.92, liquidatable
5. New borrow power = initial BP \* %age price drop = 60 \* 0.65 = 39

User2:

1. Deposits 200 DAI
2. It calls liquidate(user1, DAIAdress, USDTAddress)

Explanation

The maximum amount of DAI that user2 can transfer to user1 is 200 since it doesn't have any borrows.

Since DAI's price is 1, and 60 < 200, so user2 is able to pay the maximum value, which is 60 DAI. This is called full liquidation.

After Liquidation:\
User 1:

1. Deposits: 5 USDT&#x20;
2. Borrows: 0
3. User is not liquidatable

User 2:

1. Deposits: 95 USDT

&#x20;  2\. **Partial Liquidation**

Before Liquidation:

User1:

1. Deposits: 100 USDT
2. Loans: 60 DAI
3. Collateral price drops to 65%, new collateral value = $65
4. LTV: 0.92, liquidatable
5. &#x20;borrow power = initial BP \* %age price drop = 60 \* 0.65 = 39

User2:

1. Deposits 50 DAI
2. It calls liquidate(user1, DAIAdress, USDTAddress)

Explanation:

Here, UAAL is computed the same way as the previous example.

$$
UAAL=(60-39)\*100/(95-60)=60
$$

But here user2 only has 50DAI, which worth $50 and 50 < 60 so user2 can't be swapped to the maximum value UAAL. That way, user2 only pays 50 DAI and user1 will pay 50 / 0.95 = 52.6 USDC.

After liquidation

User 1:

1. Deposits: 100 - 50/0.95 = 47.4 USDT&#x20;
2. Borrows: 60-50 = 10DAI
3. LTV: 10 / 47.4 = 0.21, not liquidatable

User 2:

1. Deposits: 50/0.95 = 52.6 USDC

Notice here although user2 doesn't fully liquidate user1, user1 is not liquidatable after liquidation. This is because there is a gap between the initial borrow LTV and the LTV to become liquidatable.

### Pseudocode

```javascript
require(isAccountLiquidatable(_borrower);

if (liquidator has borrows){
    require(Liquidator's borrow value < Liquidator's borrow power;
}

uint tokenBalLiquidator = get deposit balance of Liquidator;

uint tokenBalBorrowedUser = get borrow balance of Borrower;

uint borrowedTokenAmountForLiquidation = tokenBalLiquidator.min(tokenBalBorrowedUser)

uint borrowerCollateralVal = getDepositBalanceCurrent(_collateralToken, _borrower);

uint collateralLTV = 60%;

uint totalBorrowwValBorwer = getBorrowETH(_borrower);
uint borrowPowerBorrower = getBorrowPower(borrower);
uint liquidationDiscountRatio = 95%;

uint limiRepaymentVal = (totalBorrowwValBorwer - borrowPowerBorrower) / (liquidationDiscountRatio - collateralLTV);

uint collateralTokenValueForLiquidation = limiRepaymentVal.min(tokenBalLiquidator);

uint liquidationVal = collateralTokenValueForLiquidation.min(borrowedTokenAmountForLiquidation * borrowedTokenPrice / liquidationDiscountRatio);

uint repaymentAmount = (liquidationVal * borrowTokenDivisor) / borrowTokenPrice;
uint payAmount = (repaymentAmount * liquidateTokenDivisor * borrowTokenPrice) / (borrowTokenDivisor * liquidationDiscountRatio * liquidateTokenPrice);

deposit(_liquidator, _collateralToken, payAmount);
_withdrawLiquidate(_liquidator, _borrowedToken, repaymentAmount);
_withdrawLiquidate(_borrower, _collateralToken, payAmount);
repay(_borrower, _borrowedToken, repaymentAmount);

return (repaymentAmount, payAmount);

```

### Source Code

```javascript
function liquidate(
        address _liquidator,
        address _borrower,
        address _borrowedToken,
        address _collateralToken
    ) external onlyAuthorized returns (uint256, uint256) {
        initCollateralFlag(_liquidator);
        initCollateralFlag(_borrower);
        require(isAccountLiquidatable(_borrower), "borrower is not liquidatable");

        // It is required that the liquidator doesn't exceed it's borrow power.
        // if liquidator has any borrows, then only check for borrowPower condition
        Account storage liquidateAcc = accounts[_liquidator];
        if (liquidateAcc.borrowBitmap > 0) {
            require(getBorrowETH(_liquidator) < getBorrowPower(_liquidator), "No extra funds used for liquidation");
        }

        LiquidationVars memory vars;

        ITokenRegistry tokenRegistry = globalConfig.tokenInfoRegistry();

        // _borrowedToken balance of the liquidator (deposit balance)
        vars.targetTokenBalance = getDepositBalanceCurrent(_borrowedToken, _liquidator);
        require(vars.targetTokenBalance > 0, "amount must be > 0");

        // _borrowedToken balance of the borrower (borrow balance)
        vars.targetTokenBalanceBorrowed = getBorrowBalanceCurrent(_borrowedToken, _borrower);
        require(vars.targetTokenBalanceBorrowed > 0, "borrower not own any debt token");

        // _borrowedToken available for liquidation
        uint256 borrowedTokenAmountForLiquidation = vars.targetTokenBalance.min(vars.targetTokenBalanceBorrowed);

        // _collateralToken balance of the borrower (deposit balance)
        vars.liquidateTokenBalance = getDepositBalanceCurrent(_collateralToken, _borrower);

        uint256 targetTokenDivisor;
        (, targetTokenDivisor, vars.targetTokenPrice, vars.borrowTokenLTV) = tokenRegistry.getTokenInfoFromAddress(
            _borrowedToken
        );

        uint256 liquidateTokendivisor;
        uint256 collateralLTV;
        (, liquidateTokendivisor, vars.liquidateTokenPrice, collateralLTV) = tokenRegistry.getTokenInfoFromAddress(
            _collateralToken
        );

        // _collateralToken to purchase so that borrower's balance matches its borrow power
        vars.totalBorrow = getBorrowETH(_borrower);
        vars.borrowPower = getBorrowPower(_borrower);
        vars.liquidationDiscountRatio = globalConfig.liquidationDiscountRatio();
        vars.limitRepaymentValue = vars.totalBorrow.sub(vars.borrowPower).mul(100).div(
            vars.liquidationDiscountRatio.sub(collateralLTV)
        );

        uint256 collateralTokenValueForLiquidation = vars.limitRepaymentValue.min(
            vars.liquidateTokenBalance.mul(vars.liquidateTokenPrice).div(liquidateTokendivisor)
        );

        uint256 liquidationValue = collateralTokenValueForLiquidation.min(
            borrowedTokenAmountForLiquidation.mul(vars.targetTokenPrice).mul(100).div(targetTokenDivisor).div(
                vars.liquidationDiscountRatio
            )
        );

        vars.repayAmount = liquidationValue.mul(vars.liquidationDiscountRatio).mul(targetTokenDivisor).div(100).div(
            vars.targetTokenPrice
        );
        vars.payAmount = vars.repayAmount.mul(liquidateTokendivisor).mul(100).mul(vars.targetTokenPrice);
        vars.payAmount = vars.payAmount.div(targetTokenDivisor).div(vars.liquidationDiscountRatio).div(
            vars.liquidateTokenPrice
        );

        deposit(_liquidator, _collateralToken, vars.payAmount);
        _withdrawLiquidate(_liquidator, _borrowedToken, vars.repayAmount);
        _withdrawLiquidate(_borrower, _collateralToken, vars.payAmount);
        repay(_borrower, _borrowedToken, vars.repayAmount);

        return (vars.repayAmount, vars.payAmount);
    }
```

###


# Smart Contract Modules


# Overview

### Contracts

We have four main contracts in our Protocol, and they are SavingAccount, Accounts, Bank, TokenRegistry, and GlobalConfig.

The first three contracts are upgradable contracts, and they contain the main business logic of our Protocol. The overall structure of our Protocol is monolithic, which means that SavingAccount, Accounts, and Bank contracts work closely with each other. We decoupled this into three contracts only for code size limit reasons. The naming here maybe a little counter intuitive. Normally when we want to deposit money to a bank, we first go to the bank and open a saving account, then we deposit money to this account. Here, SavingAccount contract behaves like a traditional bank, which is the entry point for you to deposit or borrow money from DeFiner. The Bank contract records the state of the pool of DeFiner's protocol, like the total deposit, total borrow, and the current rate. The Accounts contract records the deposit and borrow balances for each specific user.

The workflow of a transaction to DeFiner works as the following diagram. The user sends transactions by calling functions on SavingAccount contract, then the SavingAccount contract will call the Bank contract to create a rate index checkpoint, which is used to compute the accumulated interests for all the user. Then the Bank contract will call the functions in Account contract to compute the balance change in the user account.

![The workflow of a transaction](/files/-MS-wDMnNfMibc_feTx9)

The TokenRegistry and GlobalConfig contracts are used to save data that will be used among the three main contracts. Like all three contracts' addresses, so in these three contract, they only need to keep global config's address in contract's memory space.

### SavingAccount

This is the interface contract that our users will mainly interact with. Users will send transactions to this contract to do deposit, withdraw, borrow, repay,  withdrawAll, and liquidate functions to this contract to interact with our protocol. For each operation, this contract is the contract that receives and sends out the tokens. Whenever there is a transaction sent to SavingAccount contract, it will emit an event to log this transaction.

#### Borrowing Power

The borrowing power of a user is related to the collateral that the user deposited into our system. The price is obtained from Chainlink's oracle. If the LTV of a user is too large then it is at the risk of being liquidated. Currently, the liquidation threshold is set to around 0.8.&#x20;

### Bank

This contract is used to create rate indexes whenever there is an interaction with our SavingAccount contract. We are using rate indexes to compute the borrow and deposit interests. Given the different indexes, we compute the user balances here. Whenever an index is created, this contract will emit an event.

#### Rate Index&#x20;

i and j here represent two different blocks.

$$RateIndex\_i = RateIndex\_j \* (1 + RatePerBlock\_{ij} \* (i - j))$$&#x20;

#### Balance

i and j here represent two different blocks.

$$Balance\_i = Balance\_j \times RateIndex\_j \div RateIndex\_i$$&#x20;

Borrow balances and deposit balances both use this method to compute.

### Accounts

This contract is used to record the balances of each user account for different tokens. This contract also contains a BitMap which will quickly show whether a user has depositings/borrowings for each token while costs less gas.

### GlobalConfig

This contract is used to store all the contract's addresses, so all other contracts can only keep GlobalConfig's address to call functions of other contracts. It also used to config the reserve ratio and community fund ratio of the protocol.

### TokenRegistry

This contract records the meta-data about each contract supported token. We can add new supported tokens using this contract.

#### Current Supported Tokens

1. DAI
   1. Token Address: 0x6b175474e89094c44da98b954eedeac495271d0f
   2. cToken Address: 0x5d3a536e4d6dbd6114cc1ead35777bab948e3643
2. USDC
   1. Token Address: 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
   2. cToken Address: 0x39aa39c021dfbae8fac545936693ac917d5e7563
3. USDT
   1. Token Address: 0xdac17f958d2ee523a2206206994597c13d831ec7
   2. cToken Address: 0xf650c3d88d12db855b8bf7d11be6c55a4e07dcc9
4. TUSD
   1. Token Address: 0x0000000000085d4780B73119b644AE5ecd22b376
   2. cToken Address: Not Compound supported.
5. MKR
   1. Token Address: 0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2
   2. cToken Address: Not Compound supported.
6. BAT
   1. Token Address: 0x0d8775f648430679a709e98d2b0cb6250d2887ef
   2. cToken Address: 0x6c8c6b02e7b2be14d4fa6022dfd6d75921d90e4e
7. ZRX
   1. Token Address: 0xe41d2489571d322189246dafa5ebde1f4699f498
   2. cToken Address: 0xb3319f5d18bc0d84dd1b4825dcde5d5f7266d407
8. REP
   1. Token Address: 0x1985365e9f78359a9B6AD760e32412f4a445E862
   2. cToken Address: 0x158079ee67fce2f58472a96584a73c7ab9ac95c1
9. WBTC
   1. Token Address: 0x2260fac5e5542a773aa44fbcfedf7c193bc2c599
   2. cToken Address: 0xc11b1268c1a384e55c48c2391d8d480264a3a7f4
10. FIN
    1. Token Address: 0x054f76beED60AB6dBEb23502178C52d6C5dEbE40
    2. cToken Address: Not Compound supported
11. FIN LPToken
    1. Token Address: 0x054f76beED60AB6dBEb23502178C52d6C5dEbE40
    2. cToken Address: Not Compound supported

### Upgradability

For SavingAccount, Accounts, and Bank contracts, we are using OpenZeppelin proxies to conduct the upgrading process. So other than the contracts, we also have an OpenZeppelin proxy contract for each of these three main contracts. The proxy contract addresses can never be changed, but the contract of the underlying implementation is changeable.

![The workflow of a proxy contract.](/files/-MS-yAnjJY1G1GCps729)

For the GlobalConfig and TokenRegistry contracts, we can deploy a new contract and call the setter function in three main contracts to point to the new contracts, since they don't save any transactional data.


# SavingAccount

SavingAccount contract.

SavingAccount is the main interface contract that processes a user's deposit/withdraw and borrow/repay requests, the details of these methods are in the `Bank` contract.  It also provides the functionality for the third-parities for liquidation. Please check the modifier page to confirm the semantics of each modifier in the function head here.

## deposit

#### function head

`function deposit(address _token, uint256 _amount) public payable onlySupportedToken(_token) onlyEnabledToken(_token) nonReentrant`

* parameters
  * \_token: The address of the token that the user wants to deposit.
  * amount: The volume of the token that the user wants to deposit.

#### description

The function receives a certain amount of tokens from `msg.sender` and deposits them to the pool. This function calls the `deposit` function in the `Bank` contract, and emit the`Deposit` event. Please make sure your account has enough tokens to avoid gas waste.

## withdraw

#### function head

`function withdraw(address _token, uint256 _amount) external onlySupportedToken(_token) whenNotPaused nonReentrant`

* parameters
  * \_token: The address of the token that the user wants to withdraw.
  * amount: The volume of the token that the user wants to withdraw.

#### description

The function withdraws a certain amount of tokens from the pool and then send them to `msg.sender`. This function calls the `withdraw` function in the `Bank` contract, and emit the `Withdraw` event.

You can't withdraw tokens to make your borrow power that is less than the total value of your borrowed tokens. For more info about borrow power, please check the description on the Accounts page.

The actual token an account withdraw could be smaller than it requested because 10% of the interest is deducted and saved as the DeFiner community fund.

## withdrawAll

#### function head

`function withdrawAll(address _token) external onlySupportedToken(_token) whenNotPaused nonReentrant`

* parameters
  * \_token: The address of the token that the user wants to withdraw.

#### description

The function  withdraw all tokens of an account from the pool and send them to `msg.sender.` This function first checks the current deposit balance of the account by calling `getDepositBalanceCurrent` in the `Accounts` contract, and then calls the `withdraw` function in the `Bank` contract to request withdrawing that exact amount of token, and emit the `WithdrawAll` event.

The actual token an account withdraw could be smaller than its total deposit balance because 10% of the interest is deducted and saved as the DeFiner community fund.

If after withdrawing all these kinds of tokens, your borrow power will be less than the value of your borrowed tokens, this function will fail. Please check Accounts page for more info about borrow power.

## borrow

#### function head

`function borrow(address _token, uint256 _amount) external onlySupportedToken(_token) onlyEnabledToken(_token) whenNotPaused nonReentrant`

* parameters
  * \_token: The address of the token that the user wants to borrow.
  * amount: The volume of the token that the user wants to borrow.

#### description

An account uses `borrow` function to borrow a certain amount of token from the pool. This function calls the `borrow` function in the `Bank` contract, and emit the `Borrow` event.

You can't borrow tokens that have value more than your borrow power. Please check Accounts page for more info about borrow power.

## repay

#### function head

`function repay(address _token, uint256 _amount) public payable onlySupportedToken(_token) nonReentrant`

* parameters
  * \_token: The address of token you want to repay.
  * amount: The amount of token you want to repay.

#### description

An account uses `repay` function to repay a certain amount of borrowed token back to the pool. This function calls the `repay` function in the `Bank` contract, and emit the `Repay` event.

If an account repaid more than what it owes, the contract would return the extra token back to the account address.

In your wallet, you need to make sure there are enough tokens which is larger or equal to the amount you specify here to avoid failing transaction. This amount of tokens should be in your wallet not the already deposited tokens to DeFiner.

## transfer

#### function head

`function transfer(address _to, address _token, uint _amount) external onlySupportedToken(_token) onlyEnabledToken(_token) whenNotPaused nonReentrant`

* parameters
  * \_to: The account address that you want to transfer tokens to.
  * \_token: The address of the tokens you want to transfer.
  * \_amount: The volume of token you want to transfer.

#### description

An account could transfer its deposited token to another account inside DeFiner's saving pool. When a transfer happened, the deposit balance of `msg.sender` is deducted and it is added to the account that specified in the `transfer` function. This means that the transfer will only happen within the DeFiner's Protocol, the \_to address won't see the transferred tokens in its wallet, but it will show in DeFiner's balance.

If the `msg.sender` has borrowed any tokens from the pool, it is required that the account is still under the borrowing capacity after transfer.

## liquidate

#### function head

`function liquidate(address _borrower, address _borrowedToken, address _collateralToken) public onlySupportedToken(_borrowedToken) onlySupportedToken(_collateralToken) whenNotPaused nonReentrant`

* parameters
  * \_borrower: The target account that should be liquidated through this transaction.
  * \_borrowedToken: The token that the borrower has borrowed.
  * \_collateralToken: The underlying collateral token that the liquidator wants to buy.

#### description

A borrower (or debtor) is liquidatable if its LTV is above 85%. If an account is liquidatable, a liquidator can use a debt token to purchase the collateral from the borrower with a 5% discount.

For a full explanation about the liquidate function, please visit [this page](https://app.gitbook.com/@definer/s/definer/liquidate).

&#x20;  &#x20;


# Bank

Bank contract

The`Bank` contract, as its name implied, mainly deals with the methods and variables related to the saving pool. It uses three variables to track the total amount of tokens in the pool and their allocations. For each `token`,

* `totalLoans[token]` tracks total amount of `token` lend.
* `totalReserve[token]` tracks total amount of `token` reserved.
* `totalCompound[token]` tracks total amount of `token` in compound

Therefore, the total amount of `token` in the pool is the summation of these three variables. The token utilization ratio `U`, token reservation ratio `R` and compound ratio `C` are defined accordingly.&#x20;

There are three categories of methods in the contract.&#x20;

***The first category of methods deals with the total amount of tokens in the pool and their allocations. They are used to query the pool status of a token.***

* getTotalDeposit
* getPoolAmount
* getTokenState
* getCapitalUtilizationRatio
* getCapitalCompoundRatio

***The second category of methods deals with the deposit rate and borrow rate of tokens in the pool. They are used to update and get the rate indexes information of each specific token.***

* newRateIndexCheckpoint
* getDepositRatePerBlock
* getBorrowRatePerBlock
* depositRateIndexNow
* borrowRateIndexNow
* getDepositAccruedRate
* getBorrowAccruedRate

***The third category of methods deals with all the operations on the funds in the saving pool. These functions actually modify the recorded pool status.***

* Deposit
* Withdraw
* Borrow
* Repay
* Update

For more details about the modifiers of the functions, please check the modifiers page.

## getTotalDepositStore

#### function head

`function getTotalDepositStore(address _token) public view returns(uint)`

* parameters:
  * \_token: The address of the token you want to query for.
* return:
  * The number of total deposit tokens.

#### description

The method returns the sum of `totalLoans[token]`,`totalReserve[token]` and `totalCompound[token]`.

## getPoolAmount

#### function head

`function getPoolAmount(address _token) public view returns(uint)`

* parameters
  * \_token: The address of the token you want to query for.
* return:
  * The total number of tokens that are not borrowed out in DeFiner's pool.

#### description

The method returns the sum of `totalCompound[token]` and `totalReserve[token]` .

## getTokenState

#### function head

`function getTokenState(address _token) public view returns (uint256 deposits, uint256 loans, uint256 reserveBalance, uint256 remainingAssets)`

* parameters
  * \_token: The address of the token you want to query for.
* return:
  * deposits: The total number of deposited tokens.
  * loans: The total number of borrowed tokens.
  * reserveBalance: The total number of tokens that are still in the reserve pool.
  * remainingAssets: The same as getPoolAmount.

#### description

The method returns total deposit, total loans, total reservation, and total available tokens of a specific token.

## getCapitalUtilizationRatio

#### function head:

`function getCapitalUtilizationRatio(address _token) public view returns(uint)`

* parameters:
  * \_token: The address of the token you want to query for.
* return:
  * The U ratio with the precision to 18 decimals.

#### description

The method returns `U` of a token, which is the ratio of the total loan to the total deposit.

## getCapitalCompoundRatio

#### function head

`function getCapitalCompoundRatio(address _token) public view returns(uint)`

* parameters:&#x20;
  * \_token; The address of the token you want to query for.
* return:
  * The C ratio with the precision to 18 decimals.

#### description

The method returns `C` of a token, which is the ratio of the total amount in Compound to the total deposit.&#x20;

## newRateIndexCheckpoint

#### function head

`function newRateIndexCheckpoint(address _token) public onlyAuthorized`

* parameters:
  * \_token: The address of the token you want to query for.

#### description

Add a new checkpoint both on the deposit rate index curve and the borrow rate index curve. Same as Compound, DeFiner uses rate index curve to track the accumulated rate of a token. The rate index curve is updated whenever any operation on that token happens. The interests of a token earned in a specific period could be derived from the rate index curve quickly.&#x20;

## getDepositRatePerBlock

#### function head

`function getDepositRatePerBlock(address _token) public view returns(uint)`

* parameters
  * \_token: The address of the token you want to query for.
* return:
  * The current deposit rate per block of the token.

#### description

Get the per block deposit rate of a token, and it is calculated as follows

$$
\text{Deposit Rate} = U\times \text{Borrow Rate} + C\times \text{Compound Supply Rate}
$$

## getBorrowRatePerBlock

#### function head

`function getBorrowRatePerBlock(address _token) public view returns(uint)`

* parameters:
  * \_token: The address of the token you want to query for.
* return:
  * The current borrowing rate per block of the token.

#### description

Get the per block borrow rate of a token. If the token is supported in Compoud, the borrow rate is determined by the borrow rate and supply rate of Compound as

$$
\text{Borrow Rate} = \text{Compound Supply Rate} \times 0.4 + \text{Compound Borrow Rate} \times 0.6
$$

Otherwise,

$$
\text{Borrow Rate} = 0.03 + U\times 0.15
$$

The numbers in the equations are the initial value of the variables and are configurable in `GlobalConfig` contract.

## depositRateIndexNow

#### function head

`function depositRateIndexNow(address _token) public view returns(uint)`

* parameters:
  * \_token: The address of the token you want to query for.
* return:
  * The current deposit rate index.

#### description

Get deposit rate index of the current block. If the current block is a checkpoint, this method returns the exact value on the deposit index curve. Otherwise, it returns an estimated value of the deposit rate index.

## borrowRateIndexNow

#### function head

`function borrowRateIndexNow(address _token) public view returns(uint)`

* parameters:
  * \_token: The address of the token you want to query for.
* return:
  * The current borrow rate index.

#### description

Get borrow rate index of the current block. If the current block is a checkpoint, this method returns the exact value on the borrow index curve. Otherwise, it returns an estimated value of the borrow rate index.

## getDepositAccruedRate

#### function head

`function getDepositAccruedRate(address _token, uint _depositRateRecordStart) external view returns (uint256)`

* parameters:
  * \_token: The address of the token you want to query for.
  * \_depositRateRecordStart: The start block you want to query accrued rate for.
* &#x20; return:
  * Return the accrued deposit rate given a token and a start block with precision to 18 decimals.

#### description

The deposit accrued rate in a block gap from $$B\_1$$ to $$B\_2$$is $$\text{Deposit Rate Index}(B\_2)/\text{Deposit Rate Index}(B\_1)$$ . Here$$B\_1$$ is `_depositRateRecordStart` you specified in the parameter and $$B\_2$$ should be the current block number. If you deposit `n` tokens at block $$B\_1$$ , and the current block number is $$B\_2$$, the tokens you have now should be $$\text{Deposit Rate Index}(B\_2)/\text{Deposit Rate Index}(B\_1) \times n$$.

There should be a rate index created on \_depositRateRecordStart block, otherwise, it will throw an error.

## getBorrowAccruedRate

#### function head

`function getBorrowAccruedRate(address _token, uint _borrowRateRecordStart) external view returns (uint256)`

* parameters:&#x20;
  * \_token: The address of the token that you want to query for.
  * \_borrowRateRecordStart: The start block you want to query accrued rate for.
* return:
  * Return the accrued borrow rate given a token and a start block with precision to 18 decimals.

#### description

The borrow accrued rate in a block gap from $$B\_1$$ to $$B\_2$$ is $$\text{Borrow Rate Index}(B\_2)/\text{Borrow Rate Index}(B\_1)$$ . It's similar to getDepositAccruedRate.

## Deposit

#### function head

`function deposit(address _to, address _token, uint256 _amount) external onlyAuthorized`

* parameters:
  * \_to: The address of the account that tries to deposit.
  * \_token: The address of the token you want to deposit.
  * \_amount: The volume of tokens that you want to deposit.

#### description

This method will create a new checkpoint on the rate index curve. It will deposit the token to the individual account of `msg.sender` in `Accounts` contract. Then, it will update the pool balance, i.e. the value of `totalReserve[token]` and `totalCompound[token]` , accordingly.

The deposited token will be first added to the pool reservation. If the reservation ratio `R` exceeds `20%`, the contract will deposit the token to Compound to reset `R` to be `15%`.

## Withdraw

#### function head

`function withdraw(address _from, address _token, uint256 _amount) external onlyAuthorized returns(uint)`

* parameters
  * \_from: The address of the account that tries to withdraw.
  * \_token: The address of the kind of token you want to withdraw.
  * \_amount: The volume of tokens you want to withdraw.

#### description

This method will create a new checkpoint on the rate index curve. The new deposit balance is tracked in the individual account of `msg.sender` in `Accounts` contract. The withdraw is allowed only if the account has enough balance and its loan value is still below the reduced borrow power after withdrawn. Then, the contract will update the pool balance by calling `update` method.

## Borrow

#### function head

`function borrow(address _from, address _token, uint256 _amount) external onlyAuthorized`

* parameters:
  * \_from: The account that tries to borrow tokens.
  * \_token: The address of the token that you want to borrow.
  * \_amount: The volume of tokens that the user tries to borrow.

#### description

This method will create a new checkpoint on the rate index curve. The new borrowed balance is tracked in the individual account of `msg.sender` in `Accounts` contract. The borrow  is allowed only if the added loan value is below the borrow power. Then, the contract will update the pool balance by calling `update` method.

## Repay

#### function head

`function repay(address _to, address _token, uint256 _amount) external onlyAuthorized returns(uint)`

* parameters:
  * \_to: The address that tries to repay.
  * \_token: The address of the token that the account wants to repay.
  * \_amount: The volume of tokens that the account wants to repay.

#### description

This method will create a new checkpoint on the rate index curve. The new borrowed balance is tracked in the individual account of `msg.sender` in `Accounts` contract. The borrow  is allowed only if the added loan value is below the borrow power. Then, the contract will update the pool balance by calling `update` method.

## Update

#### function head

`function update(address _token, uint _amount, ActionType _action) public onlyAuthorized returns(uint256 compoundAmount)`

* parameters:&#x20;
  * \_token: The address of the token you want to update.
  * \_amount: The volume of tokens involved in this operation.
  * \_action: The type of action that changes the pool amount.
    * DepositAction
    * RepayAction
    * WithdrawAction
    * BorrowAction

#### descrption

This method is called whenever the token balance in the saving pool is changed. It checks if there is enough amount of a token in the pool, i.e. the market liquidity. If an account borrows or withdraws. When the balance of a token that changes in the pool, this method updates the allocation of the token in the reservation and the Compound.

If an account deposits or repay such that the reservation ratio exceeds `20%`, the contract will deposit an extra amount of token to Compound and reset `R` to be 15%. On the other hand,  if an account withdraw or borrow such that the reservation ratio falls behind `10%`, the contract will withdraw the token from Compound and try to reset `R` to be `15%`. However, in this case, there might not be enough tokens in Compound so that the final `R` could be below `15%`.


# Accounts

Accounts contract

The `Accounts` contract tracks the principal, interest, and other balance-related status of accounts.

## getBorrowBalanceCurrent

#### function head

`function getBorrowBalanceCurrent (address _token, address _accountAddr) public view returns (uint256 borrowBalance)`

* parameters
  * \_token: The address of token that you want to query for.
  * \_accountAddr: The address of the account that you want to query for.
* return:
  * The current borrow balance of a specific token of one user.

#### description

Get the current borrow balance of a token for an account.

## getDepositBalanceCurrent

#### function head

`function getDepositBalanceCurrent (address _token, address _accountAddr) public view returns (uint256 depositBalance)`

* parameters
  * \_token: The address of token that you want to query for.
  * \_accountAddr: The address of the account that you want to query for.
* return:
  * The current borrow balance of a specific token of one user.

Get the current deposit balance of a token for an account.

## getBorrowETH

#### function head

`function getBorrowETH(address _accountAddr) public view returns (uint256 borrowETH)`

* parameters:
  * \_accountAddr: The address that you want to query for.
* return:
  * The current total value of the borrowed asset of one user in ETH wei unit.

#### description

Get the total amount of borrowed tokens in the value of ETH for an account.

## getDepositETH

#### function head

`function getDepositETH(address _accountAddr) public view returns (uint256 depositETH)`

* parameters:
  * \_accountAddr: The address of the account that you want to query for.

#### description

Get the total amount of deposited tokens in the value of ETH for an account.

## getBorrowPrincipal

#### function head

`function getBorrowPrincipal(address _accountAddr, address _token) public view returns(uint256)`

* parameters:
  * \_accountAddr: The account address that you want to query for.
  * \_token: The address of token that you want to query for.
* return:
  * The borrow principal of the current user.

#### description

Get current borrow principal of a token for an account.

## getDepositPrincipal

#### function head

`function getDepositPrincipal(address _accountAddr, address _token) public view returns(uint256)`

* parameters:
  * \_accountAddr: The account address that you want to query for.
  * \_token: The address of token that you want to query for.
* return:
  * The deposit principal of the current user.

#### description

Get the current deposit principal of a token for an account.

## getBorrowInterest

#### function head

`function getBorrowInterest(address _accountAddr, address _token) public view returns(uint256)`

* parameters:
  * \_accountAddr: The account address that you want to query for.
  * \_token: The address of token that you want to query for.
* return:
  * The borrow interests of the current user.

#### description

Get current borrow interest of a token for an account.

## getDepositInterest

#### function head

`function getDepositInterest(address _account, address _token) public view returns(uint256)`

* parameters:
  * \_account: The account address that you want to query for.
  * \_token: The address of token that you want to query for.
* return:
  * The deposit interests of the current user.

#### description

Get current deposit interest of a token for an account.

## getBorrowPower

#### function head

`function getBorrowPower(address _borrower) public view returns (uint256 power)`

* parameters:
  * \_borrower: The account that you want to query for.
* return:
  * power: The borrowing power computed by deposited assets by this user.

#### description

Get current borrow power of an account. The borrowing power is the sum of the value of collateral tokens discounted by their borrow LTVs.

## getLastBorrowBlock

#### function head

`function getLastBorrowBlock(address _accountAddr, address _token) public view returns(uint256)`

* parameters:
  * \_accountAddr: The account address you want to query for.
  * \_token: The token address you want to query for.
* return:
  * The last recent block that the user has sent a borrow transaction.

#### description

Get the block number where the latest borrow of a token happened for an account.

## getLastDepositBlock

#### function head

`function getLastDepositBlock(address _accountAddr, address _token) public view returns(uint256)`

* parameters:
  * \_accountAddr: The account address you want to query for.
  * \_token: The token address you want to query for.
* return:
  * The last recent block that the user has sent a deposit transaction.

#### description

Get the block number where the latest deposit of a token happened for an account.

## isUserHasAnyDeposits

#### function head

`function isUserHasAnyDeposits(address _account) public view returns (bool)`

* parameters:
  * \_account: The address of the account that you want to query for.
* return:
  * A boolean value to indicate whether a user has deposited any tokens to DeFiner.

#### description

Return true if an account has the positive deposit of any token. Otherwise, return false.

## isUserHasBorrows

#### function head

`function isUserHasBorrows(address _account, uint8 _index) public view returns (bool)`

* parameters:
  * \_account: The address of the account you want to query for.
  * \_index: The index of the token that you saved in the TokenRegistry.
* return:
  * A boolean value to indicate whether a user has borrowed a specific kind of token.

#### description

Return true if an account has a positive borrow balance of a token. Otherwise, return false.

## isUserHasDeposits

#### function head

`function isUserHasDeposits(address _account, uint8 _index) public view returns (bool)`

* parameters:
  * \_account: The address of the account you want to query for.
  * \_index: The index of the token that you saved in the TokenRegistry.
* return:
  * A boolean value to indicate whether a user has deposited a specific kind of token.

#### description

Return true if an account has a positive deposit balance of a token. Otherwise, return false.


# AccountTokenLib

### Overview

This is the library that is used by the Accounts contract to track the balances of each user.

In the Accounts contract, there is a field `mapping(address => Account) public accounts;` that is used to record the balance status, and `Account` struct is:

```
struct Account {
    mapping(address => AccountTokenLib.TokenInfo) tokenInfos;
    uint128 depositBitmap;
    uint128 borrowBitmap;
}
```

The depositBitmap and borrowBitmap are used to check whether one user has depositings/borrowings for each specific token with less gas cost.

And the TokenInfo struct is the following:

```
struct TokenInfo {
    // Deposit info
    uint256 depositPrincipal;   // total deposit principal of ther user
    uint256 depositInterest;    // total deposit interest of the user
    uint256 lastDepositBlock;   // the block number of user's last deposit
    // Borrow info
    uint256 borrowPrincipal;    // total borrow principal of ther user
    uint256 borrowInterest;     // total borrow interest of ther user
    uint256 lastBorrowBlock;    // the block number of user's last borrow
}
```

For each operation one user interacting with our contract, we update `accounts` field.

## TokenInfoRegistry

Token Info Registry to manage Token information. The Owner of the contract allowed to update the information. TokenInfo struct stores Token Information, this includes: ERC20 Token address, Compound Token address, ChainLink Aggregator address etc.

```
    struct TokenInfo {
        // Token index, can store upto 255
        uint8 index;
        // ERC20 Token decimal
        uint8 decimals;
        // If token is enabled / disabled
        bool enabled;
        // Is ERC20 token charge transfer fee?
        bool isTransferFeeEnabled;
        // Is Token supported on Compound
        bool isSupportedOnCompound;
        // cToken address on Compound
        address cToken;
        // Chain Link Aggregator address for TOKEN/ETH pair
        address chainLinkAggregator;
        // Borrow LTV, by default 60%
        uint256 borrowLTV;
        // Liquidation threshold, by default 85%
        uint256 liquidationThreshold;
        // Liquidation discount ratio, by default 95%
        uint256 liquidationDiscountRatio;
    }
```


# Oracle

Price feed oracles on DeFiner

### Basics

There are three types of Oracle that DeFiner is currently using to feed the prices for available token assets on DeFiner: **Third-party oracles, DEX Oracle, and DeFiner Oracle.**

### **Third-Party Oracles**&#x20;

Third-party Oracles such as Chainlink, OKLink are used on DeFiner across different blockchains. Chainlink Oracle is currently the most adopted and trusted third-party oracle in DeFi. Chainlink feeds the price to some of the most reputable DeFi projects. That’s why DeFiner uses Chainlink Oracle whenever there is availability on different chains. ( Click [here](https://docs.chain.link/) to find more information about Chainlink Oracle.)  For chains where Chainlink is not available, we adopt the most trustworthy oracle of that particular chain. For example, the Chainlink oracle is not available on OKEx Chain and we adopted the official OKLink Oracle as the third-party price feed. <br>

### **DEX Oracles**

DEX Oracle came into the picture when tokens are not supported by Chainlink Oracle but have sufficient liquidity on one particular decentralized exchange.DEX that we adopted is different on different chains. It depends on the overall liquidity and trading volume. Currently, we use Uniswap as our DEX oracle on the Ethereum blockchain and SushiSwap on OKExChain. The community will review the source and DEX Oracle periodically to ensure DeFiner adopts the most trustworthy and deep liquidity oracle. <br>

### **DeFiner Oracle**&#x20;

DeFiner Oracle is used if there is no trustworthy third-party oracle available and the DEX trading volume and liquidity of that particular token are relatively low. The token price of DeFiner oracle is reviewed periodically to ensure the price is within an acceptable bound of the time-weighted average price of the token/USD pair across major trading venues, including both centralized and decentralized exchanges. DeFiner oracle proxy contract only stores prices that are within an acceptable bound of the Time-Weighted Average Price (TWAP) and are updated only when the TWAP deviates from the acceptable bound. If there is a significant breakthrough of the token price, the price feed would be triggered to ensure the new price is within the new acceptable bound. The DeFiner Oracle also contains logic that upscales the posted prices into the format that DeFiner's Comptroller expects.<br>

### Price Feeds Contract Addresses

{% tabs %}
{% tab title="Ethereum" %}

| Price Pair   | Price Feed Method   | Contract Address                                                                                                      |
| ------------ | ------------------- | --------------------------------------------------------------------------------------------------------------------- |
| WBTC/ETH     | Chainlink Oracle    | [0xdeb288F737066589598e9214E782fa5A8eD689e8](https://etherscan.io/address/0xdeb288F737066589598e9214E782fa5A8eD689e8) |
| ETH/USD      | Chainlink Oracle    | [0x0000000000000000000000000000000000000001](https://etherscan.io/address/0x0000000000000000000000000000000000000001) |
| DAI/ETH      | Chainlink Oracle    | [0x773616E4d11A78F511299002da57A0a94577F1f4](https://etherscan.io/address/0x773616E4d11A78F511299002da57A0a94577F1f4) |
| USDC/ETH     | Chainlink Oracle    | [0x986b5E1e1755e3C2440e960477f25201B0a8bbD4](https://etherscan.io/address/0x986b5E1e1755e3C2440e960477f25201B0a8bbD4) |
| USDT/ETH     | Chainlink Oracle    | [0xEe9F2375b4bdF6387aa8265dD4FB8F16512A1d46](https://etherscan.io/address/0xEe9F2375b4bdF6387aa8265dD4FB8F16512A1d46) |
| TUSD/ETH     | Chainlink Oracle    | [0x3886BA987236181D98F2401c507Fb8BeA7871dF2](https://etherscan.io/address/0x3886BA987236181D98F2401c507Fb8BeA7871dF2) |
| MKR/ETH      | Chainlink Oracle    | [0x24551a8Fb2A7211A25a17B1481f043A8a8adC7f2](https://etherscan.io/address/0x24551a8Fb2A7211A25a17B1481f043A8a8adC7f2) |
| BAT/ETH      | Chainlink Oracle    | [0x0d16d4528239e9ee52fa531af613AcdB23D88c94](https://etherscan.io/address/0x0d16d4528239e9ee52fa531af613AcdB23D88c94) |
| ZRX/ETH      | Chainlink Oracle    | [0x2Da4983a622a8498bb1a21FaE9D8F6C664939962](https://etherscan.io/address/0x2Da4983a622a8498bb1a21FaE9D8F6C664939962) |
| REP/ETH      | Chainlink Oracle    | [0xD4CE430C3b67b3E2F7026D86E7128588629e2455](https://etherscan.io/address/0xD4CE430C3b67b3E2F7026D86E7128588629e2455) |
| LINK/ETH     | Chainlink Oracle    | [0xDC530D9457755926550b59e8ECcdaE7624181557](https://etherscan.io/address/0xDC530D9457755926550b59e8ECcdaE7624181557) |
| FIN/ETH      | FixedPriceOracleFIN | [0xd7Cd4e27d9333013b0Fe9cE82855f71Ae126C51E](https://etherscan.io/address/0xd7Cd4e27d9333013b0Fe9cE82855f71Ae126C51E) |
| FIN-LP/ETH   | FixedPriceOracleFIN | [0x444F88FDd587C1Bd6B50bB8924f964DEC590e403](https://etherscan.io/address/0x444F88FDd587C1Bd6B50bB8924f964DEC590e403) |
| {% endtab %} |                     |                                                                                                                       |

{% tab title="OKExChain" %}

| Price Pair   | Price Feed Method                   | Contract Address                                                                                                               |
| ------------ | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| BTCK/OKT     | OKLink Oracle                       | [0x7fEe2020a0bC1bDCffe3Cf1D60B076a1a5761358](https://www.oklink.com/en/oec/address/0x7fEe2020a0bC1bDCffe3Cf1D60B076a1a5761358) |
| ETHK/OKT     | OKLink Oracle                       | [0x87Eb25bF3F9750e331f6a8CD26C4bcd86F1c255D](https://www.oklink.com/en/oec/address/0x87Eb25bF3F9750e331f6a8CD26C4bcd86F1c255D) |
| USDT/OKT     | OKLink Oracle                       | [0x7300077ee0a463c285e99D88eB9CDF0C6e616b7d](https://www.oklink.com/en/oec/address/0x7300077ee0a463c285e99D88eB9CDF0C6e616b7d) |
| OKT/USD      | OKLink Oracle                       | [0x0000000000000000000000000000000000000001](https://www.oklink.com/en/oec/address/0x0000000000000000000000000000000000000001) |
| OKB/OKT      | OKLink Oracle                       | [0xFd110ED9756135bdaa78a17C0aF453b80E5F40E2](https://www.oklink.com/en/oec/address/0xFd110ED9756135bdaa78a17C0aF453b80E5F40E2) |
| CHE          | Cherry Swap TokenBalancePair Oracle | [0x1106CaD41FE13BD5CDAbEb6dDbfffB6b647a2Efd](https://www.oklink.com/en/oec/address/0x1106CaD41FE13BD5CDAbEb6dDbfffB6b647a2Efd) |
| TPT          | DeFiner Fixed price oracle          | [0xeAFcc445B1e635Fb278f30DE996d7e2aE3dBceBa](https://www.oklink.com/en/oec/address/0xeAFcc445B1e635Fb278f30DE996d7e2aE3dBceBa) |
| FIN/USD      | DeFiner Fixed price oracle          | [0x8471CB38E37EdfC711F9979CB835015f44533bce](https://www.oklink.com/en/oec/address/0x8471CB38E37EdfC711F9979CB835015f44533bce) |
| FIN-LP/OKT   | SushiSwap Oracle                    | [0xd54fC9d46f6D3e65dD05611af55B3094B7f7f7c3](https://www.oklink.com/en/oec/address/0xd54fC9d46f6D3e65dD05611af55B3094B7f7f7c3) |
| {% endtab %} |                                     |                                                                                                                                |

{% tab title="Polygon" %}

<table><thead><tr><th>Price Pair</th><th width="233.33333333333331">Price Feed Method</th><th>Contract Address</th></tr></thead><tbody><tr><td>DAI/MATIC</td><td>Chainlink Oracle</td><td><a href="https://polygonscan.com/address/0x48152e8CeC24122e0d25397dbc162Ab717af2C09">0x48152e8CeC24122e0d25397dbc162Ab717af2C09</a></td></tr><tr><td>USDC/MATIC</td><td>Chainlink Oracle</td><td><a href="https://polygonscan.com/address/0xD6B80313F1647f7d21a24Ac7a6109169eD0CA918">0xD6B80313F1647f7d21a24Ac7a6109169eD0CA918</a></td></tr><tr><td>USDT/MATIC</td><td>Chainlink Oracle</td><td><a href="https://polygonscan.com/address/0x16212965BB17F4071d86C139aFcFab4f5DEb0FdF">0x16212965BB17F4071d86C139aFcFab4f5DEb0FdF</a></td></tr><tr><td>WBTC/MATIC</td><td>Chainlink Oracle</td><td><a href="https://polygonscan.com/address/0x3e7054619C84Fa4f6Df231A7Cd3e46258b4a074e">0x3e7054619C84Fa4f6Df231A7Cd3e46258b4a074e</a></td></tr><tr><td>SUSHI/MATIC</td><td>Chainlink Oracle</td><td><a href="https://polygonscan.com/address/0x383e4442D58A2c69D7a3982735ECed1d20EE8042">0x383e4442D58A2c69D7a3982735ECed1d20EE8042</a></td></tr><tr><td>LINK/MATIC</td><td>Chainlink Oracle</td><td><a href="https://polygonscan.com/address/0xD74C9ea5114Dd311ff3fB6F49B04Dbd2A2488F9E">0xD74C9ea5114Dd311ff3fB6F49B04Dbd2A2488F9E</a></td></tr><tr><td>CRV/MATIC</td><td>Chainlink Oracle</td><td><a href="https://polygonscan.com/address/0xcD14cCa0d42144B762E0932d241cb7c577a92abf">0xcD14cCa0d42144B762E0932d241cb7c577a92abf</a></td></tr><tr><td>QUICK/MATIC</td><td>Chainlink Oracle</td><td><a href="https://polygonscan.com/address/0xfD3ACD8E3B2E9Df9264E574BE31A4E3726fc58eB">0xfD3ACD8E3B2E9Df9264E574BE31A4E3726fc58eB</a></td></tr><tr><td>ETH/MATIC</td><td>Chainlink Oracle</td><td><a href="https://polygonscan.com/address/0x60a9224c81279B2c6eDe94Bcdc440653D3Af96b7">0x60a9224c81279B2c6eDe94Bcdc440653D3Af96b7</a></td></tr><tr><td>FIN/MATIC</td><td>FixedPriceOracleFIN </td><td><a href="https://polygonscan.com/address/0x27B938EAB0b3097447D9c87550452da112055441">0x27B938EAB0b3097447D9c87550452da112055441</a></td></tr></tbody></table>
{% endtab %}
{% endtabs %}


# Modifiers

### Overview

We describe all the modifiers used in our contracts here.

### onlySupportedToken(token)

The token need to be registered in TokenRegistry, otherwise it will throw "Unsupported token" error.

### onlyEnabledToken(token)

The token need to be enabled in TokenRegistry, otherwise it will throw "The token is not enabled" error. One token can be registered but disabled later.

### nonReentrant

We are using this modifier provided by InitializableReentrancyGuard contract of OpenZeppelin to avoid reentrancy attack.

### whenNotPaused

We added a flag variable called `_paused` to our contract, and if we set that variable to true the methods with this modifier can't be called. This is used to temporarily pause some functions in our contracts for emergency issues.


# Delayed Upgrades

DeFiner's upgradeable contracts can only be upgraded after 48 hours of scheduled upgrade

DeFiner upgradeable contracts (SavingAccount.sol, Bank.sol, Accounts.sol) are governed by the ProxyAdmin contract. These three contracts can be upgraded to new implementation via ProxyAdmin. From now on this ProxyAdmin contract's ownership is transferred to the TimelockController contract (from OpenZeppelin). Hence, any upgrade of the contract will be done via TimelockController contract. The TimelockController contract also enforces a delayed execution of the scheduled requests.

### TimelockController.sol

The TimelockController contract is developed by OpenZeppelin. This contract has three roles which manages the request and their execution. These three roles are.

1. **TIMELOCK\_ADMIN\_ROLE**: This role can grant or revoke other two roles from the contract.
2. **PROPOSER\_ROLE**: This role can propose and schedule a request to the contract for the delayed execution.
3. **EXECUTOR\_ROLE**: This role can execute an already scheduled request after the given delay is passed.

At DeFiner we are managing these roles with different hardware wallets. When in the future we plan to upgrade the contract, we will publish the information to the community, so that they can take the informed decisions. The upgrade will be executed after 48 hours of delay.

### Addresses

#### Mainnet

{% tabs %}
{% tab title="OKExChain" %}

| Contract           | Address                                                                                                                           |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------- |
| ProxyAdmin         | [0x7EbAe3a7839D8d75A228D277006FACF11A7c8675](https://www.oklink.com/okexchain/address/0x7EbAe3a7839D8d75A228D277006FACF11A7c8675) |
| TimelockController | [0xe7E657daE574f33B6FF2ee3c40f4d127C055E758](https://www.oklink.com/okexchain/address/0xe7E657daE574f33B6FF2ee3c40f4d127C055E758) |

{% endtab %}

{% tab title="Ethereum" %}

{% endtab %}
{% endtabs %}

#### Testnet

{% tabs %}
{% tab title="OKExChain" %}

| Contract           | Address                                                                                                                                |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| ProxyAdmin         | [0x3FAE1633a4E24BAc2f615Fae2F845E796b7f44F7](https://www.oklink.com/okexchain-test/address/0x3FAE1633a4E24BAc2f615Fae2F845E796b7f44F7) |
| TimelockController | [0x3B6779C6eEAa4b3b88bAf22B2c863dAF00E46a5D](https://www.oklink.com/okexchain-test/address/0x3B6779C6eEAa4b3b88bAf22B2c863dAF00E46a5D) |
| {% endtab %}       |                                                                                                                                        |

{% tab title="Ethereum" %}

{% endtab %}
{% endtabs %}


# DeFiner SDK

### Overview

Currently, we are using `web3.js` to interact with our contract on the mainnet. If there are some changes in our contract, we need to change this everywhere in different projects that are developed by different developers, which will cause much time. Currently, our web application, mobile application, liquidator bot, and even in the tests are all adopting this approach. We will save a lot of time if we build an SDK that can be used in all these files it can decouple the components more and shorten time to coordinate when upgrading our contracts.

Examples:

1. Compound: <https://github.com/compound-finance/compound-js>
2. dydx: <https://github.com/dydxprotocol/solo>

### Goal

#### Example

We need to use it to interact with the contracts just by providing the provider information. The potential usage can be like the following:

1.Download the package using npm:&#x20;

```
npm i @DeFiner/definer-protocol
```

2.Initialize the DeFiner Instance

```javascript
import DeFiner from "@DeFiner/definer-protocol"

var definer = new DeFiner(window.ethereum); // web browser

var definer = new DeFiner('http://127.0.0.1:8545'); // HTTP provider

var definer = new DeFiner(); // Uses Ethers.js fallback mainnet (for testing only)

var definer = new DeFiner('ropsten'); // Uses Ethers.js fallback (for testing only)

// Init with private key (server side)
var definer = new DeFiner('https://mainnet.infura.io/v3/_your_project_id_', {
  privateKey: '0x_your_private_key_', // preferably with environment variable
});

// Init with HD mnemonic (server side)
var definer = new DeFiner('mainnet', {
  mnemonic: 'cyber punk game...', // preferably with environment variable
});
```

3.Use the instance to send transactions:

```javascript
console.log(DeFiner.address.DAI, DeFiner.address.cETH);  // get the addresses used by the current compound

await definer.borrow(DeFiner.addresses.DAI, new BN(10).pow(new BN(18))) // Borrow one whole DAI from DeFiner
```

4\. Interact with the backend API

```javascript
// Get one account's LTV
const accLtv = await definer.API.ltv(adress)
```

### Modules

#### DeFiner

This is the main object of this SDK. Users should provide a provider to create a `DeFiner` object then use this instance to interact with the contracts. After the provider is set, we can specify one account that is available in the provider to interact with the contract. This should be a singleton. By default, it will use the first account in your provider to conduct all the transactions.

#### ContractInstance

By specifying the contract's address and ABI, this should return the corresponding contract instance.

#### ContractInstanceStore

We can use this object to get all the different contract instances. We make sure each contract only has one instance throughout the same app to ensure performance.&#x20;

#### AccountsInstance

This is the wrapper class of the Accounts contract, we can use this to interact with the Accounts contract on the chain.

#### SavAccInstance

This is the wrapper class of the SavingAccount contract, we can use this to interact with the SavingAccount contract on the chain.

#### BankInstance

This is the wrapper class of the Bank contract, we can use this to interact with the Bank contract on the chain.

#### Constants

This file contains all the constants that will be used by the SDK. Like the addresses of our protocols on different test nets and also the mainnet, and the newest ABIs of each different contract.

#### Utils

Some utility functions that can help to get some necessary data from the third-party source, as the real-time gas price.

### API

#### Contract Related

* definer.userHasAnyDeposits(user: string, target: string):&#x20;
  * Description: Return whether the target account has deposit or not.
  * Parameters:&#x20;
    * user: The address of the user who tries to call this function.
    * target: The address of the target that the user wants to query.
* definer.getDepositPrincipal(tokenName: string, user: string, target: string):&#x20;
  * Description: Return the account's deposit balance in DeFiner for a specific token.
  * Parameters:
    * tokenName: The token's name that you want to query, please check what token names are supported in the **Token Names** section.
    * user: The address of the user who tries to call this function.
    * target: The address of the target that the user wants to query.
* definer.getBorrowPrincipal(tokenName: string, user: string, target: string):&#x20;
  * Description: Return the account's borrow balance in DeFiner for a specific token.
  * Parameters:
    * tokenName: See **Token Names** section.
    * user: The address of the user who tries to call this function.
    * target: The target address that the user wants to query.
* definer.getLastDepositBlock(tokenName: string, user: string, target: string):&#x20;
  * Description: Return the last deposit block of a user for a specific token.
  * Parameters:
    * tokenName: See **Token Names** section.
    * user: The address of the user who tries to call this function.
    * target: The target address that the user wants to query.
* definer.getLastBorrowBlock(tokenName: string, user: string, target: string):&#x20;
  * Description: Return the last borrow block of a user for a speicific token.
  * Parameters:
    * tokenName: See **Token Names** section.
    * user: The address of the user who tries to call this function.
    * target: The target address that the user wants to query.&#x20;
* definer.getDepositInterest(tokenName: string, user: string, target: string):&#x20;
  * Description: Return the deposit interests since the last checkpoint.
    * Parameters:
      * tokenName: See **Token Names** section.
      * user: The address of the user who tries to call this function.
      * target: The target address that the user wants to query.&#x20;
* definer.getBorrowInterest(tokenName: string, user: string, target: string):
  * Description: Return the borrow interests since the last checkpoint.
    * Parameters:
      * tokenName: See **Token Names** section.
      * user: The address of the user who tries to call this function.
      * target: The target address that the user wants to query.&#x20;
* definer.getDepositBalanceCurrent(tokenName: string, user: string, target: string):&#x20;
  * Description: Return the total deposit balance of the target address.&#x20;
    * Parameters:
      * tokenName: See **Token Names** section.
      * user: The address of the user who tries to call this function.
      * target: The target address that the user wants to query.&#x20;
* definer.getBorrowBalanceCurrent(tokenName: string, user: string, target: string):
  * Description: Return the total borrow balance of the target user.&#x20;
    * Parameters:
      * tokenName: See **Token Names** section.
      * user: The address of the user who tries to call this function.
      * target: The target address that the user wants to query.&#x20;
* definer.getBorrowPower(user: string, target: string):&#x20;
  * Description: Return the borrow power in ETH wei unit.
  * Parameters:
    * user: The address of the user who tries to call this function.
    * target: The target address that the user wants to query.
* definer.getDepositETH(user: string, target: string):
  * Description: Return the total deposit value in ETH wei unit.
  * Parameters:
    * user: The address of the user who tries to call this function.
    * target: The target address that the user wants to query.
* definer.getBorrowETH(user: string, target: string):&#x20;
  * Description: Return the total borrow value in ETH wei unit.
  * Parameters:
    * user: The address of the user who tries to call this function.
    * target: The target address that the user wants to query.
* definer.isAccountLiquidatable(user: string, target: string):&#x20;
  * Description: Return whether one account is liquidatable or not.
  * Parameters:
    * user: The address of the user who tries to call this function.
    * target: The target address that the user wants to query.
* definer.deposit(token: Token, amount: any):
  * Description: Deposit an amount of token to DeFiner. The default account is the first account in the provider.
  * Parameters:
    * token: See **Token Names** section.
    * amount: The amount defined in BigNumber type.
* definer.borrow(token: Token, amount: any): Borrow an amount of token from Definer.
  * Description: Borrow an amount of token from DeFiner. The default account is the first account in the provider.
    * Parameters:
      * token: See **Token Names** section.
      * amount: The amount defined in BigNumber type.
* definer.repay(token: Token, amount: any): Repay an amount of token to Definer.
* Description: Repay an amount of token to DeFiner. The default account is the first account in the provider.
  * Parameters:
    * token: See **Token Names** section.
    * amount: The amount defined in BigNumber type.
* definer.withdraw(token: Token, amount: any): Withdraw an amount from Definer.
  * Description: Borrow an amount of token from DeFiner. The default account is the first account in the provider.
    * Parameters:
      * token: See **Token Names** section.
      * amount: The amount defined in BigNumber type.
* definer.withdrawAll(token: Token): Withdraw all tokens of a specific kind from Definer for a specific token.
  * Description: Withdraw all tokens from DeFiner. The default account is the first account in the provider.
    * Parameters:
      * token: see **Token Names** section.
      * amount: The amount defined in BigNumber type.
* definer.getTotalDepositStore(tokenName:string):&#x20;
  * Description: Get the total deposit amount of a specific token.
  * Parameters:
    * tokenName: See **Token Names** section.
* definer.getBorrowRatePerBlock(tokenName: string):&#x20;
  * Description: Get the borrow rate of the token.
  * Parameters:
    * tokenName: See **Token Names** section.
* definer.getDepositRatePerBlock(tokenName:string):&#x20;
  * Description: Get the deposit rate of the token.
  * Parameters:
    * tokenName: See **Token Names** section.
* definer.getCapitalUtlizationRatio(tokenName: string):&#x20;
  * Description: Get the U ratio of the token.
  * Parameters:
    * tokenName: See **Token Names** section.
* definer.getCapitalCompoundRatio(tokenName: string):&#x20;
  * Description: Get the C ratio of the token.
  * Parameters:
    * tokenName: See **Token Names** section.
* definer.getTokenState(tokenName: string):&#x20;
  * Description: Get the current token state.
  * Parameters:
    * tokenName: See **Token Names** section.
* definer.getPoolAmount(tokenName: string): Get the token still in the contract.
  * Description: Get the number of tokens that are still in the contract
    * Parameters:
      * tokenName: See **Token Names** section.

#### Token Names

* All the supported token names in definer-js:
  * BAT
  * DAI
  * ETH
  * REP
  * USDC
  * USDT
  * WBTC
  * ZRX
  * MKR
  * FIN
  * LPToken: The FIN liquidity provider token related to the uniswap.
  * TUSD
* We can use the above names as strings to pass as a parameter, or we can use enum Token type when it requires a Token type parameter.
* The enum Token type is defined as:

```javascript
export enum Token {
    BAT = 1,
    DAI,
    ETH,
    REP,
    USDC,
    USDT,
    WBTC,
    ZRX,
    MKR,
    FIN,
    LPToken,
    TUSD
}
```

#### Stat Related

For more details, please review:<https://app.gitbook.com/@definer/s/front-end/api-info-about-stat.definer.cn>

* definer.API.statusAssets(): Call `/api_v2/address/status_assets`
* definer.API.balances(): Call `/api_v2/address/balances`
* definer.API.ltv(): Call `/api_v2/address/ltv`
* definer.API.balanceLog(): Call `/api_v2/address/balance_log`
* definer.API.getSavingsOrder(): Call `/api_v2/address/get_savings_order`
* definer.API.tokenStatus(): Call `/api_v2/market/token_status`
* definer.API.tokenStatistical(): Call `/api_v2/market/token_statistical`
* definer.API.tokenPrice(): Call `/api_v2/market/token_prices`
* definer.API.totalAssets(): Call `/api_v2/market/total_assets`
* definer.API.addressList(): Call `/api_v2/market/address_list`


# Audits


# 01 - Taka Security, Aug 2020

August,2020 by Alexander Remie, who has previously worked for ChainSecurity and PwC.

DeFiner requested a security audit of the DeFiner smart contracts by Taka Security. The security audit focused on verifying that the smart contracts function as expected and also evaluates the overall design of the smart contracts.&#x20;

Taka Security performed a security review of 7 business days during two weeks in July/August 2020. The security audit uncovered 2 critical, 2 high, 2 medium and 1 low severity security issue. Also, 2 high, 10 medium, and 10 low severity design issues were found. DeFiner has updated the code according to the reported findings and managed to fix all raised security findings. As well as most design findings.

The only unresolved design findings are of low or medium severity. During the audit, as well as during the implementation of fixes, DeFiner has been very receptive to suggestions, questions, and discussions. Also, an initial in-depth call to introduce Taka Security to the DeFiner smart contracts before the audit started, has been very helpful.

The detailed report can be found [here](https://takasecurity.com/pdf/TakaSecurity_DeFiner.pdf)&#x20;


# 02 - Trail of Bits, Sep 2020

Audited by SamzSun who is a reputable white hat hacker and auditor at Trail of Bits

Trail of Bits performed an assessment of the DeFiner protocol. We sought to answer various questions about the security and correctness of the DeFiner protocol, specifically:

&#x20;● Could an attacker make the protocol calculate balances incorrectly?

● Can an attacker withdraw tokens that do not belong to them?&#x20;

● Can a malicious user break any features intended to incentivize certain behaviors?&#x20;

● Could an administrator seriously impact protocol functionality?&#x20;

● Do features function as intended? Of the findings reported, one would allow a malicious user to prevent a liquidator from claiming any collateral. Another would allow a user to borrow tokens exceeding the LTV of their locked collateral. Several issues would have caused corruption of the protocol’s internal accounting and permitted users to withdraw more tokens than the protocol actually possesses.


# 03 - Consensys Diligence, Feb 2021

Audited by Shayan Eskandari and Alex Wade from Consensys Diligence

This report presents the results of our engagement with **DeFiner** to review **DeFiner’s SavingAccount protocol**. The review was conducted over two weeks, from **Feb 8, 2021** to **Feb 19, 2021** by **Shayan Eskandari** and **Alex Wade**. A total of 15 person-days were spent.

The security audit uncovered 1 critical, 3 major, 5 medium issues. DeFiner has updated the code according to the reported findings and managed to fix all raised security findings. For the following one major 4.2 and one medium issues. DeFiner decided not to fix as it's common practice in the industry and risk is mitigated.&#x20;

[4.2 Users can borrow funds, deposit them, then borrow more ](https://consensys.net/diligence/audits/2021/02/definer/#users-can-borrow-funds-deposit-them-then-borrow-more)

[4.6 Price volatility may compromise system integrity](https://consensys.net/diligence/audits/2021/02/definer/#price-volatility-may-compromise-system-integrity)<br>

The detailed report can be found [here](https://consensys.net/diligence/audits/2021/02/definer/)&#x20;

{% embed url="<https://consensys.net/diligence/audits/2021/02/definer/>" %}


# Bug Bounty Program

Security is core to our values, and we value the input of hackers to help us maintain the highest standard for security and safety. Though the DeFiner protocol has gone through professional audits and formal verification, there is a new technology that may contain undiscovered vulnerabilities.

We encourage the community to audit our contracts and security and encourage the responsible disclosure of any issues. This program is intended to recognize the value of working with the community of independent security researchers. &#x20;

**Rewards by Threat Level**

Rewards are distributed according to the impact of the vulnerability based on the [Immunefi Vulnerability Severity Classification System](https://immunefi.com/severity-updated/). This is a simplified 5-level scale, with separate scales for websites/apps and smart contracts/blockchains, encompassing everything from the consequence of exploitation to privilege required to the likelihood of a successful exploit.

Critical smart contract vulnerabilities are capped at 10% of economic damage, primarily taking into account the funds at risk. Other considerations such as PR and branding concerns may also be considered by the team at its discretion.

Paid auditor(s) of this code is(are) not eligible for rewards in this table. Determinations of eligibility and final reward amount (for critical vulnerabilities) and all terms related to an award are at the sole and final discretion of the DeFiner Protocol team.

Payouts are handled by the **DeFiner** directly and are denominated in USD. Payouts are done in **USDT, DAI ,or USDC** for payouts up to USD 10,000 and FIN/stablecoin mix (90%/10%) for all other critical payouts.

**Smart Contract Rewards:**&#x20;

| Level    | Payouts            |
| -------- | ------------------ |
| Critical | Up to USD $100,000 |
| High     | USD $10,000        |
| Medium   | USD $5,000         |
| Low      | USD $1,000         |

**Scope**

The primary scope of the bug bounty program is for vulnerabilities affecting the on-chain deployed contracts on the Ethereum Mainnet, for contract addresses listed in this developer documentation This list may change as new contracts are deployed, or as existing contracts are removed from usage.

Only the following impacts are accepted within this bug bounty program. All other impacts are not considered as in-scope, even if they affect something in the assets in the scope table.

Smart Contracts Impacts:

* Loss of user funds staked (principal) by freezing or theft
* Loss of governance funds
* Theft of unclaimed yield
* Freezing of unclaimed yield
* Temporary freezing of funds for 1 day.
* Unable to call smart contract
* Smart contract gas drainage
* Smart contract fails to deliver promised returns

**Disclosure**

Submit all bug bounty disclosures to <contact@definer.org>. The disclosure must include clear and concise steps to reproduce the discovered vulnerability in either written or video format. DeFiner will follow up promptly with acknowledgment of the disclosure.

*DeFiner reserves the right to reject submissions and alter the terms and conditions of this program.*


# Addresses

List of addresses of the deployed contracts on various networks

## ETH

{% tabs %}
{% tab title="mainnet" %}

| Contract            | Address                                                                                                               |
| ------------------- | --------------------------------------------------------------------------------------------------------------------- |
| AccountTokenLib     | [0x0d6Cce05975967002E20354778C398A89eBEA9b4](https://etherscan.io/address/0x0d6Cce05975967002E20354778C398A89eBEA9b4) |
| Accounts            | [0xeC88BA505bC341cd590DCED6001C29F3B267970A](https://etherscan.io/address/0xeC88BA505bC341cd590DCED6001C29F3B267970A) |
| Bank                | [0xad4649a917a0e928d00c3028dB63ACb07960d25B](https://etherscan.io/address/0xad4649a917a0e928d00c3028dB63ACb07960d25B) |
| BitmapLib           | [0xc5fAB2B84c5dC7e0b9943e84D462976475D3fAf7](https://etherscan.io/address/0xc5fAB2B84c5dC7e0b9943e84D462976475D3fAf7) |
| ChainLinkAggregator | [0xaFa49a9224FE59ec3AD7b917Fa0A11E9eEE4Ea5F](https://etherscan.io/address/0xaFa49a9224FE59ec3AD7b917Fa0A11E9eEE4Ea5F) |
| Constant            | [0xA316519cb8b8722D2965f9DB1E2c6aF112dA92Ac](https://etherscan.io/address/0xA316519cb8b8722D2965f9DB1E2c6aF112dA92Ac) |
| GlobalConfig        | [0xa13B12D2c2EC945bCAB381fb596481735E24D585](https://etherscan.io/address/0xa13B12D2c2EC945bCAB381fb596481735E24D585) |
| ProxyAdmin          | [0x0347AE755BeE12D66a653E3e37B7D0aE4105058A](https://etherscan.io/address/0x0347AE755BeE12D66a653E3e37B7D0aE4105058A) |
| SavingAccount       | [0x7a9E457991352F8feFB90AB1ce7488DF7cDa6ed5](https://etherscan.io/address/0x7a9E457991352F8feFB90AB1ce7488DF7cDa6ed5) |
| SavingLib           | [0xd20a0Ba23D29e00ad5Ed638CB51C7B14CA00d836](https://etherscan.io/address/0xd20a0Ba23D29e00ad5Ed638CB51C7B14CA00d836) |
| TokenRegistry       | [0x6C1Bb97349e45fc9F497f019aF373ddba14d1A14](https://etherscan.io/address/0x6C1Bb97349e45fc9F497f019aF373ddba14d1A14) |
| Utils               | [0x8e13d5AC37110742f62bf5EEeA5045fA33FF428C](https://etherscan.io/address/0x8e13d5AC37110742f62bf5EEeA5045fA33FF428C) |
| {% endtab %}        |                                                                                                                       |

{% tab title="Kovan" %}

| Contract        | Address                                                                                                                     |
| --------------- | --------------------------------------------------------------------------------------------------------------------------- |
| TokenRegistry   | [0xa73e6bb36ADdA62372A0068D0Cc6fE448DE64879](https://kovan.etherscan.io/address/0xa73e6bb36ADdA62372A0068D0Cc6fE448DE64879) |
| ProxyAdmin      | [0x8AD674729E3b1862b60763E5c5cAB9BDF6C1D1F9](https://kovan.etherscan.io/address/0x8AD674729E3b1862b60763E5c5cAB9BDF6C1D1F9) |
| SavingAccount   | [0x4be4BBF27bd54422b9510341c816D7B9c455BEf1](https://kovan.etherscan.io/address/0x4be4bbf27bd54422b9510341c816d7b9c455bef1) |
| Bank            | [0xAf3F5B7e8e0EEFD59E47d58b3746f354400e7168](https://kovan.etherscan.io/address/0xAf3F5B7e8e0EEFD59E47d58b3746f354400e7168) |
| Accounts        | [0xE230D97a7D9C70c19D6c706163463b84DE1c5d4f](https://kovan.etherscan.io/address/0xe230d97a7d9c70c19d6c706163463b84de1c5d4f) |
| Constant        | [0x5A109f85bdA1dc089f437F9a4df1aE0a5C4606Dc](https://kovan.etherscan.io/address/0x5A109f85bdA1dc089f437F9a4df1aE0a5C4606Dc) |
| GlobalConfig    | [0x3BB382b14a3126f66B01582BD2968b155A75C8A7](https://kovan.etherscan.io/address/0x3bb382b14a3126f66b01582bd2968b155a75c8a7) |
| SavingLib       | [0x4e5562f71f5e056B6a4c9a5a661B07c5b5717755](https://kovan.etherscan.io/address/0x4e5562f71f5e056B6a4c9a5a661B07c5b5717755) |
| Utils           | [0x5437c73bdE0f103706854636C9361647910B478c](https://kovan.etherscan.io/address/0x5437c73bdE0f103706854636C9361647910B478c) |
| BitmapLib       | [0x092426D11c5007Ac5FA5F50704aA07ba6b8e44EC](https://kovan.etherscan.io/address/0x092426D11c5007Ac5FA5F50704aA07ba6b8e44EC) |
| AccountTokenLib | [0xA15Ada23e3712A751447C75324Cf6dF6cd3e5B6d](https://kovan.etherscan.io/address/0xA15Ada23e3712A751447C75324Cf6dF6cd3e5B6d) |
| {% endtab %}    |                                                                                                                             |
| {% endtabs %}   |                                                                                                                             |

## OKExChain

{% tabs %}
{% tab title="mainnet" %}

| Contract                   | Address                                                                                                                           |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| GlobalConfig               | [0xAdD7b91FA4DC452A9C105F218236B28F17562555](https://www.oklink.com/okexchain/address/0xAdD7b91FA4DC452A9C105F218236B28F17562555) |
| TokenRegistry              | [0x0E16Ada9C4Cf95d6722c65504555124A241DdA81](https://www.oklink.com/okexchain/address/0x0E16Ada9C4Cf95d6722c65504555124A241DdA81) |
| OKTPerLPToken              | [0xd54fC9d46f6D3e65dD05611af55B3094B7f7f7c3](https://www.oklink.com/okexchain/address/0xd54fC9d46f6D3e65dD05611af55B3094B7f7f7c3) |
| ProxyAdmin                 | [0x7EbAe3a7839D8d75A228D277006FACF11A7c8675](https://www.oklink.com/okexchain/address/0x7EbAe3a7839D8d75A228D277006FACF11A7c8675) |
| Constant                   | [0x49d0B6d640BFB6F108276aeC6D475D96A6621796](https://www.oklink.com/okexchain/address/0x49d0B6d640BFB6F108276aeC6D475D96A6621796) |
| Utils                      | [0x01dF7feBa38b0Ef3B1a308354C56d54Ded7AB500](https://www.oklink.com/okexchain/address/0x01dF7feBa38b0Ef3B1a308354C56d54Ded7AB500) |
| Accounts                   | [0x463D9f224F41086ead0e5cBb8c59d33a3853Eab4](https://www.oklink.com/okexchain/address/0x463D9f224F41086ead0e5cBb8c59d33a3853Eab4) |
| Bank                       | [0x74d667CEb5aF9AFd99a9cCCbF8A9E91D9953Dd32](https://www.oklink.com/okexchain/address/0x74d667CEb5aF9AFd99a9cCCbF8A9E91D9953Dd32) |
| SavingAccount              | [0xF3c87c005B04a07Dc014e1245f4Cff7A77b6697b](https://www.oklink.com/okexchain/address/0xF3c87c005B04a07Dc014e1245f4Cff7A77b6697b) |
| ExOracle: OKB/OKT          | [0xFd110ED9756135bdaa78a17C0aF453b80E5F40E2](https://www.oklink.com/okexchain/address/0xFd110ED9756135bdaa78a17C0aF453b80E5F40E2) |
| ExOracle: USDT/OKT         | [0x7300077ee0a463c285e99D88eB9CDF0C6e616b7d](https://www.oklink.com/okexchain/address/0x7300077ee0a463c285e99D88eB9CDF0C6e616b7d) |
| ExOracle: BTC/OKT          | [0x7fEe2020a0bC1bDCffe3Cf1D60B076a1a5761358](https://www.oklink.com/okexchain/address/0x7fEe2020a0bC1bDCffe3Cf1D60B076a1a5761358) |
| ExOracle: ETH/OKT          | [0x87Eb25bF3F9750e331f6a8CD26C4bcd86F1c255D](https://www.oklink.com/okexchain/address/0x87Eb25bF3F9750e331f6a8CD26C4bcd86F1c255D) |
| ExOracleFIN                | [0x8471CB38E37EdfC711F9979CB835015f44533bce](https://www.oklink.com/okexchain/address/0x8471CB38E37EdfC711F9979CB835015f44533bce) |
| BitmapLib                  | [0x486035c8380D98665BCc996854263Edf7E26C1B5](https://www.oklink.com/okexchain/address/0x486035c8380D98665BCc996854263Edf7E26C1B5) |
| AccountTokenLib            | [0x60973226E76ECD5927f21B20DcbE4eeDcBE43042](https://www.oklink.com/okexchain/address/0x60973226E76ECD5927f21B20DcbE4eeDcBE43042) |
| SavingLib                  | [0xa7DaAba4935525Ba46C67b6779913eaAc24A4deB](https://www.oklink.com/okexchain/address/0xa7DaAba4935525Ba46C67b6779913eaAc24A4deB) |
| TokenBalancePair: CHE/WOKT | [0x1106CaD41FE13BD5CDAbEb6dDbfffB6b647a2Efd](https://www.oklink.com/okexchain/address/0x1106CaD41FE13BD5CDAbEb6dDbfffB6b647a2Efd) |
| TokenBalancePair: KST/WOKT | [0xD9AAEbaf80d23257e94A317f70dd0A48AE53bAc2](https://www.oklink.com/okexchain/address/0xD9AAEbaf80d23257e94A317f70dd0A48AE53bAc2) |
| ExOracleTPT: TPT/OKT       | [0xeAFcc445B1e635Fb278f30DE996d7e2aE3dBceBa](https://www.oklink.com/okexchain/address/0xeAFcc445B1e635Fb278f30DE996d7e2aE3dBceBa) |
| {% endtab %}               |                                                                                                                                   |

{% tab title="testnet" %}

| Contract                             | Address                                                                                                                                |
| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| GlobalConfig                         | [0x683Fe30A90C310EE7d8C1917DE993706918E7cAC](https://www.oklink.com/okexchain-test/address/0x683Fe30A90C310EE7d8C1917DE993706918E7cAC) |
| Constant                             | [0x890D14a259C2054434037fdf9dd592a81f4414ba](https://www.oklink.com/okexchain-test/address/0x890D14a259C2054434037fdf9dd592a81f4414ba) |
| Accounts                             | [0xC55CEEF12511458fdD858326CbE3da46F1815B03](https://www.oklink.com/okexchain-test/address/0xC55CEEF12511458fdD858326CbE3da46F1815B03) |
| Bank                                 | [0x4602d7923f45961414D74410f9b4107D249a31A9](https://www.oklink.com/okexchain-test/address/0x4602d7923f45961414D74410f9b4107D249a31A9) |
| TokenRegistry                        | [0xd6A0Cd3B50De132284aE3331E6bEa4d94e2B2ecf](https://www.oklink.com/okexchain-test/address/0xd6A0Cd3B50De132284aE3331E6bEa4d94e2B2ecf) |
| SavingAccount                        | [0xeD3Ffc3289a3Ec372C5E1d21D34dC01d615D54b5](https://www.oklink.com/okexchain-test/address/0xeD3Ffc3289a3Ec372C5E1d21D34dC01d615D54b5) |
| AccountTokenLib                      | [0x11f994C550C16192644D72eeeA192E53dE297880](https://www.oklink.com/okexchain-test/address/0x11f994C550C16192644D72eeeA192E53dE297880) |
| <p>ExOracle pair:</p><p>OKB/OKT</p>  | [0x83c631a400Dc482E74Ef05bf390278124fFB46c0](https://www.oklink.com/okexchain-test/address/0x83c631a400Dc482E74Ef05bf390278124fFB46c0) |
| <p>ExOracle pair:</p><p>USDT/OKT</p> | [0x85BDE051176E010B87A7D70f41FFd0215757cd9f](https://www.oklink.com/okexchain-test/address/0x85BDE051176E010B87A7D70f41FFd0215757cd9f) |
| ExOracle pair BTC/OKT                | [0x3F0b1041Cd2C82D54baAD4a20CC5458c36211e67](https://www.oklink.com/okexchain-test/address/0x3F0b1041Cd2C82D54baAD4a20CC5458c36211e67) |
| ExOracle pair ETH/OKT                | [0x3b00557A8dEf5779D852FC0984402ae3e6D32c52](https://www.oklink.com/okexchain-test/address/0x3b00557A8dEf5779D852FC0984402ae3e6D32c52) |
| ExOracleFIN                          | [0x2c58127854D4385f1e53f6715B617223461a45Ec](https://www.oklink.com/okexchain-test/address/0x2c58127854D4385f1e53f6715B617223461a45Ec) |
| {% endtab %}                         |                                                                                                                                        |
| {% endtabs %}                        |                                                                                                                                        |

## Polygon

{% tabs %}
{% tab title="Mainnet" %}

<table><thead><tr><th>Contract</th><th>Address</th><th data-hidden></th></tr></thead><tbody><tr><td>GlobalConfig</td><td><a href="https://polygonscan.com/address/0x8dceE8E1555e1881fB16a546E86310aB573a6808">0x8dceE8E1555e1881fB16a546E86310aB573a6808</a></td><td></td></tr><tr><td>Constant</td><td><a href="https://polygonscan.com/address/0x7FAcD532563b19dCE6BFBFF208592fCF444dFEd6">0x7FAcD532563b19dCE6BFBFF208592fCF444dFEd6</a></td><td></td></tr><tr><td>AccountTokenLib</td><td><a href="https://polygonscan.com/address/0x6fc8c67D58f8A492098E32E988f7EF7f3e4F3564">0x6fc8c67D58f8A492098E32E988f7EF7f3e4F3564</a></td><td></td></tr><tr><td>Accounts</td><td><a href="https://polygonscan.com/address/0xc2fFfaBc279f2cc2BF0AbE939DB97339aD29bb31">0xc2fFfaBc279f2cc2BF0AbE939DB97339aD29bb31</a></td><td></td></tr><tr><td>Bank</td><td><a href="https://polygonscan.com/address/0x00F4D0a426C996BfECDD8A68f620B4c222a45C0a">0x00F4D0a426C996BfECDD8A68f620B4c222a45C0a</a></td><td></td></tr><tr><td>BitmapLib</td><td><a href="https://polygonscan.com/address/0xf340FedF3046454E64740C2dB6A63498CC096735">0xf340FedF3046454E64740C2dB6A63498CC096735</a></td><td></td></tr><tr><td>ProxyAdmin</td><td><a href="https://polygonscan.com/address/0x8EF9773CBd2939aC8ACaf10BefC3E6eB612645DD">0x8EF9773CBd2939aC8ACaf10BefC3E6eB612645DD</a></td><td></td></tr><tr><td>SavingAccount</td><td><a href="https://polygonscan.com/address/0x7C6e294E6555cD70D02D53735C6860AD03A6b34F">0x7C6e294E6555cD70D02D53735C6860AD03A6b34F</a></td><td></td></tr><tr><td>SavingLib</td><td><a href="https://polygonscan.com/address/0xAa4f09926E32e90311B82349bDe1cd7d826beb5F">0xAa4f09926E32e90311B82349bDe1cd7d826beb5F</a></td><td></td></tr><tr><td>TokenRegistry</td><td><a href="https://polygonscan.com/address/0xBB018635926A7dA559619ebc9FFDA78f54B281Fe">0xBB018635926A7dA559619ebc9FFDA78f54B281Fe</a></td><td></td></tr><tr><td>Utils</td><td><a href="https://polygonscan.com/address/0x0E49FeEFdd3b297A38CD512981a7B33c2B451A9b">0x0E49FeEFdd3b297A38CD512981a7B33c2B451A9b</a></td><td></td></tr></tbody></table>
{% endtab %}

{% tab title="Mainnet-Test" %}

<table><thead><tr><th>Contract</th><th>Address</th><th data-hidden></th></tr></thead><tbody><tr><td>GlobalConfig</td><td><a href="https://polygonscan.com/address/0x7fDe1634937DCE03275C6811b4B6E18e25b7CE34">0x7fDe1634937DCE03275C6811b4B6E18e25b7CE34</a></td><td></td></tr><tr><td>Constant</td><td><a href="https://polygonscan.com/address/0xc7Ac6b17785c90A10C31eb31f11f88D499B10AdF">0xc7Ac6b17785c90A10C31eb31f11f88D499B10AdF</a></td><td></td></tr><tr><td>AccountTokenLib</td><td><a href="https://polygonscan.com/address/0x89BEcCb4d126E422Ad8600F0AbBB5074FB7a48a9">0x89BEcCb4d126E422Ad8600F0AbBB5074FB7a48a9</a></td><td></td></tr><tr><td>Accounts</td><td><a href="https://polygonscan.com/address/0xb491D9bDD921ec39be8fAac738827B32e7e64612">0xb491D9bDD921ec39be8fAac738827B32e7e64612</a></td><td></td></tr><tr><td>Bank</td><td><a href="https://polygonscan.com/address/0x125323eB7fF4F0aB16Fa640D167Ca920D7265E09">0x125323eB7fF4F0aB16Fa640D167Ca920D7265E09</a></td><td></td></tr><tr><td>BitmapLib</td><td><a href="https://polygonscan.com/address/0x49AbbA21b43F06F3Dd0363fDaEcBE153eFd783DB">0x49AbbA21b43F06F3Dd0363fDaEcBE153eFd783DB</a></td><td></td></tr><tr><td>ProxyAdmin</td><td><a href="https://polygonscan.com/address/0x69a3D943c96bF415C9f07b3599500776613B5C3A">0x69a3D943c96bF415C9f07b3599500776613B5C3A</a></td><td></td></tr><tr><td>SavingAccount</td><td><a href="https://polygonscan.com/address/0x0054023807eE34C47348148e4E59Ff1214630550">0x0054023807eE34C47348148e4E59Ff1214630550</a></td><td></td></tr><tr><td>SavingLib</td><td><a href="https://polygonscan.com/address/0xac950A6FA187f8fF138266ed89631492C5Eb8C58">0xac950A6FA187f8fF138266ed89631492C5Eb8C58</a></td><td></td></tr><tr><td>TokenRegistry</td><td><a href="https://polygonscan.com/address/0xdF0649cc9BaC79B6548FbbA5C8bC5FF3BAcaE576">0xdF0649cc9BaC79B6548FbbA5C8bC5FF3BAcaE576</a></td><td></td></tr><tr><td>Utils</td><td><a href="https://polygonscan.com/address/0x778e35c21fE2eda42d984Eb8f2bda4458c53C663">0x778e35c21fE2eda42d984Eb8f2bda4458c53C663</a></td><td></td></tr></tbody></table>
{% endtab %}
{% endtabs %}


# Withdrawal Amount Calculations

How to calculate the withdrawal amount?

#### **Definitions:**

* **Interest (I)**: the interest earned by the user from the protocol and has not been withdrawn yet
* **Total Withdrawal Amount (TWA):** the amount deducted from the deposit balance&#x20;
* **Interest Reserve (IR):** the amount of interest reserved for the protocol and only be deducted when the user withdraws the interest&#x20;
* **Withdrawal Amount (WA)**: the final amount transferred to the user's wallet after the deduction of interest reserve from the total withdrawal amount
* **Interest Reserve Factor (IRF):** the ratio between interest reserve and the total withdrawal amount. &#x20;

When users withdraw funds from the savings contract, the interest will always be deducted first from the users' deposit balance. And there is a portion of the interest that will be reserved from users' deposit balance for the protocol upon the withdrawal of any interest. If the user didn't withdraw any interest, the reserved interest would be kept in the user's account and continue to generate interest. The interest reserve is only a portion of interest earned through the platform.&#x20;

**Calculations:**

$$Total Withdrawal Amount =Withdrawal Amount +Interest Reserve$$

If $$Total Withdrawal Amount <= Interest$$,  then $$Interest Reserve=Total Withdrawal Amount\*Interest Reserve Factor$$&#x20;

If $$Total Withdrawal Amount > Interest,$$ then $$Interest Reserve=Interest\*Interest Reserve Factor$$

$$0<=IFR<=1$$


# Introduction

### What is HODLer Market?

The DeFiner HODLer market is a configurable lending market with a lock-up function. It includes a Smart Contract Factory which produces a lending market on demand. With 3 clicks, anyone can launch their own lending market.&#x20;

The HODLer market is 100% permissionless. Just like anyone can go to UniSwap to create a token pair, anyone can come to DeFiner to be a DeFi lending market. The HODLer market is very customizable. Users can create a market by controlling aspects such as asset supported, maturity date, oracle, and more.

The following documentation describes the fundamentals of the protocol and how to interact with it. Please join the [#development](https://discord.com/invite/rUCBdTp) room in the DeFiner community Discord server; our team and members of the community look forward to helping you build on top of DeFiner.

### Basic Overview

The DeFiner protocol codebase is hosted on [Github](https://github.com/DeFinerOrg/Savings), the HODLer market code is still private.

The protocol is implemented as a set of **smart contracts** on top of the Ethereum and other EVM-compatible blockchains. Smart contracts guarantee safety and do not require a middleman.&#x20;

Users and applications can interact directly with the smart contracts, the blockchain data, or via their favorite web3 providers.

DeFiner Protocol is developed with security as a priority, having been audited by multiple auditors.

For a deeper dive into the protocol, economics, and how it works, refer to the [White Paper](https://github.com/DeFinerOrg/DeFiner-2.0-whitepaper/wiki/DeFiner-2.0-Whitepaper).

##


# FAQs


# Lending Pool Creation

What are the steps to create a HODLer Market?

The HODLer Market can be created by anyone. The same token can have multiple pools. Meaning, that even if the token currently already has a pool, it can still be created. It’s up to the creator, whoever provides more rewards will attract more users to the pool.

It takes 3 simple steps to create and run your own customized HODLer lending market.

### Step 1: Deployment

The first step is to deploy the contract. Select the collateral token, loan currency, and collateral factor. In this step, the DeFiner parent contract is cloned and then deployed onto the blockchain.

In the deployment phase, all smart contracts are identical cross all pools. At this stage, the basic functions is ready but no configurations have been set up yet.

![](https://lh4.googleusercontent.com/d7zx1OWHlN3FQEPz5wiuzm9mfzNX9sTvOsURBAbnXAUBniZYDjqotgZ3ccKrerh9du2FJK7aL6sN8QxiQMWZ1pLY_iD3Mfm8OWLxprq-OFl0qkt9v3_4N8V5O1x278YMLyxPFbCWfQDrzwhECVo)

![](https://lh6.googleusercontent.com/xONM-Bq5h7GxbWiM-u9-xDtO6otljz-FnQRB0FdinGAP34qH_ZYYcz0cQ9ycAiBYq26F1T3heZmlj1bSRqA7JYigT9nbWkRieeiEzSV_Xhua8L4OT1LzwRNEUVi3niWgBGicEINJWSzkkgpEjw)

### Step 2: Initialization

After deploying the base contract, you need to initialize the contract. The key input in this step is to tell the contractor what token you are supporting in this HODLer Market that you are creating. (We are using our native token, FIN, as an example here)

![](https://lh5.googleusercontent.com/X2W7sjquZAtsi0-lg-6kuix-kKGmEd4gsVssAJ1IMMqw88yTcLRcsYXbgP47FYRpueTLcLI5SEKmT99oKgyD9MJvyyoTOsTxi6ZZOGFOFlS7dFL4uRfc09DVKNSkKsH_x8xdpbwb1C_2DmKdAg)

All ERC-20 tokens and EVM compatible tokens are supported. After the token selection, you need to set up an initial oracle price for the token. The default oracle is a fixed-price oracle, which can be changed later by community voting. Learn more details about the DeFiner DAO configuration change process here. This initial price is used to initialize the price feed oracle for the collateral token chosen.

One advantage of the HODLer Market, as compared to purely locking up the token, is the ability to borrow. There are three stablecoin default tokens in the contract to be borrowed against. The HODLers can have the option to borrow stablecoins against their holding positions.

![](https://lh6.googleusercontent.com/rV97nM_HKEBe8ws9b31qoOcz1O1PV6cDIBhkVYuCmbJOErP1O7dl0WA4Ub0rKyopu3ed8HXitmUvcbejwH6CKty8AGO-QuKO1M2eacJ4HN4-CQm1WvW-bK7YnRIynBtkYhoVI_uveTOrP-MOSQ)

### Step 3: Configurations

The final step is to configure your HODLer market. In this step, you have more parameters to set up, such as maturity date, interest model, token rewards, and distribution.

**Maturity Date:** The HODLer Market allows you to choose the lock-up period. The maturity date is when the loan becomes due. You can set it up for any date that you want. We provide several options such as 3 months, 6 months, 12 months, and more. Learn more about maturity dates here.

**Reward Token Allocation:** Any token can be used as a reward, as long as you have enough tokens in your wallet to distribute. In most cases, users will choose their base token (collateral token) as their reward tokens. After deciding the total reward that you want to distribute to this HOLDer Market, you can choose what percentage you want to allocate to each token.

All configurations set up in this stage can be adjusted through the DeFiner DAO configurations change process.

#### Definitions:

**Collateral factor:** The collateral factor is equal to the maximum amount a user can borrow divided by the total collateral value


# About Oracle

What Oracle do we use when creating a HODLer Market?

There are three types of Oracle that DeFiner is currently using for price feed: Third-party oracles, DEX TWAP Oracle, and DeFiner Fixed Price Oracle. [*<mark style="color:blue;">Learn more details here</mark>*](https://v2docs.definer.org/v/copy-of-definer.org/smart-contract-modules/oracle).

In the initial market creation process, DeFiner keeps a list of tokens to check if they already had a Chainlink oracle or a third-party oracle available. If there is a third-party oracle available for this particular asset, it will default to the third-party oracle. If not, then the oracle will default to a DeFiner fixed-price oracle. And the creator will be asked to input an initial price for the base token.

After the market created, if there is a DEX with good liquidity available for the base token. The oracle will be changed to a TWAP oracle&#x20;

### Can we make changes to Oracle?

If there is a DEX with good liquidity available for the base token. Market creators have the option to change it to a DEX TWAPs oracle once the market is completed and running. The DeFiner protocol will assess the liquidity of the dex and make the change periodically. If you want to propose a change, please reach out to us over our Discord Help channel. &#x20;

### Definition

**Initial Oracle Price:** The initial oracle price is used to initialize the price feed oracle for the chosen collateral.


# About Maturity Date

What is a “Maturity Date” and how is it related to the lock-up period?

&#x20;The maturity date is the date on which the collateral is unlocked and ready to be withdrawn. Before the maturity date, the collateral is locked and held in the smart contract. Once the market has reached its maturity, any outstanding borrow balance should be paid off. The maximum period the market creator could set up is 10 years.&#x20;

For example, if a market creator selects a 12-month lock-up period, the system will automatically calculate a maturity date based on the market creation date. HODLers who deposited the collateral token can only withdraw after 12 months.

Maturity dates are only applicable to the base tokens (collateral tokens). Stablecoins are not controlled by the maturity date. Stablecoins depositors can deposit and withdraw stablecoins anytime.&#x20;

### What actions can be taken before the maturity date?&#x20;

Before the maturity date, the collateral is locked and held in the smart contract and cannot be withdrawn. However, users can deposit the collateral token anytime. Stablecoins are not controlled by the maturity date. Users can also deposit and withdraw stablecoins anytime.

### Do I have to set up a Maturity Date?&#x20;

There are options available to create a market without a lock-up period. Simply choose "None" in the Maturity Date section. In this case, your pool functions just like a savings pool and it is open for users to deposit and withdraw anytime for any tokens.

![](https://lh4.googleusercontent.com/KiYvcFCTv_5AHkvIRqFkrSx3M_VzErzD0_0MNVvI7JsHAMKc2vWu8pi2_0yj6s9wjpxbnxN1c5_85x041BN6Gizc-OzMhn0Wdfe66nCWhUruDipM_qf18RBf0-OAe5hDE9Z48EOiaghemBMaczY)

### What happens on the Maturity Date?&#x20;

Any borrowed balance is due to be paid back to the depositors on the maturity date. If the borrowing balance is not paid off, and the loan-to-value ratio is below 95% the underlying collateral will be liquidated and paid to the depositors within 7 days. If the loan-to-value ratio is above 95%, the settlement period will be extended to 30 days, and looking for a liquidation opportunity. After 30 days, if the outstanding loan amount still could not be settled the position would be categorized as a bad debt collection account and could be partially or fully covered by the DeFiner insurance pool.&#x20;

### What happens after the Maturity Date?&#x20;

Once reached the Maturity Date, the HODLer Market becomes a regular lending pool. Users can withdraw any available tokens in the pool. If the community wants to lock up the token again, they can propose a new maturity date. No new markets are needed.

A new lock-up period and maturity date can be proposed through the DeFiner DAO voting process. Once the newly proposed maturity date is successfully approved, users have a 7 - day window to withdraw tokens if they do not want to lock up their tokens anymore.

### Definition

**Maturity Date:** The maturity date is used to set a lock-up period for the base token and determine when the loan is due.


# Loan APR Range

![](https://lh5.googleusercontent.com/6QLbgHGhnMbu7rjbhYhEoBIJpk695Umwf4sY9V-wYhVrmL7zVtfMuOeq_6c9WJmkr4EF5Kk8rH6VF-5bfJqTA5FHpb-HfurHLkRDqn4rOaEptuFYkbRRJKbCQw44o6y_G_BQf04wN9O9qg_Q-Q)

### What is Loan APR Range?&#x20;

The loan APR range is for creators to choose the annual percentage return rate range for deposits and loans. The curve is a piecewise function curve. The minimum APR a creator can choose is 3% and the maximum is 300%

* Deposit APR (Annual Percentage Rate) is the annual rate of return earned on a deposit, without taking into account the effect of compounding interest.&#x20;
* Borrow APR (Annual Percentage Rate) is the annual rate of interest paid on borrow funds, without taking into account the effect of compounding interest.

### How is the APR calculated?&#x20;

The loan APR range can be adjusted by two parameters: *RateCurveConstant and maximum utilization rate*.&#x20;

* Borrow APR = RateCurveConstant÷(1−u), when utilization rate is larger than maximum utilization rate(umax)
* Borrow APR = RateCurveConstant÷(1−umax), learn more details here: [https://docs.definer.org/interest-model ](https://docs.definer.org/v/copy-of-definer.org/interest-model#borrow-rate-model)
* Deposit APR= Borrow APR \* Utilization

### Definition

**Loan APR Range:** The Loan APR Range allows HODLer Market creators to choose the APR rate for deposits and loans of the base token.


# Mining Rewards Mechanism

How to configure reward tokens?

Upon finishing the deployment and initialization, HODLer market creators can configure the reward token in the configuration pop-up window.

In this section, the HODLer market creator can input the total amount of rewards that they wish to distribute across different tokens in this HODLer market. After deciding the total reward that you want to distribute to this HOLDer Market, you can choose what percentage you want to allocate to each token.

![](https://lh3.googleusercontent.com/kMo6FLPn_0KjH7sogJhRdkjxb5nxsuYGjOBHSyxBIO0jZvKEuMC-7JsheaTB4l2LwIA2gq6K8dPcAXfeJI-sQfgp5NBbmJClf57KEoIacpk8E8If6xO6NEn8oEbcth_WxeaNLUj4tUOr-r6Y5A)

### How long will the reward be distributed?

if the pool has a maturity date, the reward will be distributed from the block of the first deposit transaction of the pool to the block of the pool matured. If the pool didn't have a maturity date, it will ask the creator to input a period of time in days to specify how long the reward will be distributed.

### What can I use for reward tokens?&#x20;

The reward token does not necessarily have to be the base token (collateral token). Creators have the option to choose any token as their reward token. In most cases, users will choose their base token (collateral token) as their reward token.

### Definition

**Mining Rewards:** The Mining Reward allows HODLer Market creators to choose a reward token and input the total amount of rewards for allocation.


# Distribution of Rewards

How will the reward token be distributed to the users and how is the reward calculated?

Mining rewards are calculated based on the weight of the amount of deposit and the deposited period of time.

For example, a market creator chooses 10,000 XYZ tokens as the total reward for their HODLer market and the collateral is also the XYZ token. The market creator allocates 80% of their total rewards into the XYZ token pool and 20% into the USDT pool.

Assuming the total period for the pool is 10,000 blocks. Each block will reward 0.8 tokens to the XYZ token pool depositors and 0.2 tokens to USDT token pool depositors.

If the XYZ token pool has 100 XYZ tokens total at block t, and user A has 10 XYZ tokens deposited, user A will be rewarded (10/100)\*0.8= 0.08 XYZ tokens at block t. The longer user A holds the deposit position and the more XYZ tokens user A deposits, the greater the rewards user A will receive.

### When can I claim my rewards? Is there any lock-up period?&#x20;

There is no lock-up period for the rewards. The rewarded token can be claimed anytime.

The reward calculation is weighted by the amount of their deposited token and the time of the deposit. This means that users who deposit the market’s base token will be rewarded in real-time.

Users can check the balance and claim under the market detail page and their portfolio page.

![](https://lh4.googleusercontent.com/6uQQFsA_BiC8tP0Anz6tGK683UYHi_UX14x7SCWhfzGqXbfhKBPthsK7czG9Gl2oRSi8GGxrp2TO_JwtA56Dpk3Kup7dUKk1HNvN8SlbvuoKtdVLArKQKKn51d5qEHwfCwwScXp7gnPfxwHnuw)

### Total Rewards & Speed

&#x20;The total amount of reward token is configured at the creation of the HODLer market. Once this is set up, the rewarding speed can only be increased. Any user can choose to increase the speed of the reward under the market detail page. Whoever increases the token, has to supply the total increased amount to the contract.

### **Definition**

**Reward Token Allocation:** The Reward Token Allocation function allows the HODLer Market creator to choose the reward allocation amongst crypto asset pools to reward depositors.


# Protocol Revenue

The protocol generates revenue in two ways: HODLer market creation fee and interest reserve. There is no other cost to use the protocol.&#x20;

### **HODLer Market Creation**

When a user creates a HODLer market, there is a fixed amount will be charged in the market initialization step. The fee is charged in the blockchain native coin. It's 150$ worth of native coin right now. This is used to screen out bad actors that create a market for no reason.

### **Interest Reserve**

For any interest made through the protocol, there is a percentage shared. We use the interest reserve factor to define how much the percentage is and it could be found in the market detail page. The typical ratio is between 10-15%. The interest reserve is only deducted when user withdraws the interest.&#x20;

### **Definition**

**Interest Reserve (IR):** the amount of interest reserved for the protocol and only be deducted when the user withdraws the interest&#x20;

**Liquidity Mining Reserve(LMR)**: the amount of reward reserved for the protocol and be deducted when the user claims rewards


# Risks Control Parameters

How does the protocol to control borrower default risks?

Loans on HODLer market are all over-collateralized. This design ensures borrowers have the willingness to pay back interest plus loan principal on time. The following parameters are used to control the default risks.

### Collateral Factor

The collateral factor is the maximum percentage a user can borrow against a collateral asset.

For example, if the collateral factor for ETH is 70%,  for 1 ETH collateral, a borrower is able to borrow 0.70 ETH worth of the corresponding crypto asset. (For example, if a borrower receives $700 worth of DAI, he/she must deposit $1000 worth of ETH.)

### Liquidation Threshold

The liquidation threshold is the percentage at which a loan is defined as undercollateralized. For example, a liquidation threshold of 80% means that if the loan amount rises above 80% of the collateral, the loan is undercollateralized and could be liquidated.

### Liquidation Discount

The liquidity discount is the discount percentage a liquidator gets when liquidating the collateral of a borrower.  For example, if the ETH liquidation discount is 10%, and the current market price is $2,000, the liquidator could swap the ETH collateral at 10% discount which is $1800.

### Collateral Value Cap

The collateral value cap (CVC) is the maximum value of the base token that could be used as collateral to borrow against. This parameter is introduced to mitigate the over-borrow risks of the base token. CVC is a consideration of primary market trading volume and market cap.&#x20;

Calculations: *CVC = Minimum of (Market Cap\**&#x32;%, accumulate of past 5 days’ trading volume)&#x20;

**Market Cap**: Market cap is defined as circulating supply \* average trading price.&#x20;

**Primary Market Trading volume**: Trading volume is a good indicator of the liquidity of crypto. It measures how much crypto that can be sold on the market without a sign of the price change impact of such crypto. Here we  use the accumulated 5 days' trading volume.&#x20;

**Update Frequency:** CVC should be calculated on the first day of each month and be updated 10th of each that month.

### Borrow Cap

The borrow cap is the maximum amount of loan on the market that can be borrowed against the base token, regardless of how much the collateral is worth.&#x20;

Borrow Cap= Collateral Value Cap \* Collateral Factor


# Liquidation

### When will liquidation happen?&#x20;

Liquidation can happen anytime (before or after the maturity date) if the loan to collateral ratio below the liquidation threshold.&#x20;

### How is liquidation triggered?&#x20;

There are two type of triggers of liquidation: 1) the loan to collateral factor is larger than the liquidation threshold. 2) the loan position is overdue.

Once the loan become liquidable, any users can call the liquidation function to liquidate the loan position. Learn more details regarding the liquidation here ([https://docs.definer.org/liquidate](https://docs.definer.org/v/copy-of-definer.org/liquidate)).


# Configurations

The mission of HODLer market is to be an open and permissionless lending market for any tokens and coins. Therefore, the HODLer market is designed to be as configurable as possible. We have 3 types of configurations: pre-configured, user-defined parameters, and DeFiner-defined parameters.&#x20;

### Pre-Configured

Pre-configured parameters are set up at the parent smart contract level. Those parameters are not changeable and stay the same with the parent contract for any child Hodler market which it is cloned from, such as fund reserve address.

### User-Defined&#x20;

User-defined parameters are inputted by users. When a HODLer market contract is created, configurations are set up by the creator. After the configurations are initially set up, those configurations can only be changed through the DeFiner DAO proposal process. Anyone can propose a change request under the market detail page. Those change requests will be reviewed by DeFiner DAO and voted by DeFiner DAO. Once the proposal passes, those proposed changes will be implemented within 48 hrs. Find more details regarding the voting process and details here.

### DeFiner-Defined

DeFiner-defined parameters are the default parameters for each pool by DeFiner. Those parameters are changeable through the DeFiner DAO voting process as well.

<table><thead><tr><th width="236">Configuration</th><th width="350">Description</th><th width="156">Types</th><th>Value</th></tr></thead><tbody><tr><td>liquidationThreshold</td><td>This defines the threshold of loan to collateral value used to define if the account is in the status of liquidation</td><td>DeFiner defined</td><td>85%</td></tr><tr><td>liquidationDiscountRatio</td><td>This defines the discount for liquidators when liquidating users' assets</td><td>DeFiner defined</td><td>95%</td></tr><tr><td>compoundSupplyRateWeights</td><td>This defines the weight of supply APR used to calcuate borrow APR from the money market protocol</td><td>DeFiner defined</td><td>50%</td></tr><tr><td>compoundBorrowRateWeights</td><td>This defines the weight of borrow APR used to calcuate borrow APR from the money market protocol</td><td>DeFiner defined</td><td>50%</td></tr><tr><td>deFinerRate</td><td>The percentage of the gains directed to definer</td><td>DeFiner defined</td><td>10%</td></tr><tr><td>borrow mining speed</td><td>This defines the mining rewards distributed to borrow balance</td><td>DeFiner defined</td><td>0</td></tr><tr><td>depositEnable</td><td>This defined if deposit function available</td><td>DeFiner defined</td><td>YES</td></tr><tr><td>repayEnable</td><td>This defined if repay function available</td><td>DeFiner defined</td><td>YES</td></tr><tr><td>miningDeFinerRate</td><td>This defines the percentage of fees to DeFiner for mining reward</td><td>DeFiner defined</td><td>10%</td></tr><tr><td>borrowFee Per transaction</td><td>This defines the percentage of fees to DeFiner for borrow function</td><td>DeFiner defined</td><td>0</td></tr><tr><td>collateral value cap</td><td>This defines the maximum value accepted by DeFiner as collateral for each token</td><td>DeFiner defined</td><td>varies by pool</td></tr><tr><td>minReserveRatio</td><td>Minimum boundarie to collect from compound</td><td>Pre-Configured</td><td>10%</td></tr><tr><td>maxReserveRatio</td><td>Maxmun bondarie to sent to compound</td><td>Pre-Configured</td><td>20%</td></tr><tr><td>loan currency token address</td><td>This defines the default stablecoins for each pool</td><td>Pre-Configured</td><td></td></tr><tr><td><br><br>expire_duration</td><td>maximum time to consider oracle response valid</td><td>Pre-Configured</td><td>12 hours</td></tr><tr><td>poolCreationFeeInUSD8</td><td>Pool creation fee in Dollar encoded with 8 decimal places</td><td>Pre-Configured</td><td>150 USD</td></tr><tr><td>max_maturity_date</td><td>The furtherst in the future a pool can be set to mature</td><td>Pre-Configured</td><td>10 year</td></tr><tr><td>max_apr</td><td>the maximum maximumMaturity rate of a pool</td><td>Pre-Configured</td><td>300%</td></tr><tr><td>min_apr</td><td>the minimun minMaturityRate of a pool</td><td>Pre-Configured</td><td>3%</td></tr><tr><td>blocks_per_year</td><td>The amount of blocks per year of a blockchain</td><td>Pre-Configured</td><td>varies by blockchain</td></tr><tr><td>rateCurveConstant</td><td>Constant used to calculate borrowAPR</td><td>User Defined</td><td> </td></tr><tr><td>borrowLTV</td><td>the loan to collateral ratio of the base token</td><td>User Defined</td><td> </td></tr><tr><td>collateral mining speed</td><td>the mining reward speed</td><td>User Defined</td><td> </td></tr><tr><td>mining Token Address</td><td>the mining reward token</td><td>User Defined</td><td></td></tr><tr><td>collateral token address</td><td>the base token address</td><td>User Defined</td><td> </td></tr><tr><td>borrowEnable</td><td>this defines if the asset could be borrowed or not</td><td>User Defined</td><td></td></tr><tr><td>withdrawEnable</td><td>this defines if the asset could be withdrew or not</td><td>User Defined</td><td></td></tr><tr><td>maturity date (Collateral)</td><td>this defines the time when base token could be withdrew</td><td>User Defined</td><td> </td></tr><tr><td>maximum utilization to calculate borrow APR</td><td>this defnes the maximum borrow APR of the HODLer market</td><td>User Defined</td><td> </td></tr><tr><td>mining_length</td><td>it is the period of time for distributing mining rewards, the unit is in a block</td><td>User Defined</td><td></td></tr></tbody></table>


# DeFiner HODLer SDK

Definer Hodler market programmer’s guide

This is a programmer’s guide that explains how to get DeFiner Hodler market data as well as perform transactions, such as deposit, borrow, withdraw etc.&#x20;

## Introduction

This guide is designed to help developers get a HODLer Market data and perform transactions on a HODLer market.  The guide is organized as follows:

1. Architectural overview
2. Setting up environment for either
   * NodeJS
   * Pure Javascript
3. Reading data using MarketDataObject
   * Functions and sample code to retrieve each element
4. Transacting using MarketTransactObject
   * Functions and sample code to perform transactions.

## Architectural overview

DeFiner HODLer markets are smart contracts deployed on blockchains.  A blockchain can be accessed through a URL.  Blockchains generally offer both public and private URLs.  Public URLs are usually free with no service guarantee while private URLs come for a fee with some level of service guarantee.

Each DeFiner HODLer market can be uniquely identified by the chain it’s on, the address of the smart contracts and a market ID.  Market ID is a sequential number generated at the time the market is created and assigned to that market.  The SDK abstracts away the addresses of the smart contracts, so to get data or perform transactions only the chain, market ID, and an object of the web3.

For getting data no account or authentication is required.  For performing transactions you are required to use a wallet.  While any type of wallet may work, only the following have been tested and proven to work:&#x20;

1. Metamask

This is the end of the architectural overview. The next section describes how to setup the environment

## Setting up environment

You can retrieve data or perform transactions by using either NodeJS or pure JavaScript. This section describes how to set up the environment for both.

### NodeJS

For NodeJS you need to install nodejs, npm and the definer-hodler npm package as follows:&#x20;

* Install nodejs. Download and install NodeJS from [here](https://nodejs.org/en/download/).
* Install npm. Download and install npm from [here](https://www.npmjs.com/).
* Install the definer-hodler.js npm package by running the following command:\\

```
npm install definer-holder
```

### Pure Javascript

For pure JavaScript you need to download the DeFiner SDK.

* Download the DeFiner SDK from [here](https://to-be-determined) and make it part of your website.

This is the end of the section on how to set up the environment.  The next section describes how to retrieve data.

## Reading data using MarketDataReader Object

This section describes how to retrieve data for a HODLer market.

To get data you need to instantiate the MarketDataReader object

### Instantiate MarkeDataReader object

The SDK exposes a factory class MarketDataReaderFactory with a static method: getNewInstance to create a MarketDataReader object. The MarketDataReader object provides methods to get the desired data elements of a market as specified in the next section. &#x20;

The static method: MarketDataReaderFactory.getNewInstance takes three parameters: 1) chain, 2) marketID, 3) web3Obj.

<table><thead><tr><th width="149">Parameter</th><th width="109">Type</th><th width="172">Required / Optional</th><th>Description</th></tr></thead><tbody><tr><td>chain</td><td>Object</td><td>Required</td><td>Defines the blockchain for the HODLer Market. </td></tr><tr><td>marketId</td><td>Number</td><td>Required</td><td>ID of the HODLer market.</td></tr><tr><td>web3Ojb</td><td>Object</td><td>Required</td><td>Object of the main class: Web3 of the Web3.js library.</td></tr></tbody></table>

#### Chains parameter

The chains parameter defines the chain you will be interacting with. Currently supported chains are listed in Table 1. The Chains parameter is required.

|                  | CHAINS property |
| ---------------- | --------------- |
| Ethereum mainnet | CHAINS.ETH      |
| BNB mainent      | CHAINS.BNB      |
| OKC mainnet      | CHAINS.OKC      |
| Polygon mainnet  | CHAINS.POLY     |

#### MarketID parameter

Each Hodler market is assigned a unique ID per chain, (i.e. the same ID will be present in each of the chains.) You will need to supply the marketID for which you need to retrieve data. marketID parameter is required. If you do not know the marketID you can discover it through the UI.

#### web3Obj parameter

This is the instance of web3 that is created using a provider.

#### Sample Code

*For node.js:*

```
import { MarketDataReaderFactory, CHAINS } from "definer-hodler.js";

const readerObj = await MarketDataReaderFactory.getNewInstance(CHAINS.BNB, 2, web3Obj);
```

*For pure javascript:*

```
<script src="https://domain-name.com/definer-hodler.min.js"></script>
```

```
const readerObj = await definerHodler.MarketDataReaderFactory.getNewInstance(
        definerHodler.CHAINS.BNB,
        2,
       web3Obj
      );
```

### Methods to retrieve market data points.

#### getMarketBaseTokenStakingAPR

This method returns the market base token’s staking APR.

*Sample code:*

```
const stakingAPR = readerObj.getMarketBaseTokenStakingAPR();
```

#### getMarketBaseTokenDepositMiningAPR

This method returns the market base token’s deposit mining APR.

*Sample code:*

```
const depositMiningAPR = readerObj.getMarketBaseTokenDepositMiningAPR();
```

#### getMarketBaseTokenTotalDeposit

This method returns the market base token’s total deposit. The returned amount is expressed in the smallest denomination of the market’s base token.

*Sample code:*

```
const totalDeposit = readerObj.getMarketBaseTokenTotalDeposit()
```

#### getMarketBaseTokenTotalLoan

This method returns the market base token’s total loan. The returned amount is expressed in the smallest denomination of the market’s base token.

*Sample code:*

```
const totalLoan = readerObj.getMarketBaseTokenTotalLoan();
```

#### **getMarketBaseTokenBorrowAPR**

This method returns the market base token’s borrow APR.

*Sample code:*

```
const borrowAPR = readerObj.getMarketBaseTokenBorrowAPR();
```

#### getMarketBaseTokenBorrowMiningAPR

This method returns the market base token’s borrow mining APR.

*Sample code:*

```
const borrowMiningAPR = readerObj.getMarketBaseTokenBorrowMiningAPR();
```

#### getMarketTokenStakingAPR

This method returns the staking APR of a market token.

* *Parameter*:

  tokenAddress: The address of a market’s token.
* *Sample code:*

```
const stakingAPR = readerObj.getMarketTokenStakingAPR("MARKET_TOKEN_ADDRESS");
```

#### getMarketTokenDepositMiningAPR

This method returns the deposit mining APR of a market token.

* Parameter:

  tokenAddress: The address of a market’s token.
* Sample code:

```
const depositMiningAPR = readerObj.getMarketTokenDepositMiningAPR("MARKET_TOKEN_ADDRESS");
```

#### getMarketTokenTotalDeposit

This method returns the total deposit of a market token.

* Parameter:

  tokenAddress: The address of a market’s token.
* *Sample code:*

```
const totalDeposit = readerObj.getMarketTokenTotalDeposit("MARKET_TOKEN_ADDRESS");
```

#### getMarketTokenTotalLoan

This method returns the total loan of a market token.

* Parameter:

  tokenAddress: The address of a market’s token.
* *Sample code:*

```
const totalLoan = readerObj.getMarketTokenTotalLoan("MARKET_TOKEN_ADDRESS");
```

#### getMarketTokenBorrowAPR

This method returns the borrow mining APR of a market token.

* Parameter:

  tokenAddress: The address of a market’s token.
* *Sample code:*

```
const totalLoan = readerObj.getMarketTokenBorrowAPR("MARKET_TOKEN_ADDRESS");
```

#### getMarketTokenBorrowMiningAPR

This method returns the borrow mining APR of a market token.

* Parameter:

  tokenAddress: The address of a market’s token.
* *Sample code:*

```
const totalLoan = readerObj.getMarketTokenBorrowMiningAPR("MARKET_TOKEN_ADDRESS");
```

## Perform transactions

This section describes how to transact on a HODLer market. Only the following transactions are available, however the claim related transactions are not available as part of this SDK.

* deposit
* withdraw
* withdrawAll
* borrow
* repay
* setCollateral

To be able to transact on a HODLer market, you need an instance of the class: MarketTransactionManager. The object uses the web3.js library to integrate with the blockchain. The static method of the factory class expects an instance of the main class Web3 that is part of the web3.js library (this is covered in more detail in a later section).

### Instantiate MarketTransactionManager object

The SDK exposes a factory class MarketTransManagerFactory with a static method: getNewInstance to create a MarketTransactionManager object. The MarketTransactionManager object provides methods to perform transactions specified in the next section.&#x20;

The static method: MarketTransManagerFactory.getNewInstance takes three parameters: 1) chain, 2) marketID, 3) web3Ojb.

The following are the constructor’s parameters:

<table><thead><tr><th width="134">Parameter</th><th width="96">Type</th><th width="185">Required / Optional</th><th>Description</th></tr></thead><tbody><tr><td>chain</td><td>Object</td><td>Required</td><td>Defines the blockchain for the HODLer Market. </td></tr><tr><td>marketId</td><td>Number</td><td>Required</td><td>ID of the HODLer market.</td></tr><tr><td>web3Ojb</td><td>Object</td><td>Required</td><td>Object of the main class: Web3 of the Web3.js library.</td></tr></tbody></table>

#### Chains parameter

The chain parameter defines the chain you will be interacting with. Currently supported chains are listed in Table 1. The Chains parameter is required.

| Block chain      | CHAINS property |
| ---------------- | --------------- |
| Ethereum mainnet | CHAINS.ETH      |
| BNB mainent      | CHAINS.BNB      |
| OKC mainnet      | CHAINS.OKC      |
| Polygon mainnet  | CHAINS.POLY     |

#### MarketID parameter

This is the ID of the market that you would like to transact on. As previously mentioned if you do not know the marketID you can discover it through the UI.

#### web3Ojb parameter

This is the instance of web3 that is created using a provider which must have an account.

#### Sample code for Node.js implementation:

```
import { MarketTransManagerFactory, CHAINS } from "definer-hodler.js";
const transManager = await MarketTransManagerFactory.getNewInstance(
        definerHodler.CHAINS.BNB,
        2,
       web3Obj
      );
```

#### Sample code for Pure javascript implementation:

```
<script src="https://domain-name.com/definer-hodler.min.js"></script>
```

```
const transManager= await definerHodler.MarketTransManagerFactory.getNewInstance(
        definerHodler.CHAINS.BNB,
        2,
       web3Obj
      );
```

### MarketTransactionManager methods for transacting on a HODLer market

This section covers all the methods available on the MarketTransactionManager object to transact on a HODLer market. The web3instance provide to the constructor for MarketTransactionManager object creation is expected to have a provider with an account. This account would be referenced in the transaction to be submitted.

Each one of the methods listed below returns a promise events, see [here ](https://web3js.readthedocs.io/en/v1.8.1/callbacks-promises-events.html)for more details. This allows the caller to respond to the different events emitted as a transaction is getting processed.

#### deposit

This method handles the “deposit” transaction.

* Parameters:
  * tokenAddress: The address of the token to be deposited. Only the tokens supported on the HODLer market are expected.
  * Amount: The amount of tokens to be deposited. This amount must not exceed the wallet’s balance of the given token (tokenAddress parameter). It is expected to be provided in the smallest denomination of the token to be deposited. Example: 1Eth is expected as 1000000000000000000
* Sample code:

```
transManager.desposit(3, "0x770f030fdbf63ebf1c939de8bcff8943c2c2d454");
```

#### withdraw

This method handles the “withdraw” transaction.

* Parameters:
  * tokenAddress: The address of the token to be withdrawn. Only the tokens supported on the HODLer market are expected. The account must have a deposit balance of the token.
  * Amount: The amount of tokens to be withdrawn. This amount must not exceed the account’s total deposit of the given token (tokenAddress parameter). It is expected to be provided in the smallest denomination of the token to be deposited. Example: 1Eth is expected as 1000000000000000000
* Sample code:

```
transManager.withdraw(3, "0x770f030fdbf63ebf1c939de8bcff8943c2c2d454");
```

#### withdawAll

This method handles the “withdrawAll” transaction.

* Parameters:
  * tokenAddress: The address of the token to be all withdrawn. Only the tokens supported on the HODLer market are expected. The account must have a deposit balance of the token.
* Sample code:

```
transManager.withdrawAll("0x770f030fdbf63ebf1c939de8bcff8943c2c2d454");
```

#### borrow

This method handles the “borrow” transaction.

* Parameters:
  * tokenAddress: The address of the token to be withdrawn. Only the tokens supported on the HODLer market are expected. The account must have the required collateral.
  * Amount: The amount of tokens to be withdrawn. This amount must not exceed the account’s borrowing power. It is expected to be provided in the smallest denomination of the token to be deposited.\
    Example: 1Eth is expected as 1000000000000000000
* Sample code:

```
transManager.borrow(3, "0x770f030fdbf63ebf1c939de8bcff8943c2c2d454");
```

#### repay

This method handles the "repay" transaction.

* Parameters:
  * tokenAddress: The address of the token to be repaid. Only the tokens supported on the HODLer market are expected. The account must have a loan balance of the token.
  * Amount: The amount of tokens to be repaid. This amount must not exceed the account’s total loan of the given token (tokenAddress parameter). It is expected to be provided in the smallest denomination of the token to be deposited. Example: 1Eth is expected as 1000000000000000000
* Sample code:

```
transManager.repay(3, "0x770f030fdbf63ebf1c939de8bcff8943c2c2d454");
```

#### setCollateral

This method handles the enabling or disabling of a deposited token as collateral.

* Parameters:
  * tokenAddress: The address of the desposited token that needs to be enabled or disabled as collateral.
  * enable: A boolean value for enabling or disabling the deposited token as collateral.
* Sample code:

  *Enabling a deposited token as collateral.*

```
transManager.setCollateral("0x770f030fdbf63ebf1c939de8bcff8943c2c2d454", true);
```

&#x20;     *Disabling a deposited token as collateral*

```
transManager.setCollateral("0x770f030fdbf63ebf1c939de8bcff8943c2c2d454", false);
```

### Application errors and exceptions

For most of the methods listed above there are internal validations that are executed prior to any interaction with the blockchain. When those validations fail, comprehensive error messages are returned. The following is the list of those error messages.

The errors thrown are object with the following structure:

{ code: ERROR\_CODE, \
&#x20; msg: ERROR\_MESSAGE }

<table><thead><tr><th width="246">ERROR_CODE</th><th>ERROR_MESSAGE</th></tr></thead><tbody><tr><td>ERR_TK01</td><td>The token is not supported</td></tr><tr><td>ERR_TK02</td><td>The token is not enabled</td></tr><tr><td>ERR_TK03</td><td>The maturity has not been reached</td></tr><tr><td>ERR_SC01</td><td>Smart Contra is paused</td></tr><tr><td>ERR_ACC01</td><td>The account does not have enough deposit</td></tr><tr><td>ERR_ACC02</td><td>Borrow amount exceeds the account borrow power</td></tr><tr><td>ERR_ACC03</td><td>The account does not have enough collateral</td></tr><tr><td>ERR_ACC04</td><td>The account does not have deposit</td></tr><tr><td>ERR_ACC05</td><td>The account does not have outstanding loans</td></tr><tr><td>ERR_TRS01</td><td>The amount provided is zero.</td></tr></tbody></table>

All RPC related errors encountered when a transaction is submitted must be handled by the consumer of the SDK. Examples of code for parsing RPC errors can be found on the internet.


# Use Cases

HODLer Market can be used more than just lending and borrowing. Below are 8 scenarios where users can utilize the HODLer Market in different ways.&#x20;

1. Token Lock-up&#x20;
2. LP Token Lock-up&#x20;
3. Salary Issuing&#x20;
4. Auto Vesting&#x20;
5. Airdrop Locked Tokens&#x20;
6. Leveraged Long Position
7. Governance&#x20;
8. Initial Loan Offering (ILO)&#x20;

#### Token Lock-up&#x20;

Following the Token Generation Event (TGE), new tokens are vested every certain period which generates high selling pressure. Finding a home for the upcoming liquidity seems more crucial than ever for projects. After all, as a project, the long-term goal is a loyal community.&#x20;

This is when the DeFiner HODLer market comes into the picture. A project can utilize the lock-up function in the HODLer Market to encourage its community to HODL. The lock-up prevents high selling pressure and further prevents the token price drop. The HODLer Market effectively stops the death spiral and creates a healthy community.&#x20;

On a sunny day, the community will feel satisfied as the token price goes up and they will help to promote the project due to the wealth effect. During a rainy day, the community has the option to borrow against the token locked instead of selling.

<figure><img src="/files/SwZ92dqWPYsjt88TAsrB" alt=""><figcaption></figcaption></figure>

#### LP Token Lock-up&#x20;

After TGE, the next step is to build a liquidity pool on DEX for token holders to trade.  The best way to reward the liquidity providers is via an LP pool. However, there are mercenary liquidity providers who only come to the farm, withdraw and sell. When the protocol reduces or stops the token rewards, liquidity miners will immediately move to other protocols offering higher rewards leaving a dead community behind.&#x20;

With the HODLer market, projects can create a locked pool for their LP tokens which means users will get their LP token after a certain period. Only users who are committed and target for the long run are willing to lock their LP. HODLer market efficiently helps projects filter out mercenary liquidity providers and build a strong community.

<figure><img src="/files/Gk1QHuP6HYRF1cyL4Qf2" alt=""><figcaption></figcaption></figure>

#### Salary Issuing&#x20;

To create a strong bond between the project and team members, most token issuers choose to pay the team with a certain portion of their native token. However, some team members are risk-averse. Even if they want to hold the tokens, there are basic living expenses that need to be covered. These people tend to sell the tokens immediately upon receiving which is opposite to the original purpose of rewarding them with the project's native token.&#x20;

With a HODLer market, projects can define a locking period for their native token when issuing tokens as a salary. Since the locked position can be used as collateral, team members can easily borrow against it. In this case, even risk-averse team members don't have to worry about running out of grocery money if they don't sell the tokens right away. They can hodl on without any pressure and count on a 10x or 100x return because of their hard work and contribution to the project.&#x20;

![](https://web.archive.org/web/20220725210614im_/https://help.definer.org/hubfs/Team%20Salary%20Issuing%20with%20Locked%20Token-jpg.jpeg)

#### Auto Vesting &#x20;

One creative use case for the HODLer Market is to use it as a vesting tool for projects right after TGE. &#x20;

If the vesting schedule is linear, the project can first issue a token to represent investors' position and then create a HODLer market using the about-to-issue token as a reward token and the position representation token as the base token. The project can vest the token by configuring the total amount of rewards that need to be issued based on the vesting schedule.&#x20;

<figure><img src="/files/gCahzj2HSlIxNeNnZ6Z7" alt=""><figcaption></figcaption></figure>

If the vesting schedule is based on an interval, it is even simpler with the HODLer Market. Projects can just deposit their about-to-issue token and configure a maturity date based on the schedule. The investors can claim the token after the maturity date.

<figure><img src="/files/bwMQdf1XjzNiXpsHSPwa" alt=""><figcaption></figcaption></figure>

Vesting with the HODLer Market also provides flexibility for investors. Not only can they get the token anytime they want with a fully transparent release schedule but also can transfer or sell their unvested token positions. Moreover, investors can borrow against their unvested position to unlock some liquidity.

#### Airdrop with Locked Tokens&#x20;

Airdrop events are no strangers to crypto projects. It's all about customer acquisition. The cost of which should always be lower than the Lifetime Value of the customer itself. &#x20;

While airdrop events are a good way for customer acquis, it's a double sword. Airdrops also attract mercenary stakes which creates the same issue as the mercenary liquidity miners. Projects are not gaining customers and yet losing money over airdrops campaigns. The negative effects outweighed the marketing effect.&#x20;

The HODLer market can successfully solve this situation by providing the projects with two options. Option 1 is a direct airdrop with a lock-up period. The projects can utilize the lock-up function and directly airdrop through the HODLer Market. Projects can simply deposit their airdrop token into the HODLer market and configure the maturity date. In return, they will get position tokens and distribute these to airdrop participants. Participants can directly withdraw the airdrop tokens upon maturity dates. This helps the projects filter out the mercenary stakers since they are looking to make some quick bucks.

<figure><img src="/files/jcdx7qWOBweNsloab1Hf" alt=""><figcaption></figcaption></figure>

Option 2 is linear vested airdrop rewards. Projects can also choose to have their airdrop reward tokens linearly vested over a certain period. They can configure the market with their airdrop token as a reward token. Once they deposit the airdrop token into the HODLer Market, a position token will be generated. Airdrop participants can deposit the position token in the HODLer Market and receive the airdrop token.

<figure><img src="/files/OBoWak6tQo4I5ov4JAQk" alt=""><figcaption></figcaption></figure>

By using the HODLer market, projects filter out the mercenary stakers since these people are only looking to make some quick bucks instead of long-term commitments. The real customers stay. The project's campaign money is well spent due to the real conversion and customer acquisition. This method creates a win-win situation for airdrops events.  &#x20;

#### Leveraged Long Position&#x20;

For tokens right after TGE and just released for public trading, usually, there are few venues for their token holders to buy with leverage.&#x20;

One of the creative ways that projects can do is to utilize the DeFiner HODLer market. Since token holders can borrow against the locked position, they can use the borrowed money to purchase more tokens in the secondary market and deposit the token once again to the HODLer market to earn more yield. The leveraged position encouraged the community to hodl ever more tokens.&#x20;

As the trading volume and liquidity increase, projects can choose to increase the collateral factor which provides token holders even more leverage.

![](https://web.archive.org/web/20220725210614im_/https://help.definer.org/hubfs/Leveraged%20Long%20Position-jpg.jpeg)

#### Governance&#x20;

DAO or projects can utilize HODLer Market to generate governance tokens to further facilitate their own governance. Once the community starts to deposit and lock their token in the HODLer market, they will receive a staked token (stToken) to represent their positions. DeFiner also provides a tool to convert the stToken into a voting token (veToken). Based on the number of stToken and lock period, the community will get veToken. The community can use these veToken to participate in their own governance process.&#x20;

The benefit of comparing the veToken is that it efficiently filters out the short-term token holders and grants the voting power to the long-term supporters. Those supporters are the true voice of the community since they are willing to lock up their tokens and grow with the project.&#x20;

![](https://web.archive.org/web/20220725210614im_/https://help.definer.org/hubfs/Governance-jpg.jpeg)

#### Initial Loan Offering (ILO)

People have high expectations during ICO and IDO. Whether it's private investors or public sales investors, for every penny they invested, they are looking for 100x, 1000x, or even more.  Not reaching the desired rate will cause the spread of negative comments in the community.&#x20;

The HODLer market gives the project an alternative. Instead of raising money from the token sale with high pressure and high expectations, projects can simply raise funds through debt. The project can deposit their unlaunched tokens with the specification of lock-up time and interest rate and borrow stablecoins against it.&#x20;

With a more predictable rate and time, projects have better control of their token launching and market making. Also, this is a good way of gaining more retail investors through both the projects and DeFiner's community.

<figure><img src="/files/jbxvnXrMVharWwLQJJox" alt=""><figcaption></figcaption></figure>

#### SDK&#x20;

Projects spent a lot of time and effort on seamless and holistic user experience to keep the traffic on their site. While integration is good for the ecosystem, it can direct the traffic away.&#x20;

With the HODLer Market, projects do not have to be concerned about driving traffic away as we provide detailed SDK and customizable widget functions. Projects can integrate the HODLer Market with their own UI since the HODLer smart contract is deployed on the blockchain with an open and transparent ABI. This function will save the project's time significantly which is specifically in favor of NFT, GameFi, and Metaverse projects since it is an easy token utility booster for them.&#x20;

SDK Docs: <https://docs.definer.org/definer-hodler-sdk>

#### HODLer Market Demo Video&#x20;

{% embed url="<https://www.youtube.com/watch?v=UWApsBvlAtQ>" %}

#### More on the HODLer Market&#x20;

Learn more about HODLer Market: [https://blog.definer.org/definer-hodler-market](https://web.archive.org/web/20220725210614/https://blog.definer.org/definer-hodler-market)

Start to create a HODLer Market today: [https://beta.definer.org](https://web.archive.org/web/20220725210614/https://beta.definer.org/)


