BaseTest.t.sol

December 14, 2023 ยท View on GitHub

// SPDX-License-Identifier: MIT pragma solidity ^0.8.0;

import { Test, console2 } from "forge-std/Test.sol";

import { Comptroller } from "../contracts/Comptroller.sol"; import { InterestRateModel } from "../contracts/InterestRateModel.sol"; import { CToken } from "../contracts/CToken.sol"; import { CErc20 } from "../contracts/CErc20.sol"; import { CErc721 } from "../contracts/CErc721.sol"; import { PriceOracle } from "../contracts/PriceOracle.sol"; import { JumpRateModelV2 } from "../contracts/JumpRateModelV2.sol"; import { CErc721InterestRateModel } from "../contracts/CErc721InterestRateModel.sol"; import "../contracts/CTokenInterfaces.sol";

import { AggregatorV3Interface } from "@chainlink/interfaces/AggregatorV3Interface.sol"; import { ChainlinkPriceOracle } from "../contracts/ChainlinkPriceOracle.sol"; import { FloorPriceFeedAdapter } from "../contracts/FloorPriceFeedAdapter.sol";

import { CEther, IWeth } from "../contracts/CEther.sol"; import { CEtherDelegator } from "../contracts/CEtherDelegator.sol"; import { CEtherDelegate } from "../contracts/CEtherDelegate.sol";

import { CErc721Delegate } from "../contracts/CERC721Delegate.sol"; import { CErc721Delegator } from "../contracts/CERC721Delegator.sol"; import { CErc721NoProxy } from "../contracts/CERC721NoProxy.sol";

import { CErc20InterestMarket } from "../contracts/CErc20InterestMarket.sol"; import { CErc20InterestMarketDelegator } from "../contracts/CErc20InterestMarketDelegator.sol"; import { CErc20InterestMarketDelegate } from "../contracts/CErc20InterestMarketDelegate.sol"; import { CErc20InterestMarketNoProxy } from "../contracts/CErc20InterestMarketNoProxy.sol";

import { CErc20Immutable } from "../contracts/CErc20Immutable.sol";

interface IERC721 { function transferFrom(address from, address to, uint256 tokenId) external; function balanceOf(address owner) external view returns (uint256 balance); function approve(address to, uint256 tokenId) external; function ownerOf(uint256 tokenId) external view returns (address owner); }

interface IERC20 { function transfer(address recipient, uint256 amount) external returns (bool); function balanceOf(address owner) external view returns (uint256 balance); function approve(address spender, uint256 amount) external returns (bool); }

contract MockOracle { uint price;

constructor(uint _price) {
    price = _price;
}

function setPrice(uint _price) public {
    price = _price;
}

function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80) {
    return (0, int(price), 0, block.timestamp, 0);
}

}

