Deploying Smart Contracts
After compiling your smart contract, you can deploy it to the Hedera network. The constructor's "init code" includes the contract's entire bytecode. When deploying, the EVM is expected to be supplied with both the smart contract bytecode and the gas required to execute and deploy the contract. Post-deployment, the constructor is removed, leaving only the runtime_bytecode
for future contract interactions.
Ethereum Virtual Machine (EVM)
The Ethereum Virtual Machine (EVM) is a run-time environment for executing smart contracts written in EVM native programming languages, like Solidity. The source code must be compiled into bytecode for the EVM to execute a given smart contract.
On Hedera, users can interact with the EVM-compatible environment in several ways. They can submit ContractCreate
, EthereumTransaction
, or make eth_sendRawTransaction
RPC calls with the contract bytecode directly. These various paths provide flexibility for developers to deploy and manage smart contracts efficiently.
When the EVM receives the bytecode, it will be further broken down into operation codes (opcodes). The EVM opcodes represent the specific instructions it can perform. Each opcode is one byte and has its own gas cost associated with it. The cost per opcode for the Ethereum Shanghai fork can be found here.
Smart Contract Opcode Example
References:
Hyperledger Besu EVM
The Hedera network nodes utilize the HyperLedger Besu EVM Client written in Java as an execution layer for Ethereum-type transactions. The codebase is up to date with the current Ethereum Mainnet hard forks. The Besu EVM client library is used without hooks for the consensus, networking, and storage features used by Ethereum. Instead, Hedera hooks into its own Hashgraph consensus, Gossip communication, and Virtual Merkle Trees components for greater fault tolerance, finality, and scalability. The Besu EVM client is configured to use the “Shanghai” hard fork, as of Hedera mainnet release 0.38.6
, of the Ethereum Mainnet with some changes.
Shanghai Hard Fork
The smart contract platform is upgraded to support the EVM visible changes for the “Shanghai” hard fork. This includes changes introduced in the "London," “Istanbul,” and “Berlin” hard forks. Changes relating to block production, data serialization, and the fee market will not be implemented because they are irrelevant to Hedera’s architecture.
Starting in the Hedera Services 0.22
release, the intrinsic gas cost and input data will be charged. The intrinsic gas cost is a constant that is charged before any code is executed. The intrinsic gas cost is 21,000 gas. The input data is 16 gas per non-zero byte and 4 gas per zero byte. The input data is the data provided to the external contract function parameters when calling a contract. To learn more about gas fees, check out this page.
EVM Opcodes
The list of supported Opcodes for the Shanghai hard fork can be found here.
Modified descriptions for Solidity functions and opcodes to better reflect the Hedera network.
Solidity | Opcode | Hedera |
---|---|---|
| The address is a mapping of shard.realm.number (0.0.10) into a 20 byte Solidity address. The address can be a Hedera account ID or contract ID in Solidity format. | |
|
| The |
|
| The |
|
| The |
| The index of the record file (not recommended, use | |
| The transaction consensus timestamp. | |
| Always zero. | |
|
| The |
| The address of the Hedera contract ID or account ID in Solidity format that called this contract. For the root level or for delegate chains that go to root it is the account ID paying for the transaction. | |
| The value associated to the transaction associated in tinybar. | |
| The account ID paying for the transaction, regardless of depth. | |
| Fixed (varies with the global fee schedule and exchange rate). | |
| Address will not be reusable due to Hedera’s account numbering policies. | |
| Precompile contract addresses will report no code, including HTS System contract. | |
| Precompile contract addresses will report the empty code hash. | |
| This opcode returns a random number based on the n-3 record running hash. | |
| Contracts may no longer use |
HBAR decimal places
The JSON RPC Relay msg.value
uses 18 decimals when it returns HBAR. This was to provide an equivalent decimal length for web3 tools used across multiple EVM chains. As a result, the gasPrice
also uses 18 decimal places since it is only utilized from the JSON RPC Relay. Refer to the HBAR page for a table of Hedera APIs and the decimal places they return.
Limitation on fallback()
/ receive()
Functions in Hedera Smart Contracts
fallback()
/ receive()
Functions in Hedera Smart ContractsWhile developing smart contracts on the Hedera network, it's crucial to note some behavioral differences compared to other networks like Ethereum. When a Hedera smart contract receives HBAR through a crypto transfer, the contract's fallback()
and receive()
functions do not get triggered.
In a typical smart contract on Ethereum, fallback()
and receive()
functions serve as "catch-all" mechanisms that execute when the contract receives the native cryptocurrency (Ether in Ethereum's case). Here are the impacted variables for Hedera smart contracts and their usual expected values:
msg.sender
: The address initiating the contract call.msg.value
: The amount of HBAR sent along with the call.
Because the contract's balance may change through native HAPI operations, independent of EVM message calls, it is not possible to preserve balance-related invariants simply by implementing the receive()
or fallback()
methods. This is an important design consideration. Users who want the option to entirely disable native operations against their contract are invited to contribute a Hedera Improvement Proposal (HIP) for this feature.
Understanding this limitation is crucial for anyone developing smart contracts on Hedera, especially for those who have deployed smart contracts on Ethereum. Developers should implement explicit functions to manage HBAR transfers, given that fallback()
and receive()
functions do not trigger in such scenarios.
Gas
When executing the smart contract, the EVM requires the amount of work to be paid in gas. The “work” includes computation, state transitions, and storage. Gas is the unit of measurement used to charge a fee per opcode that is executed by the EVM. Each opcode code has a defined gas cost. Gas reflects the cost necessary to pay for the computational resources used to process transactions.
Weibar
The EVM returns gas information in Weibar (introduced in HIP-410). One weibar is 10^-18th HBAR, which translates to 1 tinybar is 10^10 weibars. As noted in HIP-410, this is to maximize compatibility with third-party tools that expect ether units to be operated on in fractions of 10^18, also known as a Wei.
Gas Schedule and Fees
Gas fees paid for EVM transactions on Hedera can be composed of three different kinds of gas costs:
Intrinsic Gas
EVM opcode Gas
Hedera System Contract Gas
Gas Fee Type | Description |
---|---|
Intrinsic Gas | The minimum amount of gas required to execute a transaction. It is a fixed gas cost that is independent of the specific operations or computations performed within the transaction. Intrinsic gas cost: 21,000 gas |
EVM Operation Code | The gas required to execute the defined operation code(s) for the smart contract call |
Hedera System Contract Transaction | The required gas that is associated with a Hedera-defined transaction like using the Hedera Token Service system contract that allows you to burn ( If you are not using a system contract that maps to one of the native Hedera services, you do not need to apply this fee. The Hedera transaction gas calculation is: Cost of the transaction in USD x Gas Conversion gas/USD + 20% Example System Contracts:
|
Gas Limit
The gas limit is the maximum amount of gas you are willing to pay for an operation.
The current opcode gas fees are reflective of the 0.22 Hedera Service release.
Operation | Shanghai Cost (Gas) | Current Hedera (Gas) |
---|---|---|
Code deposit | 200 * bytes | Max of Shanghai or Hedera |
| 2600 | 2600 |
| 100 | 100 |
| 10 + 50/byte | 10 + 50/byte |
| 2600 + Mem | 2600 + Mem |
| 100 + Mem | 100 + Mem |
| 2600 | 2600 |
| 100 | 100 |
| 2600 | 2600 |
| 100 | 100 |
| 375 + 375*topics + data Mem | Max of Shanghai or Hedera |
| 2100 | 2100 |
| 100 | 100 |
| 22,100 | Max of Shanghai or Hedera |
| 2,900 | 2,900 |
| 100 | 100 |
| Only transient storage slots | Only transient storage slots |
| 2,600 | 2,600 |
| 100 | 100 |
| 9,000 | 9,000 |
| 25,000 | revert |
| 2600 | 2600 |
| 0 | 0 |
The terms 'warm' and 'cold' in the above table correspond with whether the account or storage slot has been read or written to within the current smart contract transaction, even if within a child call frame.
'CALL
et al.' includes with limitation: CALL
, CALLCODE
, DELEGATECALL
, and STATICCALL
Reference: HIP-206
Gas Per Second Throttling
Most EVM-compatible networks place a gas limit per block to manage resource allocation. This is done to place a limit on the amount of time spent in block validation so that the miner nodes can produce new nodes quickly. While Hedera does not have blocks or miners, in the context of how a Nakamoto consensus system would use it, we are constrained by the physics of time as to how many blocks we can process.
For smart contract transactions, gas is a better measure of the complexity of the EVM transaction than counting all transactions the same, so metering the limits on gas provides a more reasonable limit on resource consumption.
To allow for more flexibility in what transactions we accept and to mirror Ethereum Mainnet behavior, the transaction limits will be calculated on a per-gas basis for smart contract calls (ContractCreate
, ContractCall
, ContractCallLocalQuery
) in addition to a per-transaction limit. This dual approach allows for better resource management, providing a nuanced way to regulate smart contract executions.
The Hedera network has implemented a system gas throttle of 15 million gas per second in the Hedera Service release 0.22.
Gas Reservation and Unused Gas Refund
Hedera throttles transactions prior to consensus, and nodes limit the number of transactions they can submit to the network. Then, at consensus time, if the maximum number of transactions is exceeded, the excess transactions are not evaluated and are canceled with a busy state. Throttling by variable gas amounts provides some challenges to this system, where the nodes only submit a share of their transaction limit.
To address this, throttling will be based on a two-tiered gas measuring system: pre-consensus and post-consensus. Pre-consensus throttling will use the gasLimit
field specified in the transaction. Post-consensus will use the actual evaluated amount of gas consumed by the transaction, allowing for dynamic adjustments in the system. It is impossible to know the actual evaluated gas pre-consensus because the network state can directly impact the flow of the transaction, which is why pre-consensus uses the gasLimit
field and will be referred to as the gas reservation.
Contract query requests are unique and bypass the consensus stage altogether. These requests are executed solely on the local node that receives them and only influences that specific node's precheck throttle. On the other hand, standard contract transactions go through both the precheck and consensus stages and are subject to both sets of throttle limits. The throttle limits for precheck and consensus may be set to different values.
In order to ensure that the transactions can execute properly, setting a higher gas reservation than will be consumed by execution is common. On Ethereum Mainnet, the entire reservation is charged to the account prior to execution, and the unused portion of the reservation is credited back. However, Ethereum utilizes a memory pool (mempool) and does transaction ordering at block production time, allowing the block limit to be based only on used and not reserved gas.
To help prevent over-reservation, Hedera restricts the amount of unused gas that can be refunded to a maximum of 20% of the original gas reservation. This effectively means that users will be charged for at least 80% of their initial reservation, regardless of actual usage. This rule is designed to incentivize users to make more accurate gas estimates.
For example, if you initially reserve 5 million gas units for creating a smart contract but end up using only 2 million, Hedera will refund you 1 million gas units, i.e., 20% of your initial reservation. This setup aims to balance the network's resource management while incentivizing users to be as accurate as possible in their gas estimations.
Maximum Gas Per Transaction
Because consensus time execution is now limited by actual gas used and not based on a transaction count, raising the gas limit available for each transaction is safe. Prior to gas-based metering, it would be possible for each transaction to consume the maximum gas per transaction without regard to the other transactions, so limits were based on this worst-case scenario. Now that throttling is the aggregate gas used, we can allow each transaction to consume large amounts of gas without concern for an extreme surge.
When a transaction is submitted to a node with a gasLimit
that is greater than the per-transaction gas limit, the transaction must be rejected during precheck with a response code of INDIVIDUAL_TX_GAS_LIMIT_EXCEEDED
. The transaction must not be submitted to consensus.
Gas throttle per contract call and contract create 15 million gas per second.
Reference: HIP-185
Deploying Your Smart Contract
SDK
You can use a Hedera SDK to deploy your smart contract bytecode to the network. This approach does not require using any EVM tools like Hardhat or an instance of the Hedera JSON-RPC Relay.
pageDeploy Your First Smart ContractHardhat
Hardhat can be used to deploy your smart contract by pointing to a community-hosted JSON-RPC Relay. However, EVM tools do not support features that are native to Hedera smart contracts like:
Admin Key
Contract Memo
Automatic Token Associations
Auto Renew Account ID
Staking Node ID or Account ID
Decline Staking Rewards
If you need to set any of the above properties for your contract, you will have to call the ContractCreateTransaction
API using one of the Hedera SDKs.
Last updated