From 639f2320935f69911e7a25b87f0022a2bee43c02 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Tue, 2 Apr 2024 11:14:41 -0400 Subject: [PATCH] Require new collateral is sound when normalizing weights of a new basket (#1105) --- contracts/p0/BasketHandler.sol | 1 + contracts/p1/mixins/BasketLib.sol | 1 + test/Main.test.ts | 29 ++++++++++++++++++++++++++--- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/contracts/p0/BasketHandler.sol b/contracts/p0/BasketHandler.sol index 30a8f64d84..165c86ca9c 100644 --- a/contracts/p0/BasketHandler.sol +++ b/contracts/p0/BasketHandler.sol @@ -855,6 +855,7 @@ contract BasketHandlerP0 is ComponentP0, IBasketHandler { uint192 newP; // {UoA/BU} for (uint256 i = 0; i < len; ++i) { ICollateral coll = main.assetRegistry().toColl(erc20s[i]); // reverts if unregistered + require(coll.status() == CollateralStatus.SOUND, "unsound new collateral"); (low, high) = coll.price(); // {UoA/tok} require(low > 0 && high < FIX_MAX, "invalid price"); diff --git a/contracts/p1/mixins/BasketLib.sol b/contracts/p1/mixins/BasketLib.sol index 216935c2b9..80244c0567 100644 --- a/contracts/p1/mixins/BasketLib.sol +++ b/contracts/p1/mixins/BasketLib.sol @@ -361,6 +361,7 @@ library BasketLibP1 { uint192 newPrice; // {UoA/BU} for (uint256 i = 0; i < len; ++i) { ICollateral coll = assetRegistry.toColl(erc20s[i]); // reverts if unregistered + require(coll.status() == CollateralStatus.SOUND, "unsound new collateral"); (uint192 low, uint192 high) = coll.price(); // {UoA/tok} require(low > 0 && high < FIX_MAX, "invalid price"); diff --git a/test/Main.test.ts b/test/Main.test.ts index 053ffa7553..d316337d31 100644 --- a/test/Main.test.ts +++ b/test/Main.test.ts @@ -2136,11 +2136,10 @@ describe(`MainP${IMPLEMENTATION} contract`, () => { ).to.be.revertedWith('new target weights') }) - it('Should normalize price by USD for index RTokens', async () => { - // Basket starts out worth $1 and holding USD targets + it('Should normalize by price for index RTokens', async () => { // Throughout this test the $ value of the RToken should remain - // Group the 4 USD tokens together + // Set initial basket await indexBH.connect(owner).setPrimeBasket([token0.address], [fp('1')]) await indexBH.connect(owner).refreshBasket() let [erc20s, tokAmts] = await indexBH.quote(fp('1'), 0) @@ -2195,6 +2194,30 @@ describe(`MainP${IMPLEMENTATION} contract`, () => { expect(tokAmts[1]).to.equal(fp('0.5')) }) + it('Should not normalize by price when the current basket is unsound', async () => { + await indexBH.connect(owner).setPrimeBasket([token0.address], [fp('1')]) + await indexBH.connect(owner).refreshBasket() + await setOraclePrice(collateral0.address, fp('0.5')) + await assetRegistry.refresh() + expect(await collateral0.status()).to.equal(CollateralStatus.IFFY) + expect(await collateral1.status()).to.equal(CollateralStatus.SOUND) + await expect( + indexBH.connect(owner).setPrimeBasket([token1.address], [fp('1')]) + ).to.be.revertedWith('unsound basket') + }) + + it('Should not normalize by price if the new collateral is unsound', async () => { + await indexBH.connect(owner).setPrimeBasket([token0.address], [fp('1')]) + await indexBH.connect(owner).refreshBasket() + await setOraclePrice(collateral1.address, fp('0.5')) + await assetRegistry.refresh() + expect(await collateral0.status()).to.equal(CollateralStatus.SOUND) + expect(await collateral1.status()).to.equal(CollateralStatus.IFFY) + await expect( + indexBH.connect(owner).setPrimeBasket([token1.address], [fp('1')]) + ).to.be.revertedWith('unsound new collateral') + }) + describe('Custom Redemption', () => { const issueAmount = fp('10000') let usdcChainlink: MockV3Aggregator