Skip to content

Commit

Permalink
Merge pull request #152 from Gearbox-protocol/audits-fixes
Browse files Browse the repository at this point in the history
fix: fixes after ChainSec and ABDK audits
  • Loading branch information
0xmikko authored Nov 4, 2023
2 parents e9622d1 + 6ec8078 commit 605e89d
Show file tree
Hide file tree
Showing 60 changed files with 2,321 additions and 6,216 deletions.
4 changes: 2 additions & 2 deletions contracts/core/AccountFactoryV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ contract AccountFactoryV3 is IAccountFactoryV3, ACLTrait, ContractsRegisterTrait
/// @dev Mapping credit manager => factory params
mapping(address => FactoryParams) internal _factoryParams;

/// @dev Mapping credit manager => queued accounts
mapping(address => QueuedAccount[2 ** 32]) internal _queuedAccounts;
/// @dev Mapping (credit manager, index) => queued account
mapping(address => mapping(uint256 => QueuedAccount)) internal _queuedAccounts;

/// @notice Constructor
/// @param addressProvider Address provider contract address
Expand Down
437 changes: 124 additions & 313 deletions contracts/core/BotListV3.sol

Large diffs are not rendered by default.

115 changes: 81 additions & 34 deletions contracts/core/PriceOracleV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pragma solidity ^0.8.17;

import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";

