mapping(address => address) public referencePools;
// mapping from uni v3 pool to bool of whether or not they are being utilized
mapping(address => bool) public isSupportedPool;
Non-library/interface files should use fixed compiler versions, not floating ones
/**
* @dev gets the breakdown of a LP Token in the pool's underlying tokens, utilizing an instantaneous or TWAP tick
* @param tokenId The tokenId to get a breakdown of
* @param isTwap Whether to use a TWAP or instantaneous tick for calculations
* @return token0 The first token of tokenId's pool
* token1 The second token of tokenId's pool
* amountToken0Fees Amount of token0 in fees
* amountToken1Fees Amount of token1 in fees
* amountToken0Liquidity Amount of token0 contributing to liquidity value
* amountToken1Liquidity Amount of token1 contributing to liquidity value
* amountLiquidity Amount of liquidity that tokenId represents
*/
function _getTokenBreakdown(
uint256 tokenId,
bool isTwap,
address nfpManager,
address factory,
address tickOracle
)
internal
view
returns (
address token0,
address token1,
uint256 amountToken0Fees,
uint256 amountToken1Fees,
uint256 amountToken0Liquidity,
uint256 amountToken1Liquidity,
uint256 amountLiquidity
/**
* @dev generates an in-memory struct of position information of the tokenId to be used for computations
* @param tokenId The tokenId to generate position information of
* @return vars The in-memory struct containing all most recently updated information about our tokenId
*/
function _generateTokenValueLocalVars(
uint256 tokenId,
address nfpmManager,
address factory
) internal view returns (TokenValueLocalVars memory vars) {
/**
* @dev calculates updated fees for a tokenId position given old stats
* @param vars The in-memory struct containing all most recently updated information about our tokenId
* @return tokensOwed0 The updated amount of token0 collected in fees
* tokensOwed1 The updated amount of token1 collected in fees
*/
function _getTokensOwed(TokenValueLocalVars memory vars, int24 tick)
internal
view
returns (uint256 tokensOwed0, uint256 tokensOwed1)
/**
* @notice get twap converted with base & quote token decimals
* @dev if period is longer than the current timestamp - first timestamp stored in the pool, this will revert with "OLD"
* @param _pool uniswap pool address
* @param _base base currency. to get eth/usd price, eth is base token
* @param _quote quote currency. to get eth/usd price, usd is the quote currency
* @param _period number of seconds in the past to start calculating time-weighted average
* @return price of 1 base currency in quote currency. scaled by 1e18
*/
function getTwap(
address _pool,
address _base,
address _quote,
uint32 _period,
bool _checkPeriod
) internal view returns (uint256) {
/**
* @notice get balances of token0 / token1 in a uniswap position
* @dev knowing liquidity, tick range, and current tick gives balances
* Opyn team (https://github.com/opynfinance/squeeth-monorepo/blob/main/packages/hardhat/contracts/libs/VaultLib.sol)
* @param _tickLower address of the uniswap position manager
* @param _tickUpper uniswap position token id
* @param _tick current price tick used for calculation
* @return amount0 the amount of token0 in the uniswap position token
* @return amount1 the amount of token1 in the uniswap position token
*/
function _getToken0Token1Balances(
int24 _tickLower,
int24 _tickUpper,
int24 _tick,
uint128 _liquidity
) internal pure returns (uint256 amount0, uint256 amount1) {
* @param tokenId The tokenId of the NFT we are collecting fees from
*/
function _collectMax(uint256 tokenId) internal returns (uint256 amount0, uint256 amount1) {
* @param state new value for whether periphery UX functions are paused
*/
function _pausePeripheryFunctions(bool state) external override returns (bool) {
/**
* @dev Constructor to initialize state variables.
* @param _tokens The underlying ERC20 token addresses to link to `_pools`.
* @param _pools The Uniswap V3 Pools to be assigned to `_tokens`.
* @param _twapPeriod The period used to calculate our TWAP from the Uni V3 pool
* @param _admin The admin who can assign pools to tokens.
* @param _canAdminOverwrite Controls if `admin` can overwrite existing assignments of pools to tokens.
*/
constructor(
address[] memory _tokens,
address[] memory _pools,
uint32 _twapPeriod,
address _wethAddress,
address _nfpManager,
address _factory,
address _admin,
bool _canAdminOverwrite
/**
* @notice Returns the price in ETH of the token underlying `cToken`.
* @return Price in ETH of the token underlying `cToken`, scaled by `10 ** (36 - underlyingDecimals)`.
*/
function getUnderlyingPrice(CTokenInterface cToken) external view override returns (uint256) {
/**
* @dev Constructor to initialize state variables.
* @param underlyings The underlying ERC20 token addresses to link to `_oracles`.
* @param _oracles The `PriceOracle` contracts to be assigned to `underlyings`.
* @param _admin The admin who can assign oracles to underlying tokens.
* @param _canAdminOverwrite Controls if `admin` can overwrite existing assignments of oracles to underlying tokens.
*/
constructor(
address[] memory underlyings,
PriceOracleInterface[] memory _oracles,
address _wethAddress,
address _admin,
bool _canAdminOverwrite
/**
* @notice Returns the price in ETH of the token underlying `cToken`.
* @dev Implements the `PriceOracle` interface for Fuse pools (and Compound v2).
* @return Price in ETH of the token underlying `cToken`, scaled by `10 ** (36 - underlyingDecimals)`.
*/
function getUnderlyingPrice(CTokenInterface cToken) external view override returns (uint256) {
/**
* @notice Initialize the money market
* @param comptroller_ The address of the Comptroller
* @param interestRateModel_ The address of the interest rate model
* @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18
* @param name_ EIP-20 name of this token
* @param symbol_ EIP-20 symbol of this token
* @param decimals_ EIP-20 decimal precision of this token
*/
function initialize(
ComptrollerInterface comptroller_,
InterestRateModel interestRateModel_,
uint256 initialExchangeRateMantissa_,
string memory name_,
string memory symbol_,
uint8 decimals_,
uint256 reserveFactorMantissa_
/**
* @notice Sender redeems cTokens on behalf of redeemer in exchange for a specified amount of underlying asset
* @dev Accrues interest whether or not the operation succeeds, unless reverted
* @param redeemAmount The amount of underlying to receive from redeeming cTokens
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeemUnderlyingBehalfInternal(address redeemer, uint256 redeemAmount)
internal
nonReentrant(false)
returns (uint256)
/**
* @notice Sets a new comptroller for the market
* @dev Internal function to set a new comptroller
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setComptroller(ComptrollerInterface newComptroller) internal returns (uint256) {
/**
* @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh
* @dev Admin function to accrue interest and set a new reserve factor
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setReserveFactor(uint256 newReserveFactorMantissa) external nonReentrant(false) returns (uint256) {
/**
* @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual)
* @dev Admin function to set a new reserve factor
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setReserveFactorFresh(uint256 newReserveFactorMantissa) internal returns (uint256) {
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
* @param data The call data (encoded using abi.encode or one of its variants).
* @param errorMessage The revert string to return on failure.
*/
function _functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
/**
* @notice Sets a new price oracle for the comptroller
* @dev Admin function to set a new price oracle
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setPriceOracle(PriceOracle newOracle) public returns (uint256) {
/**
* @notice Sets a new UniV3LpVault for the comptroller
* @dev Admin function to set a new UniV3LpVault
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setUniV3LpVault(IUniV3LpVault newVault) public returns (uint256) {
/**
* @notice Initialize the new money market
* @param underlying_ The address of the underlying asset
* @param comptroller_ The address of the Comptroller
* @param interestRateModel_ The address of the interest rate model
* @param name_ ERC-20 name of this token
* @param symbol_ ERC-20 symbol of this token
*/
function initialize(
address underlying_,
ComptrollerInterface comptroller_,
InterestRateModel interestRateModel_,
string memory name_,
string memory symbol_,
uint256 reserveFactorMantissa_
Missing: @param reserveFactorMantissa_
Event is missing indexed fields
Each event should use three indexed fields if there are three or more fields
Use a solidity version of at least 0.8.0 to get overflow protection without needing SafeMath
Use a solidity version of at least 0.8.4 to get bytes.concat() instead of abi.encodePacked(<bytes>,<bytes>)
Use a solidity version of at least 0.8.12 to get string.concat() instead of abi.encodePacked(<str>,<str>)
require(pools.length > 0, "must have at least one pool");
Non-exploitable re-entrancies
Reentrancy in UniV3LpVault._beforeNonReentrant(bool) (contracts/vault_and_oracles/UniV3LpVault.sol#934-938):
External calls:
- comptroller._beforeNonReentrant() (contracts/vault_and_oracles/UniV3LpVault.sol#936)
State variables written after the call(s):
- _notEntered = false (contracts/vault_and_oracles/UniV3LpVault.sol#937)
Reentrancy in CToken.borrowFresh(address,address,uint256) (contracts/compound_rari_fork/CToken.sol#835-916):
External calls:
- allowed = comptroller.borrowAllowed(address(this),borrower,borrowAmount) (contracts/compound_rari_fork/CToken.sol#841)
State variables written after the call(s):
- accountBorrows[borrower].principal = vars.accountBorrowsNew (contracts/compound_rari_fork/CToken.sol#908)
- accountBorrows[borrower].interestIndex = borrowIndex (contracts/compound_rari_fork/CToken.sol#909)
- totalBorrows = vars.totalBorrowsNew (contracts/compound_rari_fork/CToken.sol#910)
Reentrancy in CErc20.initialize(address,ComptrollerInterface,InterestRateModel,string,string,uint256) (contracts/compound_rari_fork/CErc20.sol#20-44):
External calls:
- super.initialize(comptroller_,interestRateModel_,initialExchangeRateMantissa_,name_,symbol_,decimals_,reserveFactorMantissa_) (contracts/compound_rari_fork/CErc20.sol#31-39)
- address(oldInterestRateModel).call(abi.encodeWithSignature(resetInterestCheckpoints())) (contracts/compound_rari_fork/CToken.sol#1624)
- address(newInterestRateModel).call(abi.encodeWithSignature(checkpointInterest())) (contracts/compound_rari_fork/CToken.sol#1627)
State variables written after the call(s):
- underlying = underlying_ (contracts/compound_rari_fork/CErc20.sol#42)
Reentrancy in UniV3LpVault._mint(INonfungiblePositionManager.MintParams) (contracts/vault_and_oracles/UniV3LpVault.sol#696-728):
External calls:
- IERC20Detailed(params.token0).approve(address(nonfungiblePositionManager),params.amount0Desired) (contracts/vault_and_oracles/UniV3LpVault.sol#704)
- IERC20Detailed(params.token1).approve(address(nonfungiblePositionManager),params.amount1Desired) (contracts/vault_and_oracles/UniV3LpVault.sol#705)
- (tokenId,None,amount0,amount1) = nonfungiblePositionManager.mint(INonfungiblePositionManager.MintParams(params.token0,params.token1,params.fee,params.tickLower,params.tickUpper,params.amount0Desired,params.amount1Desired,params.amount0Min,params.amount1Min,address(this),params.deadline)) (contracts/vault_and_oracles/UniV3LpVault.sol#707-721)
- IERC20Detailed(params.token0).approve(address(nonfungiblePositionManager),0) (contracts/vault_and_oracles/UniV3LpVault.sol#723)
- IERC20Detailed(params.token1).approve(address(nonfungiblePositionManager),0) (contracts/vault_and_oracles/UniV3LpVault.sol#724)
State variables written after the call(s):
- _processNewToken(tokenId,params.recipient) (contracts/vault_and_oracles/UniV3LpVault.sol#727)
- ownerOf[tokenId] = account (contracts/vault_and_oracles/UniV3LpVault.sol#757)
- _processNewToken(tokenId,params.recipient) (contracts/vault_and_oracles/UniV3LpVault.sol#727)
- userTokens[account].push(tokenId) (contracts/vault_and_oracles/UniV3LpVault.sol#756)
Low Risk Issues
approve()
return value not checkedCheck the result, or use
safeApprove()
require()
should be used instead ofassert()
Missing checks for
address(0x0)
when assigning values toaddress
state variablesOpen TODOs
Code architecture, incentives, and error handling/reporting questions/issues should be resolved before deployment
Non-critical Issues
public
functions not called by the contract should be declaredexternal
insteadContracts are allowed to override their parents' functions and change the visibility from
external
topublic
.constant
s should be defined rather than using magic numbersMultiple
address
mappings can be combined into a singlemapping
of anaddress
to astruct
, where appropriateFile: contracts/vault_and_oracles/UniswapTwapOracle.sol (lines 57-60)
Non-library/interface files should use fixed compiler versions, not floating ones
File does not contain an SPDX Identifier
File is missing NatSpec
NatSpec is incomplete
File: contracts/libs/LpBreakdownLibrary.sol (lines 31-59)
Missing:
@param nfpManager
@param factory
@param tickOracle
File: contracts/libs/LpBreakdownLibrary.sol (lines 84-93)
Missing:
@param nfpmManager
@param factory
File: contracts/libs/LpBreakdownLibrary.sol (lines 121-130)
Missing:
@param tick
File: contracts/libs/UniswapTwapLibrary.sol (lines 26-41)
Missing:
@param _checkPeriod
File: contracts/libs/LiquidityLibrary.sol (lines 17-32)
Missing:
@param _liquidity
File: contracts/vault_and_oracles/UniV3LpVault.sol (lines 619-621)
Missing:
@return
File: contracts/vault_and_oracles/UniV3LpVault.sol (lines 682-684)
Missing:
@return
File: contracts/vault_and_oracles/UniV3LpVault.sol (lines 694-701)
Missing:
@return
File: contracts/vault_and_oracles/UniV3LpVault.sol (lines 831-833)
Missing:
@return
File: contracts/vault_and_oracles/UniV3LpVault.sol (lines 847-849)
Missing:
@return
File: contracts/vault_and_oracles/UniV3LpVault.sol (lines 863-865)
Missing:
@return
File: contracts/vault_and_oracles/UniV3LpVault.sol (lines 875-877)
Missing:
@return
File: contracts/vault_and_oracles/UniswapTwapOracle.sol (lines 62-78)
Missing:
@param _wethAddress
@param _nfpManager
@param _factory
File: contracts/vault_and_oracles/UniswapTwapOracle.sol (lines 109-113)
Missing:
@param cToken
File: contracts/vault_and_oracles/MasterPriceOracle.sol (lines 30-42)
Missing:
@param _wethAddress
File: contracts/vault_and_oracles/MasterPriceOracle.sol (lines 100-105)
Missing:
@param cToken
File: contracts/compound_rari_fork/CToken.sol (lines 17-33)
Missing:
@param reserveFactorMantissa_
File: contracts/compound_rari_fork/CToken.sol (lines 627-636)
Missing:
@param redeemer
File: contracts/compound_rari_fork/CToken.sol (lines 1396-1401)
Missing:
@param newComptroller
File: contracts/compound_rari_fork/CToken.sol (lines 1415-1420)
Missing:
@param newReserveFactorMantissa
File: contracts/compound_rari_fork/CToken.sol (lines 1430-1435)
Missing:
@param newReserveFactorMantissa
File: contracts/compound_rari_fork/CToken.sol (lines 1702-1717)
Missing:
@param target
@return
File: contracts/compound_rari_fork/Comptroller.sol (lines 471-479)
Missing:
@return
File: contracts/compound_rari_fork/Comptroller.sol (lines 521-529)
Missing:
@return
File: contracts/compound_rari_fork/Comptroller.sol (lines 573-581)
Missing:
@return
File: contracts/compound_rari_fork/Comptroller.sol (lines 690-702)
Missing:
@param account
File: contracts/compound_rari_fork/Comptroller.sol (lines 715-727)
Missing:
@param account
File: contracts/compound_rari_fork/Comptroller.sol (lines 1059-1064)
Missing:
@param newOracle
File: contracts/compound_rari_fork/Comptroller.sol (lines 1100-1105)
Missing:
@param newVault
File: contracts/compound_rari_fork/Comptroller.sol (lines 1518-1520)
Missing:
@return
File: contracts/compound_rari_fork/CErc20.sol (lines 12-26)
Missing:
@param reserveFactorMantissa_
Event is missing
indexed
fieldsEach
event
should use threeindexed
fields if there are three or more fieldsNot using the named return variables when a function returns, is confusing
Use a more recent version of solidity
Use a solidity version of at least 0.8.0 to get overflow protection without needing
SafeMath
Use a solidity version of at least 0.8.4 to getbytes.concat()
instead ofabi.encodePacked(<bytes>,<bytes>)
Use a solidity version of at least 0.8.12 to getstring.concat()
instead ofabi.encodePacked(<str>,<str>)
Don't compare boolean expressions to boolean literals
if (<x> == true)
=>if (<x>)
,if (<x> == false)
=>if (!<x>)
Remove unused variables
Duplicated
require()
/revert()
checks should be refactored to a modifier or functionCopy-pasted code is error-prone when conditions need to be updated
Non-exploitable re-entrancies