From e3bb53aac40b8222d73276765c9465b56a7766fd Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Thu, 5 Oct 2023 19:50:36 -0400 Subject: [PATCH 01/12] RTokenAsset.refresh() change --- contracts/facade/FacadeRead.sol | 4 ---- contracts/facade/FacadeTest.sol | 1 - contracts/p0/BackingManager.sol | 2 -- contracts/p0/Main.sol | 1 - contracts/p1/BackingManager.sol | 2 -- contracts/p1/Main.sol | 1 - contracts/p1/RToken.sol | 5 ----- contracts/p1/RevenueTrader.sol | 6 ++---- contracts/plugins/assets/RTokenAsset.sol | 5 +++++ 9 files changed, 7 insertions(+), 20 deletions(-) diff --git a/contracts/facade/FacadeRead.sol b/contracts/facade/FacadeRead.sol index 10f60d918..7faf0bc35 100644 --- a/contracts/facade/FacadeRead.sol +++ b/contracts/facade/FacadeRead.sol @@ -33,7 +33,6 @@ contract FacadeRead is IFacadeRead { // Poke Main main.assetRegistry().refresh(); - main.furnace().melt(); // {BU} BasketRange memory basketsHeld = main.basketHandler().basketsHeldBy(account); @@ -74,7 +73,6 @@ contract FacadeRead is IFacadeRead { // Poke Main reg.refresh(); - main.furnace().melt(); // Compute # of baskets to create `amount` qRTok uint192 baskets = (rTok.totalSupply() > 0) // {BU} @@ -120,7 +118,6 @@ contract FacadeRead is IFacadeRead { // Poke Main main.assetRegistry().refresh(); - main.furnace().melt(); uint256 supply = rTok.totalSupply(); @@ -241,7 +238,6 @@ contract FacadeRead is IFacadeRead { { IMain main = rToken.main(); main.assetRegistry().refresh(); - main.furnace().melt(); erc20s = main.assetRegistry().erc20s(); balances = new uint256[](erc20s.length); diff --git a/contracts/facade/FacadeTest.sol b/contracts/facade/FacadeTest.sol index d16c6ab6d..78ee2173e 100644 --- a/contracts/facade/FacadeTest.sol +++ b/contracts/facade/FacadeTest.sol @@ -97,7 +97,6 @@ contract FacadeTest is IFacadeTest { // Poke Main reg.refresh(); - main.furnace().melt(); address backingManager = address(main.backingManager()); IERC20 rsr = main.rsr(); diff --git a/contracts/p0/BackingManager.sol b/contracts/p0/BackingManager.sol index c22df732c..e288171c8 100644 --- a/contracts/p0/BackingManager.sol +++ b/contracts/p0/BackingManager.sol @@ -86,7 +86,6 @@ contract BackingManagerP0 is TradingP0, IBackingManager { /// @custom:interaction function rebalance(TradeKind kind) external notTradingPausedOrFrozen { main.assetRegistry().refresh(); - main.furnace().melt(); // DoS prevention: unless caller is self, require 1 empty block between like-kind auctions require( @@ -149,7 +148,6 @@ contract BackingManagerP0 is TradingP0, IBackingManager { require(ArrayLib.allUnique(erc20s), "duplicate tokens"); main.assetRegistry().refresh(); - main.furnace().melt(); require(tradesOpen == 0, "trade open"); require(main.basketHandler().isReady(), "basket not ready"); diff --git a/contracts/p0/Main.sol b/contracts/p0/Main.sol index 9493b72c5..e014ed657 100644 --- a/contracts/p0/Main.sol +++ b/contracts/p0/Main.sol @@ -38,7 +38,6 @@ contract MainP0 is Versioned, Initializable, Auth, ComponentRegistry, IMain { /// @custom:refresher function poke() external { assetRegistry.refresh(); - if (!frozen()) furnace.melt(); stRSR.payoutRewards(); // NOT basketHandler.refreshBasket } diff --git a/contracts/p1/BackingManager.sol b/contracts/p1/BackingManager.sol index a64ff3f41..20195c92a 100644 --- a/contracts/p1/BackingManager.sol +++ b/contracts/p1/BackingManager.sol @@ -113,7 +113,6 @@ contract BackingManagerP1 is TradingP1, IBackingManager { function rebalance(TradeKind kind) external nonReentrant notTradingPausedOrFrozen { // == Refresh == assetRegistry.refresh(); - furnace.melt(); // DoS prevention: unless caller is self, require 1 empty block between like-kind auctions require( @@ -184,7 +183,6 @@ contract BackingManagerP1 is TradingP1, IBackingManager { require(ArrayLib.allUnique(erc20s), "duplicate tokens"); assetRegistry.refresh(); - furnace.melt(); BasketRange memory basketsHeld = basketHandler.basketsHeldBy(address(this)); diff --git a/contracts/p1/Main.sol b/contracts/p1/Main.sol index 43bddcaed..42eb77ab0 100644 --- a/contracts/p1/Main.sol +++ b/contracts/p1/Main.sol @@ -46,7 +46,6 @@ contract MainP1 is Versioned, Initializable, Auth, ComponentRegistry, UUPSUpgrad assetRegistry.refresh(); // == CE block == - if (!frozen()) furnace.melt(); stRSR.payoutRewards(); } diff --git a/contracts/p1/RToken.sol b/contracts/p1/RToken.sol index 77f15bef5..cfbbdcd92 100644 --- a/contracts/p1/RToken.sol +++ b/contracts/p1/RToken.sol @@ -108,7 +108,6 @@ contract RTokenP1 is ComponentP1, ERC20PermitUpgradeable, IRToken { // == Refresh == assetRegistry.refresh(); - furnace.melt(); // == Checks-effects block == @@ -182,8 +181,6 @@ contract RTokenP1 is ComponentP1, ERC20PermitUpgradeable, IRToken { function redeemTo(address recipient, uint256 amount) public notFrozen { // == Refresh == assetRegistry.refresh(); - // solhint-disable-next-line no-empty-blocks - try furnace.melt() {} catch {} // nice for the redeemer, but not necessary // == Checks and Effects == @@ -254,8 +251,6 @@ contract RTokenP1 is ComponentP1, ERC20PermitUpgradeable, IRToken { ) external notFrozen { // == Refresh == assetRegistry.refresh(); - // solhint-disable-next-line no-empty-blocks - try furnace.melt() {} catch {} // nice for the redeemer, but not necessary // == Checks and Effects == diff --git a/contracts/p1/RevenueTrader.sol b/contracts/p1/RevenueTrader.sol index 1065fb96e..c716bc81a 100644 --- a/contracts/p1/RevenueTrader.sol +++ b/contracts/p1/RevenueTrader.sol @@ -123,10 +123,8 @@ contract RevenueTraderP1 is TradingP1, IRevenueTrader { IAsset assetToBuy = assetRegistry.toAsset(tokenToBuy); // Refresh everything if RToken is involved - if (involvesRToken) { - assetRegistry.refresh(); - furnace.melt(); - } else { + if (involvesRToken) assetRegistry.refresh(); + else { // Otherwise: refresh just the needed assets and nothing more for (uint256 i = 0; i < len; ++i) { assetRegistry.toAsset(erc20s[i]).refresh(); diff --git a/contracts/plugins/assets/RTokenAsset.sol b/contracts/plugins/assets/RTokenAsset.sol index 2dd0010f0..f187651e3 100644 --- a/contracts/plugins/assets/RTokenAsset.sol +++ b/contracts/plugins/assets/RTokenAsset.sol @@ -22,6 +22,7 @@ contract RTokenAsset is IAsset, VersionedAsset, IRTokenOracle { IBasketHandler public immutable basketHandler; IAssetRegistry public immutable assetRegistry; IBackingManager public immutable backingManager; + IFurnace public immutable furnace; IERC20Metadata public immutable erc20; @@ -41,6 +42,7 @@ contract RTokenAsset is IAsset, VersionedAsset, IRTokenOracle { basketHandler = main.basketHandler(); assetRegistry = main.assetRegistry(); backingManager = main.backingManager(); + furnace = main.furnace(); erc20 = IERC20Metadata(address(erc20_)); erc20Decimals = erc20_.decimals(); @@ -81,6 +83,9 @@ contract RTokenAsset is IAsset, VersionedAsset, IRTokenOracle { function refresh() public virtual override { // No need to save lastPrice; can piggyback off the backing collateral's saved prices + if (msg.sender != address(assetRegistry)) assetRegistry.refresh(); + furnace.melt(); + cachedOracleData.cachedAtTime = 0; // force oracle refresh } From 06a45a23efdbaa311528ada61a06ef1c2fc0588f Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Thu, 5 Oct 2023 20:34:10 -0400 Subject: [PATCH 02/12] gas snapshots --- test/__snapshots__/FacadeWrite.test.ts.snap | 2 +- test/__snapshots__/Main.test.ts.snap | 2 +- test/__snapshots__/RToken.test.ts.snap | 6 +-- .../Recollateralization.test.ts.snap | 12 ++--- test/__snapshots__/Revenues.test.ts.snap | 4 +- test/__snapshots__/ZZStRSR.test.ts.snap | 8 +-- .../ATokenFiatCollateral.test.ts.snap | 8 +-- .../StargateETHTestSuite.test.ts.snap | 49 ------------------- .../StargateUSDCTestSuite.test.ts.snap | 25 ++++++++++ .../__snapshots__/MaxBasketSize.test.ts.snap | 16 +++--- 10 files changed, 54 insertions(+), 78 deletions(-) delete mode 100644 test/plugins/individual-collateral/stargate/__snapshots__/StargateETHTestSuite.test.ts.snap create mode 100644 test/plugins/individual-collateral/stargate/__snapshots__/StargateUSDCTestSuite.test.ts.snap diff --git a/test/__snapshots__/FacadeWrite.test.ts.snap b/test/__snapshots__/FacadeWrite.test.ts.snap index 4b4c7894f..eab61beb0 100644 --- a/test/__snapshots__/FacadeWrite.test.ts.snap +++ b/test/__snapshots__/FacadeWrite.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`FacadeWrite contract Deployment Process Gas Reporting Phase 1 - RToken Deployment 1`] = `8497592`; +exports[`FacadeWrite contract Deployment Process Gas Reporting Phase 1 - RToken Deployment 1`] = `8571217`; exports[`FacadeWrite contract Deployment Process Gas Reporting Phase 2 - Deploy governance 1`] = `5464253`; diff --git a/test/__snapshots__/Main.test.ts.snap b/test/__snapshots__/Main.test.ts.snap index 9591a2762..cc8fbde0d 100644 --- a/test/__snapshots__/Main.test.ts.snap +++ b/test/__snapshots__/Main.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`MainP1 contract Gas Reporting Asset Registry - Refresh 1`] = `357740`; +exports[`MainP1 contract Gas Reporting Asset Registry - Refresh 1`] = `406142`; exports[`MainP1 contract Gas Reporting Asset Registry - Register Asset 1`] = `195889`; diff --git a/test/__snapshots__/RToken.test.ts.snap b/test/__snapshots__/RToken.test.ts.snap index ee00025ae..871294287 100644 --- a/test/__snapshots__/RToken.test.ts.snap +++ b/test/__snapshots__/RToken.test.ts.snap @@ -1,10 +1,10 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`RTokenP1 contract Gas Reporting Issuance: within block 1`] = `787553`; +exports[`RTokenP1 contract Gas Reporting Issuance: within block 1`] = `785463`; -exports[`RTokenP1 contract Gas Reporting Issuance: within block 2`] = `614557`; +exports[`RTokenP1 contract Gas Reporting Issuance: within block 2`] = `612467`; -exports[`RTokenP1 contract Gas Reporting Redemption 1`] = `589266`; +exports[`RTokenP1 contract Gas Reporting Redemption 1`] = `587171`; exports[`RTokenP1 contract Gas Reporting Transfer 1`] = `56658`; diff --git a/test/__snapshots__/Recollateralization.test.ts.snap b/test/__snapshots__/Recollateralization.test.ts.snap index 4222c553e..c564236f2 100644 --- a/test/__snapshots__/Recollateralization.test.ts.snap +++ b/test/__snapshots__/Recollateralization.test.ts.snap @@ -1,19 +1,19 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Recollateralization - P1 Gas Reporting rebalance() - DutchTrade 1`] = `1370490`; +exports[`Recollateralization - P1 Gas Reporting rebalance() - DutchTrade 1`] = `1368422`; -exports[`Recollateralization - P1 Gas Reporting rebalance() - DutchTrade 2`] = `1506234`; +exports[`Recollateralization - P1 Gas Reporting rebalance() - DutchTrade 2`] = `1504166`; -exports[`Recollateralization - P1 Gas Reporting rebalance() - DutchTrade 3`] = `760457`; +exports[`Recollateralization - P1 Gas Reporting rebalance() - DutchTrade 3`] = `745365`; -exports[`Recollateralization - P1 Gas Reporting rebalance() - GnosisTrade 1`] = `1665048`; +exports[`Recollateralization - P1 Gas Reporting rebalance() - GnosisTrade 1`] = `1662980`; exports[`Recollateralization - P1 Gas Reporting rebalance() - GnosisTrade 2`] = `174808`; -exports[`Recollateralization - P1 Gas Reporting rebalance() - GnosisTrade 3`] = `1607593`; +exports[`Recollateralization - P1 Gas Reporting rebalance() - GnosisTrade 3`] = `1605169`; exports[`Recollateralization - P1 Gas Reporting rebalance() - GnosisTrade 4`] = `174808`; -exports[`Recollateralization - P1 Gas Reporting rebalance() - GnosisTrade 5`] = `1695355`; +exports[`Recollateralization - P1 Gas Reporting rebalance() - GnosisTrade 5`] = `1693643`; exports[`Recollateralization - P1 Gas Reporting rebalance() - GnosisTrade 6`] = `202908`; diff --git a/test/__snapshots__/Revenues.test.ts.snap b/test/__snapshots__/Revenues.test.ts.snap index 4275db183..c51004924 100644 --- a/test/__snapshots__/Revenues.test.ts.snap +++ b/test/__snapshots__/Revenues.test.ts.snap @@ -12,11 +12,11 @@ exports[`Revenues - P1 Gas Reporting Claim and Sweep Rewards 5`] = `229377`; exports[`Revenues - P1 Gas Reporting Claim and Sweep Rewards 6`] = `212277`; -exports[`Revenues - P1 Gas Reporting Selling RToken 1`] = `1025829`; +exports[`Revenues - P1 Gas Reporting Selling RToken 1`] = `1023827`; exports[`Revenues - P1 Gas Reporting Settle Trades / Manage Funds 1`] = `774070`; -exports[`Revenues - P1 Gas Reporting Settle Trades / Manage Funds 2`] = `1181105`; +exports[`Revenues - P1 Gas Reporting Settle Trades / Manage Funds 2`] = `1179125`; exports[`Revenues - P1 Gas Reporting Settle Trades / Manage Funds 3`] = `311446`; diff --git a/test/__snapshots__/ZZStRSR.test.ts.snap b/test/__snapshots__/ZZStRSR.test.ts.snap index f4ec1f241..61e4ce620 100644 --- a/test/__snapshots__/ZZStRSR.test.ts.snap +++ b/test/__snapshots__/ZZStRSR.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`StRSRP1 contract Gas Reporting Stake 1`] = `156559`; +exports[`StRSRP1 contract Gas Reporting Stake 1`] = `139717`; exports[`StRSRP1 contract Gas Reporting Stake 2`] = `134917`; @@ -10,10 +10,10 @@ exports[`StRSRP1 contract Gas Reporting Transfer 2`] = `41509`; exports[`StRSRP1 contract Gas Reporting Transfer 3`] = `58621`; -exports[`StRSRP1 contract Gas Reporting Unstake 1`] = `241951`; +exports[`StRSRP1 contract Gas Reporting Unstake 1`] = `222609`; exports[`StRSRP1 contract Gas Reporting Unstake 2`] = `139758`; -exports[`StRSRP1 contract Gas Reporting Withdraw 1`] = `572112`; +exports[`StRSRP1 contract Gas Reporting Withdraw 1`] = `609578`; -exports[`StRSRP1 contract Gas Reporting Withdraw 2`] = `526116`; +exports[`StRSRP1 contract Gas Reporting Withdraw 2`] = `539716`; diff --git a/test/plugins/individual-collateral/aave/__snapshots__/ATokenFiatCollateral.test.ts.snap b/test/plugins/individual-collateral/aave/__snapshots__/ATokenFiatCollateral.test.ts.snap index 70324e7f4..579773bc8 100644 --- a/test/plugins/individual-collateral/aave/__snapshots__/ATokenFiatCollateral.test.ts.snap +++ b/test/plugins/individual-collateral/aave/__snapshots__/ATokenFiatCollateral.test.ts.snap @@ -14,12 +14,12 @@ exports[`ATokenFiatCollateral - Mainnet Forking P1 Gas Reporting refresh() after exports[`ATokenFiatCollateral - Mainnet Forking P1 Gas Reporting refresh() after soft default 1`] = `91147`; -exports[`ATokenFiatCollateral - Mainnet Forking P1 Gas Reporting refresh() after soft default 2`] = `91073`; +exports[`ATokenFiatCollateral - Mainnet Forking P1 Gas Reporting refresh() after soft default 2`] = `91147`; -exports[`ATokenFiatCollateral - Mainnet Forking P1 Gas Reporting refresh() during SOUND 1`] = `92285`; +exports[`ATokenFiatCollateral - Mainnet Forking P1 Gas Reporting refresh() during SOUND 1`] = `92211`; -exports[`ATokenFiatCollateral - Mainnet Forking P1 Gas Reporting refresh() during SOUND 2`] = `92211`; +exports[`ATokenFiatCollateral - Mainnet Forking P1 Gas Reporting refresh() during SOUND 2`] = `92285`; exports[`ATokenFiatCollateral - Mainnet Forking P1 Gas Reporting refresh() during soft default 1`] = `127356`; -exports[`ATokenFiatCollateral - Mainnet Forking P1 Gas Reporting refresh() during soft default 2`] = `91414`; +exports[`ATokenFiatCollateral - Mainnet Forking P1 Gas Reporting refresh() during soft default 2`] = `91488`; diff --git a/test/plugins/individual-collateral/stargate/__snapshots__/StargateETHTestSuite.test.ts.snap b/test/plugins/individual-collateral/stargate/__snapshots__/StargateETHTestSuite.test.ts.snap deleted file mode 100644 index 3eb694220..000000000 --- a/test/plugins/individual-collateral/stargate/__snapshots__/StargateETHTestSuite.test.ts.snap +++ /dev/null @@ -1,49 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Collateral: Stargate ETH Pool collateral functionality Gas Reporting refresh() after full price timeout 1`] = `55263`; - -exports[`Collateral: Stargate ETH Pool collateral functionality Gas Reporting refresh() after full price timeout 2`] = `50795`; - -exports[`Collateral: Stargate ETH Pool collateral functionality Gas Reporting refresh() after hard default 1`] = `68999`; - -exports[`Collateral: Stargate ETH Pool collateral functionality Gas Reporting refresh() after hard default 2`] = `66385`; - -exports[`Collateral: Stargate ETH Pool collateral functionality Gas Reporting refresh() after oracle timeout 1`] = `55263`; - -exports[`Collateral: Stargate ETH Pool collateral functionality Gas Reporting refresh() after oracle timeout 2`] = `50795`; - -exports[`Collateral: Stargate ETH Pool collateral functionality Gas Reporting refresh() after soft default 1`] = `50454`; - -exports[`Collateral: Stargate ETH Pool collateral functionality Gas Reporting refresh() after soft default 2`] = `50454`; - -exports[`Collateral: Stargate ETH Pool collateral functionality Gas Reporting refresh() during SOUND 1`] = `66260`; - -exports[`Collateral: Stargate ETH Pool collateral functionality Gas Reporting refresh() during SOUND 2`] = `66260`; - -exports[`Collateral: Stargate ETH Pool collateral functionality Gas Reporting refresh() during soft default 1`] = `73810`; - -exports[`Collateral: Stargate ETH Pool collateral functionality Gas Reporting refresh() during soft default 2`] = `66542`; - -exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() after full price timeout 1`] = `55263`; - -exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() after full price timeout 2`] = `50795`; - -exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() after hard default 1`] = `68999`; - -exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() after hard default 2`] = `66385`; - -exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() after oracle timeout 1`] = `55263`; - -exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() after oracle timeout 2`] = `50795`; - -exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() after soft default 1`] = `50454`; - -exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() after soft default 2`] = `50454`; - -exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() during SOUND 1`] = `66260`; - -exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() during SOUND 2`] = `66260`; - -exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() during soft default 1`] = `73810`; - -exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() during soft default 2`] = `66542`; diff --git a/test/plugins/individual-collateral/stargate/__snapshots__/StargateUSDCTestSuite.test.ts.snap b/test/plugins/individual-collateral/stargate/__snapshots__/StargateUSDCTestSuite.test.ts.snap new file mode 100644 index 000000000..fc27356e8 --- /dev/null +++ b/test/plugins/individual-collateral/stargate/__snapshots__/StargateUSDCTestSuite.test.ts.snap @@ -0,0 +1,25 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() after full price timeout 1`] = `56094`; + +exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() after full price timeout 2`] = `51626`; + +exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() after hard default 1`] = `74579`; + +exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() after hard default 2`] = `66897`; + +exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() after oracle timeout 1`] = `56094`; + +exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() after oracle timeout 2`] = `51626`; + +exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() after soft default 1`] = `51285`; + +exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() after soft default 2`] = `51285`; + +exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() during SOUND 1`] = `66894`; + +exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() during SOUND 2`] = `66894`; + +exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() during soft default 1`] = `74444`; + +exports[`Collateral: Stargate USDC Pool collateral functionality Gas Reporting refresh() during soft default 2`] = `67176`; diff --git a/test/scenario/__snapshots__/MaxBasketSize.test.ts.snap b/test/scenario/__snapshots__/MaxBasketSize.test.ts.snap index fa7f07dd1..85d4622d4 100644 --- a/test/scenario/__snapshots__/MaxBasketSize.test.ts.snap +++ b/test/scenario/__snapshots__/MaxBasketSize.test.ts.snap @@ -1,19 +1,19 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Max Basket Size - P1 ATokens/CTokens Should Issue/Redeem with max basket correctly 1`] = `12090932`; +exports[`Max Basket Size - P1 ATokens/CTokens Should Issue/Redeem with max basket correctly 1`] = `12085598`; -exports[`Max Basket Size - P1 ATokens/CTokens Should Issue/Redeem with max basket correctly 2`] = `9829293`; +exports[`Max Basket Size - P1 ATokens/CTokens Should Issue/Redeem with max basket correctly 2`] = `9827198`; exports[`Max Basket Size - P1 ATokens/CTokens Should claim rewards correctly 1`] = `2281990`; -exports[`Max Basket Size - P1 ATokens/CTokens Should switch basket correctly 1`] = `13615367`; +exports[`Max Basket Size - P1 ATokens/CTokens Should switch basket correctly 1`] = `13658589`; -exports[`Max Basket Size - P1 ATokens/CTokens Should switch basket correctly 2`] = `20701409`; +exports[`Max Basket Size - P1 ATokens/CTokens Should switch basket correctly 2`] = `20693277`; -exports[`Max Basket Size - P1 Fiatcoins Should Issue/Redeem with max basket correctly 1`] = `10991970`; +exports[`Max Basket Size - P1 Fiatcoins Should Issue/Redeem with max basket correctly 1`] = `10987348`; -exports[`Max Basket Size - P1 Fiatcoins Should Issue/Redeem with max basket correctly 2`] = `8713193`; +exports[`Max Basket Size - P1 Fiatcoins Should Issue/Redeem with max basket correctly 2`] = `8711098`; -exports[`Max Basket Size - P1 Fiatcoins Should switch basket correctly 1`] = `6561514`; +exports[`Max Basket Size - P1 Fiatcoins Should switch basket correctly 1`] = `6596661`; -exports[`Max Basket Size - P1 Fiatcoins Should switch basket correctly 2`] = `14454943`; +exports[`Max Basket Size - P1 Fiatcoins Should switch basket correctly 2`] = `14446099`; From 440cd91ccde5f7438bd850de11d1ab7c54d11dd3 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Fri, 6 Oct 2023 14:03:43 -0400 Subject: [PATCH 03/12] make furnace.melt() succeed while frozen --- contracts/facade/FacadeRead.sol | 2 +- contracts/p0/Furnace.sol | 12 +++--------- contracts/p0/Main.sol | 2 +- contracts/p1/Furnace.sol | 12 +++--------- contracts/p1/Main.sol | 2 +- 5 files changed, 9 insertions(+), 21 deletions(-) diff --git a/contracts/facade/FacadeRead.sol b/contracts/facade/FacadeRead.sol index 7faf0bc35..a42d5c613 100644 --- a/contracts/facade/FacadeRead.sol +++ b/contracts/facade/FacadeRead.sol @@ -199,7 +199,7 @@ contract FacadeRead is IFacadeRead { IBasketHandler basketHandler = rToken.main().basketHandler(); // solhint-disable-next-line no-empty-blocks - try rToken.main().furnace().melt() {} catch {} + try rToken.main().furnace().melt() {} catch {} // <3.1.0 RTokens may revert while frozen (erc20s, deposits) = basketHandler.quote(FIX_ONE, CEIL); diff --git a/contracts/p0/Furnace.sol b/contracts/p0/Furnace.sol index aa99a8140..ea0a404a2 100644 --- a/contracts/p0/Furnace.sol +++ b/contracts/p0/Furnace.sol @@ -36,7 +36,7 @@ contract FurnaceP0 is ComponentP0, IFurnace { /// Performs any melting that has vested since last call. /// @custom:refresher - function melt() public notFrozen { + function melt() public { if (uint48(block.timestamp) < uint64(lastPayout) + PERIOD) return; // # of whole periods that have passed since lastPayout @@ -58,15 +58,9 @@ contract FurnaceP0 is ComponentP0, IFurnace { /// Ratio setting /// @custom:governance function setRatio(uint192 ratio_) public governance { - if (lastPayout > 0) { - // solhint-disable-next-line no-empty-blocks - try this.melt() {} catch { - uint48 numPeriods = uint48((block.timestamp) - lastPayout) / PERIOD; - lastPayout += numPeriods * PERIOD; - lastPayoutBal = main.rToken().balanceOf(address(this)); - } - } require(ratio_ <= MAX_RATIO, "invalid ratio"); + melt(); // cannot revert + // The ratio can safely be set to 0, though it is not recommended emit RatioSet(ratio, ratio_); ratio = ratio_; diff --git a/contracts/p0/Main.sol b/contracts/p0/Main.sol index e014ed657..1859ad8ec 100644 --- a/contracts/p0/Main.sol +++ b/contracts/p0/Main.sol @@ -37,7 +37,7 @@ contract MainP0 is Versioned, Initializable, Auth, ComponentRegistry, IMain { /// @custom:refresher function poke() external { - assetRegistry.refresh(); + assetRegistry.refresh(); // runs furnace.melt() stRSR.payoutRewards(); // NOT basketHandler.refreshBasket } diff --git a/contracts/p1/Furnace.sol b/contracts/p1/Furnace.sol index 923ba3373..63dcc695d 100644 --- a/contracts/p1/Furnace.sol +++ b/contracts/p1/Furnace.sol @@ -71,7 +71,7 @@ contract FurnaceP1 is ComponentP1, IFurnace { // actions: // rToken.melt(payoutAmount), paying payoutAmount to RToken holders - function melt() external notFrozen { + function melt() public { if (uint48(block.timestamp) < uint64(lastPayout) + PERIOD) return; // # of whole periods that have passed since lastPayout @@ -90,15 +90,9 @@ contract FurnaceP1 is ComponentP1, IFurnace { /// Ratio setting /// @custom:governance function setRatio(uint192 ratio_) public governance { - if (lastPayout > 0) { - // solhint-disable-next-line no-empty-blocks - try this.melt() {} catch { - uint48 numPeriods = uint48((block.timestamp) - lastPayout) / PERIOD; - lastPayout += numPeriods * PERIOD; - lastPayoutBal = rToken.balanceOf(address(this)); - } - } require(ratio_ <= MAX_RATIO, "invalid ratio"); + melt(); // cannot revert + // The ratio can safely be set to 0 to turn off payouts, though it is not recommended emit RatioSet(ratio, ratio_); ratio = ratio_; diff --git a/contracts/p1/Main.sol b/contracts/p1/Main.sol index 42eb77ab0..21781ca08 100644 --- a/contracts/p1/Main.sol +++ b/contracts/p1/Main.sol @@ -43,7 +43,7 @@ contract MainP1 is Versioned, Initializable, Auth, ComponentRegistry, UUPSUpgrad /// @dev Not intended to be used in production, only for equivalence with P0 function poke() external { // == Refresher == - assetRegistry.refresh(); + assetRegistry.refresh(); // runs furnace.melt() // == CE block == stRSR.payoutRewards(); From ba13fe159b98518b35bdf99496f301c2b06610d1 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Fri, 6 Oct 2023 14:03:52 -0400 Subject: [PATCH 04/12] adjust furnace regression test --- test/Furnace.test.ts | 49 +++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/test/Furnace.test.ts b/test/Furnace.test.ts index 15776210b..84d16f32c 100644 --- a/test/Furnace.test.ts +++ b/test/Furnace.test.ts @@ -204,9 +204,9 @@ describe(`FurnaceP${IMPLEMENTATION} contract`, () => { await furnace.connect(addr1).melt() }) - it('Should not melt if frozen #fast', async () => { + it('Should melt if frozen #fast', async () => { await main.connect(owner).freezeShort() - await expect(furnace.connect(addr1).melt()).to.be.revertedWith('frozen') + await furnace.connect(addr1).melt() }) it('Should not melt any funds in the initial block #fast', async () => { @@ -450,40 +450,57 @@ describe(`FurnaceP${IMPLEMENTATION} contract`, () => { it('Regression test -- C4 June 2023 Issue #29', async () => { // https://github.com/code-423n4/2023-06-reserve-findings/issues/29 + const firstRatio = fp('1e-6') + const secondRatio = fp('1e-4') + const mintAmount = fp('100') + + // Set ratio to something cleaner + await expect(furnace.connect(owner).setRatio(firstRatio)) + .to.emit(furnace, 'RatioSet') + .withArgs(config.rewardRatio, firstRatio) + // Transfer to Furnace and do first melt - await rToken.connect(addr1).transfer(furnace.address, bn('10e18')) + await rToken.connect(addr1).transfer(furnace.address, mintAmount) await setNextBlockTimestamp(Number(await getLatestBlockTimestamp()) + Number(ONE_PERIOD)) await furnace.melt() // Should have updated lastPayout + lastPayoutBal expect(await furnace.lastPayout()).to.be.closeTo(await getLatestBlockTimestamp(), 12) expect(await furnace.lastPayout()).to.be.lte(await getLatestBlockTimestamp()) - expect(await furnace.lastPayoutBal()).to.equal(bn('10e18')) + expect(await furnace.lastPayoutBal()).to.equal(mintAmount) - // Advance 99 periods -- should melt at old ratio - await setNextBlockTimestamp(Number(await getLatestBlockTimestamp()) + 99 * Number(ONE_PERIOD)) + // Advance 100 periods -- should melt at old ratio + await setNextBlockTimestamp( + Number(await getLatestBlockTimestamp()) + 100 * Number(ONE_PERIOD) + ) - // Freeze and change ratio + // Freeze and change ratio (melting as a pre-step) await main.connect(owner).freezeForever() - const maxRatio = bn('1e14') - await expect(furnace.connect(owner).setRatio(maxRatio)) + await expect(furnace.connect(owner).setRatio(secondRatio)) .to.emit(furnace, 'RatioSet') - .withArgs(config.rewardRatio, maxRatio) + .withArgs(firstRatio, secondRatio) - // Should have updated lastPayout + lastPayoutBal + // Should have melted expect(await furnace.lastPayout()).to.be.closeTo(await getLatestBlockTimestamp(), 12) expect(await furnace.lastPayout()).to.be.lte(await getLatestBlockTimestamp()) - expect(await furnace.lastPayoutBal()).to.equal(bn('10e18')) // no change + expect(await furnace.lastPayoutBal()).to.eq(fp('99.990000494983830300')) - // Unfreeze and advance 1 period + // Unfreeze and advance 100 periods await main.connect(owner).unfreeze() - await setNextBlockTimestamp(Number(await getLatestBlockTimestamp()) + Number(ONE_PERIOD)) + await setNextBlockTimestamp( + Number(await getLatestBlockTimestamp()) + 100 * Number(ONE_PERIOD) + ) await expect(furnace.melt()).to.emit(rToken, 'Melted') - // Should have updated lastPayout + lastPayoutBal + // Should have updated lastPayout + lastPayoutBal and melted at new ratio expect(await furnace.lastPayout()).to.be.closeTo(await getLatestBlockTimestamp(), 12) expect(await furnace.lastPayout()).to.be.lte(await getLatestBlockTimestamp()) - expect(await furnace.lastPayoutBal()).to.equal(bn('9.999e18')) + expect(await furnace.lastPayoutBal()).to.equal(fp('98.995033865808581644')) + // if the ratio were not increased 100x, this would be more like 99.980001989868666200 + + // Total supply should have decreased by the cumulative melted amount + expect(await rToken.totalSupply()).to.equal(mintAmount.add(await furnace.lastPayoutBal())) + expect(await rToken.basketsNeeded()).to.equal(mintAmount.mul(2)) }) }) From 7665a3b9d1c6ce0cba9c00f0565c707e61c364c6 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Fri, 6 Oct 2023 14:14:34 -0400 Subject: [PATCH 05/12] nit: fix comment in interface --- contracts/interfaces/IAssetRegistry.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/interfaces/IAssetRegistry.sol b/contracts/interfaces/IAssetRegistry.sol index caeaac2f3..add18d69b 100644 --- a/contracts/interfaces/IAssetRegistry.sol +++ b/contracts/interfaces/IAssetRegistry.sol @@ -34,7 +34,7 @@ interface IAssetRegistry is IComponent { function init(IMain main_, IAsset[] memory assets_) external; /// Fully refresh all asset state - /// @custom:interaction + /// @custom:refresher function refresh() external; /// Register `asset` From 451fd37032a1f0cf987e13e00eec43433d0ff809 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Fri, 6 Oct 2023 15:04:12 -0400 Subject: [PATCH 06/12] nit: comment --- contracts/p1/AssetRegistry.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/p1/AssetRegistry.sol b/contracts/p1/AssetRegistry.sol index 098e47f93..c556a9612 100644 --- a/contracts/p1/AssetRegistry.sol +++ b/contracts/p1/AssetRegistry.sol @@ -57,6 +57,8 @@ contract AssetRegistryP1 is ComponentP1, IAssetRegistry { // tracks basket status on basketHandler function refresh() public { // It's a waste of gas to require notPausedOrFrozen because assets can be updated directly + // Assuming an RTokenAsset is registered, furnace.melt() will also be called + uint256 length = _erc20s.length(); for (uint256 i = 0; i < length; ++i) { assets[IERC20(_erc20s.at(i))].refresh(); From eadcfe16336daa49639c5a2aea7dd2fae4b32a63 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Fri, 6 Oct 2023 15:04:23 -0400 Subject: [PATCH 07/12] docs: new pause freeze doc with table --- CHANGELOG.md | 4 +- README.md | 1 + docs/pause-freeze-states.md | 73 +++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 docs/pause-freeze-states.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 95af3e13a..1b73a106a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Upgrade Steps -- Required -Upgrade `BackingManager`, `Broker`, and _all_ assets. ERC20s do not need to be upgraded. +Upgrade all core contracts and _all_ assets. ERC20s do not need to be upgraded. Use `Deployer.deployRTokenAsset()` to create a new `RTokenAsset` instance. This asset should be swapped too. Then, call `Broker.cacheComponents()`. @@ -16,6 +16,8 @@ Then, call `Broker.cacheComponents()`. - Remove `lotPrice()` - `Broker` [+1 slot] - Disallow starting dutch trades with non-RTokenAsset assets when `lastSave() != block.timestamp` +- `Furnace` + - Allow melting while frozen ## Plugins diff --git a/README.md b/README.md index 1c569eb49..e8ab78fae 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ For a much more detailed explanation of the economic design, including an hour-l - [Testing with Echidna](https://github.com/reserve-protocol/protocol/blob/master/docs/using-echidna.md): Notes so far on setup and usage of Echidna (which is decidedly an integration-in-progress!) - [Deployment](https://github.com/reserve-protocol/protocol/blob/master/docs/deployment.md): How to do test deployments in our environment. - [System Design](https://github.com/reserve-protocol/protocol/blob/master/docs/system-design.md): The overall architecture of our system, and some detailed descriptions about what our protocol is _intended_ to do. +- [Pause and Freeze States](https://github.com/reserve-protocol/protocol/blob/master/docs/pause-freeze-states.md): An overview of which protocol functions are halted in the paused and frozen states. - [Deployment Variables](https://github.com/reserve-protocol/protocol/blob/master/docs/deployment-variables.md) A detailed description of the governance variables of the protocol. - [Our Solidity Style](https://github.com/reserve-protocol/protocol/blob/master/docs/solidity-style.md): Common practices, details, and conventions relevant to reading and writing our Solidity source code, estpecially where those go beyond standard practice. - [Writing Collateral Plugins](https://github.com/reserve-protocol/protocol/blob/master/docs/collateral.md): An overview of how to develop collateral plugins and the concepts / questions involved. diff --git a/docs/pause-freeze-states.md b/docs/pause-freeze-states.md new file mode 100644 index 000000000..009ab64b2 --- /dev/null +++ b/docs/pause-freeze-states.md @@ -0,0 +1,73 @@ +# Pause Freeze States + +Some protocol functions may be halted while the protocol is either (i) issuance-paused; (ii) trading-paused; or (iii) frozen. Below is a table that shows which protocol interactions (`@custom:interaction`) and refreshers (`@custom:refresher`) execute during paused/frozen states, as of the 3.1.0 release. + +All governance functions (`@custom:governance`) remain enabled during all paused/frozen states. They are not mentioned here. + +A :heavy_check_mark: indicates the function still executes in this state. +A :x: indicates it reverts. + +| Function | Issuance-Paused | Trading-Paused | Frozen | +| --------------------------------------- | ------------------ | ----------------------- | ----------------------- | +| `BackingManager.claimRewards()` | :heavy_check_mark: | :x: | :x: | +| `BackingManager.claimRewardsSingle()` | :heavy_check_mark: | :x: | :x: | +| `BackingManager.grantRTokenAllowance()` | :heavy_check_mark: | :heavy_check_mark: | :x: | +| `BackingManager.forwardRevenue()` | :heavy_check_mark: | :x: | :x: | +| `BackingManager.rebalance()` | :heavy_check_mark: | :x: | :x: | +| `BackingManager.settleTrade()` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | +| `BasketHandler.refreshBasket()` | :heavy_check_mark: | :x: (unless governance) | :x: (unless governance) | +| `Broker.openTrade()` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | +| `Broker.reportViolation()` | :heavy_check_mark: | :x: | :x: | +| `Distributor.distribute()` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | +| `Furnace.melt()` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | +| `Main.poke()` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | +| `RevenueTrader.claimRewards()` | :heavy_check_mark: | :x: | :x: | +| `RevenueTrader.claimRewardsSingle()` | :heavy_check_mark: | :x: | :x: | +| `RevenueTrader.distributeTokenToBuy()` | :heavy_check_mark: | :x: | :x: | +| `RevenueTrader.manageTokens()` | :heavy_check_mark: | :x: | :x: | +| `RevenueTrader.returnTokens()` | :heavy_check_mark: | :x: | :x: | +| `RevenueTrader.settleTrade()` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | +| `RToken.issue()` | :x: | :heavy_check_mark: | :x: | +| `RToken.issueTo()` | :x: | :heavy_check_mark: | :x: | +| `RToken.redeem()` | :heavy_check_mark: | :heavy_check_mark: | :x: | +| `RToken.redeemTo()` | :heavy_check_mark: | :heavy_check_mark: | :x: | +| `RToken.redeemCustom()` | :heavy_check_mark: | :heavy_check_mark: | :x: | +| `StRSR.cancelUnstake()` | :heavy_check_mark: | :heavy_check_mark: | :x: | +| `StRSR.payoutRewards()` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | +| `StRSR.stake()` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | +| `StRSR.seizeRSR()` | :heavy_check_mark: | :x: | :x: | +| `StRSR.unstake()` | :heavy_check_mark: | :x: | :x: | +| `StRSR.withdraw()` | :heavy_check_mark: | :x: | :x: | + +## Issuance-pause + +The issuance-paused states indicates that RToken issuance should be paused, and _only_ that. It is a narrow control knob that is designed solely to protect against a case where bad debt is being injected into the protocol, say, because default detection for an asset has a false negative. + +## Trading-pause + +The trading-paused state has significantly more scope than the issuance-paused state. It is designed to prevent against cases where the protocol may trade unneccesarily. Many other functions in addition to just `BackingManager.rebalance()` and `RevenueTrader.manageTokens()` are halted. In general anything that manages the backing and revenue for an RToken is halted. This may become neccessary to use due to (among other things): + +- An asset's `price()` malfunctions or is manipulated +- A collateral's default detection has a false positive or negative + +## Freezing + +The scope of freezing is the largest, and it should be used least frequently. Nearly all protocol interactions (`@custom:interaction`) are halted. Any refreshers (`@custom:refresher`) remain enabled, as well as `StRSR.stake()` and the "wrap up" routine `*.settleTrade()`. + +An important function of freezing is to provide a finite time for governance to push through a repair proposal an RToken in the event that a 0-day is discovered that requires a contract upgrade. + +### `Furnace.melt()` + +It is necessary for `Furnace.melt()` to remain emabled in order to allow `RTokenAsset.refresh()` to update its `price()`. Any revenue RToken that has already accumulated at the Furnace will continue to be melted, but the flow of new revenue RToken into the contract is halted. + +### `StRSR.payoutRewards()` + +It is necessary for `StRSR.payoutRewards()` to remain enabled in order for `StRSR.stake()` to use the up-to-date StRSR-RSR exchange rate. If it did not, then in the event of freezing there would be an unfair benefit to new stakers. Any revenue RSR that has already accumulated at the StRSR contract will continue to be paid out, but the flow of new revenue RSR into the contract is halted. + +### `StRSR.stake()` + +It is important for `StRSR.stake()` to remain emabled while frozen in order to allow honest RSR to flow into an RToken to vote against malicious governance proposals. + +### `*.settleTrade()` + +The settleTrade functionality must remain enabled in order to maintain the property that dutch auctions will discover the optimal price. If settleTrade were halted, it could become possible for a dutch auction to clear at a much lower price than it should have, simply because bidding was disabled during the earlier portion of the auction. From b0b3cff310607aac78f10a8d73125e2c6e2c3750 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Fri, 6 Oct 2023 18:06:33 -0400 Subject: [PATCH 08/12] gas snapshots --- test/__snapshots__/FacadeWrite.test.ts.snap | 2 +- test/__snapshots__/Furnace.test.ts.snap | 34 +++++++++---------- test/__snapshots__/Main.test.ts.snap | 2 +- test/__snapshots__/RToken.test.ts.snap | 6 ++-- .../Recollateralization.test.ts.snap | 12 +++---- test/__snapshots__/Revenues.test.ts.snap | 4 +-- test/__snapshots__/ZZStRSR.test.ts.snap | 4 +-- .../SDaiCollateralTestSuite.test.ts.snap | 2 +- .../__snapshots__/MaxBasketSize.test.ts.snap | 16 ++++----- 9 files changed, 41 insertions(+), 41 deletions(-) diff --git a/test/__snapshots__/FacadeWrite.test.ts.snap b/test/__snapshots__/FacadeWrite.test.ts.snap index eab61beb0..143651b3a 100644 --- a/test/__snapshots__/FacadeWrite.test.ts.snap +++ b/test/__snapshots__/FacadeWrite.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`FacadeWrite contract Deployment Process Gas Reporting Phase 1 - RToken Deployment 1`] = `8571217`; +exports[`FacadeWrite contract Deployment Process Gas Reporting Phase 1 - RToken Deployment 1`] = `8572904`; exports[`FacadeWrite contract Deployment Process Gas Reporting Phase 2 - Deploy governance 1`] = `5464253`; diff --git a/test/__snapshots__/Furnace.test.ts.snap b/test/__snapshots__/Furnace.test.ts.snap index af06969a2..e905f3eec 100644 --- a/test/__snapshots__/Furnace.test.ts.snap +++ b/test/__snapshots__/Furnace.test.ts.snap @@ -1,35 +1,35 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`FurnaceP1 contract Gas Reporting Melt - A million periods, all at once 1`] = `83931`; +exports[`FurnaceP1 contract Gas Reporting Melt - A million periods, all at once 1`] = `71626`; -exports[`FurnaceP1 contract Gas Reporting Melt - A million periods, all at once 2`] = `89820`; +exports[`FurnaceP1 contract Gas Reporting Melt - A million periods, all at once 2`] = `77515`; -exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 1`] = `83931`; +exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 1`] = `71626`; -exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 2`] = `78303`; +exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 2`] = `65998`; -exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 3`] = `78303`; +exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 3`] = `65998`; -exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 4`] = `78303`; +exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 4`] = `65998`; -exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 5`] = `78303`; +exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 5`] = `65998`; -exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 6`] = `78303`; +exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 6`] = `65998`; -exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 7`] = `78303`; +exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 7`] = `65998`; -exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 8`] = `78303`; +exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 8`] = `65998`; -exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 9`] = `78303`; +exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 9`] = `65998`; -exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 10`] = `78303`; +exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 10`] = `65998`; -exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 11`] = `78303`; +exports[`FurnaceP1 contract Gas Reporting Melt - Many periods, one after the other 11`] = `65998`; -exports[`FurnaceP1 contract Gas Reporting Melt - One period 1`] = `64031`; +exports[`FurnaceP1 contract Gas Reporting Melt - One period 1`] = `51726`; -exports[`FurnaceP1 contract Gas Reporting Melt - One period 2`] = `80663`; +exports[`FurnaceP1 contract Gas Reporting Melt - One period 2`] = `68358`; -exports[`FurnaceP1 contract Gas Reporting Melt - One period 3`] = `78303`; +exports[`FurnaceP1 contract Gas Reporting Melt - One period 3`] = `65998`; -exports[`FurnaceP1 contract Gas Reporting Melt - One period 4`] = `40761`; +exports[`FurnaceP1 contract Gas Reporting Melt - One period 4`] = `28452`; diff --git a/test/__snapshots__/Main.test.ts.snap b/test/__snapshots__/Main.test.ts.snap index cc8fbde0d..ffecb35bc 100644 --- a/test/__snapshots__/Main.test.ts.snap +++ b/test/__snapshots__/Main.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`MainP1 contract Gas Reporting Asset Registry - Refresh 1`] = `406142`; +exports[`MainP1 contract Gas Reporting Asset Registry - Refresh 1`] = `393837`; exports[`MainP1 contract Gas Reporting Asset Registry - Register Asset 1`] = `195889`; diff --git a/test/__snapshots__/RToken.test.ts.snap b/test/__snapshots__/RToken.test.ts.snap index 871294287..c725eeb99 100644 --- a/test/__snapshots__/RToken.test.ts.snap +++ b/test/__snapshots__/RToken.test.ts.snap @@ -1,10 +1,10 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`RTokenP1 contract Gas Reporting Issuance: within block 1`] = `785463`; +exports[`RTokenP1 contract Gas Reporting Issuance: within block 1`] = `782158`; -exports[`RTokenP1 contract Gas Reporting Issuance: within block 2`] = `612467`; +exports[`RTokenP1 contract Gas Reporting Issuance: within block 2`] = `609158`; -exports[`RTokenP1 contract Gas Reporting Redemption 1`] = `587171`; +exports[`RTokenP1 contract Gas Reporting Redemption 1`] = `583862`; exports[`RTokenP1 contract Gas Reporting Transfer 1`] = `56658`; diff --git a/test/__snapshots__/Recollateralization.test.ts.snap b/test/__snapshots__/Recollateralization.test.ts.snap index c564236f2..ddde5b4fe 100644 --- a/test/__snapshots__/Recollateralization.test.ts.snap +++ b/test/__snapshots__/Recollateralization.test.ts.snap @@ -1,19 +1,19 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Recollateralization - P1 Gas Reporting rebalance() - DutchTrade 1`] = `1368422`; +exports[`Recollateralization - P1 Gas Reporting rebalance() - DutchTrade 1`] = `1365473`; -exports[`Recollateralization - P1 Gas Reporting rebalance() - DutchTrade 2`] = `1504166`; +exports[`Recollateralization - P1 Gas Reporting rebalance() - DutchTrade 2`] = `1500861`; -exports[`Recollateralization - P1 Gas Reporting rebalance() - DutchTrade 3`] = `745365`; +exports[`Recollateralization - P1 Gas Reporting rebalance() - DutchTrade 3`] = `755062`; -exports[`Recollateralization - P1 Gas Reporting rebalance() - GnosisTrade 1`] = `1662980`; +exports[`Recollateralization - P1 Gas Reporting rebalance() - GnosisTrade 1`] = `1659319`; exports[`Recollateralization - P1 Gas Reporting rebalance() - GnosisTrade 2`] = `174808`; -exports[`Recollateralization - P1 Gas Reporting rebalance() - GnosisTrade 3`] = `1605169`; +exports[`Recollateralization - P1 Gas Reporting rebalance() - GnosisTrade 3`] = `1602220`; exports[`Recollateralization - P1 Gas Reporting rebalance() - GnosisTrade 4`] = `174808`; -exports[`Recollateralization - P1 Gas Reporting rebalance() - GnosisTrade 5`] = `1693643`; +exports[`Recollateralization - P1 Gas Reporting rebalance() - GnosisTrade 5`] = `1689982`; exports[`Recollateralization - P1 Gas Reporting rebalance() - GnosisTrade 6`] = `202908`; diff --git a/test/__snapshots__/Revenues.test.ts.snap b/test/__snapshots__/Revenues.test.ts.snap index c51004924..bb7a77e72 100644 --- a/test/__snapshots__/Revenues.test.ts.snap +++ b/test/__snapshots__/Revenues.test.ts.snap @@ -12,11 +12,11 @@ exports[`Revenues - P1 Gas Reporting Claim and Sweep Rewards 5`] = `229377`; exports[`Revenues - P1 Gas Reporting Claim and Sweep Rewards 6`] = `212277`; -exports[`Revenues - P1 Gas Reporting Selling RToken 1`] = `1023827`; +exports[`Revenues - P1 Gas Reporting Selling RToken 1`] = `1020522`; exports[`Revenues - P1 Gas Reporting Settle Trades / Manage Funds 1`] = `774070`; -exports[`Revenues - P1 Gas Reporting Settle Trades / Manage Funds 2`] = `1179125`; +exports[`Revenues - P1 Gas Reporting Settle Trades / Manage Funds 2`] = `1175816`; exports[`Revenues - P1 Gas Reporting Settle Trades / Manage Funds 3`] = `311446`; diff --git a/test/__snapshots__/ZZStRSR.test.ts.snap b/test/__snapshots__/ZZStRSR.test.ts.snap index 61e4ce620..63500d716 100644 --- a/test/__snapshots__/ZZStRSR.test.ts.snap +++ b/test/__snapshots__/ZZStRSR.test.ts.snap @@ -14,6 +14,6 @@ exports[`StRSRP1 contract Gas Reporting Unstake 1`] = `222609`; exports[`StRSRP1 contract Gas Reporting Unstake 2`] = `139758`; -exports[`StRSRP1 contract Gas Reporting Withdraw 1`] = `609578`; +exports[`StRSRP1 contract Gas Reporting Withdraw 1`] = `606273`; -exports[`StRSRP1 contract Gas Reporting Withdraw 2`] = `539716`; +exports[`StRSRP1 contract Gas Reporting Withdraw 2`] = `536407`; diff --git a/test/plugins/individual-collateral/dsr/__snapshots__/SDaiCollateralTestSuite.test.ts.snap b/test/plugins/individual-collateral/dsr/__snapshots__/SDaiCollateralTestSuite.test.ts.snap index 08efe17a7..eb9ff1862 100644 --- a/test/plugins/individual-collateral/dsr/__snapshots__/SDaiCollateralTestSuite.test.ts.snap +++ b/test/plugins/individual-collateral/dsr/__snapshots__/SDaiCollateralTestSuite.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Collateral: SDaiCollateral collateral functionality Gas Reporting refresh() after full price timeout 1`] = `116743`; +exports[`Collateral: SDaiCollateral collateral functionality Gas Reporting refresh() after full price timeout 1`] = `116848`; exports[`Collateral: SDaiCollateral collateral functionality Gas Reporting refresh() after full price timeout 2`] = `108431`; diff --git a/test/scenario/__snapshots__/MaxBasketSize.test.ts.snap b/test/scenario/__snapshots__/MaxBasketSize.test.ts.snap index 85d4622d4..156f63233 100644 --- a/test/scenario/__snapshots__/MaxBasketSize.test.ts.snap +++ b/test/scenario/__snapshots__/MaxBasketSize.test.ts.snap @@ -1,19 +1,19 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Max Basket Size - P1 ATokens/CTokens Should Issue/Redeem with max basket correctly 1`] = `12085598`; +exports[`Max Basket Size - P1 ATokens/CTokens Should Issue/Redeem with max basket correctly 1`] = `12082293`; -exports[`Max Basket Size - P1 ATokens/CTokens Should Issue/Redeem with max basket correctly 2`] = `9827198`; +exports[`Max Basket Size - P1 ATokens/CTokens Should Issue/Redeem with max basket correctly 2`] = `9836895`; exports[`Max Basket Size - P1 ATokens/CTokens Should claim rewards correctly 1`] = `2281990`; -exports[`Max Basket Size - P1 ATokens/CTokens Should switch basket correctly 1`] = `13658589`; +exports[`Max Basket Size - P1 ATokens/CTokens Should switch basket correctly 1`] = `13653640`; -exports[`Max Basket Size - P1 ATokens/CTokens Should switch basket correctly 2`] = `20693277`; +exports[`Max Basket Size - P1 ATokens/CTokens Should switch basket correctly 2`] = `20688663`; -exports[`Max Basket Size - P1 Fiatcoins Should Issue/Redeem with max basket correctly 1`] = `10987348`; +exports[`Max Basket Size - P1 Fiatcoins Should Issue/Redeem with max basket correctly 1`] = `10984043`; -exports[`Max Basket Size - P1 Fiatcoins Should Issue/Redeem with max basket correctly 2`] = `8711098`; +exports[`Max Basket Size - P1 Fiatcoins Should Issue/Redeem with max basket correctly 2`] = `8707789`; -exports[`Max Basket Size - P1 Fiatcoins Should switch basket correctly 1`] = `6596661`; +exports[`Max Basket Size - P1 Fiatcoins Should switch basket correctly 1`] = `6592417`; -exports[`Max Basket Size - P1 Fiatcoins Should switch basket correctly 2`] = `14446099`; +exports[`Max Basket Size - P1 Fiatcoins Should switch basket correctly 2`] = `14441485`; From 42a119b5789f857634f225fe44ce3eccf30d73a9 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Mon, 16 Oct 2023 19:03:45 -0400 Subject: [PATCH 09/12] solidity impl --- contracts/plugins/assets/RTokenAsset.sol | 29 ++++++++++++------- .../CurveStableRTokenMetapoolCollateral.sol | 6 ++++ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/contracts/plugins/assets/RTokenAsset.sol b/contracts/plugins/assets/RTokenAsset.sol index f187651e3..785755974 100644 --- a/contracts/plugins/assets/RTokenAsset.sol +++ b/contracts/plugins/assets/RTokenAsset.sol @@ -19,12 +19,14 @@ contract RTokenAsset is IAsset, VersionedAsset, IRTokenOracle { // Component addresses are not mutable in protocol, so it's safe to cache these IMain public immutable main; - IBasketHandler public immutable basketHandler; IAssetRegistry public immutable assetRegistry; IBackingManager public immutable backingManager; + IBasketHandler public immutable basketHandler; IFurnace public immutable furnace; + IERC20 public immutable rsr; + IStRSR public immutable stRSR; - IERC20Metadata public immutable erc20; + IERC20Metadata public immutable erc20; // The RToken uint8 public immutable erc20Decimals; @@ -39,10 +41,12 @@ contract RTokenAsset is IAsset, VersionedAsset, IRTokenOracle { require(maxTradeVolume_ > 0, "invalid max trade volume"); main = erc20_.main(); - basketHandler = main.basketHandler(); assetRegistry = main.assetRegistry(); backingManager = main.backingManager(); + basketHandler = main.basketHandler(); furnace = main.furnace(); + rsr = main.rsr(); + stRSR = main.stRSR(); erc20 = IERC20Metadata(address(erc20_)); erc20Decimals = erc20_.decimals(); @@ -79,18 +83,15 @@ contract RTokenAsset is IAsset, VersionedAsset, IRTokenOracle { assert(low <= high); // not obviously true } - // solhint-disable no-empty-blocks function refresh() public virtual override { // No need to save lastPrice; can piggyback off the backing collateral's saved prices if (msg.sender != address(assetRegistry)) assetRegistry.refresh(); furnace.melt(); - cachedOracleData.cachedAtTime = 0; // force oracle refresh + cachedOracleData.cachedAtTime = 0; // clear oracle cache } - // solhint-enable no-empty-blocks - /// Should not revert /// @dev See `tryPrice` caveat about possible compounding error in calculating price /// @return {UoA/tok} The lower end of the price estimate @@ -130,10 +131,13 @@ contract RTokenAsset is IAsset, VersionedAsset, IRTokenOracle { // solhint-enable no-empty-blocks + /// Force an update to the cache, including refreshing underlying assets + /// @dev Can revert if RToken is unpriced function forceUpdatePrice() external { _updateCachedPrice(); } + /// @dev Can revert if RToken is unpriced function latestPrice() external returns (uint192 rTokenPrice, uint256 updatedAt) { // Situations that require an update, from most common to least common. if ( @@ -152,6 +156,9 @@ contract RTokenAsset is IAsset, VersionedAsset, IRTokenOracle { // Update Oracle Data function _updateCachedPrice() internal { + assetRegistry.refresh(); + furnace.melt(); + (uint192 low, uint192 high) = price(); require(low != 0 && high != FIX_MAX, "invalid price"); @@ -183,12 +190,12 @@ contract RTokenAsset is IAsset, VersionedAsset, IRTokenOracle { TradingContext memory ctx; ctx.basketsHeld = basketsHeld; + ctx.ar = assetRegistry; ctx.bm = backingManager; ctx.bh = basketHandler; - ctx.ar = assetRegistry; - ctx.stRSR = main.stRSR(); - ctx.rsr = main.rsr(); - ctx.rToken = main.rToken(); + ctx.rsr = rsr; + ctx.rToken = IRToken(address(erc20)); + ctx.stRSR = stRSR; ctx.minTradeVolume = backingManager.minTradeVolume(); ctx.maxTradeSlippage = backingManager.maxTradeSlippage(); diff --git a/contracts/plugins/assets/curve/CurveStableRTokenMetapoolCollateral.sol b/contracts/plugins/assets/curve/CurveStableRTokenMetapoolCollateral.sol index 420e002f4..80dab39fd 100644 --- a/contracts/plugins/assets/curve/CurveStableRTokenMetapoolCollateral.sol +++ b/contracts/plugins/assets/curve/CurveStableRTokenMetapoolCollateral.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BlueOak-1.0.0 pragma solidity 0.8.19; +import "../RTokenAsset.sol"; import "./CurveStableMetapoolCollateral.sol"; /** @@ -42,6 +43,11 @@ contract CurveStableRTokenMetapoolCollateral is CurveStableMetapoolCollateral { pairedAssetRegistry = IRToken(address(pairedToken)).main().assetRegistry(); } + function refresh() public override { + pairedAssetRegistry.refresh(); // refresh all registered assets + super.refresh(); // already handles all necessary default checks + } + /// Can revert, used by `_anyDepeggedOutsidePool()` /// Should not return FIX_MAX for low /// @return lowPaired {UoA/pairedTok} The low price estimate of the paired token From 8a26bbf150c38673fc6c833620c4764cb5abfd4e Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Mon, 16 Oct 2023 19:03:52 -0400 Subject: [PATCH 10/12] regression tests --- contracts/plugins/mocks/AssetMock.sol | 9 ++++- .../CrvStableRTokenMetapoolTestSuite.test.ts | 35 +++++++++++++++++++ .../CvxStableRTokenMetapoolTestSuite.test.ts | 35 +++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/contracts/plugins/mocks/AssetMock.sol b/contracts/plugins/mocks/AssetMock.sol index c1b495380..0396a5ea3 100644 --- a/contracts/plugins/mocks/AssetMock.sol +++ b/contracts/plugins/mocks/AssetMock.sol @@ -4,6 +4,8 @@ pragma solidity 0.8.19; import "../assets/Asset.sol"; contract AssetMock is Asset { + bool public stale; + uint192 private lowPrice; uint192 private highPrice; @@ -40,13 +42,18 @@ contract AssetMock is Asset { uint192 ) { + require(!stale, "stale price"); return (lowPrice, highPrice, 0); } /// Should not revert /// Refresh saved prices function refresh() public virtual override { - // pass + stale = false; + } + + function setStale(bool _stale) external { + stale = _stale; } function setPrice(uint192 low, uint192 high) external { diff --git a/test/plugins/individual-collateral/curve/crv/CrvStableRTokenMetapoolTestSuite.test.ts b/test/plugins/individual-collateral/curve/crv/CrvStableRTokenMetapoolTestSuite.test.ts index a97702d5a..fd62e8ee7 100644 --- a/test/plugins/individual-collateral/curve/crv/CrvStableRTokenMetapoolTestSuite.test.ts +++ b/test/plugins/individual-collateral/curve/crv/CrvStableRTokenMetapoolTestSuite.test.ts @@ -241,6 +241,41 @@ const collateralSpecificStatusTests = () => { // refresh() should not revert await collateral.refresh() }) + + it('Regression test -- refreshes inner RTokenAsset on refresh()', async () => { + const [collateral] = await deployCollateral({}) + const initialPrice = await collateral.price() + expect(initialPrice[0]).to.be.gt(0) + expect(initialPrice[1]).to.be.lt(MAX_UINT192) + + // Swap out eUSD's RTokenAsset with a mock one + const AssetMockFactory = await ethers.getContractFactory('AssetMock') + const mockRTokenAsset = await AssetMockFactory.deploy( + bn('1'), // unused + ONE_ADDRESS, // unused + bn('1'), // unused + eUSD, + bn('1'), // unused + bn('1') // unused + ) + const eUSDAssetRegistry = await ethers.getContractAt( + 'IAssetRegistry', + '0x9B85aC04A09c8C813c37de9B3d563C2D3F936162' + ) + await whileImpersonating('0xc8Ee187A5e5c9dC9b42414Ddf861FFc615446a2c', async (signer) => { + await eUSDAssetRegistry.connect(signer).swapRegistered(mockRTokenAsset.address) + }) + + // Set RTokenAsset price to stale + await mockRTokenAsset.setStale(true) + expect(await mockRTokenAsset.stale()).to.be.true + + // Refresh CurveStableRTokenMetapoolCollateral + await collateral.refresh() + + // Stale should be false again + expect(await mockRTokenAsset.stale()).to.be.false + }) } /* diff --git a/test/plugins/individual-collateral/curve/cvx/CvxStableRTokenMetapoolTestSuite.test.ts b/test/plugins/individual-collateral/curve/cvx/CvxStableRTokenMetapoolTestSuite.test.ts index bfb1f3018..ab50ef36a 100644 --- a/test/plugins/individual-collateral/curve/cvx/CvxStableRTokenMetapoolTestSuite.test.ts +++ b/test/plugins/individual-collateral/curve/cvx/CvxStableRTokenMetapoolTestSuite.test.ts @@ -243,6 +243,41 @@ const collateralSpecificStatusTests = () => { // refresh() should not revert await collateral.refresh() }) + + it('Regression test -- refreshes inner RTokenAsset on refresh()', async () => { + const [collateral] = await deployCollateral({}) + const initialPrice = await collateral.price() + expect(initialPrice[0]).to.be.gt(0) + expect(initialPrice[1]).to.be.lt(MAX_UINT192) + + // Swap out eUSD's RTokenAsset with a mock one + const AssetMockFactory = await ethers.getContractFactory('AssetMock') + const mockRTokenAsset = await AssetMockFactory.deploy( + bn('1'), // unused + ONE_ADDRESS, // unused + bn('1'), // unused + eUSD, + bn('1'), // unused + bn('1') // unused + ) + const eUSDAssetRegistry = await ethers.getContractAt( + 'IAssetRegistry', + '0x9B85aC04A09c8C813c37de9B3d563C2D3F936162' + ) + await whileImpersonating('0xc8Ee187A5e5c9dC9b42414Ddf861FFc615446a2c', async (signer) => { + await eUSDAssetRegistry.connect(signer).swapRegistered(mockRTokenAsset.address) + }) + + // Set RTokenAsset price to stale + await mockRTokenAsset.setStale(true) + expect(await mockRTokenAsset.stale()).to.be.true + + // Refresh CurveStableRTokenMetapoolCollateral + await collateral.refresh() + + // Stale should be false again + expect(await mockRTokenAsset.stale()).to.be.false + }) } /* From 31bc3a58b5072c14fe17dadc2ab0fe3bb3d6690f Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Mon, 16 Oct 2023 19:08:18 -0400 Subject: [PATCH 11/12] nits --- contracts/plugins/assets/RTokenAsset.sol | 2 +- .../assets/curve/CurveStableRTokenMetapoolCollateral.sol | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/plugins/assets/RTokenAsset.sol b/contracts/plugins/assets/RTokenAsset.sol index 785755974..ebcad1e72 100644 --- a/contracts/plugins/assets/RTokenAsset.sol +++ b/contracts/plugins/assets/RTokenAsset.sol @@ -89,7 +89,7 @@ contract RTokenAsset is IAsset, VersionedAsset, IRTokenOracle { if (msg.sender != address(assetRegistry)) assetRegistry.refresh(); furnace.melt(); - cachedOracleData.cachedAtTime = 0; // clear oracle cache + cachedOracleData.cachedAtTime = 0; // force oracle refresh } /// Should not revert diff --git a/contracts/plugins/assets/curve/CurveStableRTokenMetapoolCollateral.sol b/contracts/plugins/assets/curve/CurveStableRTokenMetapoolCollateral.sol index 80dab39fd..780a083a8 100644 --- a/contracts/plugins/assets/curve/CurveStableRTokenMetapoolCollateral.sol +++ b/contracts/plugins/assets/curve/CurveStableRTokenMetapoolCollateral.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: BlueOak-1.0.0 pragma solidity 0.8.19; -import "../RTokenAsset.sol"; import "./CurveStableMetapoolCollateral.sol"; /** From aa132e92e86ddfc5909cb54fc53317d5109bc193 Mon Sep 17 00:00:00 2001 From: Taylor Brent Date: Tue, 17 Oct 2023 14:13:40 -0400 Subject: [PATCH 12/12] cosmetic changes only --- contracts/plugins/assets/RTokenAsset.sol | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/contracts/plugins/assets/RTokenAsset.sol b/contracts/plugins/assets/RTokenAsset.sol index ebcad1e72..f82f2ee18 100644 --- a/contracts/plugins/assets/RTokenAsset.sol +++ b/contracts/plugins/assets/RTokenAsset.sol @@ -86,8 +86,8 @@ contract RTokenAsset is IAsset, VersionedAsset, IRTokenOracle { function refresh() public virtual override { // No need to save lastPrice; can piggyback off the backing collateral's saved prices - if (msg.sender != address(assetRegistry)) assetRegistry.refresh(); furnace.melt(); + if (msg.sender != address(assetRegistry)) assetRegistry.refresh(); cachedOracleData.cachedAtTime = 0; // force oracle refresh } @@ -138,6 +138,8 @@ contract RTokenAsset is IAsset, VersionedAsset, IRTokenOracle { } /// @dev Can revert if RToken is unpriced + /// @return rTokenPrice {UoA/tok} The mean price estimate + /// @return updatedAt {s} The timestamp of the cache update function latestPrice() external returns (uint192 rTokenPrice, uint256 updatedAt) { // Situations that require an update, from most common to least common. if ( @@ -149,18 +151,17 @@ contract RTokenAsset is IAsset, VersionedAsset, IRTokenOracle { _updateCachedPrice(); } - return (cachedOracleData.cachedPrice, cachedOracleData.cachedAtTime); + rTokenPrice = cachedOracleData.cachedPrice; + updatedAt = cachedOracleData.cachedAtTime; } // ==== Private ==== // Update Oracle Data function _updateCachedPrice() internal { - assetRegistry.refresh(); - furnace.melt(); + assetRegistry.refresh(); // will call furnace.melt() (uint192 low, uint192 high) = price(); - require(low != 0 && high != FIX_MAX, "invalid price"); cachedOracleData = CachedOracleData(