2

I know it is possible to calculate the contract address in solidity by using the create2 opcode.

Let's say I transfer 1 ether to a random address.

Then I deploy a contract with a payable transfer function on that address.

Is it possible to deploy that contract and transfer out the ether?

1 Answer 1

2

I know it is possible to calculate the contract address in solidity by using the create2 opcode. Let's say I transfer 1 ether to a random address. Then I deploy a contract with a payable transfer function on that address.

The address should not be random. This should be the address you get after pre-computing the future smart contract address.

What happens if i deploy a contract to an address that already has eth?

The ethers will remain on the address and belong to the newly deployed smart contract. So if no function has been implemented to handle these ethers, they will be lost forever. On the other hand, yes, a payable function should be able to transfer them.

We can verify this in the Ethereum yellow paper with equations (83) and (86), part 7 "Contract Creation".

enter image description here

enter image description here

sigma^*[a] is the mutated account state of the smart contract computed during its creation before the initialization code execution. It is made up of four fields, the second one being the account balance.

The contract thus receives v+v' Wei once created :

  • v is the amount sent to the contract during the deployment (endowment)
  • v' is defined by the yellow paper as the account’s pre-existing value, in the event it was previously in existence. Indeed, sigma[a]b represents the current balance of the account, under the assumption that the account exists.

We can check too the Ethereum go implementation of the yellow paper.

Create2 function

Github file : https://github.com/ethereum/go-ethereum/blob/master/core/vm/evm.go.

This is the function used for the create2 OPCODE :

// Create2 creates a new contract using code as deployment code.
//
// The different between Create2 with Create is Create2 uses sha3(0xff ++ msg.sender ++ salt ++ sha3(init_code))[12:]
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
    codeAndHash := &codeAndHash{code: code}
    contractAddr = crypto.CreateAddress2(caller.Address(), salt.Bytes32(), codeAndHash.Hash().Bytes())
    return evm.create(caller, codeAndHash, gas, endowment, contractAddr)
}

create function

Github file : https://github.com/ethereum/go-ethereum/blob/master/core/vm/evm.go.

As you can see, Create2 calls a create function. This one is very big so I will only show the relevant part here :

// Create a new account on the state
snapshot := evm.StateDB.Snapshot()
evm.StateDB.CreateAccount(address)

A CreateAccount method is called to store a new account on the computed address.

CreateAccount

Github file : https://github.com/ethereum/go-ethereum/blob/master/core/state/statedb.go.

// CreateAccount explicitly creates a state object. If a state object with the address
// already exists the balance is carried over to the new account.
//
// CreateAccount is called during the EVM CREATE operation. The situation might arise that
// a contract does the following:
//
//   1. sends funds to sha(account ++ (nonce + 1))
//   2. tx_create(sha(account ++ nonce)) (note that this gets the address of 1)
//
// Carrying over the balance ensures that Ether doesn't disappear.
func (s *StateDB) CreateAccount(addr common.Address) {
    newObj, prev := s.createObject(addr)
    if prev != nil {
        newObj.setBalance(prev.data.Balance)
    }
}

Note the comment CreateAccount explicitly creates a state object. If a state object with the address already exists the balance is carried over to the new account. which confirms to us that the ethers are preserved. Here, state object refers to the account states of the world state trie.

The ethers are "carried over" to the new account object with this line : newObj.setBalance(prev.data.Balance).

3
  • Just as additional info, you could also get those ETH in that contract if you code a method that calls the selfdestruct OPCODE, this would effectively empty the contract's storage and bytecode and sends all the ETH that the contract address contains to a recipient address. Jun 26, 2021 at 16:26
  • @scorpion9979 will selfdestruct empty the contract's nonce? It is also required for a new deployment at the same address.
    – Rutrus
    Mar 9, 2022 at 14:12
  • 1
    @Rutrus Apparently yes, according to the accepted answer here: ethereum.stackexchange.com/questions/76496/… Mar 9, 2022 at 15:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.