HIP-729 Expands CREATE Logic Support on Hedera
T035 PD799 T9 U036 XV20 L21 dc0a917aadc2 512
Jul 31, 2023
by Nana Essilfie-Conduah
Smart Contracts Engineering & Experience

Currently, the Hedera Smart Contract Service (HSCS) supports smart contract transactions through the Besu EVM client on the Hedera network. As such, the network provides out-of-the-box support for many EVM execution features similar to how they operate on other EVM chains.

However, Hedera’s support of EVM transactions and account features hasn’t always been a perfect 1:1 match, which has been the inspiration for our EVM equivalence goals. Hedera aims to ensure:

  • Smart contracts executed on Hedera behave as expected by EVM users from other EVM chains.

  • EVM native tools can utilize expected EVM APIs to carry out transactions and queries.

By maintaining support of the Ethereum yellow paper definitions and continued EVM upgrade specifications, the Hedera network provides a space to execute the EVM transactions developers are used to but on a faster, cheaper, more fair and decentralized Layer 1 (L1) network.

Summary

v0.40 of the Hedera services code will bring improvements that make contract creation transactions more EVM equivalent:

  • Contracts created by other contracts will now have a familiar EVM address format.

  • The address calculation logic is a result of tracking contract nonces and executing the CREATE operation, which utilizes the contract’s nonce and address.

  • DApp developers should check and update their logic to ensure they utilize the appropriate existing SDK methods when going from a contract address string to a ContractID object.

  • DApp developers may query the Mirror Node to obtain the contract num and nonce details from the CREATE EVM address.

CREATE Operations

One feature that offered a difference in behavior to date has been the 20-byte address identifier of contract accounts. On most EVM chains, this address is always the result of 1 of 2 CREATE operations — CREATE or CREATE2.

  1. CREATE – The Ethereum yellow paper introduced the original CREATE opcode, which utilizes an account address and nonce values to calculate the address of a new contract. Support for CREATE1 as part of EOA contract creation became possible with the introduction of the EthereumTransaction type (HIP-410) and nonce value tracking on EOAs.

  2. CREATE2 – EIP-1014 introduced the new CREATE2 opcode, which utilized non-account-related properties to allow for predetermined address values ahead of contract creation. Hedera added support for CREATE2 with HIP-329 in its services version v0.23.0.


Since nonce values were initially tracked only for EOAs, it was only possible to support CREATE address logic for EOA-initiated contracts created through the EthereumTransaction type.

CREATE Feature Gap

The CREATE operation utilizes the creating account’s address and nonce to calculate the new address.

The CREATE operation is composed of the following steps:

  1. The Recursive-Length Prefix (RLP) serialization of the sender address and nonce is performed.

  2. The Keccak-256 hash of the serialized result is performed.

  3. The rightmost 20 bytes of the hash result is taken.


The sequential combination of the three steps defines the new contract address, which is:

keccak256(rlp([sender_address, sender_nonce]))[12:].
1 EOA Contract A rev

Contract A created by an EOA has an equivalent EVM address, but with no nonce tracking the nonce is null.

Originally, the nonce field targeted EOAs and not contract accounts, as such accurate contract nonce values were not available to support the CREATE operation as illustrated above. However, since Hedera provided a rich account identifier in the form of the <shard>.<realm>.<num> e.g. 0.0.1007, the HSCS was able to provide a data type-compliant solution known as the the account-num alias (fka long-zero address) that could be assigned to newly created contracts created by a contract.

This address calculation is composed of the following steps:

  1. Encode the 8-byte entity num value from an entityId.

  2. Concatenate the 8-bytes with a 12-byte zero prefix.


The combination of these steps provided a compliant address format 0x000000000000{8byteEncodedEntityNum} . For example, 0.0.1007 ⇒ 0x00000000000000000000000000000000000003f0. HIP-583 provides more details regarding account identifiers in the HSCS EVM logic.

2 Contract A Contract B rev

Without contract nonce tracking, Contract B created by Contract A has a compatible but not equivalent EVM address.

Notably, the alternate 20-byte address format along with the lack of accurate contract nonce values, resulted in a solution that was EVM-compatible but not EVM-equivalent!

HIP-729 Nonce Tracking Resolution

With the onset of HIP-729 (planned release in v0.40), the HSCS took an update to fill in the feature gap and accurately capture a contract’s nonce value in an EVM equivalent manner. The nonce management follows the EVM standard steps:

  1. Upon creation, a contract’s nonce is defaulted to 1.

  2. When a contract creates another contract, its nonce value is incremented by 1.

With this nonce tracking standard, a second update was enabled by HIP-729 in which contract creation logic could now utilize the CREATE operation logic and calculate an address using the creating contract’s address and nonce.

This means that should Contract A create Contract C, Contract C will now have a nonce of 1 and an EVM address that is the result of the CREATE operation using Contract A’s address and Contract A’s nonce at the time. With this, contract addresses will line up with the expected EVM format (e.g., 0x329681bcE1e3b2af3a1174D134E0179585D859b2).

3 Contract A Contract C rev2

With accurate contract nonce tracking, Contract C created by Contract A now has an equivalent EVM address.

For developers, this means two things:

  • Consistent/identical results when creating contracts on Hedera and other EVM chains.

  • The address of a smart contract can be anticipated ahead of deployment.

Applicability and Audit Impact

The ability for contract addresses to take on an EVM equivalent address format pushes the HSCS maturity further along its EVM equivalence journey and allows for previously blocked scenarios to now be applicable.

On an EVM chain the consistent tracking of contract nonces enables three scenarios:

  • CREATE transaction counts – a counter of the number of contracts a contract has created.

  • Unique address creation – a contract’s unique address can be confirmed with the address and nonce at a point in time.

  • Contract validation – a valid contract can be confirmed to exist in state with a non-zero nonce.

These scenarios, which are sometimes incorporated into execution layers and DApps scenarios for validation flows, can now be extended to smart contracts on Hedera.

Developer Impact

Notably, as contract address forms will differ (account-num alias vs. EVM address alias), the applicability of certain SDK methods should be highlighted to avoid undesired errors for developers.

Developers should utilize the appropriate SDK method when converting from address to a ContractId object, depending on the contract address format:

  • Long-zero address (aka account-num alias) → ContractId.fromSolidityAddress() e.g. 0.0.1007

  • EVM address → ContractId.fromEvmAddress(); for example, 0.0.329681bcE1e3b2af3a1174D134E0179585D859b2

DApp code may explore logic similar to the following to help decide which method to call.

Code Snippet Background

// identifying prefix for account-num alias (aka long-zero)

const LONG_ZERO_PREFIX = '0x000000000000000000000000'

let contractId;

// given a 20 byte string contractAddress of form 0x....

if (contractAddress.startsWith(constants.LONG_ZERO_PREFIX)) {

// assumes 0 value shard and realm and converts adddress to num

contractId = ContractId.fromSolidityAddress(contractAddress);

} else {

// uses hex address instead of num in id

contractId = ContractId.fromEvmAddress(0, 0, contractAddress);

}

Additionally, if developers need to obtain the ContractId string (e.g., “0.0.1000”) from an EVM address, they must query the Mirror Nodes getContractById (api/v1/contracts/{contractAddress}) endpoint and retrieve the contract_id field. The newly tracked nonce field may also be exposed on this endpoint for developers.

Continue Learning