Skip to content

Commit

Permalink
setup test suit, fix SFraxETHCollatera.
Browse files Browse the repository at this point in the history
  • Loading branch information
pmckelvy1 committed Dec 12, 2023
1 parent 3ae2f07 commit 3293a1d
Show file tree
Hide file tree
Showing 11 changed files with 220 additions and 42 deletions.
3 changes: 3 additions & 0 deletions common/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ export const networkConfig: { [key: string]: INetworkConfig } = {
stETHUSD: '0xCfE54B5cD566aB89272946F602D76Ea879CAb4a8', // stETH/USD
rETH: '0x536218f9E9Eb48863970252233c8F271f554C2d0', // rETH/ETH
cbETH: '0xf017fcb346a1885194689ba23eff2fe6fa5c483b', // cbETH/ETH
sfrxETH: '0xc58f3385fbc1c8ad2c0c9a061d7c13b141d7a5df' // sfrxETH/ETH
},
AAVE_LENDING_POOL: '0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9',
AAVE_INCENTIVES: '0xd784927Ff2f95ba542BfC824c8a8a98F3495f6b5',
Expand Down Expand Up @@ -326,6 +327,7 @@ export const networkConfig: { [key: string]: INetworkConfig } = {
stETHUSD: '0xCfE54B5cD566aB89272946F602D76Ea879CAb4a8', // stETH/USD
rETH: '0x536218f9E9Eb48863970252233c8F271f554C2d0', // rETH/ETH
cbETH: '0xf017fcb346a1885194689ba23eff2fe6fa5c483b', // cbETH/ETH
sfrxETH: '0xc58f3385fbc1c8ad2c0c9a061d7c13b141d7a5df' // sfrxETH/ETH
},
AAVE_LENDING_POOL: '0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9',
AAVE_RESERVE_TREASURY: '0x464C71f6c2F760DdA6093dCB91C24c39e5d6e18c',
Expand Down Expand Up @@ -425,6 +427,7 @@ export const networkConfig: { [key: string]: INetworkConfig } = {
stETHUSD: '0xCfE54B5cD566aB89272946F602D76Ea879CAb4a8', // stETH/USD
rETH: '0x536218f9E9Eb48863970252233c8F271f554C2d0', // rETH/ETH
cbETH: '0xf017fcb346a1885194689ba23eff2fe6fa5c483b', // cbETH/ETH
sfrxETH: '0xc58f3385fbc1c8ad2c0c9a061d7c13b141d7a5df' // sfrxETH/ETH
},
AAVE_LENDING_POOL: '0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9',
AAVE_RESERVE_TREASURY: '0x464C71f6c2F760DdA6093dCB91C24c39e5d6e18c',
Expand Down
5 changes: 4 additions & 1 deletion contracts/plugins/assets/AppreciatingFiatCollateral.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import "../../libraries/Fixed.sol";
import "./FiatCollateral.sol";
import "./Asset.sol";
import "./OracleLib.sol";

