Last active
August 4, 2022 15:47
-
-
Save JTraversa/9656be91f49d3271c0c187e901449ccd to your computer and use it in GitHub Desktop.
LibCompound -- Compound Math
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: BUSL-1.1 | |
pragma solidity >=0.8.4; | |
import {FixedPointMathLib} from "./Marketplace/FixedPointMathLib.sol"; | |
import "./ExponentialNoError.sol"; | |
import "./Marketplace/Interfaces.sol"; | |
/// @notice Get up to date cToken data without mutating state. | |
/// @author Transmissions11 (https://github.com/transmissions11/libcompound) | |
library LibCompound { | |
error RATE(); | |
struct Exp { | |
uint mantissa; | |
} | |
struct Double { | |
uint mantissa; | |
} | |
uint constant expScale = 1e18; | |
uint constant doubleScale = 1e36; | |
uint constant halfExpScale = expScale/2; | |
uint constant mantissaOne = expScale; | |
/** | |
* @dev Truncates the given exp to a whole number value. | |
* For example, truncate(Exp{mantissa: 15 * expScale}) = 15 | |
*/ | |
function truncate(Exp memory exp) pure internal returns (uint) { | |
// Note: We are not using careful math here as we're performing a division that cannot fail | |
return exp.mantissa / expScale; | |
} | |
/** | |
* @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. | |
*/ | |
function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) { | |
Exp memory product = mul_(a, scalar); | |
return truncate(product); | |
} | |
/** | |
* @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. | |
*/ | |
function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) { | |
Exp memory product = mul_(a, scalar); | |
return (truncate(product) + addend); | |
} | |
function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { | |
return Exp({mantissa: a.mantissa * b}); | |
} | |
using FixedPointMathLib for uint256; | |
function viewUnderlyingBalanceOf(ICERC20 cToken, address user) internal view returns (uint256) { | |
return cToken.balanceOf(user).mulWadDown(viewExchangeRate(cToken)); | |
} | |
function viewExchangeRate(ICERC20 cToken) internal view returns (uint256) { | |
uint256 accrualBlockNumberPrior = cToken.accrualBlockNumber(); | |
uint256 currentBlockNumber = block.number; | |
if (accrualBlockNumberPrior == currentBlockNumber) return cToken.exchangeRateStored(); | |
uint256 totalCash = cToken.underlying().balanceOf(address(cToken)); | |
uint256 borrowsPrior = cToken.totalBorrows(); | |
uint256 reservesPrior = cToken.totalReserves(); | |
uint256 borrowRateMantissa = cToken.interestRateModel().getBorrowRate(totalCash, borrowsPrior, reservesPrior); | |
if(borrowRateMantissa > 0.0005e16) { revert RATE(); } // Same as borrowRateMaxMantissa in CTokenInterfaces.sol | |
/* Calculate the number of blocks elapsed since the last accrual */ | |
uint blockDelta = currentBlockNumber - accrualBlockNumberPrior; | |
Exp memory simpleInterestFactor = mul_(Exp({mantissa: borrowRateMantissa}), blockDelta); | |
uint interestAccumulated = mul_ScalarTruncate(simpleInterestFactor, borrowsPrior); | |
uint totalBorrowsNew = interestAccumulated + borrowsPrior; | |
uint totalReservesNew = mul_ScalarTruncateAddUInt(Exp({mantissa: cToken.reserveFactorMantissa()}), interestAccumulated, reservesPrior); | |
uint cashPlusBorrowsMinusReserves = totalCash + totalBorrowsNew - totalReservesNew; | |
uint exchangeRate = cashPlusBorrowsMinusReserves * expScale / cToken.totalSupply(); | |
return (exchangeRate); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment