Skip to content

Commit

Permalink
Merge pull request #222 from morpho-labs/feat/compound-1
Browse files Browse the repository at this point in the history
feat: compound interest
  • Loading branch information
MathisGD authored Aug 9, 2023
2 parents a5272b4 + 1e74522 commit 3de9d77
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/Blue.sol
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ contract Blue is IBlue {

if (marketTotalBorrow != 0) {
uint256 borrowRate = IIrm(market.irm).borrowRate(market);
uint256 accruedInterests = marketTotalBorrow.mulWadDown(borrowRate * elapsed);
uint256 accruedInterests = marketTotalBorrow.mulWadDown(borrowRate.wTaylorCompounded(elapsed));
totalBorrow[id] = marketTotalBorrow + accruedInterests;
totalSupply[id] += accruedInterests;

Expand Down
21 changes: 21 additions & 0 deletions src/libraries/FixedPointMathLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ library FixedPointMathLib {
return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
}

/// @dev The sum of the last three terms in a four term taylor series expansion
/// to approximate a compound interest rate: (1 + x)^n - 1.
function wTaylorCompounded(uint256 x, uint256 n) internal pure returns (uint256) {
uint256 firstTerm = x * n;
uint256 secondTerm = mulWadDown(firstTerm, x * zeroFloorSub(n, 1)) / 2;
uint256 thirdTerm = mulWadDown(secondTerm, x * zeroFloorSub(n, 2)) / 3;

return firstTerm + secondTerm + thirdTerm;
}

/*//////////////////////////////////////////////////////////////
LOW LEVEL FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
Expand All @@ -55,4 +65,15 @@ library FixedPointMathLib {
z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
}
}

/*//////////////////////////////////////////////////////////////
INTEGER OPERATIONS
//////////////////////////////////////////////////////////////*/

/// @dev Returns max(x - y, 0).
function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
z := mul(gt(x, y), sub(x, y))
}
}
}
31 changes: 31 additions & 0 deletions test/forge/Math.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "forge-std/Test.sol";

import "src/libraries/FixedPointMathLib.sol";

contract MathTest is Test {
using FixedPointMathLib for uint256;

function testWTaylorCompounded(uint256 rate, uint256 timeElapsed) public {
// Assume rate is less than a ~500% APY. (~180% APR)
vm.assume(rate < (FixedPointMathLib.WAD / 20_000_000) && timeElapsed < 365 days);
uint256 result = rate.wTaylorCompounded(timeElapsed) + FixedPointMathLib.WAD;
uint256 toCompare = wPow(FixedPointMathLib.WAD + rate, timeElapsed);
assertLe(result, toCompare, "rate should be less than the compounded rate");
assertGe(
result, FixedPointMathLib.WAD + timeElapsed * rate, "rate should be greater than the simple interest rate"
);
assertLe((toCompare - result) * 100_00 / toCompare, 8_00, "The error should be less than or equal to 8%");
}

// Exponentiation by squaring with rounding up.
function wPow(uint256 x, uint256 n) private pure returns (uint256 z) {
z = FixedPointMathLib.WAD;
for (; n != 0; n /= 2) {
z = n % 2 != 0 ? z.mulWadUp(x) : z;
x = x.mulWadUp(x);
}
}
}

0 comments on commit 3de9d77

Please sign in to comment.