import {
AddressIsNotContractException,
Expand All @@ -22,10 +23,13 @@ import {PriceFeedValidationTrait} from "../traits/PriceFeedValidationTrait.sol";
/// e.g., implement `latestRoundData` and always return answers with 8 decimals.
/// They may also implement their own price checks, in which case they may incidcate it
/// to the price oracle by returning `skipPriceCheck = true`.
/// Price oracle also allows to set a reserve price feed for a token, that can be activated
/// @notice Price oracle also allows to set a reserve price feed for a token, that can be activated
/// in case the main one becomes stale or starts returning wrong values.
/// One should not expect the reserve price feed to always differ from the main one, although
/// most often that would be the case.
/// @notice Price oracle additionaly provides "safe" conversion functions, which use minimum of main
/// and reserve feed prices (the latter is assumed to be zero if reserve feed is not set).
/// There are also trusted price feeds, for which safe prices are simply main feed prices.
contract PriceOracleV3 is ACLNonReentrantTrait, PriceFeedValidationTrait, IPriceOracleV3 {
/// @notice Contract version
uint256 public constant override version = 3_00;
Expand All @@ -37,67 +41,98 @@ contract PriceOracleV3 is ACLNonReentrantTrait, PriceFeedValidationTrait, IPrice
/// @param addressProvider Address provider contract address
constructor(address addressProvider) ACLNonReentrantTrait(addressProvider) {}

/// @notice Returns `token`'s price in USD (with 8 decimals)
/// @notice Returns `token`'s price in USD (with 8 decimals) from the currently active price feed
function getPrice(address token) external view override returns (uint256 price) {
(address priceFeed, uint32 stalenessPeriod, bool skipCheck, uint8 decimals) = priceFeedParams(token);
(price,) = _getPrice(priceFeed, stalenessPeriod, skipCheck, decimals);
(price,) = _getPrice(token);
}

/// @notice Returns `token`'s price in USD (with 8 decimals) with explicitly specified price feed
/// @notice Returns `token`'s safe price in USD (with 8 decimals)
function getPriceSafe(address token) external view override returns (uint256 price) {
(price,) = _getPriceSafe(token);
}

/// @notice Returns `token`'s price in USD (with 8 decimals) from the specified price feed
function getPriceRaw(address token, bool reserve) external view returns (uint256 price) {
(address priceFeed, uint32 stalenessPeriod, bool skipCheck, uint8 decimals,) =
_getPriceFeedParams(reserve ? _getTokenReserveKey(token) : token);
if (priceFeed == address(0)) revert PriceFeedDoesNotExistException();
(price,) = _getPrice(priceFeed, stalenessPeriod, skipCheck, decimals);
(price,) = _getPriceRaw(token, reserve);
}

/// @notice Converts `amount` of `token` into USD amount (with 8 decimals)
function convertToUSD(uint256 amount, address token) public view override returns (uint256) {
(address priceFeed, uint32 stalenessPeriod, bool skipCheck, uint8 decimals) = priceFeedParams(token);
(uint256 price, uint256 scale) = _getPrice(priceFeed, stalenessPeriod, skipCheck, decimals);
function convertToUSD(uint256 amount, address token) external view override returns (uint256) {
(uint256 price, uint256 scale) = _getPrice(token);
return amount * price / scale; // U:[PO-9]
}

/// @notice Converts `amount` of USD (with 8 decimals) into `token` amount
function convertFromUSD(uint256 amount, address token) public view override returns (uint256) {
(address priceFeed, uint32 stalenessPeriod, bool skipCheck, uint8 decimals) = priceFeedParams(token);
(uint256 price, uint256 scale) = _getPrice(priceFeed, stalenessPeriod, skipCheck, decimals);
function convertFromUSD(uint256 amount, address token) external view override returns (uint256) {
(uint256 price, uint256 scale) = _getPrice(token);
return amount * scale / price; // U:[PO-9]
}

/// @notice Converts `amount` of `tokenFrom` into `tokenTo` amount
function convert(uint256 amount, address tokenFrom, address tokenTo) external view override returns (uint256) {
(address priceFeed, uint32 stalenessPeriod, bool skipCheck, uint8 decimals) = priceFeedParams(tokenFrom);
(uint256 priceFrom, uint256 scaleFrom) = _getPrice(priceFeed, stalenessPeriod, skipCheck, decimals);

(priceFeed, stalenessPeriod, skipCheck, decimals) = priceFeedParams(tokenTo);
(uint256 priceTo, uint256 scaleTo) = _getPrice(priceFeed, stalenessPeriod, skipCheck, decimals);

(uint256 priceFrom, uint256 scaleFrom) = _getPrice(tokenFrom);
(uint256 priceTo, uint256 scaleTo) = _getPrice(tokenTo);
return amount * priceFrom * scaleTo / (priceTo * scaleFrom); // U:[PO-10]
}

/// @notice Converts `amount` of `token` into USD amount (with 8 decimals) using safe price
function safeConvertToUSD(uint256 amount, address token) external view override returns (uint256) {
(uint256 price, uint256 scale) = _getPriceSafe(token);
return amount * price / scale; // U:[PO-11]
}

/// @notice Returns the price feed for `token` or reverts if price feed is not set
function priceFeeds(address token) external view override returns (address priceFeed) {
(priceFeed,,,) = priceFeedParams(token); // U:[PO-8]
(priceFeed,,,,) = priceFeedParams(token); // U:[PO-8]
}

/// @notice Returns the price feed for `token` with explicitly specified price feed
/// @notice Returns the specified price feed for `token`
function priceFeedsRaw(address token, bool reserve) external view override returns (address priceFeed) {
(priceFeed,,,,) = _getPriceFeedParams(reserve ? _getTokenReserveKey(token) : token);
(priceFeed,,,,,) = _getPriceFeedParams(reserve ? _getTokenReserveKey(token) : token);
}

/// @notice Returns price feed parameters for `token` or reverts if price feed is not set
/// @notice Returns currently active price feed parameters for `token` or reverts if price feed is not set
function priceFeedParams(address token)
public
view
override
returns (address priceFeed, uint32 stalenessPeriod, bool skipCheck, uint8 decimals)
returns (address priceFeed, uint32 stalenessPeriod, bool skipCheck, uint8 decimals, bool trusted)
{
bool useReserve;
(priceFeed, stalenessPeriod, skipCheck, decimals, useReserve) = _getPriceFeedParams(token);
if (decimals == 0) revert PriceFeedDoesNotExistException();
(priceFeed, stalenessPeriod, skipCheck, decimals, useReserve, trusted) = _getPriceFeedParams(token);
if (useReserve) {
(priceFeed, stalenessPeriod, skipCheck, decimals,) = _getPriceFeedParams(_getTokenReserveKey(token));
(priceFeed, stalenessPeriod, skipCheck, decimals,, trusted) =
_getPriceFeedParams(_getTokenReserveKey(token));
}
}

// --------- //
// INTERNALS //
// --------- //

/// @dev Returns `token`'s price and scale from the currently active price feed
function _getPrice(address token) internal view returns (uint256 price, uint256 scale) {
(address priceFeed, uint32 stalenessPeriod, bool skipCheck, uint8 decimals,) = priceFeedParams(token);
return _getPrice(priceFeed, stalenessPeriod, skipCheck, decimals);
}

/// @dev Returns `token`'s price and scale from the explicitly specified price feed
function _getPriceRaw(address token, bool reserve) internal view returns (uint256 price, uint256 scale) {
(address priceFeed, uint32 stalenessPeriod, bool skipCheck, uint8 decimals,,) =
_getPriceFeedParams(reserve ? _getTokenReserveKey(token) : token);
return _getPrice(priceFeed, stalenessPeriod, skipCheck, decimals);
}

/// @dev Returns `token`'s safe price and scale
function _getPriceSafe(address token) internal view returns (uint256 price, uint256 scale) {
(address priceFeed, uint32 stalenessPeriod, bool skipCheck, uint8 decimals,, bool trusted) =
_getPriceFeedParams(token);
(price, scale) = _getPrice(priceFeed, stalenessPeriod, skipCheck, decimals); // U:[PO-11]

if (!trusted) {
if (_priceFeedsParams[_getTokenReserveKey(token)].priceFeed == address(0)) return (0, scale); // U:[PO-11]
(uint256 reservePrice,) = _getPriceRaw(token, true);
price = Math.min(price, reservePrice); // U:[PO-11]
}
}

Expand All @@ -122,7 +157,14 @@ contract PriceOracleV3 is ACLNonReentrantTrait, PriceFeedValidationTrait, IPrice
function _getPriceFeedParams(address token)
internal
view
returns (address priceFeed, uint32 stalenessPeriod, bool skipCheck, uint8 decimals, bool useReserve)
returns (
address priceFeed,
uint32 stalenessPeriod,
bool skipCheck,
uint8 decimals,
bool useReserve,
bool trusted
)
{
PriceFeedParams storage params = _priceFeedsParams[token];
assembly {
Expand All @@ -132,7 +174,10 @@ contract PriceOracleV3 is ACLNonReentrantTrait, PriceFeedValidationTrait, IPrice
skipCheck := and(shr(192, data), 0x01)
decimals := shr(200, data)
useReserve := and(shr(208, data), 0x01)
trusted := and(shr(216, data), 0x01)
} // U:[PO-2]

if (priceFeed == address(0)) revert PriceFeedDoesNotExistException(); // U:[PO-2]
}

/// @dev Returns key that is used to store `token`'s reserve feed in `_priceFeedParams`
Expand All @@ -149,7 +194,7 @@ contract PriceOracleV3 is ACLNonReentrantTrait, PriceFeedValidationTrait, IPrice
// ------------- //

/// @notice Sets price feed for a given token
function setPriceFeed(address token, address priceFeed, uint32 stalenessPeriod)
function setPriceFeed(address token, address priceFeed, uint32 stalenessPeriod, bool trusted)
external
override
nonZeroAddress(token) // U:[PO-6]
Expand All @@ -165,9 +210,10 @@ contract PriceOracleV3 is ACLNonReentrantTrait, PriceFeedValidationTrait, IPrice
stalenessPeriod: stalenessPeriod,
skipCheck: skipCheck,
decimals: decimals,
useReserve: false
useReserve: false,
trusted: trusted
}); // U:[PO-6]
emit SetPriceFeed(token, priceFeed, stalenessPeriod, skipCheck); // U:[PO-6]
emit SetPriceFeed(token, priceFeed, stalenessPeriod, skipCheck, trusted); // U:[PO-6]
}

/// @notice Sets reserve price feed for a given token
Expand All @@ -188,7 +234,8 @@ contract PriceOracleV3 is ACLNonReentrantTrait, PriceFeedValidationTrait, IPrice
stalenessPeriod: stalenessPeriod,
skipCheck: skipCheck,
decimals: decimals,
useReserve: false
useReserve: false,
trusted: false
}); // U:[PO-7]
emit SetReservePriceFeed(token, priceFeed, stalenessPeriod, skipCheck); // U:[PO-7]
}
Expand Down
Loading

0 comments on commit 605e89d

Please sign in to comment.