# Withdrawals -- what it could have been?
### How we got here?
A little over a year ago when the two initial approaches (pull vs push) were discussed, we only had ideas for a relatively complex pull process with contracts.
[One version](https://notes.ethereum.org/@ipsilon/H1lC5OAJ5) required users to submit proofs of their CL withdrawals on EL. Unfortunately it didn't come without changes to the EL layer, as the balance of such a withdrawal contract had to be updated in an irregular fashion.
Unsurprisingly, due to a number of UX improvements (no need to submit proofs), eventually the push method ([EIP-4985](https://eips.ethereum.org/EIPS/eip-4895)) was chosen.
**Even if the method below would be superior (and I'm not 100% convinced it is), I do not argue for replacing the current solution, because that is almost rolled out 😬**
### The what if?
(We use the notations of EIP-4895 below.)
1. On `FORK_TIMESTAMP` insert the below `WithdrawalContract` at a known address (e.g. `0x0000000000000000000000000000000000001234`).
```solidity
pragma solidity 0.8.18;
contract WithdrawalContract {
event Transfer(address indexed from, address indexed to, uint256 amount);
/// The key calculation for SSTORE: `keccak256(address)`.
mapping (address => uint256) public balanceOf;
/// Withdraw at most maxBalance for the sender.
function withdraw(uint256 maxBalance) external {
// This will revert if maxBalance > balanceOf[msg.sender]
balanceOf[msg.sender] -= maxBalance;
emit Transfer(address(0), msg.sender, maxBalance);
(bool ret, ) = msg.sender.call{gas: gasleft(), value: maxBalance}("");
assert(ret);
}
}
```
**Note:** This contract is a high-level example. A production version would have likely been written in assembly.
2. The `withdrawals` in an execution payload are processed after any user-level transactions are applied. For each `withdrawal` in the list of `execution_payload.withdrawals`, the implementation
- increases the balance of the `WithdrawalContract` specified by the `amount` given,
- increases the storage value of `WithdrawalContact.storage[keccak256(address)]` by the `amount` given.
The first benefit here is that instead of updating the balances of all deposit recipients (and the need for "operations"), we only update a single account (without charging gas for it). The second benefit is that recipients still get execution on the value transfer (when they perform the claim). The downside is that small periodic withdrawals are not automatically added to recipients, and so those cases are more expensive here.
### Comparison
| | Old Push | EIP-4895 | Nice Push |
|---|---|---|---|
| User initiated on EL | Yes | No | Partially |
| Efficient for small withdrawals | No | Yes | Partially |
| Executes target | Yes | No | Yes |
| CL complexity | Low | Medium | Medium |
| EL complexity | Medium | Medium/High | Low |
| User complexity | High | Low | Low |