Skip to content

Commit

Permalink
feat: base network ezETH/WETH uniswap flashswap strategy and spot/res…
Browse files Browse the repository at this point in the history
…erve oracles and tests
  • Loading branch information
junkim012 committed Jul 23, 2024
1 parent d1204b5 commit 269e008
Show file tree
Hide file tree
Showing 10 changed files with 956 additions and 2 deletions.
6 changes: 6 additions & 0 deletions src/Constants.sol
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,9 @@ IUniswapV3Pool constant BASE_WSTETH_WETH_UNISWAP = IUniswapV3Pool(0x20E068D76f9E
IChainlink constant BASE_SEQUENCER_UPTIME_FEED = IChainlink(0xBCF85224fc0756B9Fa45aA7892530B47e10b6433);
IERC20 constant BASE_WEETH = IERC20(0x04C0599Ae5A44757c0af6F9eC3b93da8976c150A);
IWETH9 constant BASE_WETH = IWETH9(0x4200000000000000000000000000000000000006);

// Renzo
IERC20 constant BASE_EZETH = IERC20(0x2416092f143378750bb29b79eD961ab195CcEea5);
IUniswapV3Pool constant BASE_EZETH_WETH_AERODROME = IUniswapV3Pool(0xDC7EAd706795eDa3FEDa08Ad519d9452BAdF2C0d);
IChainlink constant BASE_EZETH_ETH_EXCHANGE_RATE_CHAINLINK = IChainlink(0xC4300B7CF0646F0Fe4C5B2ACFCCC4dCA1346f5d8);
IChainlink constant BASE_EZETH_ETH_PRICE_CHAINLINK = IChainlink(0x960BDD1dFD20d7c98fa482D793C3dedD73A113a3);
41 changes: 41 additions & 0 deletions src/flash/lrt/base/BaseEzEthWethHandler.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import { IonPool } from "./../../../IonPool.sol";
import { IonPool } from "./../../../IonPool.sol";
import { GemJoin } from "./../../../join/GemJoin.sol";
import { Whitelist } from "./../../../Whitelist.sol";
import { IonHandlerBase } from "./../../IonHandlerBase.sol";
import { IWETH9 } from "./../../../interfaces/IWETH9.sol";
import { UniswapFlashswapHandler } from "./../../UniswapFlashswapHandler.sol";
import { IUniswapV3Pool } from "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";

/**
* @notice Handler for the ezETH collateral in the ezETH/WETH market on Base.
*
* @custom:security-contact security@molecularlabs.io
*/
contract BaseEzEthWethHandler is UniswapFlashswapHandler {
/**
* @notice Creates a new `EzEthWethHandler` instance.
* @param _ilkIndex Ilk index of the pool.
* @param _ionPool address.
* @param _gemJoin address.
* @param _whitelist address.
* @param _pool address of the ezETH/WETH Aerodrome pool.
* @param _wethIsToken0 Whether WETH is token0 or token1.
* @param _weth The WETH address of this chain.
*/
constructor(
uint8 _ilkIndex,
IonPool _ionPool,
GemJoin _gemJoin,
Whitelist _whitelist,
IUniswapV3Pool _pool,
bool _wethIsToken0,
IWETH9 _weth
)
IonHandlerBase(_ilkIndex, _ionPool, _gemJoin, _whitelist, _weth)
UniswapFlashswapHandler(_pool, _wethIsToken0)
{ }
}
71 changes: 71 additions & 0 deletions src/oracles/reserve/lrt/base/BaseEzEthWethReserveOracle.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

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

/**
* @notice Reserve Oracle for ezETH denominated in WETH.
*
* @custom:security-contact security@molecularlabs.io
*/
contract BaseEzEthWethReserveOracle 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 `BaseEzEthWethReserveOracle` instance. Provides
* the amount of WETH equal to one ezETH (ETH / ezETH).
* @dev The value of ezETH denominated in WETH by Chainlink.
* @param _feeds List of alternative data sources for the WETH/ezETH exchange rate.
* @param _quorum The amount of alternative data sources to aggregate.
* @param _maxChange Maximum percent change between exchange rate updates. [RAY]
*/
constructor(
uint8 _ilkIndex,
address[] memory _feeds,
uint8 _quorum,
uint256 _maxChange,
uint256 _maxTimeFromLastUpdate,
uint256 _gracePeriod
)
ReserveOracle(_ilkIndex, _feeds, _quorum, _maxChange)
{
MAX_TIME_FROM_LAST_UPDATE = _maxTimeFromLastUpdate;
GRACE_PERIOD = _gracePeriod;
_initializeExchangeRate();
}

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 ethPerEzEth,, uint256 ethPerEzEthUpdatedAt,) =
BASE_EZETH_ETH_EXCHANGE_RATE_CHAINLINK.latestRoundData();

if (block.timestamp - ethPerEzEthUpdatedAt > MAX_TIME_FROM_LAST_UPDATE) {
revert MaxTimeFromLastUpdateExceeded(block.timestamp - ethPerEzEthUpdatedAt, MAX_TIME_FROM_LAST_UPDATE);
} else {
return ethPerEzEth.toUint256();
}
}
}
87 changes: 87 additions & 0 deletions src/oracles/spot/lrt/base/BaseEzEthWethSpotOracle.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// SPDX-License-Identifier: MIT

pragma solidity 0.8.21;

import { SpotOracle } from "../../../../oracles/spot/SpotOracle.sol";
import { WadRayMath } from "../../../../libraries/math/WadRayMath.sol";
import { BASE_SEQUENCER_UPTIME_FEED, BASE_EZETH_ETH_PRICE_CHAINLINK } from "../../../../Constants.sol";

import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";

/**
* @notice The ezETH spot oracle denominated in WETH on Base.
*
* @custom:security-contact security@molecularlabs.io
*/
contract BaseEzEthWethSpotOracle is SpotOracle {
using WadRayMath for uint256;
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.
* @param _reserveOracle The associated reserve oracle.
* @param _maxTimeFromLastUpdate The maximum delay for the oracle update in seconds
*/
constructor(
uint256 _ltv,
address _reserveOracle,
uint256 _maxTimeFromLastUpdate,
uint256 _gracePeriod
)
SpotOracle(_ltv, _reserveOracle)
{
MAX_TIME_FROM_LAST_UPDATE = _maxTimeFromLastUpdate;
GRACE_PERIOD = _gracePeriod;
}

/**
* @notice Gets the price of weETH in WETH.
* @dev Redstone oracle returns ETH per weETH with 8 decimals. This
* @return wethPerWeEth price of weETH in WETH. [WAD]
*/
function getPrice() public 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();

(
/*uint80 roundID*/
,
int256 ethPerEzEth,
/*uint startedAt*/
,
uint256 ethPerEzEthUpdatedAt,
/*uint80 answeredInRound*/
) = BASE_EZETH_ETH_PRICE_CHAINLINK.latestRoundData(); // [WAD]

if (block.timestamp - ethPerEzEthUpdatedAt > MAX_TIME_FROM_LAST_UPDATE) {
return 0; // collateral valuation is zero if oracle data is stale
} else {
return ethPerEzEth.toUint256(); // [wad]
}
}
}
Loading

0 comments on commit 269e008

Please sign in to comment.