-
Notifications
You must be signed in to change notification settings - Fork 83
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
WOETH: Donation attack prevention #2106
base: master
Are you sure you want to change the base?
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #2106 +/- ##
==========================================
+ Coverage 53.26% 53.85% +0.58%
==========================================
Files 79 79
Lines 4098 4120 +22
Branches 1079 1081 +2
==========================================
+ Hits 2183 2219 +36
+ Misses 1912 1898 -14
Partials 3 3 ☔ View full report in Codecov by Sentry. |
RequirementsWhat is the PR trying to do? Is this the right thing? Are there bugs in the requirements? Easy ChecksAuthentication
Ethereum
Cryptographic code
Gas problems
Black magic
Overflow
Proxy
Events
Medium ChecksRounding
Dependencies
External calls
Tests
Deploy
ThinkingLogicAre there bugs in the logic?
Deployment ConsiderationsAre there things that must be done on deploy, or in the wider ecosystem for this code to work. Are they done? Internal State
For all 3 questions above it is important that: The internal credits stored in WOETH and stored in OETH (for WOETH contract) should always match unless someone sends extra OETH to the WOETH contract manually. Does this code do that? AttackWhat could the impacts of code failure in this code be. What conditions could cause this code to fail if they were not true. Does this code successfully block all attacks. FlavorCould this code be simpler? |
contracts/contracts/token/WOETH.sol
Outdated
using StableMath for uint256; | ||
// doesn't need to be public, but convenient to be able to confirm the state on the mainnet | ||
uint256 public oethCreditsHighres; | ||
bool _oethCreditsInitialized; |
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.
Missing an explicit visibility.
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.
thanks nice catch, corrected
The core attack we are trying to stop is someone sending the OETH to the wOETH contract, causing the value of wOETH in OETH terms to go suddenly up. It looks like totalAssets uses the amount of OETH held by the contract as one of two multipliers. totalAssets is in turn used to calculate the exchange ratio. If someone donates to the contract, one of these two multipliers goes up, and the donation has perfectly succeeded in increasing the value of each wOETH. This attack does not appear to be blocked at all? Or am I missing something? |
It also feels really scary that were are minting and burning using old ratios. That doesn't cause rektness? |
I misread the code and got the credits per token and the credits switched. Nevermind everything I said - I'll have to stare at it more! |
function totalAssets() public view virtual override returns (uint256) { | ||
(, uint256 creditsPerTokenHighres, ) = OETH(asset()) | ||
.creditsBalanceOfHighres(address(this)); | ||
|
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.
If we used in credits
here as well from the call from creditsBalanceOfHighres
, we would have ever piece of data already loaded inside this function to check that our actual assets was equal or greater than our expected assets.
May or may not be such a great idea though to revert in a view function.
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.
Hmm, that would be a good check that would detect possible mathematical irregularities (perhaps due to rounding). Though as you point out it would be weird to revert in a view function.
Monitoring sounds like a good place for it though. Have Grafana regularly query both credits values and check that the ones in OETH.sol are greater or equal to the ones in WOETH.sol.
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.
Invariants I can think of:
|
WOETH: Ignore donations
🚨 Report Summary
For more details view the full report in OpenZeppelin Code Inspector |
A donation to increase the OETH price remains possible via the OETH contract but will require significant funds to increase the entire OETH vault value. |
@pandadefi yes the donation attack on OETH with donating WETH to the Vault and calling |
* Add wOETH donation fork tests * test: add fork test for deposit/mint/withdraw/redeem. * test: add test for redeem after rebase. --------- Co-authored-by: clement-ux <[email protected]>
using StableMath for uint256; | ||
uint256 public oethCreditsHighres; | ||
bool private _oethCreditsInitialized; |
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.
WOETHBase
inherits WOETH
, so might as well add some gaps here now
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.
good point, done
//@dev TODO: we could implement a feature where if anyone sends OETH direclty to | ||
// the contract, that we can let the governor transfer the excess of the token. |
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.
nit: perhaps we could just treat any donation as "yield"?
* is internally being done in OETH: | ||
*/ | ||
// solhint-disable-next-line max-line-length | ||
/** https://github.com/OriginProtocol/origin-dollar/blob/2314cccf2933f5c1f76a6549c1f5c9cc935b6f05/contracts/contracts/token/OUSD.sol#L242-L249 |
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.
nit: Points to older code (pre-yield-delegation). Would be nice to update it to point to latest commit hash on master
Overview
This PR prevents an attacker to manipulate the exchange rate between WOETH & OETH by donating OETH to the contract .
Code Change Checklist
To be completed before internal review begins:
Internal review: