contract MixinWethUtils {

    uint256 constant internal MAX_UINT256 = uint256(-1);

     // solhint-disable var-name-mixedcase
    IEtherToken internal WETH;
    bytes internal WETH_ASSET_DATA;
    // solhint-enable var-name-mixedcase

    using LibSafeMath for uint256;

    constructor (
        address exchange,
        address weth
    )
        public
    {
        WETH = IEtherToken(weth);
        WETH_ASSET_DATA = abi.encodeWithSelector(
            IAssetData(address(0)).ERC20Token.selector,
            weth
        );

        address proxyAddress = IExchange(exchange).getAssetProxy(IAssetData(address(0)).ERC20Token.selector);
        if (proxyAddress == address(0)) {
            LibRichErrors.rrevert(LibWethUtilsRichErrors.UnregisteredAssetProxyError());
        }
        WETH.approve(proxyAddress, MAX_UINT256);

        address protocolFeeCollector = IExchange(exchange).protocolFeeCollector();
        if (protocolFeeCollector != address(0)) {
            WETH.approve(protocolFeeCollector, MAX_UINT256);
        }
    }

    /// @dev Default payable function, this allows us to withdraw WETH
    function ()
        external
        payable
    {
        if (msg.sender != address(WETH)) {
            LibRichErrors.rrevert(LibWethUtilsRichErrors.DefaultFunctionWethContractOnlyError(
                msg.sender
            ));
        }
    }

    /// @dev Transfers ETH denominated fees to all feeRecipient addresses
    /// @param ethFeeAmounts Amounts of ETH, denominated in Wei, that are paid to corresponding feeRecipients.
    /// @param feeRecipients Addresses that will receive ETH when orders are filled.
    /// @return ethRemaining msg.value minus the amount of ETH spent on affiliate fees.
    function _transferEthFeesAndWrapRemaining(
        uint256[] memory ethFeeAmounts,
        address payable[] memory feeRecipients
    )
        internal
        returns (uint256 ethRemaining)
    {
        uint256 feesLen = ethFeeAmounts.length;
        // ethFeeAmounts len must equal feeRecipients len
        if (feesLen != feeRecipients.length) {
            LibRichErrors.rrevert(LibWethUtilsRichErrors.EthFeeLengthMismatchError(
                feesLen,
                feeRecipients.length
            ));
        }

        // This function is always called before any other function, so we assume that
        // the ETH remaining is the entire msg.value.
        ethRemaining = msg.value;

        for (uint256 i = 0; i != feesLen; i++) {
            uint256 ethFeeAmount = ethFeeAmounts[i];
            // Ensure there is enough ETH to pay the fee
            if (ethRemaining < ethFeeAmount) {
                LibRichErrors.rrevert(LibWethUtilsRichErrors.InsufficientEthForFeeError(
                    ethFeeAmount,
                    ethRemaining
                ));
            }
            // Decrease ethRemaining and transfer fee to corresponding feeRecipient
            ethRemaining = ethRemaining.safeSub(ethFeeAmount);
            feeRecipients[i].transfer(ethFeeAmount);
        }

        // Convert remaining ETH to WETH.
        WETH.deposit.value(ethRemaining)();

        return ethRemaining;
    }

    /// @dev Unwraps WETH and transfers ETH to msg.sender.
    /// @param transferAmount Amount of WETH balance to unwrap and transfer.
    function _unwrapAndTransferEth(
        uint256 transferAmount
    )
        internal
    {
        // Do nothing if amount is zero
        if (transferAmount > 0) {
            // Convert WETH to ETH
            WETH.withdraw(transferAmount);
            // Transfer ETH to sender
            msg.sender.transfer(transferAmount);
        }
    }

    /// @dev  transfers ETH to address.
    /// @param transferAmount Amount of eth to transfer.
    function _transferEthToAddress(
        uint256 transferAmount,
        address transferAddress
    )
        internal
    {
        // Do nothing if amount is zero
        if (transferAmount > 0) {
            address payable transferAddresspayable = address(uint160(transferAddress));
            transferAddresspayable.transfer(transferAmount);
        }
    }


}
function _unwrapAndTransferEth(
    uint256 transferAmount
)
    internal
{
    // Do nothing if amount is zero
    if (transferAmount > 0) {
        // Convert WETH to ETH
        WETH.withdraw(transferAmount);
        // Transfer ETH to sender
        msg.sender.transfer(transferAmount);
    }
}

/// @dev Unwraps WETH and transfers ETH to msg.sender.
/// @param transferAmount Amount of WETH balance to unwrap and transfer.