-
Notifications
You must be signed in to change notification settings - Fork 93
OETH - Full Changes #1271
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OETH - Full Changes #1271
Conversation
sparrowDom
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM I am surprised by how little changes to the Vault are required for it to support a token with an exchange rate. Elegantly solved! Left a couple of comments inline
…ar into DanielVF/oeth
* Allow initialize time control of OUSD resolution * Remove debugging
…ar into DanielVF/oeth
OETH Zapper Code ReviewRequirementsWe want to allow users with raw ETH to being able to send it to an address and get OETH. We also want to allow users with sFXETH to mint OETH. By having this as a separate contract, we keep the vault simple, and avoid handling ETH in the vault. Deployment ConsiderationsMonitoring would be nice, but not necessary. Good to see how much this is used. Will need to check constructor addresses when deployed. Internal StateNo stored state. Intended to only ephemerally hold balances. AttackIf this contract failed, the worst case would a transaction's worth of user's funds (not protocol funds). All publicly callable methods also use a minimum amount which will revert if the user does not get back that much OETH. Could funds could become stuck in this contract? Every publicly callable method ends by sending all OETH on the contract to the caller. If a someone accidentally sends mintable funds or OETH to this contract, they will be folded into the next deposit and returned to the next depositor. Any other ERC20 would become stuck, which is acceptable. If OETH had a rounding error, and returned less funds than expected, it could break the deposit. LogicThere are no if statements, and all external paths end with funds going to the user. Tests🔅 This code has no unit test or fork tests. Don't need unit tests since this hardcodes live contract addresses for simplicity. Fork tests would be good. FlavorCould this code be simpler? Not that I see. 🔅✔︎ The repeated 🔅✔︎ No document strings on methods. Added. Could this code be less vulnerable to other code behaving weirdly? In the end the requires ensure that they user gets what they expect. If something breaks one day in a called token or contract, we can just deploy a new zapper, and there is no state that needs to carry over. OverflowNo math! ProxyNo proxy! Black magic
DependenciesOnly interfaces are used. Deploy
Authentication
Cryptographic codeNo crypto. Gas problemsNo Loops. External calls
EthereumThis contract sends and receives ethereum. The only receiving is in We send eth, but only to the trusted WETH contract, and we have minimum amount checks afterwords that prevent any funny business. |
* Deploy 56 Zapper * Remove forceDeploy
Code Review: Frax ETH StrategyRequirementsThis stakes FRXETH tokens into the 4626 sFRXETH contract. This also works as a generic 4626 strategy to wrap any token into a 4626. As with any Strategy, the three key concerns are:
Deployment ConsiderationsShould be in our monitoring / event logging. Internal StateThis contract only holds configuration.
AttackThis strategy could be holding a large portion of our backing funds. It's important that it works. The most common danger with these strategies is a balance checking problem, with an attacker being able to force an incorrect high balance, rebasing to catch the gains, and then withdrawing. 🔆 Check balance uses 4626 contracts can sometimes be vulnerable to rounding attacks on initial deposits. stfxeth has protection against loosing all your money (might only lose half?). However this would be very gas expensive to check check for. Perhaps a comment on only going into pools that have existing funds. stfxeth also uses stored asset amounts, which should be donation proof. The canonical 4626, and stfxeth, correctly rounds Deposit and withdraw look correct. LogicLooks good Tests
FlavorCode is elegant. OverflowNo math Proxy
Black magic
DependenciesNo change to standard strategy dependancies. Deploy
Authentication
Cryptographic codeno crypto Gas problemsno loops, other than one in our control in initialization. External calls
I notice that we have a reentrancy checks on the state changing methods, but not on check 📛 Vault Admin needs to have reentrancy checks on the strategist moving funds. If an attacker somehow gains execution in the middle of a funds move, this will prevent the attacker from being able to make a rebase. ( Issue created on this #1366 ) Ethereum
|
Code Review: Oracle RouterRequirementsThe Oracle Router provides depeg resistance to the vault. If a coin coin loses peg, then the vault will block new mints. If a tiny depeg happens, then less OETH will be minted. If a small increase happens, then the vault will redeem less of that kind of coin. (This happens in stablecoins during deepens, the non-depegging coin gets more expensive) However, our oracles are currently dog biscuits compared with what we are used to in stablecoin land: 🟪 steth and reth have 2% update margins - they could get very depegged without OETH knowing anything about it. In practice, we get one update every 24 hours. Besides being late to catch depegs, we would be late to catch repegs, and might continue to use an old price for 24 hours. 🟪 We have no oracle on sfrxeth. This means that if it depegs, the only thing we can do is pause the whole vault. 🔆 We don't currently check if oracle prices are out of date. This is probably the right thing to do, since we would probably want to fail to live if chainlink goes down, but it would be good to monitor the last update times and amounts in external monitoring. This applies to OUSD as well. Given the poor oracles we have, OETH at launch will be much less depeg resistant than OUSD is. The redeem fee should act against depegs that are less than the size of the redeem fee. Between the redeem price and the area where the oracles update, we should expect to see a shift in the assets held by OETH. This shift is somewhat self limiting, since the more bad assets are put in with minting, the less of good coins the arber gets back on redeeming. If this shift happened, and the asset later repegged, we would make a lot of money. This stable point depends on how bad the depeg is and what the redeem fee is. For example, at 0.98, and 0.5%, 25% of assets should still be good coins. Arber mints for 0.98, gets back 75% coins worth 0.98, 25% worth 1.00, and pays a 0.5% fee that cancels out the their projected gains. (A 0.25% fee, like ousd, would leave 12.5% good assets) Deployment Considerations🔆 We should monitor, with alerting, the pool balances for the three collateral we use, like we do for LUSD/threepool on OUSD. Internal StateThe only internal state is the cached decimals per oracle. If these are not setup via AttackAs discussed in the requirements, this really only comes into play if a coin is out of peg, or reported out of peg. If we had a false positive high report, it would make redeeming uneconomical. 🔆 Another obvious problem would be an oracle not getting updated. It would be good to record the time since last oracle update in our monitoring. A MEV bot could do actions to OETH strategically around price updates. This should not affect the protocol though, just get a little more profits than they otherwise would. LogicAre there bugs in the logic? We require that feed != address(0) in production however there's no way to reach that state. However, it's a really cheap sanity check, so let's keep it. Tests
Flavor🔴 We added a new OETHOracleRouter for the new launch. It is correct for OETH. We still have the old OracleRouter, however changes that were made in in the base code, make it neither compatible with the deployed OUSD code, nor correct for a new deploy of the new shared vault code. I've created an issue for this. Since the current code works correctly for OETH, we won't fix now. We should throw Overflow
Proxy
Black magic
Dependencies
DeployNo deployer permissions Oracle has been tested live Authentication
Cryptographic codeNo crypto Gas problemsNo loops Might be nice to sort the feeds and put core price feeds first. Okay to leave as is though. External calls
Ethereum
|
Governance Ownership Checks✅ All looks good Multisig ownedOETH Proxy VaultProxy Vault VaultAdmin VaultCore FraxEthStrategyProxy Frax Strategy Implementation Woeth Proxy Dripper Proxy Deployer owned:OETH Impl Woeth Impl Dripper IMPL No Owner:OETH Oracle Router Zapper OUSD Oracle Router |
Code Review: OETH VaultRequirementsThis change is designed to allow the vault to work with rebasing tokens that are not always worth 1 ETH (or 1 USD). The vault does this by internaly converting these coins into 1e18 units that correspond to an ETH (or USD). This actually simplifies a lot of the code, since before the vault constantly had to do conversions in and out of the token's decimals. This change is intended to be backwards compatible (outside of the OracleRouter, and price views) with the old code. This means that all existing tests should pass. Deployment Considerations🔆 Requires new OracleRouter AttackThese new changes affect the three most critical parts of the vault - minting, redeeming, and balance calculations for rebasing. A calculation failure in any one of these areas would be GG for the protocol. An attacker's goal would be to create the impression that their assets are worth too much during mints, worth too much during rebase, or worth too little during a redeem. There's a discussion of oracles on the OracleRouter review. Even with bad oracles, the total number of stables should only go up -- as long as the exchange rate does not go down. The fact that an exchange rate could go down is a new twist that we didn't have in OUSD. We also have rebasing tokens that could balance down. To some degree, this "we have less backing funds now" is a core risk we are taking with OETH. 📛 I belive there is a profitable attack that would require several things to line up. Attack goes like this: Attacker knows that a bigger than redeem fee exchange rate drop on reth is coming. Attacker can force the chainlink oracle to update to reflect the new exchange rate, but the Attacker can buy/sell reth at approximately the same price before and after the exchange rate drop. In this case, the attacker would wrap the exchange rate and oracle update transactions, acquiring a large amount of RETH before the updates and depositing into OETH. Then after the update, they would redeem. Given the new exchange rate, OETH would treat rETH as less valuable, and send more of it to make up an ETH. In the right circumstances then, the attacker would net more than they put in. If the chainlink oracle doesn't update at the same time, this attack does not work. If the oracle is at the new low price, the mint gets subtracted from, if the oracle is at the old high price, the redeem gets subtracted from. If the oracle is in between, it affects both sides. We do have defenses intended to limit the scope of such an attack. If the vault value is too low of a percentage of the ousd total supply, then the mints will revert. However this vault check happened before the redeem happened. Here's why this is bad:
The vault value check should happen after the redeem, not before. I've added this change here: LogicI've simmed out the math on paper and it seems to work. Old OUSD tests pass, and new exchange rates test pass. Tests
FlavorWhy do we have all the virtuals in VaultCore? Those should not be needed? Overflow
Proxy
Black magic
🔆 We don't have our vault core proxy fix merged in. This means that we MUST have multisig ownership of the VaultCore implementation contract. We do have this in the current live contract. DependenciesNo new dependancies, and no change in dependancies. Deploy
Authentication
Cryptographic codeNo crypto Gas problems
External calls
As in the long discussion in the OracleRouters review, our current oracles are bad. However, we should still keep at least the same assets. Ethereum
|
sparrowDom
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Lets merge this to master since it is already live on mainnet for some time
If you made a contract change, make sure to complete the checklist below before merging it in master.
Refer to our documentation for more details about contract security best practices.
TODO:
Contract change checklist: