Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 0.7 mainnet fuzzing #783

Merged
merged 8 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {CollateralTokenTester} from "./CollateralTokenTester.sol";
import {Governor} from "../Governor.sol";
import {EBTCDeployer} from "../EBTCDeployer.sol";
import {Actor} from "./invariants/Actor.sol";
import {CRLens} from "../CRLens.sol";
import {CRLens} from "./CRLens.sol";
import {Simulator} from "./invariants/Simulator.sol";

abstract contract BaseStorageVariables {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,22 @@

pragma solidity 0.8.17;

import "./Interfaces/IPriceFeed.sol";
import "./Interfaces/ICdpManager.sol";
import "@crytic/properties/contracts/util/Hevm.sol";

import "../Interfaces/IPriceFeed.sol";
import "../Interfaces/IBorrowerOperations.sol";
import "../Interfaces/ICdpManager.sol";

/// @notice The contract allows to check real CR of Cdps
/// Acknowledgement: https://github.com/Uniswap/v3-periphery/blob/main/contracts/lens/Quoter.sol
contract CRLens {
ICdpManager public immutable cdpManager;
IBorrowerOperations public immutable borrowerOperations;
IPriceFeed public immutable priceFeed;

constructor(address _cdpManager, address _priceFeed) {
constructor(address _cdpManager, address _borrowerOperations, address _priceFeed) {
cdpManager = ICdpManager(_cdpManager);
borrowerOperations = IBorrowerOperations(_borrowerOperations);
priceFeed = IPriceFeed(_priceFeed);
}

Expand Down Expand Up @@ -42,6 +47,7 @@ contract CRLens {
/// @notice Return the ICR of a CDP after the fee split
/// @dev Call this from offChain with `eth_call` to avoid paying for gas
function getRealICR(bytes32 cdpId, bool revertValue) external returns (uint256) {
hevm.prank(address(borrowerOperations));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The addition of hevm.prank(address(borrowerOperations)); in the getRealICR and getRealNICR functions is an interesting change. It's important to note that hevm.prank is typically used in testing environments to simulate transactions from specific addresses. Including it in production code could be a mistake unless this contract is specifically designed for testing purposes. If this is intended for a production environment, further clarification on the use of hevm.prank in these functions is needed to ensure security and correctness.

Consider removing or guarding hevm.prank calls if this contract is intended for production use. If it's for testing purposes, ensure that it's clearly documented and not deployable to production environments.

Also applies to: 69-69

cdpManager.syncAccounting(cdpId);
uint price = priceFeed.fetchPrice();
uint256 icr = cdpManager.getCachedICR(cdpId, price);
Expand All @@ -60,6 +66,7 @@ contract CRLens {
/// @notice Return the ICR of a CDP after the fee split
/// @dev Call this from offChain with `eth_call` to avoid paying for gas
function getRealNICR(bytes32 cdpId, bool revertValue) external returns (uint256) {
hevm.prank(address(borrowerOperations));
cdpManager.syncAccounting(cdpId);
uint price = priceFeed.fetchPrice();
uint256 icr = cdpManager.getCachedNominalICR(cdpId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ abstract contract BeforeAfter is BaseStorageVariables {
vars.sortedCdpsSizeBefore = sortedCdps.getSize();
vars.tcrBefore = cdpManager.getCachedTCR(vars.priceBefore);
vars.ebtcTotalSupplyBefore = eBTCToken.totalSupply();
vars.ethPerShareBefore = collateral.getEthPerShare();
vars.ethPerShareBefore = collateral.getPooledEthByShares(1e18);
vars.activePoolDebtBefore = activePool.getSystemDebt();
vars.activePoolCollBefore = activePool.getSystemCollShares();
vars.collSurplusPoolBefore = collSurplusPool.getTotalSurplusCollShares();
Expand All @@ -126,7 +126,7 @@ abstract contract BeforeAfter is BaseStorageVariables {
cdpManager.recoveryModeGracePeriodDuration();
vars.systemDebtRedistributionIndexBefore = cdpManager.systemDebtRedistributionIndex();
vars.newTcrBefore = crLens.quoteRealTCR();
vars.newIcrBefore = crLens.quoteRealICR(_cdpId);
vars.newIcrBefore = _cdpId != bytes32(0) ? crLens.quoteRealICR(_cdpId) : 0;

vars.valueInSystemBefore ==
(collateral.getPooledEthByShares(
Expand Down Expand Up @@ -169,7 +169,7 @@ abstract contract BeforeAfter is BaseStorageVariables {
vars.sortedCdpsSizeAfter = sortedCdps.getSize();
vars.tcrAfter = cdpManager.getCachedTCR(vars.priceAfter);
vars.ebtcTotalSupplyAfter = eBTCToken.totalSupply();
vars.ethPerShareAfter = collateral.getEthPerShare();
vars.ethPerShareAfter = collateral.getPooledEthByShares(1e18);
vars.activePoolDebtAfter = activePool.getSystemDebt();
vars.activePoolCollAfter = activePool.getSystemCollShares();
vars.collSurplusPoolAfter = collSurplusPool.getTotalSurplusCollShares();
Expand All @@ -184,7 +184,7 @@ abstract contract BeforeAfter is BaseStorageVariables {
vars.systemDebtRedistributionIndexAfter = cdpManager.systemDebtRedistributionIndex();

vars.newTcrAfter = crLens.quoteRealTCR();
vars.newIcrAfter = crLens.quoteRealICR(_cdpId);
vars.newIcrAfter = _cdpId != bytes32(0) ? crLens.quoteRealICR(_cdpId) : 0;

// Value in system after
vars.valueInSystemAfter =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {PriceFeedTestnet} from "../testnet/PriceFeedTestnet.sol";
import {ICdpManagerData} from "../../Interfaces/ICdpManagerData.sol";
import {BeforeAfter} from "./BeforeAfter.sol";
import {PropertiesDescriptions} from "./PropertiesDescriptions.sol";
import {CRLens} from "../../CRLens.sol";
import {CRLens} from "../CRLens.sol";
import {LiquidationSequencer} from "../../LiquidationSequencer.sol";
import {SyncedLiquidationSequencer} from "../../SyncedLiquidationSequencer.sol";

Expand Down Expand Up @@ -162,9 +162,9 @@ abstract contract Properties is BeforeAfter, PropertiesDescriptions, Asserts, Pr
CdpManager cdpManager,
SortedCdps sortedCdps,
PriceFeedTestnet priceFeedMock
) internal view returns (bool) {
) internal returns (bool) {
bytes32 _first = sortedCdps.getFirst();
uint256 _price = priceFeedMock.getPrice();
uint256 _price = priceFeedMock.fetchPrice();
uint256 _firstICR = cdpManager.getCachedICR(_first, _price);
uint256 _TCR = cdpManager.getCachedTCR(_price);

Expand All @@ -182,10 +182,10 @@ abstract contract Properties is BeforeAfter, PropertiesDescriptions, Asserts, Pr
CdpManager cdpManager,
PriceFeedTestnet priceFeedMock,
SortedCdps sortedCdps
) internal view returns (bool) {
) internal returns (bool) {
bytes32 currentCdp = sortedCdps.getFirst();

uint256 _price = priceFeedMock.getPrice();
uint256 _price = priceFeedMock.fetchPrice();
if (_price == 0) return true;

while (currentCdp != bytes32(0)) {
Expand Down Expand Up @@ -239,17 +239,17 @@ abstract contract Properties is BeforeAfter, PropertiesDescriptions, Asserts, Pr
PriceFeedTestnet priceFeedMock,
EBTCToken eBTCToken,
ICollateralToken collateral
) internal view returns (bool) {
) internal returns (bool) {
// TODO how to calculate "the dollar value of eBTC"?
// TODO how do we take into account underlying/shares into this calculation?
return
cdpManager.getCachedTCR(priceFeedMock.getPrice()) > 1e18
cdpManager.getCachedTCR(priceFeedMock.fetchPrice()) > 1e18
? (collateral.getPooledEthByShares(cdpManager.getSystemCollShares()) *
priceFeedMock.getPrice()) /
priceFeedMock.fetchPrice()) /
1e18 >=
eBTCToken.totalSupply()
: (collateral.getPooledEthByShares(cdpManager.getSystemCollShares()) *
priceFeedMock.getPrice()) /
priceFeedMock.fetchPrice()) /
1e18 <
eBTCToken.totalSupply();
}
Expand Down Expand Up @@ -385,8 +385,8 @@ abstract contract Properties is BeforeAfter, PropertiesDescriptions, Asserts, Pr
SortedCdps sortedCdps,
PriceFeedTestnet priceFeedTestnet,
ICollateralToken collateral
) internal view returns (bool) {
uint256 curentPrice = priceFeedTestnet.getPrice();
) internal returns (bool) {
uint256 curentPrice = priceFeedTestnet.fetchPrice();

bytes32 currentCdp = sortedCdps.getFirst();

Expand Down Expand Up @@ -438,7 +438,7 @@ abstract contract Properties is BeforeAfter, PropertiesDescriptions, Asserts, Pr
PriceFeedTestnet priceFeedMock,
CRLens crLens
) internal returns (bool) {
uint256 curentPrice = priceFeedMock.getPrice();
uint256 curentPrice = priceFeedMock.fetchPrice();
return crLens.quoteRealTCR() == cdpManager.getSyncedTCR(curentPrice);
}

Expand All @@ -450,7 +450,7 @@ abstract contract Properties is BeforeAfter, PropertiesDescriptions, Asserts, Pr
) internal returns (bool) {
bytes32 currentCdp = sortedCdps.getFirst();

uint256 _price = priceFeedMock.getPrice();
uint256 _price = priceFeedMock.fetchPrice();

// Compare synched with quote for all Cdps
while (currentCdp != bytes32(0)) {
Expand Down Expand Up @@ -504,7 +504,7 @@ abstract contract Properties is BeforeAfter, PropertiesDescriptions, Asserts, Pr
uint256 n = cdpManager.getActiveCdpsCount();

// Get
uint256 price = priceFeedTestnet.getPrice();
uint256 price = priceFeedTestnet.fetchPrice();

// Get lists
bytes32[] memory cdpsFromCurrent = ls.sequenceLiqToBatchLiqWithPrice(n, price);
Expand All @@ -527,8 +527,8 @@ abstract contract Properties is BeforeAfter, PropertiesDescriptions, Asserts, Pr
return true;
}

function invariant_DUMMY_01(PriceFeedTestnet priceFeedTestnet) internal view returns (bool) {
return priceFeedTestnet.getPrice() > 0;
function invariant_DUMMY_01(PriceFeedTestnet priceFeedTestnet) internal returns (bool) {
return priceFeedTestnet.fetchPrice() > 0;
}

function invariant_BO_09(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ pragma solidity 0.8.17;
import "@crytic/properties/contracts/util/PropertiesConstants.sol";
import "@crytic/properties/contracts/util/Hevm.sol";

import "../../Interfaces/ICdpManagerData.sol";
import "../../Dependencies/SafeMath.sol";
import "../../CdpManager.sol";
import "../AccruableCdpManager.sol";
Expand Down Expand Up @@ -316,7 +315,11 @@ abstract contract TargetContractSetup is BaseStorageVariables, PropertiesConstan
authority.setUserRole(defaultGovernance, 4, true);
authority.setUserRole(defaultGovernance, 5, true);

crLens = new CRLens(address(cdpManager), address(priceFeedMock));
crLens = new CRLens(
address(cdpManager),
address(borrowerOperations),
address(priceFeedMock)
);

liquidationSequencer = new LiquidationSequencer(
address(cdpManager),
Expand All @@ -338,23 +341,27 @@ abstract contract TargetContractSetup is BaseStorageVariables, PropertiesConstan
event Log(string);

function _setUpFork() internal {
defaultGovernance = address(0xA967Ba66Fb284EC18bbe59f65bcf42dD11BA8128);
ebtcDeployer = EBTCDeployer(0xe90f99c08F286c48db4D1AfdAE6C122de69B7219);
collateral = CollateralTokenTester(payable(0xf8017430A0efE03577f6aF88069a21900448A373));
defaultGovernance = address(0x0);
ebtcDeployer = EBTCDeployer(0xA93A9CBBD47AA7B57853D460f442E2de2FB1dA4D);
collateral = CollateralTokenTester(payable(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84)); // stETH
{
authority = Governor(0x4945Fc25282b1bC103d2C62C251Cd022138c1de9);
liqudationLibrary = LiquidationLibrary(0xE8943a17363DE9A6e0d4A5d48d5Ab45283199F77);
cdpManager = CdpManager(0x0c5C2B93b96C9B3aD7fb9915952BD7BA256C4f04);
borrowerOperations = BorrowerOperations(0xA178BFBc42E3D886d540CDDcf4562c53a8Fc02c1);
priceFeedMock = PriceFeedTestnet(0x5C819E5D61EFCfBd7e4635f1112f3bF94663999b);
sortedCdps = SortedCdps(0xDeFF25eC3cd3041BC8B9A464F9BEc12EB8247Be6);
activePool = ActivePool(0x55abdfb760dd032627D531f7cF3DAa72549CEbA2);
collSurplusPool = CollSurplusPool(0x7b4D951D7b8090f62bD009b371abd7Fe04aB7e1A);
hintHelpers = HintHelpers(0xCaBdBc4218dd4b9E3fB9842232aD0aFc7c431693);
eBTCToken = EBTCTokenTester(0x9Aa69Db8c53E504EF22615390EE9Eb72cb8bE498);
feeRecipient = FeeRecipient(0x40FF68eaE525233950B63C2BCEa39770efDE52A4);

crLens = new CRLens(address(cdpManager), address(priceFeedMock));
authority = Governor(0x93d4f82903B87E94796Ec3665efa5f67F2072c6e);
liqudationLibrary = LiquidationLibrary(0x55262e1128FafD9Bb0B0fD59A8998c13299c4AD4);
cdpManager = CdpManager(0x3c672ee8e13Cde7617923658138B111e157C8997);
borrowerOperations = BorrowerOperations(0x99c4ea5d7aDF5d115c85AEEDD98Bd26DdBa714Cb);
priceFeedMock = PriceFeedTestnet(address(0x4039ca03Ce49021655c9B7C52Ab817d42DB7325e)); // PriceFeed
sortedCdps = SortedCdps(0x6cb99cF839c5AD3C24431c85da5Fdb7c7ab66d97);
activePool = ActivePool(0x1e3Bf0965dca89Cd057d63c0cD65A37Acf920590);
collSurplusPool = CollSurplusPool(0x596EfaF17dFb3fd2CAE7543Ffa399F6e31658E4D);
hintHelpers = HintHelpers(0xE5A25E39A95750326322175249699eC5Cd66919F);
eBTCToken = EBTCTokenTester(0xead18fD27CAa1CFf909B5f2BD26ac9a46a6Ab1b5);
feeRecipient = FeeRecipient(0x522ef088d94BD2125eC47F0967bf5B4E79Af4ed8);

crLens = new CRLens(
address(cdpManager),
address(borrowerOperations),
address(priceFeedMock)
);

liquidationSequencer = new LiquidationSequencer(
address(cdpManager),
Expand Down Expand Up @@ -383,11 +390,7 @@ abstract contract TargetContractSetup is BaseStorageVariables, PropertiesConstan
actors[addresses[i]] = new Actor(tokens, callers);
(success, ) = address(actors[addresses[i]]).call{value: INITIAL_ETH_BALANCE}("");
assert(success);
(success, ) = actors[addresses[i]].proxy(
address(collateral),
abi.encodeWithSelector(CollateralTokenTester.deposit.selector, ""),
INITIAL_COLL_BALANCE
);
(success, ) = actors[addresses[i]].proxy(address(collateral), "", INITIAL_COLL_BALANCE);
assert(success);
actorsArray[i] = actors[addresses[i]];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ abstract contract TargetFunctions is Properties {
uint256 ans;
bytes32 currentCdp = sortedCdps.getFirst();

uint256 _price = priceFeedMock.getPrice();
uint256 _price = priceFeedMock.fetchPrice();

while (currentCdp != bytes32(0)) {
if (cdpManager.getCachedICR(currentCdp, _price) < cdpManager.MCR()) {
Expand All @@ -54,12 +54,12 @@ abstract contract TargetFunctions is Properties {
return ans;
}

function _getCdpIdsAndICRs() internal view returns (Cdp[] memory ans) {
function _getCdpIdsAndICRs() internal returns (Cdp[] memory ans) {
ans = new Cdp[](sortedCdps.getSize());
uint256 i = 0;
bytes32 currentCdp = sortedCdps.getFirst();

uint256 _price = priceFeedMock.getPrice();
uint256 _price = priceFeedMock.fetchPrice();

while (currentCdp != bytes32(0)) {
uint256 _currentCdpDebt = cdpManager.getSyncedCdpDebt(currentCdp);
Expand Down Expand Up @@ -179,7 +179,7 @@ abstract contract TargetFunctions is Properties {
// Find the first cdp with ICR >= MCR
while (
currentBorrower != address(0) &&
cdpManager.getCachedICR(_cId, priceFeedMock.getPrice()) < cdpManager.MCR()
cdpManager.getCachedICR(_cId, priceFeedMock.fetchPrice()) < cdpManager.MCR()
) {
_cId = sortedCdps.getPrev(_cId);
currentBorrower = sortedCdps.getOwnerAddress(_cId);
Expand Down Expand Up @@ -225,7 +225,7 @@ abstract contract TargetFunctions is Properties {

_before(_cdpId);

uint256 _icrToLiq = cdpManager.getSyncedICR(_cdpId, priceFeedMock.getPrice());
uint256 _icrToLiq = cdpManager.getSyncedICR(_cdpId, priceFeedMock.fetchPrice());
(success, returnData) = actor.proxy(
address(cdpManager),
abi.encodeWithSelector(CdpManager.liquidate.selector, _cdpId)
Expand Down Expand Up @@ -531,7 +531,7 @@ abstract contract TargetFunctions is Properties {
_before(_cdpId);

{
uint price = priceFeedMock.getPrice();
uint price = priceFeedMock.fetchPrice();

(bytes32 firstRedemptionHintVal, uint256 partialRedemptionHintNICR, , ) = hintHelpers
.getRedemptionHints(_EBTCAmount, price, _maxIterations);
Expand Down Expand Up @@ -722,7 +722,7 @@ abstract contract TargetFunctions is Properties {
bytes memory returnData;

// we pass in CCR instead of MCR in case it's the first one
uint price = priceFeedMock.getPrice();
uint price = priceFeedMock.fetchPrice();

uint256 requiredCollAmount = (_EBTCAmount * cdpManager.CCR()) / (price);
uint256 minCollAmount = max(
Expand Down Expand Up @@ -797,7 +797,7 @@ abstract contract TargetFunctions is Properties {

gte(_EBTCAmount, borrowerOperations.MIN_CHANGE(), GENERAL_16);
gte(vars.cdpDebtAfter, borrowerOperations.MIN_CHANGE(), GENERAL_15);
require(invariant_BO_09(cdpManager, priceFeedMock.getPrice(), _cdpId), BO_09);
require(invariant_BO_09(cdpManager, priceFeedMock.fetchPrice(), _cdpId), BO_09);
} else {
assertRevertReasonNotEqual(returnData, "Panic(17)"); /// Done
}
Expand Down Expand Up @@ -1285,7 +1285,7 @@ abstract contract TargetFunctions is Properties {
// > There are 11 slashing ongoing with the RockLogic GmbH node operator in Lido.
// > the total projected impact is around 20 ETH,
// > or about 3% of average daily protocol rewards/0.0004% of TVL.
function setEthPerShare(uint256 _newEthPerShare) public {
function setEthPerShare(uint256 _newEthPerShare) public virtual {
uint256 currentEthPerShare = collateral.getEthPerShare();
_newEthPerShare = between(
_newEthPerShare,
Expand All @@ -1306,8 +1306,8 @@ abstract contract TargetFunctions is Properties {
// PriceFeed
///////////////////////////////////////////////////////

function setPrice(uint256 _newPrice) public {
uint256 currentPrice = priceFeedMock.getPrice();
function setPrice(uint256 _newPrice) public virtual {
uint256 currentPrice = priceFeedMock.fetchPrice();
_newPrice = between(
_newPrice,
(currentPrice * 1e18) / MAX_PRICE_CHANGE_PERCENT,
Expand All @@ -1320,7 +1320,7 @@ abstract contract TargetFunctions is Properties {
// Governance
///////////////////////////////////////////////////////

function setGovernanceParameters(uint256 parameter, uint256 value) public {
function setGovernanceParameters(uint256 parameter, uint256 value) public virtual {
parameter = between(parameter, 0, 6);

if (parameter == 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,20 @@ contract EchidnaForkTester is EchidnaAsserts, EchidnaProperties, TargetFunctions
constructor() payable {
_setUpFork();
_setUpActors();
hevm.roll(4368824);
hevm.warp(1695742536);
// https://etherscan.io/tx/0x3d20c053b83d4d49ba12c3251f14546511f8af7b5b99dbeb692f6f9458c075ab
hevm.roll(19258626);
hevm.warp(1708307303);
}

function setPrice(uint256) public pure override {
require(false, "Skip. TODO: call hevm.store to update the price");
}

function setGovernanceParameters(uint256, uint256) public pure override {
require(false, "Skip. TODO: call hevm.store to bypass timelock");
}

function setEthPerShare(uint256) public pure override {
require(false, "Skip. TODO: call hevm.store to seth ETH per share");
}
}
Loading
Loading