> For the complete documentation index, see [llms.txt](https://zokyo-auditing-tutorials.gitbook.io/zokyo-tutorials/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://zokyo-auditing-tutorials.gitbook.io/zokyo-tutorials/tutorial-25-cross-chain-bridges-vulnerabilities/erc777-bridge-vulnerability-reentrancy-attack-in-token-accounting/vulnerability-withdrawals-can-be-locked-forever-if-recipient-is-a-contract.md).

# Vulnerability: Withdrawals Can Be Locked Forever If Recipient Is a Contract

In some Ethereum smart contracts, withdrawals of assets like ETH or ERC20 tokens are handled through a function that transfers the tokens back to the user after a cooldown period. One common method for sending ETH is the low-level **`transfer()`** function. However, using **`transfer()`** can inadvertently lock funds forever when the recipient is a contract, particularly if the recipient contract has a **receive()** or **fallback** function that requires more gas than what is forwarded by **`transfer()`**.

This vulnerability can result in the **permanent loss of funds**, as the transfer fails and the user cannot retrieve their assets. This section will explain the mechanics of this vulnerability, the specific attack flow, and how to mitigate the issue to ensure that users, including contracts, can safely withdraw their funds.

***

#### Vulnerability Explanation

When the **`transfer()`** function is used to send ETH, it only forwards **2300 gas** to the recipient. While this is sufficient for basic operations like receiving ETH in a standard externally owned account (EOA), it is not enough to cover more complex logic that might exist in a **contract account** (e.g., a multisig wallet or a contract implementing more complex functionality).

In scenarios where a user initiates a withdrawal from a contract account that requires more than 2300 gas to execute the **`receive()`** or **`fallback()`** function, the **`transfer()`** call will fail, causing the transaction to revert. Since the recipient contract cannot execute its logic, the funds remain locked in the smart contract, and the user cannot retrieve their assets.

***

#### Example Scenario: Locked Withdrawals

Let’s explore how this issue can occur in the context of a **WithdrawQueue** contract, where users are allowed to withdraw ETH or ERC20 tokens after a cooldown period.

**Scenario Steps:**

1. **User Initiates Withdrawal**:
   * Alice calls the **`withdraw()`** function from her **multisig wallet contract** to withdraw 10 ETH worth of tokens. The multisig contract is registered as the **msg.sender** and is stored as the **withdrawal requester** in the smart contract.
2. **Cooldown Period**:
   * After the cooldown period, Alice is ready to claim her withdrawn ETH using the **`claim()`** function.
3. **Withdrawal via `transfer()`**:
   * The contract attempts to send ETH back to Alice’s multisig wallet using **`transfer()`**

```
payable(msg.sender).transfer(_withdrawRequest.amountToRedeem);

```

1. However, since **`transfer()`** only forwards **2300 gas**, it is not enough for Alice’s multisig wallet to execute its **`receive()`** function, which requires more than 2300 gas.
2. **Transaction Fails**:
   * The **`transfer()`** call fails due to an **out of gas** error, and the **`claim()`** transaction reverts. Alice is unable to withdraw her funds because her contract requires more gas to process the ETH transfer.
3. **Funds Locked Forever**:
   * The 10 ETH is now permanently locked in the **WithdrawQueue** contract. Since the withdrawal request was tied to Alice's multisig wallet, no one else can claim the funds, and Alice cannot retrieve them due to the gas limitation imposed by **`transfer()`**.

***

#### Why This Happens

The core issue lies in the fact that **`transfer()`** is too restrictive in the amount of gas it forwards to the recipient. While **`transfer()`** is considered a safer method for sending ETH because it limits the gas available to the recipient, it fails when interacting with **contracts** that need more than 2300 gas to process the transfer.

Many **multisig wallets**, **smart contract wallets**, or **DeFi protocols** have a **`receive()`** or **`fallback()`** function that may require significantly more gas to perform necessary actions, such as emitting events, updating internal state, or interacting with other contracts. When **`transfer()`** is used, these contracts cannot process the transaction, causing it to fail.