import "hardhat/console.sol";
/**

Check failure on line 11 in contracts/plugins/assets/AppreciatingFiatCollateral.sol

View workflow job for this annotation

GitHub Actions / Lint Checks

Insert ⏎
* @title AppreciatingFiatCollateral
* Collateral that may need revenue hiding to become truly "up only"
Expand Down Expand Up @@ -112,11 +112,14 @@ abstract contract AppreciatingFiatCollateral is FiatCollateral {
// If the price is below the default-threshold price, default eventually
// uint192(+/-) is the same as Fix.plus/minus
if (pegPrice < pegBottom || pegPrice > pegTop || low == 0) {
console.log("here", pegTop, pegBottom, pegPrice);
markStatus(CollateralStatus.IFFY);
} else {
markStatus(CollateralStatus.SOUND);
}
} catch (bytes memory errData) {
console.log("over ther");
console.logBytes(errData);
// see: docs/solidity-style.md#Catching-Empty-Data
if (errData.length == 0) revert(); // solhint-disable-line reason-string
markStatus(CollateralStatus.IFFY);
Expand Down
60 changes: 60 additions & 0 deletions contracts/plugins/assets/FraxOracleLib.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;

import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "../../libraries/Fixed.sol";
import "./OracleErrors.sol";
import "hardhat/console.sol";
interface FraxAggregatorV3Interface is AggregatorV3Interface {

Check failure on line 8 in contracts/plugins/assets/FraxOracleLib.sol

View workflow job for this annotation

GitHub Actions / Lint Checks

Insert ⏎
function priceSource() external view returns (address);
function addRoundData(bool _isBadData, uint104 _priceLow, uint104 _priceHigh, uint40 _timestamp) external;

Check failure on line 10 in contracts/plugins/assets/FraxOracleLib.sol

View workflow job for this annotation

GitHub Actions / Lint Checks

Line length must be no more than 100 but current length is 110

Check failure on line 10 in contracts/plugins/assets/FraxOracleLib.sol

View workflow job for this annotation

GitHub Actions / Lint Checks

Replace ····function·addRoundData(bool·_isBadData,·uint104·_priceLow,·uint104·_priceHigh,·uint40·_timestamp with ⏎····function·addRoundData(⏎········bool·_isBadData,⏎········uint104·_priceLow,⏎········uint104·_priceHigh,⏎········uint40·_timestamp⏎····
}

/// Used by asset plugins to price their collateral
library FraxOracleLib {
/// @dev Use for nested calls that should revert when there is a problem
/// @param timeout The number of seconds after which oracle values should be considered stale
/// @return {UoA/tok}
function price(FraxAggregatorV3Interface chainlinkFeed, uint48 timeout)
internal
view
returns (uint192)
{
try chainlinkFeed.latestRoundData() returns (
uint80 roundId,
int256 p,
uint256,
uint256 updateTime,
uint80 answeredInRound
) {
if (updateTime == 0 || answeredInRound < roundId) {
revert StalePrice();
}

// Downcast is safe: uint256(-) reverts on underflow; block.timestamp assumed < 2^48
uint48 secondsSince = uint48(block.timestamp - updateTime);
if (secondsSince > timeout) revert StalePrice();

if (p == 0) revert ZeroPrice();

// {UoA/tok}
return shiftl_toFix(uint256(p), -int8(chainlinkFeed.decimals()));
} catch (bytes memory errData) {
// Check if the priceSource was not set: if so, the chainlink feed has been deprecated
// and a _specific_ error needs to be raised in order to avoid looking like OOG
if (errData.length == 0) {
if (chainlinkFeed.priceSource() == address(0)) {
revert StalePrice();
}
// solhint-disable-next-line reason-string
revert();
}

// Otherwise, preserve the error bytes
// solhint-disable-next-line no-inline-assembly
assembly {
revert(add(32, errData), mload(errData))
}
}
}
}
7 changes: 7 additions & 0 deletions contracts/plugins/assets/OracleErrors.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;

// 0x19abf40e
error StalePrice();
// 0x4dfba023
error ZeroPrice();
4 changes: 1 addition & 3 deletions contracts/plugins/assets/OracleLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ pragma solidity 0.8.19;

import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "../../libraries/Fixed.sol";

error StalePrice();
error ZeroPrice();
import "./OracleErrors.sol";

interface EACAggregatorProxy {
function aggregator() external view returns (address);
Expand Down
42 changes: 27 additions & 15 deletions contracts/plugins/assets/frax-eth/SFraxEthCollateral.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import "@openzeppelin/contracts/utils/math/Math.sol";
import "../../../libraries/Fixed.sol";
import "../AppreciatingFiatCollateral.sol";
import "../OracleLib.sol";
import "../FraxOracleLib.sol";
import "./vendor/IsfrxEth.sol";
import "hardhat/console.sol";

/**
* ************************************************************
Expand All @@ -23,17 +25,27 @@ import "./vendor/IsfrxEth.sol";
*/
contract SFraxEthCollateral is AppreciatingFiatCollateral {
using OracleLib for AggregatorV3Interface;
using FraxOracleLib for FraxAggregatorV3Interface;
using FixLib for uint192;

// solhint-disable no-empty-blocks
/// @param config.chainlinkFeed Feed units: {UoA/target}
constructor(CollateralConfig memory config, uint192 revenueHiding)
AppreciatingFiatCollateral(config, revenueHiding)
{
FraxAggregatorV3Interface public immutable targetPerTokChainlinkFeed; // {target/tok}
uint48 public immutable targetPerTokChainlinkTimeout;

/// @param config.chainlinkFeed {UoA/target} price of ETH in USD terms
/// @param _targetPerTokChainlinkFeed {target/tok} price of cbETH in ETH terms
constructor(
CollateralConfig memory config,
uint192 revenueHiding,
FraxAggregatorV3Interface _targetPerTokChainlinkFeed,
uint48 _targetPerTokChainlinkTimeout
) AppreciatingFiatCollateral(config, revenueHiding) {
require(config.defaultThreshold > 0, "defaultThreshold zero");
}
require(address(_targetPerTokChainlinkFeed) != address(0), "missing targetPerTok feed");
require(_targetPerTokChainlinkTimeout != 0, "targetPerTokChainlinkTimeout zero");

// solhint-enable no-empty-blocks
targetPerTokChainlinkFeed = _targetPerTokChainlinkFeed;
targetPerTokChainlinkTimeout = _targetPerTokChainlinkTimeout;
}

/// Can revert, used by other contract functions in order to catch errors
/// @return low {UoA/tok} The low price estimate
Expand All @@ -49,22 +61,22 @@ contract SFraxEthCollateral is AppreciatingFiatCollateral {
uint192 pegPrice
)
{
// {UoA/tok} = {UoA/target} * {ref/tok} * {target/ref} (1)
uint192 p = chainlinkFeed.price(oracleTimeout).mul(_underlyingRefPerTok());
console.log(address(targetPerTokChainlinkFeed), address(chainlinkFeed));
uint192 targetPerTok = targetPerTokChainlinkFeed.price(targetPerTokChainlinkTimeout);
// {UoA/tok} = {UoA/target} * {target/tok}
uint192 p = chainlinkFeed.price(oracleTimeout).mul(targetPerTok);
uint192 err = p.mul(oracleError, CEIL);

low = p - err;
high = p + err;
low = p - err;
// assert(low <= high); obviously true just by inspection

// TODO: Currently not checking for depegs between `frxETH` and `ETH`
// Should be modified to use a `frxETH/ETH` oracle when available
pegPrice = targetPerRef();
// {target/ref} = {target/tok} / {ref/tok}
pegPrice = targetPerTok.div(_underlyingRefPerTok());
}

/// @return {ref/tok} Quantity of whole reference units per whole collateral tokens
function _underlyingRefPerTok() internal view override returns (uint192) {
uint256 rate = IsfrxEth(address(erc20)).pricePerShare();
return _safeWrap(rate);
return _safeWrap(IsfrxEth(address(erc20)).pricePerShare());
}
}
13 changes: 13 additions & 0 deletions contracts/plugins/mocks/ChainlinkMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ contract MockV3Aggregator is AggregatorV3Interface {
// Additional variable to be able to test invalid behavior
uint256 public latestAnsweredRound;
address public aggregator;
address public priceSource;

mapping(uint256 => int256) public getAnswer;
mapping(uint256 => uint256) public getTimestamp;
Expand All @@ -32,6 +33,7 @@ contract MockV3Aggregator is AggregatorV3Interface {
constructor(uint8 _decimals, int256 _initialAnswer) {
decimals = _decimals;
aggregator = address(this);
priceSource = address(this);
updateAnswer(_initialAnswer);
}

Expand All @@ -49,6 +51,17 @@ contract MockV3Aggregator is AggregatorV3Interface {
latestAnsweredRound = latestRound;
}

// used by Frax oracl
function addRoundData(bool isBadData, uint104 low, uint104 high, uint40 timestamp) public {
latestAnswer = int104(low + high) / 2;
latestTimestamp = block.timestamp;
latestRound++;
getAnswer[latestRound] = latestAnswer;
getTimestamp[latestRound] = block.timestamp;
getStartedAt[latestRound] = block.timestamp;
latestAnsweredRound = latestRound;
}

// Additional function to be able to test invalid Chainlink behavior
function setInvalidTimestamp() public {
getTimestamp[latestRound] = 0;
Expand Down
6 changes: 4 additions & 2 deletions test/plugins/individual-collateral/collateralTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export default function fn<X extends CollateralFixtureContext>(
} = fixtures

getDescribeFork(targetNetwork)(`Collateral: ${collateralName}`, () => {
before(resetFork)
beforeEach(resetFork)

describe('constructor validation', () => {
it('validates targetName', async () => {
Expand Down Expand Up @@ -394,7 +394,6 @@ export default function fn<X extends CollateralFixtureContext>(
const invalidChainlinkFeed = <InvalidMockV3Aggregator>(
await InvalidMockV3AggregatorFactory.deploy(8, chainlinkDefaultAnswer)
)

const invalidCollateral = await deployCollateral({
erc20: ctx.tok.address,
chainlinkFeed: invalidChainlinkFeed.address,
Expand Down Expand Up @@ -520,7 +519,9 @@ export default function fn<X extends CollateralFixtureContext>(
const delayUntilDefault = await collateral.delayUntilDefault()

// Check initial state
console.log("start")
expect(await collateral.status()).to.equal(CollateralStatus.SOUND)
console.log("1")
expect(await collateral.whenDefault()).to.equal(MAX_UINT48)

// Depeg - Reducing price by 20%
Expand Down Expand Up @@ -809,6 +810,7 @@ export default function fn<X extends CollateralFixtureContext>(
// Should issue
await collateralERC20.connect(addr1).approve(rToken.address, MAX_UINT256)
await pairedERC20.connect(addr1).approve(rToken.address, MAX_UINT256)
console.log("is ready?", await collateral.status())
await rToken.connect(addr1).issue(supply)
})

Expand Down
Loading

0 comments on commit 3293a1d

Please sign in to comment.