Skip to content

Latest commit

 

History

History
113 lines (91 loc) · 4.2 KB

030.md

File metadata and controls

113 lines (91 loc) · 4.2 KB

Dizzy Brunette Mule

High

Both the swap and defiToStablecoinSwap functions can be DoSed under certain conditions

Summary

When the AmirX::swap function is called, we enter the following block of code:

 function swap(
        address wallet,
        bool directional,
        StablecoinSwap memory ss,
        DefiSwap memory defi
    ) external payable onlyRole(SWAPPER_ROLE) whenNotPaused {
        // checks if it will fail
        if (ss.destination != address(0)) _verifyStablecoinSwap(wallet, ss);
        if (defi.walletData.length != 0) _verifyDefiSwap(wallet, defi);

        if (directional) {
            // if only defi swap
            if (ss.destination == address(0)) _defiSwap(wallet, defi);
            else {
                // if defi then stablecoin swap
                //check balance to adjust second swap
                uint256 iBalance = ERC20(ss.origin).balanceOf(wallet);
                if (defi.walletData.length != 0) _defiSwap(wallet, defi);
                uint256 fBalance = ERC20(ss.origin).balanceOf(wallet);
                //change balance to reflect change
                if (fBalance - iBalance != 0) ss.oAmount = fBalance - iBalance;
                _stablecoinSwap(wallet, ss);
            }
...

Right here the system performs the swap for ss.origin token, then changes the ss.oAmount and calls _stablecoinSwap. Peeking into the _stablecoinSwap function, we see the following transfer:

function _stablecoinSwap(
        address wallet,
        StablecoinSwap memory ss
    ) internal {
        if (
            ss.stablecoinFeeCurrency != address(0) &&
            ss.stablecoinFeeSafe != address(0)
        )
            ERC20PermitUpgradeable(ss.stablecoinFeeCurrency).safeTransferFrom(
                wallet,
                ss.stablecoinFeeSafe,
                ss.feeAmount
            );

Now, Imagine the following scenario. The swap function is called for the wallet, and defiSwap to StablecoinSwap is performed. at first the balance of user for origin token is 0 and after the swap it becomes 100, respectively ss.oAmount == 100. Then the _stablecoinSwap function is called, and it performs the transfer ss.stablecoinFeeCurrency from wallet to ss.stablecoinFeeSafe. If ss.feeAmount == 10, users balance of origin token becomes 90 (Because origin token and ss.stablecoinFeeCurrency are the same token). The problem comes right after that, in the following lines of code:

function _stablecoinSwap(
        address wallet,
        StablecoinSwap memory ss
    ) internal {

...

 if (isXYZ(ss.origin)) {
            Stablecoin(ss.origin).burnFrom(wallet, ss.oAmount);
        } else {
            ERC20PermitUpgradeable(ss.origin).safeTransferFrom(
                wallet,
                ss.liquiditySafe,
                ss.oAmount
            );
        }

        // Handle the minting or transferring of the target currency:
        // If the target is a recognized stablecoin (XYZ), mint the required amount to the destination address.
        if (isXYZ(ss.target)) {
            Stablecoin(ss.target).mintTo(ss.destination, ss.tAmount);
        } else {
            ERC20PermitUpgradeable(ss.target).safeTransferFrom(
                ss.liquiditySafe,
                ss.destination,
                ss.tAmount
            );
        }
    }

The system tries to burn/transfer tokens from the wallet, but this tokens may not be in the wallet as in the presented edge case (balance of wallet == 90; system wants to burn == 100). This can lead to DoS of the swap and defiToStablecoinSwap functions

Root Cause

Making some fee transfers before the before the main burning/transferring functionality

Internal pre-conditions

ss.origin and ss.stablecoinFeeCurrency to be the same token. ss.Amount + ss.feeAmount to be higher than the user balance of origin token.

External pre-conditions

None

Attack Path

Described in the Summary department

Impact

DoS of both swap and defiToStablecoinSwap functions for users with low starting ss.origin token balance

PoC

No response

Mitigation

No response