aave-protocol-v2/contracts/libraries/math/MathUtils.sol
2020-08-20 09:51:21 +02:00

73 lines
2.5 KiB
Solidity

// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.6.8;
import {SafeMath} from '@openzeppelin/contracts/math/SafeMath.sol';
import {WadRayMath} from './WadRayMath.sol';
library MathUtils {
using SafeMath for uint256;
using WadRayMath for uint256;
uint256 internal constant SECONDS_PER_YEAR = 365 days;
/**
* @dev function to calculate the interest using a linear interest rate formula
* @param _rate the interest rate, in ray
* @param _lastUpdateTimestamp the timestamp of the last update of the interest
* @return the interest rate linearly accumulated during the timeDelta, in ray
**/
function calculateLinearInterest(uint256 _rate, uint40 _lastUpdateTimestamp)
internal
view
returns (uint256)
{
//solium-disable-next-line
uint256 timeDifference = block.timestamp.sub(uint256(_lastUpdateTimestamp));
uint256 timeDelta = timeDifference.wadToRay().rayDiv(SECONDS_PER_YEAR.wadToRay());
return _rate.rayMul(timeDelta).add(WadRayMath.ray());
}
/**
* @dev function to calculate the interest using a compounded interest rate formula.
* To avoid expensive exponentiation, the calculation is performed using a binomial approximation:
*
* (1+x)^n = 1+n*x+[n/2*(n-1)]*x^2+[n/6*(n-1)*(n-2)*x^3...
*
* 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.
*
* @param _rate the interest rate, in ray
* @param _lastUpdateTimestamp the timestamp of the last update of the interest
* @return the interest rate compounded during the timeDelta, in ray
**/
function calculateCompoundedInterest(uint256 _rate, uint40 _lastUpdateTimestamp)
internal
view
returns (uint256)
{
//solium-disable-next-line
uint256 exp = block.timestamp.sub(uint256(_lastUpdateTimestamp));
if (exp == 0) {
return WadRayMath.ray();
}
uint256 expMinusOne = exp.sub(1);
uint256 expMinusTwo = exp > 2 ? exp.sub(2) : 0;
uint256 ratePerSecond = _rate.div(31536000);
uint256 basePowerTwo = ratePerSecond.rayMul(ratePerSecond);
uint256 basePowerThree = basePowerTwo.rayMul(ratePerSecond);
uint256 secondTerm = exp.mul(expMinusOne).mul(basePowerTwo).div(2);
uint256 thirdTerm = exp.mul(expMinusOne).mul(expMinusTwo).mul(basePowerThree).div(6);
return WadRayMath.ray().add(ratePerSecond.mul(exp)).add(secondTerm).add(thirdTerm);
}
}