Skip to content

Latest commit

 

History

History
88 lines (64 loc) · 3.37 KB

066.md

File metadata and controls

88 lines (64 loc) · 3.37 KB

Sneaky Macaroon Sealion

Medium

Inconsistency between ss.oAmount handling defi to stablecoin swaps

Summary

Handling of ss.oAmount in defiToStablecoinSwap and swap functions (under certain swap conditions) when fBalance - iBalance == 0 greatly differ despite which can lead to stablecoin swaps being done for free or users paying for both defiswap and stablecoin swap.

Root Cause

defiToStablecoinSwap function has three major steps, it performs a defi swap, sets ss.oAmount to balance difference before and after the defi swap and performs a stablecoin swap.

    function defiToStablecoinSwap(
        address wallet,
        StablecoinSwap memory ss,
        DefiSwap memory defi
    ) external payable onlyRole(SWAPPER_ROLE) whenNotPaused {
        // checks if defi will fail
        _verifyDefiSwap(wallet, defi);
        // checks if stablecoin swap will fail
        _verifyStablecoinSwap(wallet, ss);

        //check balance to adjust second swap
        uint256 iBalance = ERC20(ss.origin).balanceOf(wallet);
@>1     _defiSwap(wallet, defi);
        uint256 fBalance = ERC20(ss.origin).balanceOf(wallet);
@>2     ss.oAmount = fBalance - iBalance;
        //change balance to reflect change
@>3     _stablecoinSwap(wallet, ss);
    }

Also, under the hood, directional swap function when ss.destination destination is is not 0, functions exactly as a defi to stablecoin swap. The function first performs a _defiSwap and later performs a _stablecoinSwap swap but in between sets ss.oAmount to balance difference before and after the defi swap. The difference here being that ss.oAmount is only set if fBalance - iBalance == 0

   function swap(
        address wallet,
        bool directional,
        StablecoinSwap memory ss,
        DefiSwap memory defi
    ) external payable onlyRole(SWAPPER_ROLE) whenNotPaused {
//...
        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);
@>1             if (defi.walletData.length != 0) _defiSwap(wallet, defi);
                uint256 fBalance = ERC20(ss.origin).balanceOf(wallet);
                //change balance to reflect change
@>2             if (fBalance - iBalance != 0) ss.oAmount = fBalance - iBalance;
@>3             _stablecoinSwap(wallet, ss);
            }
//...
    }

As can be seen, even though the functions(swap function under some conditions) perform the same steps, the ss.oAmount set during for stablecoin swap in the two functions are different and in case of the defiToStablecoinSwap function, can lead to users conducting free swaps.

Internal pre-conditions

No response

External pre-conditions

No response

Attack Path

No response

Impact

Users conducting free swaps with 0 amount.

PoC

No response

Mitigation

Add the if (fBalance - iBalance != 0) check to defiToStablecoinSwap function.