Skip to content

Commit

Permalink
feat: SpotOracle and ReserveOracle for Base weETH/WETH now checks for…
Browse files Browse the repository at this point in the history
… sequencer downtime and grace periods
  • Loading branch information
junkim012 committed Jul 3, 2024
1 parent e4e127f commit 0b4cfcc
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 11 deletions.
3 changes: 2 additions & 1 deletion deployment-config/05_DeployInitialReserveAndSpotOracles.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"maxChange": "30000000000000000000000000",
"ltv": "930000000000000000000000000",
"maxTimeFromLastUpdate": "87000"
"maxTimeFromLastUpdate": "87000",
"gracePeriod": "3600"
}
9 changes: 5 additions & 4 deletions script/deploy/05_DeployInitialReserveAndSpotOracles.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ contract DeployInitialReserveAndSpotOraclesScript is DeployScript {
string config = vm.readFile(configPath);

uint256 maxChange = config.readUint(".maxChange");
uint256 gracePeriod = config.readUint(".gracePeriod");
uint256 ltv = config.readUint(".ltv");

function run() public broadcast returns (address reserveOracle, address spotOracle) {
Expand All @@ -30,16 +31,16 @@ contract DeployInitialReserveAndSpotOraclesScript is DeployScript {
if (deployCreate2) {
reserveOracle = address(
new WeEthWethReserveOracle{ salt: DEFAULT_SALT }(
0, new address[](3), 0, maxChange, maxTimeFromLastUpdate
0, new address[](3), 0, maxChange, maxTimeFromLastUpdate, gracePeriod
)
);
spotOracle = address(
new WeEthWethSpotOracle{ salt: DEFAULT_SALT }(ltv, address(reserveOracle), maxTimeFromLastUpdate)
new WeEthWethSpotOracle{ salt: DEFAULT_SALT }(ltv, address(reserveOracle), maxTimeFromLastUpdate, gracePeriod)
);
} else {
reserveOracle =
address(new WeEthWethReserveOracle(0, new address[](3), 0, maxChange, maxTimeFromLastUpdate));
spotOracle = address(new WeEthWethSpotOracle(ltv, address(reserveOracle), maxTimeFromLastUpdate));
address(new WeEthWethReserveOracle(0, new address[](3), 0, maxChange, maxTimeFromLastUpdate, gracePeriod));
spotOracle = address(new WeEthWethSpotOracle(ltv, address(reserveOracle), maxTimeFromLastUpdate, gracePeriod));
}
}
}
22 changes: 20 additions & 2 deletions src/oracles/reserve/lrt/WeEthWethReserveOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity 0.8.21;

import { ReserveOracle } from "../ReserveOracle.sol";
import { BASE_WEETH_ETH_EXCHANGE_RATE_CHAINLINK } from "../../../Constants.sol";
import { BASE_WEETH_ETH_EXCHANGE_RATE_CHAINLINK, BASE_SEQUENCER_UPTIME_FEED } from "../../../Constants.sol";
import { WadRayMath } from "../../../libraries/math/WadRayMath.sol";
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";

Expand All @@ -15,9 +15,12 @@ contract WeEthWethReserveOracle is ReserveOracle {
using WadRayMath for uint256;
using SafeCast for int256;

error SequencerDown();
error GracePeriodNotOver();
error MaxTimeFromLastUpdateExceeded(uint256, uint256);

uint256 public immutable MAX_TIME_FROM_LAST_UPDATE; // seconds
uint256 public immutable GRACE_PERIOD;

/**
* @notice Creates a new `WeEthWethReserveOracle` instance. Provides
Expand All @@ -35,11 +38,13 @@ contract WeEthWethReserveOracle is ReserveOracle {
address[] memory _feeds,
uint8 _quorum,
uint256 _maxChange,
uint256 _maxTimeFromLastUpdate
uint256 _maxTimeFromLastUpdate,
uint256 _gracePeriod
)
ReserveOracle(_ilkIndex, _feeds, _quorum, _maxChange)
{
MAX_TIME_FROM_LAST_UPDATE = _maxTimeFromLastUpdate;
GRACE_PERIOD = _gracePeriod;
_initializeExchangeRate();
}

Expand All @@ -48,6 +53,19 @@ contract WeEthWethReserveOracle is ReserveOracle {
* @return Exchange rate between WETH and weETH.
*/
function _getProtocolExchangeRate() internal view override returns (uint256) {
(
/*uint80 roundID*/
,
int256 answer,
uint256 startedAt,
/*uint256 updatedAt*/
,
/*uint80 answeredInRound*/
) = BASE_SEQUENCER_UPTIME_FEED.latestRoundData();

if (answer == 1) revert SequencerDown();
if (block.timestamp - startedAt <= GRACE_PERIOD) revert GracePeriodNotOver();

(, int256 ethPerWeEth,, uint256 ethPerWeEthUpdatedAt,) =
BASE_WEETH_ETH_EXCHANGE_RATE_CHAINLINK.latestRoundData();

Expand Down
15 changes: 14 additions & 1 deletion src/oracles/spot/lrt/WeEthWethSpotOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,19 @@ contract WeEthWethSpotOracle is SpotOracle {
using SafeCast for int256;

error SequencerDown();
error GracePeriodNotOver();

/**
* @notice The maximum delay for the oracle update in seconds before the
* data is considered stale.
*/
uint256 public immutable MAX_TIME_FROM_LAST_UPDATE; // seconds

/**
* @notice Amount of time to wait after the sequencer restarts.
*/
uint256 public immutable GRACE_PERIOD;

/**
* @notice Creates a new `WeEthWethSpotOracle` instance.
* @param _ltv The loan to value ratio for the weETH/WETH market.
Expand All @@ -30,11 +40,13 @@ contract WeEthWethSpotOracle is SpotOracle {
constructor(
uint256 _ltv,
address _reserveOracle,
uint256 _maxTimeFromLastUpdate
uint256 _maxTimeFromLastUpdate,
uint256 _gracePeriod
)
SpotOracle(_ltv, _reserveOracle)
{
MAX_TIME_FROM_LAST_UPDATE = _maxTimeFromLastUpdate;
GRACE_PERIOD = _gracePeriod;
}

/**
Expand All @@ -54,6 +66,7 @@ contract WeEthWethSpotOracle is SpotOracle {
) = BASE_SEQUENCER_UPTIME_FEED.latestRoundData();

if (answer == 1) revert SequencerDown();
if (block.timestamp - startedAt <= GRACE_PERIOD) revert GracePeriodNotOver();

(
/*uint80 roundID*/
Expand Down
3 changes: 2 additions & 1 deletion test/fork/concrete/lrt/ReserveOracle.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -430,10 +430,11 @@ contract WeEthWethReserveOracle_ForkTest is ReserveOracle_ForkTest {
error MaxTimeFromLastUpdateExceeded(uint256, uint256);

uint256 public immutable MAX_TIME_FROM_LAST_UPDATE = 87_000; // seconds
uint256 public immutable GRACE_PERIOD = 3600;

function setUp() public override {
super.setUp();
reserveOracle = new WeEthWethReserveOracle(ILK_INDEX, emptyFeeds, QUORUM, MAX_CHANGE, MAX_TIME_FROM_LAST_UPDATE);
reserveOracle = new WeEthWethReserveOracle(ILK_INDEX, emptyFeeds, QUORUM, MAX_CHANGE, MAX_TIME_FROM_LAST_UPDATE, GRACE_PERIOD);
}

function _getForkRpc() internal override returns (string memory) {
Expand Down
5 changes: 3 additions & 2 deletions test/fork/concrete/lrt/SpotOracle.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,15 @@ contract EzEthWethSpotOracle_ForkTest is SpotOracle_ForkTest {
}

contract WeEthWethSpotOracle_ForkTest is SpotOracle_ForkTest {
uint256 constant GRACE_PERIOD = 3600;
uint256 constant MAX_TIME_FROM_LAST_UPDATE = 87_000;
uint256 constant MAX_LTV = 0.8e27;

function setUp() public override {
super.setUp();
reserveOracle =
new WeEthWethReserveOracle(ILK_INDEX, emptyFeeds, QUORUM, DEFAULT_MAX_CHANGE, MAX_TIME_FROM_LAST_UPDATE);
spotOracle = new WeEthWethSpotOracle(MAX_LTV, address(reserveOracle), MAX_TIME_FROM_LAST_UPDATE);
new WeEthWethReserveOracle(ILK_INDEX, emptyFeeds, QUORUM, DEFAULT_MAX_CHANGE, MAX_TIME_FROM_LAST_UPDATE, GRACE_PERIOD);
spotOracle = new WeEthWethSpotOracle(MAX_LTV, address(reserveOracle), MAX_TIME_FROM_LAST_UPDATE, GRACE_PERIOD);
}

function _getForkRpc() internal override returns (string memory) {
Expand Down

0 comments on commit 0b4cfcc

Please sign in to comment.