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
B o r r o w A P R = C o m p o u n d S u p p l y R a t e W e i g h t s × C o m p o u n d S u p p l y R a t e + C o m p o u n d B o r r o w R a t e W e i g h t s × C o m p o u n d B o r r o w R a t e ( ) + R a t e C u r v e C o n s t a n t ÷ ( 1 − u ) Borrow APR= Compound Supply Rate Weights \times Compound Supply Rate + Compound Borrow Rate Weights \times Compound Borrow Rate () + RateCurve Constant\div(1-u) B orro w A PR = C o m p o u n d S u ppl y R a t e W e i g h t s × C o m p o u n d S u ppl y R a t e + C o m p o u n d B orro wR a t e W e i g h t s × C o m p o u n d B orro wR a t e ( ) + R a t e C u r v e C o n s t an t ÷ ( 1 − u )
When u u u >0.98,
R a t e C u r v e C o n s t a n t ÷ ( 1 − u ) = R a t e C u r v e C o n s t a n t ÷ ( 1 − 0.98 ) = R a t e C u r v e C o n s t a n t × 50 Rate Curve Constant\div(1-u) = Rate Curve Constant \div(1-0.98)= RateCurveConstant\times50 R a t e C u r v e C o n s t an t ÷ ( 1 − u ) = R a t e C u r v e C o n s t an t ÷ ( 1 − 0.98 ) = R a t e C u r v e C o n s t an t × 50
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.
Compound Supply
Rate Weight
Compound Borrow
Rate Weight
Below is how the borrow interest rate curve varies at different capital utilization levels based on three strategies.
Pseudocode:
Copy 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:
Copy 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
D e p o s i t R a t e = C o m p o u n d S u p p l y R a t i o × C o m p o u n d S u p p l y R a t e + B o r r o w R a t e × u Deposit Rate= CompoundSupplyRatio\times CompoundSupplyRate +BorrowRate\times u De p os i tR a t e = C o m p o u n d S u ppl y R a t i o × C o m p o u n d S u ppl y R a t e + B orro wR a t e × u
For assets that are not available on Compound or other money markets, Compound Supply Rate Weights=0, Compound Borrow Rate Weights=0
PseudoCode
Copy 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:
Copy 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
Formular:
D e p o s i t I n t e r e s t R a t e P e r B l o c k = B o r r o w A P R ÷ B l o c k s P e r Y e a r Deposit Interest Rate Per Block = BorrowAPR\div BlocksPerYear De p os i t I n t eres tR a t e P er Bl oc k = B orro w A PR ÷ Bl oc k s P er Y e a r
D e p o s i t I n t e r e s t P e r B l o c k = ( D e p o s i t P r i n c i p l e + D e p o s i t S t o r a g e I n t e r e s t ) × D e p o s i t I n t e r e s t R a t e P e r B l o c k Deposit Interest Per Block = (Deposit Principle+Deposit Storage Interest) \times Deposit Interest Rate Per Block De p os i t I n t eres tP er Bl oc k = ( De p os i tP r in c i pl e + De p os i tSt or a g e I n t eres t ) × De p os i t I n t eres tR a t e P er Bl oc k
D e p o s i t I n t e r e s t ( b l o c k t ) = D e p o s i t I n t e r e s t ( b l o c k t − 1 ) ) + D e p o s i t I n t e r e s t P e r B l o c k DepositInterest(block_t)=DepositInterest(block_t -_1))+DepositInterestPerBlock De p os i t I n t eres t ( b l oc k t ) = De p os i t I n t eres t ( b l oc k t − 1 )) + De p os i t I n t eres tP er Bl oc k
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.