3.0.0
Bump solidity version to 0.8.19
Upgrade Steps
Required Steps
Update all component contracts, including Main.
Call the following functions:
BackingManager.cacheComponents()
RevenueTrader.cacheComponents()
(for both rsrTrader and rTokenTrader)Distributor.cacheComponents()
All asset plugins (and their corresponding ERC20s) must be upgraded. The only exception is the StaticATokenLM
ERC20s from Aave V2. These can be left the same, however their assets should upgraded.
- Note: Make sure to use
Deployer.deployRTokenAsset()
to create newRTokenAsset
instances. This asset should be swapped too.
Optional Steps
Call the following functions, once it is desired to turn on the new features:
BasketHandler.setWarmupPeriod()
StRSR.setWithdrawalLeak()
Broker.setDutchAuctionLength()
Broker.setDutchTradeImplementation()
It is acceptable to leave these function calls out of the initial upgrade tx and follow up with them later. The protocol will continue to function, just without dutch auctions, RSR unstaking gas-savings, and the warmup period.
Core Protocol Contracts
-
AssetRegistry
[+1 slot]
Summary: Other component contracts need to know when refresh() was last called- Add
lastRefresh()
timestamp getter - Add
size()
getter for number of registered assets - Require asset is SOUND on registration
- Bugfix: Fix gas attack that could result in someone disabling the basket
- Add
-
BackingManager
[+2 slots]
Summary: manageTokens was broken out into separate rebalancing and surplus-forwarding functions to allow users to more precisely call the protocol- Replace
manageTokens(IERC20[] memory erc20s)
with:rebalance(TradeKind)
- Modify trading algorithm to not trade RToken, and instead dissolve it when it has a balance above ~1e6 RToken quanta. "dissolve" = melt() with a basketsNeeded change, similar to redemption but without transfer of RToken collateral.
- Use
lotPrice()
to set trade prices instead ofprice()
- Add significant caching to save gas
forwardRevenue(IERC20[] memory erc20s)
- Modify backingBuffer logic to keep the backing buffer in collateral tokens only. Fix subtle and inconsequential bug that resulted in not maximizing RToken minting locally, though overall RToken production does not change.
- Use
nonReentrant
over CEI pattern for gas improvement. related to discussion of this cross-contract reentrancy risk
- move
nonReentrant
up outsidetryTrade
internal helper
- Remove
manageTokensSortedOrder(IERC20[] memory erc20s)
- Modify
settleTrade(IERC20 sell)
to callrebalance()
when caller is a trade it deployed. - Remove all
delegatecall
during reward claiming; callclaimRewards()
directly on ERC20 - Functions now revert on unproductive executions, instead of no-op
- Do not trade until a warmupPeriod (last time SOUND was newly attained) has passed
- Add
cacheComponents()
refresher to be called on upgrade - Add concept of
tradeNonce
- Bugfix: consider
maxTradeVolume()
from both assets on a trade, not just 1
- Replace
-
BasketHandler
[+5 slots]
Summary: Introduces a notion of basket warmup to defend against short-term oracle manipulation attacks. Prevent RTokens from changing in value due to governance- Add new gov param:
warmupPeriod
with settersetWarmupPeriod(..)
and eventWarmupPeriodSet()
- Add
trackStatus()
refresher - Add
isReady()
view - Extract basket switching logic out into external library
BasketLibP1
- Enforce
setPrimeBasket()
does not change the net value of a basket in terms of its target units - Add
quoteCustomRedemption(uint48[] basketNonces, uint192[] memory portions, ..)
to quote a linear combination of current-or-previous baskets for redemption - Add
getHistoricalBasket(uint48 basketNonce)
view - Bugfix: Protect against high BU price overflow
- Add new gov param:
-
Broker
[+2 slot]
Summary: Add a second trading method for single-lot dutch auctions. Batch auctions via Gnosis EasyAuction are expected to be the backup auction going forward.- Add new dutch auction
DutchTrade
- Add minimum auction length of 20 blocks based on network block time
- Rename variable
auctionLength
->batchAuctionLength
- Rename setter
setAuctionLength()
->setBatchAuctionLength()
- Rename event
AuctionLengthSet()
->BatchAuctionLengthSet()
- Add
dutchAuctionLength
andsetDutchAuctionLength()
setter andDutchAuctionLengthSet()
event - Add
dutchTradeImplementation
andsetDutchTradeImplementation()
setter andDutchTradeImplementationSet()
event - Modify
setBatchTradeDisabled(bool)
->enableBatchTrade()
- Modify
setDutchTradeDisabled(IERC20 erc20, bool)
->enableDutchTrade(IERC20 erc20)
- Unlike batch auctions, dutch auctions can be disabled per-ERC20, and can only be disabled by BackingManager-started trades
- Modify
openTrade(TradeRequest memory reg)
->openTrade(TradeKind kind, TradeRequest memory req, TradePrices memory prices)
- Allow when paused / frozen, since caller must be in-system
- Add new dutch auction
-
Deployer
[+0 slots]
Summary: Support new governance params- Modify to handle new gov params:
warmupPeriod
,dutchAuctionLength
, andwithdrawalLeak
- Do not grant OWNER any of the roles other than ownership
- Add
deployRTokenAsset()
to allow easy creation of newRTokenAsset
instances
- Modify to handle new gov params:
-
Distributor
[+2 slots]
Summary: Restrict callers to system components and remove paused/frozen checks- Remove
notPausedOrFrozen
modifier fromdistribute()
- Remove
-
Furnace
[+0 slots]
Summary: Allow melting while paused- Allow melting while paused
- Melt during updates to the melting ratio
- Lower
MAX_RATIO
from 1e18 to 1e14.
-
Main
[+0 slots]
Summary: Split pausing into two types of pausing: issuance and trading- Split
paused
intoissuancePaused
andtradingPaused
pause()
->pauseTrading()
andpauseIssuance()
unpause()
->unpauseTrading()
andunpauseIssuance()
pausedOrFrozen()
->tradingPausedOrFrozen()
andissuancePausedOrFrozen()
PausedSet()
event ->TradingPausedSet()
andIssuancePausedSet()
- Split
-
RevenueTrader
[+4 slots]
Summary: QoL improvements. Make compatible with new dutch auction trading method- Remove
delegatecall
during reward claiming; callclaimRewards()
directly on ERC20 - Add
cacheComponents()
refresher to be called on upgrade manageToken(IERC20 sell)
->manageTokens(IERC20[] calldata erc20s, TradeKind[] memory kinds)
- Allow multiple auctions to be launched at once
- Allow opening dust auctions (i.e ignore
minTradeVolume
) - Revert on 0 balance or collision auction instead of no-op
- Refresh buy and sell asset before trade
settleTrade(IERC20)
now distributestokenToBuy
automatically, instead of requiring separatemanageToken(IERC20)
call- Add
returnTokens(IERC20[] memory erc20s)
to return tokens to the BackingManager when the distribution is set to 0 - Add concept of
tradeNonce
- Remove
-
RToken
[+0 slots]
Summary: Provide multiple redemption methods for fullyCollateralized vs uncollateralized.- Gas: Remove
exchangeRateIsValidAfter
modifier from all functions exceptsetBasketsNeeded()
- Modify issuance
to revert before
warmupPeriod` - Modify
redeem(uint256 amount, uint48 basketNonce)
->redeem(uint256 amount)
. Redemptions are always on the current basket nonce and revert under partial redemption - Modify
redeemTo(address recipient, uint256 amount, uint48 basketNonce)
->redeemTo(address recipient, uint256 amount)
. Redemptions are on the current basket nonce and revert under partial redemption - Add new
redeemCustom(.., uint256 amount, uint48[] memory basketNonces, uint192[] memory portions, ..)
function to allow redemption from a linear combination of current and previous baskets. During rebalancing this method of redemption may provide a higher overall redemption value than prorata redemption on the current basket nonce would. - Modify
mint(address recipient, uint256 amtRToken)
->mint(uint256 amtRToken)
, since recipient is always BackingManager. Expand scope to include adjustments tobasketsNeeded
- Add
dissolve(uint256 amount)
: burns RToken and reducesbasketsNeeded
, similar to redemption. Only callable by BackingManager - Modify
setBasketsNeeded(..)
to revert when supply is 0 - Bugfix: Accumulate throttles upon change
- Gas: Remove
-
StRSR
[+2 slots]
Summary: Add the ability to cancel unstakings and a withdrawal() gas-saver to allow small RSR amounts to be exempt from asset refreshes- Lower
MAX_REWARD_RATIO
from 1e18 to 1e14. - Remove duplicate
stakeRate()
getter (same as1 / exchangeRate()
) - Add
withdrawalLeak
gov param, withsetWithdrawalLeak(..)
setter andWithdrawalLeakSet()
event - Modify
withdraw()
to allow a small % of RSR to exit without paying to refresh all assets - Modify
withdraw()
to check forwarmupPeriod
- Add
cancelUnstake(uint256 endId)
to allow re-staking during unstaking - Add
UnstakingCancelled()
event - Allow payout of (already acquired) RSR rewards while frozen
- Add ability for governance to
resetStakes()
when stake rate falls outside (1e12, 1e24)
- Lower
-
StRSRVotes
[+0 slots]- Add
stakeAndDelegate(uint256 rsrAmount, address delegate)
function to encourage people to receive voting weight upon staking
- Add
Facades
Remove FacadeMonitor
- now redundant with nextRecollateralizationAuction()
and revenueOverview()
-
FacadeAct
Summary: Remove unusedgetActCalldata()
and add way to run revenue auctions- Remove
getActCalldata(..)
- Remove
canRunRecollateralizationAuctions(..)
- Remove
runRevenueAuctions(..)
- Add
revenueOverview(IRevenueTrader) returns ( IERC20[] memory erc20s, bool[] memory canStart, uint256[] memory surpluses, uint256[] memory minTradeAmounts)
- Add
nextRecollateralizationAuction(..) returns (bool canStart, IERC20 sell, IERC20 buy, uint256 sellAmount)
- Modify all functions to work on both 3.0.0 and 2.1.0 RTokens
- Remove
-
FacadeRead
Summary: Add new data summary views frontends may be interested in -
Remove
basketNonce
fromredeem(.., uint48 basketNonce)
-
Add
redeemCustom(.., uint48[] memory basketNonces, uint192[] memory portions)
callstatic to simulate multi-basket redemptions -
Remove
traderBalances(..)
-
Add
balancesAcrossAllTraders(IBackingManager) returns (IERC20[] memory erc20s, uint256[] memory balances, uint256[] memory balancesNeededByBackingManager)
-
FacadeWrite
Summary: More expressive and fine-grained control over the set of pausers and freezers- Do not automatically grant Guardian PAUSER/SHORT_FREEZER/LONG_FREEZER
- Do not automatically grant Owner PAUSER/SHORT_FREEZER/LONG_FREEZER
- Add ability to initialize with multiple pausers, short freezers, and long freezers
- Modify
setupGovernance(.., address owner, address guardian, address pauser)
->setupGovernance(.., GovernanceRoles calldata govRoles)
Plugins
DutchTrade
A cheaper, simpler, trading method. Intended to be the new dominant trading method, with GnosisTrade (batch auctions) available as a backup option. Generally speaking the batch auction length can be kept shorter than the dutch auction length.
DutchTrade implements a four-stage, single-lot, falling price dutch auction:
- In the first 20% of the auction, the price falls from 1000x the best price to the best price in a geometric/exponential decay as a price manipulation defense mechanism. Bids are not expected to occur (but note: unlike the GnosisTrade batch auction, this mechanism is not resistant to arbitrary price manipulation). If a bid occurs, then trading for the pair of tokens is disabled as long as the trade was started by the BackingManager.
- Between 20% and 45%, the price falls linearly from 1.5x the best price to the best price.
- Between 45% and 95%, the price falls linearly from the best price to the worst price.
- Over the last 5% of the auction, the price remains constant at the worst price.
Duration: 30 min (default)
Assets and Collateral
- Add
version() return (string)
getter to pave way for separation of asset versioning and core protocol versioning - Deprecate
claimRewards()
- Add
lastSave()
toRTokenAsset
- Remove
CurveVolatileCollateral
- Switch
CToken*Collateral
(Compound V2) to using a CTokenVault ERC20 rather than the raw cToken - Bugfix:
lotPrice()
now begins at 100% the lastSavedPrice, instead of below 100%. It can be at 100% for up to the oracleTimeout in the worst-case. - Bugfix: Handle oracle deprecation as indicated by the
aggregator()
being set to the zero address - Bugfix:
AnkrStakedETHCollateral
/CBETHCollateral
/RethCollateral
now correctly detects soft default (note that Ankr still requires a new oracle before it can be deployed) - Bugfix: Adjust
Curve*Collateral
andRTokenAsset
to treat FIX_MAX correctly as +inf - Bugfix: Continue updating cached price after collateral default (impacts all appreciating collateral)