contract BaseTest is Test { Comptroller comptroller; JumpRateModelV2 jumpRateModel; CErc721InterestRateModel cErc721InterestRateModel;

address lender = makeAddr("lender");
address borrower = makeAddr("borrower");
address liquidator = makeAddr("liquidator");
address attacker = makeAddr("attacker");

address constant BAYC = 0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D;
address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
IWeth constant WETH = IWeth(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
AggregatorV3Interface constant ETHUSD = AggregatorV3Interface(0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419);
address constant USDUSDC = 0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6;
address constant BAYCETH = 0x352f2Bc3039429fC2fe62004a1575aE74001CfcE;

uint constant blocksPerYear = 2628000;

ChainlinkPriceOracle oracle;
CErc721 baycCERC721;
CErc20 erc20Market;
CErc20InterestMarket imMarket;
CEther cether;

function setUp() virtual public {

    vm.createSelectFork("https://mainnet.infura.io/v3/fb419f740b7e401bad5bec77d0d285a5", 18764789); // ~1pm monday

    //////////////////////////////////
    ////////// COMPTROLLER ///////////
    //////////////////////////////////

    comptroller = new Comptroller();
    comptroller.initialize();

    //////////////////////////////////
    ////// INTEREST RATE MODELS //////
    //////////////////////////////////

    jumpRateModel = new JumpRateModelV2(0, 0.04e18, 1.09e18, 0.8e18, address(this));
    cErc721InterestRateModel = new CErc721InterestRateModel(2628000, 0.02e18, 0.1e18);

    //////////////////////////////////
    //////////// MARKETS /////////////
    //////////////////////////////////

    address baycCERC721Impl = address(new CErc721Delegate());
    baycCERC721 = CErc721(address(new CErc721Delegator(
        BAYC,
        ComptrollerInterface(address(comptroller)),
        InterestRateModel(address(cErc721InterestRateModel)),
        2e26,
        "BAYC Market",
        "cBAYC",
        8,
        payable(address(this)),
        baycCERC721Impl,
        ""
    )));
    baycCERC721._setReserveFactor(7.5e16);

    imMarket = CErc20InterestMarket(address(new CErc20InterestMarketNoProxy(
        USDC,
        ComptrollerInterface(address(comptroller)),
        InterestRateModel(address(jumpRateModel)),
        2e14,
        "cUSDC Interest Market",
        "imcUSDC",
        8,
        payable(address(this))
    )));
    imMarket._setReserveFactor(7.5e16);
    imMarket._setProtocolSeizeShare(2.8e16);

    erc20Market = CErc20(address(new CErc20Immutable(
        USDC,
        ComptrollerInterface(address(comptroller)),
        InterestRateModel(address(jumpRateModel)),
        2e14,
        "Fungify cUSDC",
        "fcUSDC",
        8,
        payable(address(this))
    )));
    erc20Market._setReserveFactor(7.5e16);
    erc20Market._setProtocolSeizeShare(2.8e16);

    cether = CEther(payable(address(new CEtherDelegator(
        ComptrollerInterface(address(comptroller)),
        InterestRateModel(address(jumpRateModel)),
        2e14,
        "Fungify cETH",
        "fcETH",
        8,
        payable(address(this)),
        address(new CEtherDelegate(WETH)),
        ""
    ))));
    cether._setReserveFactor(7.5e16);
    cether._setProtocolSeizeShare(2.8e16);

    //////////////////////////////////
    //////////// ORACLES /////////////
    //////////////////////////////////

    oracle = new ChainlinkPriceOracle();

    address baycAdapter = address(new FloorPriceFeedAdapter(
        AggregatorV3Interface(BAYCETH),
        ETHUSD
    ));

    oracle.setAssetPriceFeed(CToken(address(baycCERC721)), baycAdapter);
    oracle.setAssetPriceFeed(CToken(address(imMarket)), USDUSDC);
    oracle.setAssetPriceFeed(CToken(address(erc20Market)), USDUSDC);
    oracle.setAssetPriceFeed(CToken(address(cether)), address(ETHUSD));


    //////////////////////////////////
    ////// COMPTROLLER SETTINGS //////
    //////////////////////////////////

    comptroller._setPriceOracle(PriceOracle(address(oracle)));
    comptroller._setLiquidationIncentive(1.08e18);

    comptroller._supportMarket(CToken(address(baycCERC721)));
    comptroller._setCollateralFactor(CToken(address(baycCERC721)), 0.85e18);

    comptroller._supportMarket(CToken(address(erc20Market)));
    comptroller._setCollateralFactor(CToken(address(erc20Market)), 0.85e18);

    comptroller._supportMarket(CToken(address(cether)));
    comptroller._setCollateralFactor(CToken(address(cether)), 0.85e18);

    comptroller._supportMarket(CToken(address(imMarket)));
    comptroller._setCollateralFactor(CToken(address(imMarket)), 0.85e18);
    comptroller._updateInterestMarket(address(imMarket));

    comptroller._setAdminWhitelist(liquidator, true);
    comptroller._setAdminWhitelist(attacker, true);

    //////////////////////////////////
    ////////// TOKEN SETUP ///////////
    //////////////////////////////////

    address USDC_WHALE = 0x28C6c06298d514Db089934071355E5743bf21d60;
    vm.prank(USDC_WHALE);
    IERC20(USDC).transfer(address(this), 100_000_000e6);
}

function _distributeERC20(address token, address to, uint amount, address marketToApprove) internal {
    IERC20(token).transfer(to, amount);
    vm.prank(to);
    IERC20(token).approve(marketToApprove, amount);
}

function _distributeERC721(address token, address to, uint tokenId, address marketToApprove) internal {
    address from = IERC721(token).ownerOf(tokenId);
    vm.prank(from);
    IERC721(token).transferFrom(from, to, tokenId);
    vm.prank(to);
    IERC721(token).approve(marketToApprove, tokenId);
}

}