-
Notifications
You must be signed in to change notification settings - Fork 84
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
Yield Delegation / Rebasing Token Rewrite #2298
Conversation
5795ca3
to
07293d2
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #2298 +/- ##
===========================================
- Coverage 53.36% 17.97% -35.40%
===========================================
Files 79 79
Lines 4098 4134 +36
Branches 1079 1087 +8
===========================================
- Hits 2187 743 -1444
- Misses 1908 3389 +1481
+ Partials 3 2 -1 ☔ View full report in Codecov by Sentry. |
contracts/contracts/token/OUSD.sol
Outdated
_allowances[_from][msg.sender] = _allowances[_from][msg.sender].sub( | ||
_value | ||
); | ||
allowances[_from][msg.sender] -= _value; |
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.
A good practice is to keep the allowance at maximum value if it's set to max value, it saves some gas avoiding a write. You could use unchecked
math
contracts/contracts/token/OUSD.sol
Outdated
require(_to != address(0), "Transfer to zero address"); | ||
require(_value <= balanceOf(_from), "Transfer greater than balance"); | ||
require(_value <= allowances[_from][msg.sender], "Allowance exceeded"); |
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.
You could cache the allowance otherwise it's read on line 225 and on line 227.
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 thanks: d285b32
* add missing natspec * corrections to code comments
contracts/contracts/token/OUSD.sol
Outdated
alternativeCreditsPerToken[_account] > 0 || | ||
// Accounts may explicitly `rebaseOptIn` regardless of | ||
// accounting if they have a 0 balance. | ||
balance == 0 |
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.
After decoding the certora ping on this method, I've tracked it down to bad accounting created when account credits are > 0 but < rebasingCreditsPerToken. I'm not sure that this can actually happen in real life, however, if it does then the already rebasing credits on that are already account are not accounted for when updating the globals.
- Do we need the balance==0 check at all?
- If so, can we replace it with a
creditBalances[_account] == 0
check, which should be a stronger check?
Me to certora.
Looks like the exampe is a rebasing account that is opting into being a rebasing account. It's skipping the accounting check because the balance is zero. However that zero balance in the example is coming from having some credits on the account that are divided by a larger global rebasingCreditsPerToken, resulting in 0.
I'm not sure this is a situation that could actually happen in practice, since in order to have any credits at all, then the account would have had to been transfered or minted >= 1 raw balance. If they had 1 raw balance, then they would have had account credits = the global rebasingCreditsPerToken. Since global rebasingCreditsPerToken only goes down, it shouldn't be possible in real life to have a rebasing account with (account credits < rebasingCreditsPerToken AND account credits > 0) and thus should not be possible to have an stdRebasing account with credits but not a balance.
Nevertheless, we'll probably the code so this rule would pass successfully as the rule is currently written. Given a choice, I'd rather have the code be correct in all circumstances, not just all possible circumstances.
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.
Test reproduction:
ousd.mint(user, 1);
// Negative rebase shouldn't happen in the real world.
ousd.changeSupply(ousd.totalSupply()-1e18);
// At this point the user has a 0 balance and nonzero credits.
vm.prank(user);
ousd.rebaseOptIn();
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.
I just temporarily altered the check to use creditBalances[_account] == 0
, so that we can see with certora if there are any other bad behaviors out of this 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.
Yes agreed, the creditBalance
check should be a stronger one and still perform its old duty by allowing an empty rebasing account to explicitly optIn into rebasing.
I think your finding is correct that this failed state can only be reached if one rebases negatively consequently changing the supply downwards.
The storage data from the tests suggest the same with really large numbers for rebasingCreditsPerToken
:
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.
@sparrowDom What was the reason for allowing zero balance rebaseOptIns for rebasing accounts? Just ease of setting up new contracts?
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.
Yes that is the only reason I can think of. We do allow calling rebaseOptIn
for EOA accounts with 0 balance as well, though I see no real utility there.
* Add OUSD spec files and running scripts * Small updates to running scripts. * Add invariants to SumOfBalances spec.
We are revamping the our rebasing token contract.
The primary objective is to allow delegated yield. Delegated yield allows an account to seemlessly transfer all earned yield to another account.