contract P1WethProxy is
    P1Proxy,
    ReentrancyGuard
{
    // ============ Storage ============

    WETH9 public _WETH_;

    // ============ Constructor ============

    constructor (
        address payable weth
    )
        public
    {
        _WETH_ = WETH9(weth);
    }

    // ============ External Functions ============

    /**
     * Fallback function. Disallows ether to be sent to this contract without data except when
     * unwrapping WETH.
     */
    function ()
        external
        payable
    {
        require(
            msg.sender == address(_WETH_),
            "Cannot receive ETH"
        );
    }

    /**
     * @notice Deposit ETH into a Perpetual, by first wrapping it as WETH. Any ETH paid to this
     *  function will be converted and deposited.
     *
     * @param  perpetual  Address of the Perpetual contract to deposit to.
     * @param  account    The account on the Perpetual for which to credit the deposit.
     */
    function depositEth(
        address perpetual,
        address account
    )
        external
        payable
        nonReentrant
    {
        WETH9 weth = _WETH_;
        address marginToken = I_PerpetualV1(perpetual).getTokenContract();
        require(
            marginToken == address(weth),
            "The perpetual does not use WETH for margin deposits"
        );

        // Wrap ETH.
        weth.deposit.value(msg.value)();

        // Deposit all WETH into the perpetual.
        uint256 amount = weth.balanceOf(address(this));
        I_PerpetualV1(perpetual).deposit(account, amount);
    }

    /**
     * @notice Withdraw ETH from a Perpetual, by first withdrawing and unwrapping WETH.
     *
     * @param  perpetual    Address of the Perpetual contract to withdraw from.
     * @param  account      The account on the Perpetual to withdraw from.
     * @param  destination  The address to send the withdrawn ETH to.
     * @param  amount       The amount of ETH/WETH to withdraw.
     */
    function withdrawEth(
        address perpetual,
        address account,
        address payable destination,
        uint256 amount
    )
        external
        nonReentrant
    {
        WETH9 weth = _WETH_;
        address marginToken = I_PerpetualV1(perpetual).getTokenContract();
        require(
            marginToken == address(weth),
            "The perpetual does not use WETH for margin deposits"
        );

        require(
            // Short-circuit if sender is the account owner.
            msg.sender == account ||
                I_PerpetualV1(perpetual).hasAccountPermissions(account, msg.sender),
            "Sender does not have withdraw permissions for the account"
        );

        // Withdraw WETH from the perpetual.
        I_PerpetualV1(perpetual).withdraw(account, address(this), amount);

        // Unwrap all WETH and send it as ETH to the provided destination.
        uint256 balance = weth.balanceOf(address(this));
        weth.withdraw(balance);
        destination.transfer(balance);
    }
}
/**
 * @title P1WethProxy
 * @author dYdX
 *
 * @notice A proxy for depositing and withdrawing ETH to/from a Perpetual contract that uses WETH as
 *  its margin token. The ETH will be wrapper and unwrapped by the proxy.
 */
function ()
        external
        payable
    {
        require(
            msg.sender == address(_WETH_),
            "Cannot receive ETH"
        );
    }
/**
 * Fallback function. Disallows ether to be sent to this contract without data except when
 * unwrapping WETH.
 */