Skip to content
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

Merged
merged 3 commits into from
Mar 25, 2024
Merged

Conversation

ChefMist
Copy link
Collaborator

@ChefMist ChefMist commented Mar 22, 2024

Description

In #2 as we have balanceOf() and transfer(). We are prone to vulnerability when an ERC20 supports beforeTokenTransfer callback.

Example: assume $APE has beforeTokenTransfer and Alice is attacker

1/ Someone transfer 10 $APE to vault 
2/ Alice call settleAndRefund
3/ At the last part of settleAndRefund, vault transfer $APE trigger _beforeTokenTransfer
-> this is the part where we might get a call to `settleAndRefund` again 

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 the address() instead. Then it'll be up to how the caller want to handle this minted token (can take 0 action or eventually call vault.burn() -> vault.take()

thx @ChefSnoopy and @chefburger for spotting this

@ChefMist ChefMist changed the title feat: fix settleAndRefund vulnerability` feat: fix settleAndRefund vulnerability Mar 22, 2024
@@ -0,0 +1 @@
34513
Copy link
Collaborator Author

@ChefMist ChefMist Mar 22, 2024

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
Copy link
Collaborator Author

@ChefMist ChefMist Mar 22, 2024

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()) {

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;
            }
        }

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?

Copy link
Collaborator Author

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?

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;

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?

Copy link
Collaborator Author

@ChefMist ChefMist Mar 25, 2024

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

Copy link
Collaborator

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.

@ChefMist ChefMist merged commit b402267 into main Mar 25, 2024
2 checks passed
@ChefMist ChefMist deleted the feat/settle-and-refund-v2 branch March 25, 2024 04:29
@ChefMist ChefMist restored the feat/settle-and-refund-v2 branch March 25, 2024 04:29
@kritsadanuansutha
Copy link


@ChefMist ChefMist deleted the feat/settle-and-refund-v2 branch April 16, 2024 08:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants