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

0x73696d616f - Users redeeming with Ds in the Psm will not decrease the correct amount of locked Ra, leading to stolen funds on withdrawals #179

Closed
sherlock-admin2 opened this issue Sep 10, 2024 · 3 comments
Labels
Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label High A High severity issue. Reward A payout will be made for this issue Sponsor Confirmed The sponsor acknowledged this issue is valid Will Fix The sponsor confirmed this issue will be fixed

Comments

@sherlock-admin2
Copy link
Contributor

sherlock-admin2 commented Sep 10, 2024

0x73696d616f

High

Users redeeming with Ds in the Psm will not decrease the correct amount of locked Ra, leading to stolen funds on withdrawals

Summary

Psm::redeemRaWithDs() calls PsmLib::redeemWithDs(), which calls PsmLib::_afterRedeemWithDs() to send the unlocked Ra to the owner and decrease self.psm.balances.ra.locked by calling self.psm.balances.ra.unlockTo(owner, received);, that is, the amount of Ra locked in the contract.

However, in the process, the Ra amount decreased from self.psm.balances.ra.locked is just the received, which has been subtracted the fee. But, this fee is used to provide liquidity, which means it is no longer locked and available, leading to the Psm having a bigger self.psm.balances.ra.locked than it should.

As such, on PsmLib::_separateLiquidity(), more Ra than what really exists is assumed to be available for withdrawal, which will make some users steal Ra when withdrawing and the last users not being able to withdraw.

Root Cause

In PsmLib:346, the Ra locked is decreased by the received amount minus the fee.

Internal pre-conditions

None.

External pre-conditions

None.

Attack Path

  1. User calls Psm::redeemWithDs().

Impact

Users withdrawing first steal funds and the last users will not be able to withdraw their funds at all.

PoC

In PsmLib::_afterRedeemWithDs(), self.psm.balances.ra.unlockTo(owner, received); is called with the received amount minus the fee:

function _afterRedeemWithDs(
    State storage self,
    DepegSwap storage ds,
    address owner,
    uint256 amount,
    uint256 feePrecentage
) internal returns (uint256 received, uint256 _exchangeRate, uint256 fee) {
    IERC20(ds._address).transferFrom(owner, address(this), amount);

    _exchangeRate = ds.exchangeRate();
    received = MathHelper.calculateRedeemAmountWithExchangeRate(amount, _exchangeRate);

    fee = MathHelper.calculatePrecentageFee(received, feePrecentage);
    received -= fee;

    IERC20(self.info.peggedAsset().asErc20()).safeTransferFrom(owner, address(this), amount);

    self.psm.balances.ra.unlockTo(owner, received);
}

In RedemptionAssetManagerLib::unlockTo() it decreases the locked Ra by the amount passed:

function unlockTo(PsmRedemptionAssetManager storage self, address to, uint256 amount) internal {
    decLocked(self, amount);
    unlockToUnchecked(self, amount, to);
}

Mitigation

In PsmLib::_afterRedeemWithDs(), the user should receive the amount minus the fee but the locked Ra should decrease by the full amount:

function _afterRedeemWithDs(
    State storage self,
    DepegSwap storage ds,
    address owner,
    uint256 amount,
    uint256 feePrecentage
) internal returns (uint256 received, uint256 _exchangeRate, uint256 fee) {
    IERC20(ds._address).transferFrom(owner, address(this), amount);

    _exchangeRate = ds.exchangeRate();
    received = MathHelper.calculateRedeemAmountWithExchangeRate(amount, _exchangeRate);

    fee = MathHelper.calculatePrecentageFee(received, feePrecentage);

    self.psm.balances.ra.decLocked(received); //@audit full amount is decreased
    received -= fee;
    self.psm.balances.ra.unlockToUnchecked(received, owner); //@audit owner receives amount - fee

    IERC20(self.info.peggedAsset().asErc20()).safeTransferFrom(owner, address(this), amount);
}

Duplicate of #155

@github-actions github-actions bot added Has Duplicates A valid issue with 1+ other issues describing the same vulnerability Medium A Medium severity issue. labels Sep 14, 2024
@ziankork
Copy link
Collaborator

This is valid. will fix

@sherlock-admin3 sherlock-admin3 added Sponsor Confirmed The sponsor acknowledged this issue is valid Will Fix The sponsor confirmed this issue will be fixed labels Sep 24, 2024
@cvetanovv cvetanovv added Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label and removed Has Duplicates A valid issue with 1+ other issues describing the same vulnerability labels Sep 24, 2024
@sherlock-admin3 sherlock-admin3 changed the title Blurry Blush Mouse - Users redeeming with Ds in the Psm will not decrease the correct amount of locked Ra, leading to stolen funds on withdrawals 0x73696d616f - Users redeeming with Ds in the Psm will not decrease the correct amount of locked Ra, leading to stolen funds on withdrawals Sep 25, 2024
@sherlock-admin3 sherlock-admin3 added the Reward A payout will be made for this issue label Sep 25, 2024
@ziankork
Copy link
Collaborator

ziankork commented Oct 3, 2024

this isn't a dup of #155, it's a similar issue but on a different function and feature altogether

@sherlock-admin2
Copy link
Contributor Author

The protocol team fixed this issue in the following PRs/commits:
Cork-Technology/Depeg-swap#96

@WangSecurity WangSecurity added High A High severity issue. and removed Medium A Medium severity issue. labels Oct 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label High A High severity issue. Reward A payout will be made for this issue Sponsor Confirmed The sponsor acknowledged this issue is valid Will Fix The sponsor confirmed this issue will be fixed
Projects
None yet
Development

No branches or pull requests

5 participants