2020-06-30 12:09:28 +00:00
|
|
|
// SPDX-License-Identifier: agpl-3.0
|
|
|
|
pragma solidity ^0.6.8;
|
|
|
|
|
2020-10-15 13:41:56 +00:00
|
|
|
import {SafeMath} from '../../dependencies/openzeppelin/contracts/SafeMath.sol';
|
2020-08-20 07:51:21 +00:00
|
|
|
import {WadRayMath} from './WadRayMath.sol';
|
2020-06-30 12:09:28 +00:00
|
|
|
|
|
|
|
library MathUtils {
|
2020-07-13 08:54:08 +00:00
|
|
|
using SafeMath for uint256;
|
|
|
|
using WadRayMath for uint256;
|
|
|
|
|
2020-10-27 09:44:37 +00:00
|
|
|
/// @dev Ignoring leap years
|
2020-07-13 08:54:08 +00:00
|
|
|
uint256 internal constant SECONDS_PER_YEAR = 365 days;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @dev function to calculate the interest using a linear interest rate formula
|
2020-08-21 16:18:12 +00:00
|
|
|
* @param rate the interest rate, in ray
|
|
|
|
* @param lastUpdateTimestamp the timestamp of the last update of the interest
|
2020-07-13 08:54:08 +00:00
|
|
|
* @return the interest rate linearly accumulated during the timeDelta, in ray
|
|
|
|
**/
|
|
|
|
|
2020-08-21 16:18:12 +00:00
|
|
|
function calculateLinearInterest(uint256 rate, uint40 lastUpdateTimestamp)
|
2020-07-13 08:54:08 +00:00
|
|
|
internal
|
|
|
|
view
|
|
|
|
returns (uint256)
|
|
|
|
{
|
|
|
|
//solium-disable-next-line
|
2020-08-21 16:18:12 +00:00
|
|
|
uint256 timeDifference = block.timestamp.sub(uint256(lastUpdateTimestamp));
|
2020-07-13 08:54:08 +00:00
|
|
|
|
2020-10-27 11:44:30 +00:00
|
|
|
return (rate.mul(timeDifference) / SECONDS_PER_YEAR).add(WadRayMath.ray());
|
2020-07-13 08:54:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-08-11 07:36:46 +00:00
|
|
|
* @dev function to calculate the interest using a compounded interest rate formula.
|
|
|
|
* To avoid expensive exponentiation, the calculation is performed using a binomial approximation:
|
|
|
|
*
|
2020-08-20 07:51:21 +00:00
|
|
|
* (1+x)^n = 1+n*x+[n/2*(n-1)]*x^2+[n/6*(n-1)*(n-2)*x^3...
|
2020-08-11 07:36:46 +00:00
|
|
|
*
|
|
|
|
* The approximation slightly underpays liquidity providers, with the advantage of great gas cost reductions.
|
|
|
|
* The whitepaper contains reference to the approximation and a table showing the margin of error per different time periods.
|
|
|
|
*
|
2020-08-21 16:18:12 +00:00
|
|
|
* @param rate the interest rate, in ray
|
|
|
|
* @param lastUpdateTimestamp the timestamp of the last update of the interest
|
2020-07-13 08:54:08 +00:00
|
|
|
* @return the interest rate compounded during the timeDelta, in ray
|
|
|
|
**/
|
2020-08-21 16:18:12 +00:00
|
|
|
function calculateCompoundedInterest(uint256 rate, uint40 lastUpdateTimestamp)
|
2020-07-13 08:54:08 +00:00
|
|
|
internal
|
|
|
|
view
|
|
|
|
returns (uint256)
|
|
|
|
{
|
|
|
|
//solium-disable-next-line
|
2020-08-21 16:18:12 +00:00
|
|
|
uint256 exp = block.timestamp.sub(uint256(lastUpdateTimestamp));
|
2020-08-11 07:36:46 +00:00
|
|
|
|
2020-08-20 07:51:21 +00:00
|
|
|
if (exp == 0) {
|
2020-08-11 07:36:46 +00:00
|
|
|
return WadRayMath.ray();
|
|
|
|
}
|
|
|
|
|
2020-09-09 19:26:52 +00:00
|
|
|
uint256 expMinusOne = exp - 1;
|
2020-08-11 08:11:35 +00:00
|
|
|
|
2020-09-09 19:26:52 +00:00
|
|
|
uint256 expMinusTwo = exp > 2 ? exp - 2 : 0;
|
2020-08-11 07:36:46 +00:00
|
|
|
|
2020-09-09 19:26:52 +00:00
|
|
|
uint256 ratePerSecond = rate / SECONDS_PER_YEAR;
|
2020-08-11 07:36:46 +00:00
|
|
|
|
2020-08-20 07:51:21 +00:00
|
|
|
uint256 basePowerTwo = ratePerSecond.rayMul(ratePerSecond);
|
|
|
|
uint256 basePowerThree = basePowerTwo.rayMul(ratePerSecond);
|
2020-08-11 07:36:46 +00:00
|
|
|
|
2020-09-09 19:26:52 +00:00
|
|
|
uint256 secondTerm = exp.mul(expMinusOne).mul(basePowerTwo) / 2;
|
|
|
|
uint256 thirdTerm = exp.mul(expMinusOne).mul(expMinusTwo).mul(basePowerThree) / 6;
|
2020-07-13 08:54:08 +00:00
|
|
|
|
2020-08-11 07:36:46 +00:00
|
|
|
return WadRayMath.ray().add(ratePerSecond.mul(exp)).add(secondTerm).add(thirdTerm);
|
2020-07-13 08:54:08 +00:00
|
|
|
}
|
|
|
|
}
|