Skip to content

Latest commit

 

History

History
137 lines (112 loc) · 6.25 KB

067.md

File metadata and controls

137 lines (112 loc) · 6.25 KB

Low Tangerine Cod

High

Cds holders will not be able to withdraw when they need collaterla from other chain

Summary

The protocol will attempt to refund msg.value - fee.nativeFee, but it has already been used for a call to another chain.

Root Cause

Here is an attempt to give user refund on his withdraw - optionsFeesToGetFromOtherChain == 0 && withdrawResult.ethAmount == 0

    function withdraw(
        uint64 index,
        uint256 excessProfitCumulativeValue,
        uint256 nonce,
        bytes memory signature
    ) external payable nonReentrant whenNotPaused(IMultiSign.Functions(5)) {
    ...
        if (optionsFeesToGetFromOtherChain == 0 && withdrawResult.ethAmount == 0) {
            (bool sent, ) = payable(msg.sender).call{value: msg.value - fee.nativeFee}("");
            if (!sent) revert CDS_ETH_TransferFailed();
        }
      ...
      }

Core_logic/CDS.sol#L409

But withdrawResult.ethAmount == 0 is not the only condition when a request to another chain will be made. E.x. params.ethAmount can be 0 but weETHAmount or rsETHAmount will not 0, so protocol will make a request to another chain with msg.value - params.fee and there will not be enougth gas to refund user, so transaction reverts.

   if (
                    params.optionsFeesToGetFromOtherChain > 0 ||
                    collateralToGetFromOtherChain > 0
                ) {
                    uint128 ethAmountFromOtherChain;
                    uint128 weETHAmountFromOtherChain;
                    uint128 rsETHAmountFromOtherChain;
                    // If needs to get the liquidated collateral from other chain
                    if (collateralToGetFromOtherChain != 0) {
                        // again call getLiquidatedCollateralToGive in cds library
                        (
                            ,
                            ethAmountFromOtherChain,
                            weETHAmountFromOtherChain,
                            rsETHAmountFromOtherChain,

                        ) = getLiquidatedCollateralToGive(
                            CDSInterface.GetLiquidatedCollateralToGiveParam(
                                collateralToGetFromOtherChain,
                                0,
                                0,
                                interfaces.globalVariables.getOmniChainCollateralData(IBorrowing.AssetName.ETH).totalLiquidatedAmount -
                                    interfaces.treasury.liquidatedCollateralAmountInWei(IBorrowing.AssetName.ETH),
                                interfaces.globalVariables.getOmniChainCollateralData(IBorrowing.AssetName.WeETH).totalLiquidatedAmount -
                                    interfaces.treasury.liquidatedCollateralAmountInWei(IBorrowing.AssetName.WeETH),
                                interfaces.globalVariables.getOmniChainCollateralData(IBorrowing.AssetName.WrsETH).totalLiquidatedAmount -
                                    interfaces.treasury.liquidatedCollateralAmountInWei(IBorrowing.AssetName.WrsETH),
                                params.omniChainData.totalVolumeOfBorrowersAmountLiquidatedInWei -
                                    interfaces.treasury.totalVolumeOfBorrowersAmountLiquidatedInWei(),
                                params.weETH_ExchangeRate,
                                params.rsETH_ExchangeRate
                            )
                        );

                        params.ethAmount = ethAmountFromOtherChain +  params.ethAmount;
                        weETHAmount = weETHAmountFromOtherChain + weETHAmount;
                        rsETHAmount = rsETHAmountFromOtherChain + rsETHAmount;
                    }
                    // Get the assets from other chain
                    interfaces.globalVariables.oftOrCollateralReceiveFromOtherChains{
->                        value: msg.value - params.fee
                    }(
                        IGlobalVariables.FunctionToDo(
                            // Call getLzFunctionToDo in cds library to get, which action needs to do in dst chain
                            getLzFunctionToDo(params.optionsFeesToGetFromOtherChain, collateralToGetFromOtherChain)
                        ),
                        IGlobalVariables.USDaOftTransferData(address(interfaces.treasury), params.optionsFeesToGetFromOtherChain),
                        IGlobalVariables.CollateralTokenTransferData(
                            address(interfaces.treasury),
                            ethAmountFromOtherChain,
                            weETHAmountFromOtherChain,
                            rsETHAmountFromOtherChain
                        ),
                        IGlobalVariables.CallingFunction.CDS_WITHDRAW,
                        msg.sender
                    );

collateralToGetFromOtherChain is a parameter that determines whether the call to another chain occurs or not.

Internal pre-conditions

user's withdrawal will get not get eth from other chain, but other collateral which will happen

External pre-conditions

No response

Attack Path

always happening

Impact

Users will not be able to withdraw when they will not need eth from another chain but other collateral which is possible from code.

PoC

No response

Mitigation

collateralToGetFromOtherChain is a parameter that determines whether the call to another chain occurs or not.

            return CDSInterface.WithdrawResult(
                        params.cdsDepositDetails,
                        params.omniChainData,
                        params.ethAmount,
                        params.usdaToTransfer,
                        params.optionFees,
                        totalCdsDepositedAmount,
                        totalCdsDepositedAmountWithOptionFees
+            collateralToGetFromOtherChain
                    );
-        if (optionsFeesToGetFromOtherChain == 0 && withdrawResult.ethAmount == 0) {
+        if (optionsFeesToGetFromOtherChain == 0 && withdrawResult.collateralToGetFromOtherChain == 0) {
            
            (bool sent, ) = payable(msg.sender).call{value: msg.value - fee.nativeFee}("");
            if (!sent) revert CDS_ETH_TransferFailed();
        }