Skip to main content
All CollectionsOther FAQ
Why can't I transfer ETH from a contract into a Safe?
Why can't I transfer ETH from a contract into a Safe?

This is a technical article explain why moving ETH into a Safe might fail with “out of gas”.

Tobias Schubotz avatar
Written by Tobias Schubotz
Updated over a week ago

Context:

In the recent Berlin hardfork, gas costs have been adapted as follows:

Gas costs before Berlin hardfork:

  • Access account: 700 gas

  • Read storage slot: 800 gas

Gas costs after Berlin hardfork (changed by EIP-2929)

  • Access account:

    • First time per address in tx: 2600 gas

    • Any additional time in tx: 100 gas

  • Read storage slot:

    • First time per storage slot in tx: 2100 gas

    • Any additional time in tx: 100 gas

Problem:

In case a contract uses `transfer` or `send` to move ETH to a different account, the available gas is limited to 2300. Before the Berlin hardfork this was sufficient for most contracts. But now accessing a contract for the first time (which would be done when ETH is moved to the account that is a contract) the gas costs are already 2600 gas and therefore it will fail with “out of gas”.

Solution:

To prevent this from happening EIP-2930 was included along with EIP-2929. This EIP introduces an access list. For any address or storage slot on the access list the gas is paid ahead of time, reducing the runtime costs to 100 gas. This will allow to overcome the issue that not enough gas is available when moving ETH from a contract to another with the default Solidity methods.

This opens up 2 options to mitigate the issue:

Option 1:

  • Make use of the access list feature. Currently this is only possible by writing a script that uses a low level Ethereum lib (e.g. Ethers) to populate the access list. The access list should contain the address of the receiving Safe and the address of the Safe singleton.

  • An example for this solution can be found here: https://github.com/folia-app/eip-2929

Option 2:

  • Make sure that the Safe has been accessed before in the transaction. E.g. use a Safe transaction to trigger the contract that is moving ETH.

Did this answer your question?