// SPDX-License-Identifier: agpl-3.0 pragma solidity ^0.6.8; import {SafeMath} from '../../dependencies/openzeppelin/contracts/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 - 1; uint256 expMinusTwo = exp > 2 ? exp - 2 : 0; uint256 ratePerSecond = rate / SECONDS_PER_YEAR; uint256 basePowerTwo = ratePerSecond.rayMul(ratePerSecond); uint256 basePowerThree = basePowerTwo.rayMul(ratePerSecond); uint256 secondTerm = exp.mul(expMinusOne).mul(basePowerTwo) / 2; uint256 thirdTerm = exp.mul(expMinusOne).mul(expMinusTwo).mul(basePowerThree) / 6; return WadRayMath.ray().add(ratePerSecond.mul(exp)).add(secondTerm).add(thirdTerm); } }