ebtc-protocol / ebtc

GNU General Public License v3.0
48 stars 24 forks source link

Implementing fixed 1:1 collateral feed #772

Closed wtj2021 closed 5 months ago

wtj2021 commented 5 months ago
CodingNameKiki commented 5 months ago

@wtj2021 l think it would be great to specify on deployment whether the dynamic feed will be used or not, so the system is able to fetch the correct chainlink responses.

    constructor(
        address _fallbackCallerAddress,
        address _authorityAddress,
        address _collEthCLFeed,
        address _ethBtcCLFeed,
+       bool _useDynamicFeed
    ) {
        fallbackCaller = IFallbackCaller(_fallbackCallerAddress);

        _initializeAuthority(_authorityAddress);

        emit FallbackCallerChanged(address(0), _fallbackCallerAddress);

        ETH_BTC_CL_FEED = AggregatorV3Interface(_ethBtcCLFeed);
        STETH_ETH_CL_FEED = AggregatorV3Interface(_collEthCLFeed);
        STETH_ETH_FIXED_FEED = new FixedAdapter();

        uint8 ethBtcDecimals = ETH_BTC_CL_FEED.decimals();
        require(ethBtcDecimals <= MAX_DECIMALS);
        uint8 stEthEthDecimals = STETH_ETH_CL_FEED.decimals();
        require(stEthEthDecimals <= MAX_DECIMALS);

        DENOMINATOR =
            10 ** ((stEthEthDecimals > ethBtcDecimals ? stEthEthDecimals : ethBtcDecimals) * 2);
        SCALED_DECIMAL = stEthEthDecimals > ethBtcDecimals
            ? 10 ** (stEthEthDecimals - ethBtcDecimals)
            : 10 ** (ethBtcDecimals - stEthEthDecimals);

+       useDynamicFeed = _useDynamicFeed;

        // Get an initial price from Chainlink to serve as first reference for lastGoodPrice
        ChainlinkResponse memory chainlinkResponse = _getCurrentChainlinkResponse();
        ChainlinkResponse memory prevChainlinkResponse = _getPrevChainlinkResponse(
            chainlinkResponse.roundEthBtcId,
            chainlinkResponse.roundStEthEthId
        );

        require(
            !_chainlinkIsBroken(chainlinkResponse, prevChainlinkResponse) &&
                !_chainlinkIsFrozen(chainlinkResponse),
            "PriceFeed: Chainlink must be working and current"
        );

        _storeChainlinkPrice(chainlinkResponse.answer);

        // Explicitly set initial system status after `require` checks
        status = Status.chainlinkWorking;

        // emit STETH_ETH_FIXED_FEED address
        emit CollateralFeedSourceUpdated(address(_collateralFeed()));
    }
getrecon-bot commented 5 months ago
Job ID aac3bd22-a4b4-4b01-9abf-9e4413c42930
Command yarn && git submodule init && git submodule update && solc-select use 0.8.17 && cd packages/contracts/ && yarn echidna --test-mode assertion --test-limit 600000
Instance ID i-0610f6ccfcde4a836
Instance Type c5.2xlarge
Status Started
Elapsed
getrecon-bot commented 5 months ago
Job ID aac3bd22-a4b4-4b01-9abf-9e4413c42930
Command yarn && git submodule init && git submodule update && solc-select use 0.8.17 && cd packages/contracts/ && yarn echidna --test-mode assertion --test-limit 600000
Instance ID i-0610f6ccfcde4a836
Instance Type c5.2xlarge
Status Running
Elapsed 1 minute 12 seconds
getrecon-bot commented 5 months ago
Job ID aac3bd22-a4b4-4b01-9abf-9e4413c42930
Command yarn && git submodule init && git submodule update && solc-select use 0.8.17 && cd packages/contracts/ && yarn echidna --test-mode assertion --test-limit 600000
Instance ID i-0610f6ccfcde4a836
Instance Type c5.2xlarge
Status Running
Elapsed 1 minute 13 seconds
getrecon-bot commented 5 months ago
Job ID aac3bd22-a4b4-4b01-9abf-9e4413c42930
Command yarn && git submodule init && git submodule update && solc-select use 0.8.17 && cd packages/contracts/ && yarn echidna --test-mode assertion --test-limit 600000
Instance ID i-0610f6ccfcde4a836
Instance Type c5.2xlarge
Status Success
Elapsed 1 day 8 hours 45 minutes 33 seconds
GalloDaSballo commented 5 months ago

This change rounds out the rest of the PRs , especially for ChainlinkAdapter

By adding the fixed price oracle we can quickly write E2E integration tests

See a quick and dirty example that I wrote on ebtc-chainlink-oracle-adapter

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;

import "forge-std/Test.sol";
import {MockAggregator} from "../contracts/TestContracts/MockAggregator.sol";
import {ChainlinkAdapter} from "../contracts/ChainlinkAdapter.sol";
import {PriceFeedTester} from "../contracts/TestContracts/PriceFeedTester.sol";

// Integration test of the Price Feed
contract PriceFeedChainlinkAdapter is Test {
    MockAggregator internal usdBtcAggregator;
    MockAggregator internal ethUsdAggregator;
    ChainlinkAdapter internal chainlinkAdapter;
    PriceFeedTester internal priceFeed;

    function setUp() public {
        usdBtcAggregator = new MockAggregator();
        ethUsdAggregator = new MockAggregator();
        chainlinkAdapter = new ChainlinkAdapter(usdBtcAggregator, ethUsdAggregator);

        usdBtcAggregator.setLatestRoundId(110680464442257320246);
        usdBtcAggregator.setPrevRoundId(110680464442257320245);
        usdBtcAggregator.setPrice(3983705362408);
        usdBtcAggregator.setPrevPrice(3983705362408);
        usdBtcAggregator.setUpdateTime(block.timestamp);

        ethUsdAggregator.setLatestRoundId(110680464442257320664);
        ethUsdAggregator.setPrevRoundId(110680464442257320663);
        ethUsdAggregator.setPrice(221026137517);
        ethUsdAggregator.setPrevPrice(221026137517);
        ethUsdAggregator.setUpdateTime(block.timestamp);

        priceFeed = new PriceFeedTester(
            address(0),
            address(0),
            address(chainlinkAdapter),
            address(chainlinkAdapter) // NOTE: WRONG | /// TODO: Replace with this feed in this pr!
        );
    }

    function testIntegrationLatestRound() public {
        usdBtcAggregator.setLatestRoundId(110680464442257320247);
        usdBtcAggregator.setPrevRoundId(110680464442257320246);
        usdBtcAggregator.setPrice(3983705362408);
        usdBtcAggregator.setUpdateTime(1706208946);

        ethUsdAggregator.setLatestRoundId(110680464442257320665);
        ethUsdAggregator.setPrevRoundId(110680464442257320664);
        ethUsdAggregator.setPrice(221026137517);
        ethUsdAggregator.setUpdateTime(1706208947);

        (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) =
            chainlinkAdapter.latestRoundData();

        assertEq(answer, 55482551396170026);
        assertEq(roundId, chainlinkAdapter.CURRENT_ROUND());
        assertEq(updatedAt, 1706208946);

        priceFeed.fetchPrice();
    }
}
GalloDaSballo commented 5 months ago

I would recommend merging down to one PR and then doing more extensive integration tests

Specifically:

Fully tracking the precision loss is ideal