-
Notifications
You must be signed in to change notification settings - Fork 47
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
feat: fix settleAndRefund
vulnerability
#4
Conversation
settleAndRefund
vulnerability`settleAndRefund
vulnerability
@@ -0,0 +1 @@ | |||
34513 |
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.
before was 36514
now 34513
in cases wheres theres nothing to refund
@@ -0,0 +1 @@ | |||
73023 |
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.
before was 56176
in erc20 transfer, now 73023
in cases where there's excess token to refund
src/Vault.sol
Outdated
|
||
int256 currentDelta = SettlementGuard.getCurrencyDelta(msg.sender, currency); | ||
if (currentDelta >= 0 && paid > currentDelta.toUint256()) { |
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.
Can cache currentDelta after casting to uint256 so you don't have to keep casting it again, wasting gas.
if (currentDelta >= 0) {
uint256 currentDeltaUint256 = currentDelta.toUint256();
if (paid > currentDeltaUint256 ) {
// msg.sender owes vault but paid more than whats owed
refund = paid - currentDeltaUint256;
paid = currentDeltaUint256;
}
}
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.
Also just to confirm, refund is only done, and paid is only adjusted if currentDelta is positive or zero, never if currentDelta is negative?
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.
Also just to confirm, refund is only done, and paid is only adjusted if currentDelta is positive or zero, never if currentDelta is negative?
yep. do you think theres a scenario where negative balanceDelta (vault owes caller token) might need to handled?
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.
Not sure, that's why I'm asking.
int256 currentDelta = SettlementGuard.getCurrencyDelta(msg.sender, currency); | ||
uint256 reservesBefore = reservesOfVault[currency]; | ||
reservesOfVault[currency] = currency.balanceOfSelf(); | ||
paid = reservesOfVault[currency] - reservesBefore; |
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.
For this part, the function would revert if reservesBefore is larger than the current reserve, since it would mean that the locker did not transfer anything to increase the current balance right?
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 the locker didn't transfer anything, this function shouldn't revert. The behavior should be the same as settle()
.
Can think of 1 scenario for revert:
1/ might be for rebasing token, where a negative rebase was done which cause the current balance in vault to be lesser than reserveBefore
cc @chefburger or @ChefSnoopy if can add on to more scenarios where revert might happen
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 cant come with other cases either, but i think it's fine to just let it revert if reservesBefore is greater than current.
|
Description
In #2 as we have
balanceOf()
andtransfer()
. We are prone to vulnerability when an ERC20 supports beforeTokenTransfer callback.Example: assume $APE has beforeTokenTransfer and Alice is attacker
REF: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.3/contracts/token/ERC20/ERC20.sol#L305
Fix
1/ instead of transfer, we
mint
the token to theaddress()
instead. Then it'll be up to how the caller want to handle this minted token (can take 0 action or eventually callvault.burn() -> vault.take()
thx @ChefSnoopy and @chefburger for spotting this