code-423n4 / 2022-03-lifinance-findings

6 stars 4 forks source link

[WP-M9] `sendNative` with CBridge will always revert #162

Closed code423n4 closed 2 years ago

code423n4 commented 2 years ago

Lines of code

https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Facets/CBridgeFacet.sol#L142-L157

Vulnerability details

https://github.com/code-423n4/2022-03-lifinance/blob/699c2305fcfb6fe8862b75b26d1d8a2f46a551e6/src/Facets/CBridgeFacet.sol#L142-L157

function _startBridge(CBridgeData memory _cBridgeData) internal {
    Storage storage s = getStorage();
    address bridge = _bridge();

    // Do CBridge stuff
    require(s.cBridgeChainId != _cBridgeData.dstChainId, "Cannot bridge to the same network.");

    if (LibAsset.isNativeAsset(_cBridgeData.token)) {
        ICBridge(bridge).sendNative(
            _cBridgeData.receiver,
            _cBridgeData.amount,
            _cBridgeData.dstChainId,
            _cBridgeData.nonce,
            _cBridgeData.maxSlippage
        );
    } else {
        ...

See: https://github.com/celer-network/sgn-v2-contracts/blob/b0cf02c15e25f66279420e3ff6a8b2fe07404bab/contracts/Bridge.sol#L69-L91

/**
    * @notice Send a cross-chain transfer via the liquidity pool-based bridge using the native token.
    * @param _receiver The address of the receiver.
    * @param _amount The amount of the transfer.
    * @param _dstChainId The destination chain ID.
    * @param _nonce A unique number. Can be timestamp in practice.
    * @param _maxSlippage The max slippage accepted, given as percentage in point (pip). Eg. 5000 means 0.5%.
    * Must be greater than minimalMaxSlippage. Receiver is guaranteed to receive at least (100% - max slippage percentage) * amount or the
    * transfer can be refunded.
    */
function sendNative(
    address _receiver,
    uint256 _amount,
    uint64 _dstChainId,
    uint64 _nonce,
    uint32 _maxSlippage
) external payable nonReentrant whenNotPaused {
    require(msg.value == _amount, "Amount mismatch");
    require(nativeWrap != address(0), "Native wrap not set");
    bytes32 transferId = _send(_receiver, nativeWrap, _amount, _dstChainId, _nonce, _maxSlippage);
    IWETH(nativeWrap).deposit{value: _amount}();
    emit Send(transferId, msg.sender, _receiver, nativeWrap, _amount, _dstChainId, _nonce, _maxSlippage);
}

ICBridge(bridge).sendNative() should be ICBridge(bridge).sendNative{ value: msg.value }(), and the current implementation will simply revert on the cBridge's side with the "Amount mismatch" error.

Recommendation

Change to: ICBridge(bridge).sendNative{ value: msg.value }()

H3xept commented 2 years ago

Duplicate of #35