> For the complete documentation index, see [llms.txt](https://paymasterdocs.gitbook.io/paymasterdocs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://paymasterdocs.gitbook.io/paymasterdocs/vectors-of-paymaster/general-vectors/mismanagement-of-funds.md).

# Mismanagement of funds

## Missing fund withdrawal logic

{% hint style="info" %}
Users have the right to reclaim their funds!
{% endhint %}

A mechanism is needed to allow users to withdraw the funds they have deposited.

Example Case:

When a user accidentally sends tokens or ETH to the paymaster, or when there is logic that allows assets to be deposited using the deposit function, the user’s funds may become locked if there’s NO mechanism within the paymaster to withdraw the received tokens/ETH.

<figure><img src="/files/00SZQV4aASpxFLHb7y06" alt=""><figcaption></figcaption></figure>

* Mitigation : Add `withdraw` function that is based on `onlyOwner` or `msg.sender`

```
 + function withdraw(...) onlyOwner {...}
```

or

```
+ function withdraw(...) {
+    deposit[msg.sender] -= amount;
+} 
```

***

## Missing updates to balance-related variables upon fund changes

{% hint style="info" %}
Balance changes must be updated whenever there is a change in the flow of funds. If balance changes aren’t correctly updated, it can cause mismatches in funds and lead to issues like double spending.
{% endhint %}

If the user is managing withdrawals through a variable and receives a refund, the value of the variable must be updated to reflect the refunded amount. If this update is not performed correctly, it could potentially lead to a **double withdrawal** vulnerability.

Example case:

The paymaster is set up to calculate the gas fees during the validation phase and then allow any leftover funds to be withdrawn in advance during the transaction for purposes like swaps or minting. However, in the `postOp` function, where the final balance is adjusted and refunded, the `_withdrawableETH` variable—which tracks the amount available for withdrawal—was not cleared after refunding. This oversight allows users to call the `withdraw` function again, letting them receive the refund a second time.

Example Code:

```solidity
src/vulnerablePaymaster.sol


function validatePaymasterUserOp(UserOperation calldata userOp, bytes32, uint256 maxCost) external onlyEntryPoint
        returns (bytes memory context, uint256 validationData) {
       ...
       ...

        _withdrawableETH[userOp.sender] += withdrawAmount - maxCost;
        
        ...
    }


function postOp(IPaymaster.PostOpMode mode, bytes calldata context, uint256 actualGasCost) external onlyEntryPoint {
    
    ...
    ...
    ...
    
    uint256 excess = _withdrawableETH[account] + (withheld - actualGasCost);
    
    if (excess > 0) {
        _withdraw(address(0), account, excess);
    }
    ...
}
 
```

* Mitigation : Update the mapping variable that manages balances when a refund is processed in the postOp function.

```solidity
function postOp(IPaymaster.PostOpMode mode, bytes calldata context, uint256 actualGasCost) external onlyEntryPoint {
    
    ...
    ...
    ...
    
    uint256 excess = _withdrawableETH[account] + (withheld - actualGasCost);
    + delete _withdrawableETH[account];
    
    if (excess > 0) {
        _withdraw(address(0), account, excess);
    }
}
```

***

## Duplicate update of balance changes

{% hint style="info" %}
Counterfeiting is illegal.
{% endhint %}

#### When the balance in the paymaster changes, applying the balance change in multiple places can create differences between the actual amount the paymaster has and the recorded balance.

Example Case:

Whenever `_postOp` is called, the owner’s balance increases by the amount of gas used in addition to the gas processed. If the owner withdraws even a small amount of ETH, inconsistencies can occur between the EP deposit and the balance recorded in the paymaster, potentially preventing some users from accessing their full deposits.

Example Code:

```solidity
src/vulnerablePaymaster.sol

function _postOp(PostOpMode /* mode */, bytes calldata context, uint256 actualGasCost) internal override {
        (address account, uint256 gasPricePostOp) = abi.decode(context, (address, uint256));
        
        uint256 ethCost = (actualGasCost + COST_OF_POST * gasPricePostOp);
        balances[account] -= ethCost;
        contractSpent[account] += ethCost;
        balances[owner()] += ethCost; // This part causes inconsistency
    }
```

* Mitigation : Eliminate code that causes redundant balance updates.

```solidity
function _postOp(PostOpMode /* mode */, bytes calldata context, uint256 actualGasCost) internal override {
        (address account, uint256 gasPricePostOp) = abi.decode(context, (address, uint256));
        
        uint256 ethCost = (actualGasCost + COST_OF_POST * gasPricePostOp);
        balances[account] -= ethCost;
        contractSpent[account] += ethCost;
-       balances[owner()] += ethCost; // REMOVE
    }
```
