Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,9 @@ contract CurveAppreciatingRTokenFiatCollateral is CurveStableCollateral {
/// Refresh exchange rates and update default status.
/// Have to override to add custom default checks
function refresh() public virtual override {
// solhint-disable-next-line no-empty-blocks
try pairedAssetRegistry.refresh() {} catch {
// must allow failure since cannot brick refresh()
}
// Note: Intentionally not refreshing AssetRegistry as an acceptable trade-off
// Issuance throttle becomes worst-case outcome in case of issuance frontruns in
// response to picking up bad collateral

CollateralStatus oldStatus = status();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,9 @@ contract CurveStableRTokenMetapoolCollateral is CurveStableMetapoolCollateral {
/// Refresh exchange rates and update default status.
/// Have to override to add custom default checks
function refresh() public virtual override {
// solhint-disable-next-line no-empty-blocks
try pairedAssetRegistry.refresh() {} catch {
// must allow failure since cannot brick refresh()
}
// Note: Intentionally not refreshing AssetRegistry as an acceptable trade-off
// Issuance throttle becomes worst-case outcome in case of issuance frontruns in
// response to picking up bad collateral

CollateralStatus oldStatus = status();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ const collateralSpecificStatusTests = () => {
await collateral.refresh()
})

it('Regression test -- refreshes inner RTokenAsset on refresh()', async () => {
it('Regression test -- does not refresh inner RTokenAsset on refresh()', async () => {
const [collateral] = await deployCollateral({})
const initialPrice = await collateral.price()
expect(initialPrice[0]).to.be.gt(0)
Expand Down Expand Up @@ -276,8 +276,8 @@ const collateralSpecificStatusTests = () => {
// Refresh CurveStableRTokenMetapoolCollateral
await collateral.refresh()

// Stale should be false again
expect(await mockRTokenAsset.stale()).to.be.false
// Stale remains true
expect(await mockRTokenAsset.stale()).to.be.true
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ const collateralSpecificStatusTests = () => {
await collateral.refresh()
})

it('Regression test -- refreshes inner RTokenAsset on refresh()', async () => {
it('Regression test -- does not refresh inner RTokenAsset on refresh()', async () => {
const [collateral] = await deployCollateral({})
const initialPrice = await collateral.price()
expect(initialPrice[0]).to.be.gt(0)
Expand Down Expand Up @@ -258,8 +258,8 @@ const collateralSpecificStatusTests = () => {
// Refresh CurveAppreciatingRTokenSelfReferentialCollateral
await collateral.refresh()

// Stale should be false again
expect(await mockRTokenAsset.stale()).to.be.false
// Stale remains true
expect(await mockRTokenAsset.stale()).to.be.true
})

it('Regression test -- stays IFFY throughout inner RToken default + rebalancing', async () => {
Expand Down Expand Up @@ -297,9 +297,28 @@ const collateralSpecificStatusTests = () => {
const uoaPerRefOracle = await overrideOracle(uoaPerRefFeed)
await uoaPerRefOracle.updateAnswer(await uoaPerRefOracle.latestAnswer())

// wstETHCollateral + CurveAppreciatingRTokenSelfReferentialCollateral should
// become IFFY through the top-level refresh
// wstETHCollateral + CurveAppreciatingRTokenSelfReferentialCollateral will NOT
// become IFFY through the top-level refresh (optimization)
await expectEvents(collateral.refresh(), [
{
contract: ethplusBasketHandler,
name: 'BasketStatusChanged',
emitted: false,
},
{
contract: wstETHCollateral,
name: 'CollateralStatusChanged',
emitted: false,
},
{
contract: collateral,
name: 'CollateralStatusChanged',
emitted: false,
},
])

// Refresh inner RToken to set IFFY
await expectEvents(ethplusAssetRegistry.refresh(), [
{
contract: ethplusBasketHandler,
name: 'BasketStatusChanged',
Expand All @@ -312,13 +331,19 @@ const collateralSpecificStatusTests = () => {
args: [0, 1],
emitted: true,
},
])

// Now we can refresh CurveAppreciatingRTokenSelfReferentialCollateral
// and it should become IFFY
await expectEvents(collateral.refresh(), [
{
contract: collateral,
name: 'CollateralStatusChanged',
args: [0, 1],
emitted: true,
},
])

expect(await wstETHCollateral.status()).to.equal(1)
expect(await collateral.status()).to.equal(1)
expect(await ethplusBasketHandler.status()).to.equal(1)
Expand Down Expand Up @@ -380,7 +405,6 @@ const collateralSpecificStatusTests = () => {
// refPerTok should finally fall after a 50% haircut
const basketsNeeded = await ethplus.basketsNeeded()
await whileImpersonating(ETHPLUS_BACKING_MANAGER, async (bm) => {
console.log('whale', whaleBal, basketsNeeded, await weth.balanceOf(bm.address))
await weth.connect(bm).transfer(whale, whaleBal.sub(basketsNeeded.mul(26).div(100))) // leave >25% WETH backing
expect(await ethplusBasketHandler.fullyCollateralized()).to.equal(false)
await ethplus.connect(bm).setBasketsNeeded(basketsNeeded.div(2)) // 50% haircut = WETH backing is sufficient
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ const collateralSpecificStatusTests = () => {
await collateral.refresh()
})

it('Regression test -- refreshes inner RTokenAsset on refresh()', async () => {
it('Regression test -- does not refresh inner RTokenAsset on refresh()', async () => {
const [collateral] = await deployCollateral({})
const initialPrice = await collateral.price()
expect(initialPrice[0]).to.be.gt(0)
Expand Down Expand Up @@ -285,8 +285,8 @@ const collateralSpecificStatusTests = () => {
// Refresh CurveStableRTokenMetapoolCollateral
await collateral.refresh()

// Stale should be false again
expect(await mockRTokenAsset.stale()).to.be.false
// Stale remains true
expect(await mockRTokenAsset.stale()).to.be.true
})

it('Regression test -- stays IFFY throughout inner RToken default + rebalancing', async () => {
Expand All @@ -308,9 +308,28 @@ const collateralSpecificStatusTests = () => {
const latestAnswer = await oracle.latestAnswer()
await oracle.updateAnswer(latestAnswer.mul(4).div(5))

// CTokenFiatCollateral + CurveStableRTokenMetapoolCollateral should
// become IFFY through the top-level refresh
// CTokenFiatCollateral + CurveStableRTokenMetapoolCollateral will NOT
// become IFFY through the top-level refresh (optimization)
await expectEvents(collateral.refresh(), [
{
contract: eusdBasketHandler,
name: 'BasketStatusChanged',
emitted: false,
},
{
contract: cUSDTCollateral,
name: 'CollateralStatusChanged',
emitted: false,
},
{
contract: collateral,
name: 'CollateralStatusChanged',
emitted: false,
},
])

// Refresh inner RToken to set IFFY
await expectEvents(eusdAssetRegistry.refresh(), [
{
contract: eusdBasketHandler,
name: 'BasketStatusChanged',
Expand All @@ -323,13 +342,19 @@ const collateralSpecificStatusTests = () => {
args: [0, 1],
emitted: true,
},
])

// Now we can refresh CurveStableRTokenMetapoolCollateral
// and it should become IFFY
await expectEvents(collateral.refresh(), [
{
contract: collateral,
name: 'CollateralStatusChanged',
args: [0, 1],
emitted: true,
},
])

expect(await cUSDTCollateral.status()).to.equal(1)
expect(await collateral.status()).to.equal(1)
expect(await eusdBasketHandler.status()).to.equal(1)
Expand Down
Loading