Skip to content

Instantly share code, notes, and snippets.

@JTraversa
Last active August 4, 2022 15:47
Show Gist options
  • Save JTraversa/9656be91f49d3271c0c187e901449ccd to your computer and use it in GitHub Desktop.
Save JTraversa/9656be91f49d3271c0c187e901449ccd to your computer and use it in GitHub Desktop.
LibCompound -- Compound Math
// 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