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.
address
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.
block.basefee
BASEFEE
The BASEFEE
opcode will return zero. Hedera does not use the Fee Market mechanism this is designed to support.
block.chainid
CHAINID
The CHAINID
opcode will return 295(hex 0x0127
) for mainnet, 296( hex 0x0128
) for testnet, 297( hex 0x0129
) for previewnet, and 298 (0x12A
) for development networks.
block.coinbase
COINBASE
The COINBASE
operation will return the funding account (Hedera transaction fee collecting account 0.0.98
).
block.number
The index of the record file (not recommended, use block.timestamp
).
block.timestamp
The transaction consensus timestamp.
block.difficulty
Always zero.
block.gaslimit
GASLIMIT
The GASLIMIT
operation will return the gasLimit
of the transaction. The transaction gasLimit
will be the lowest of the gas limit requested in the transaction or a global upper gas limit configured for all smart contracts.
msg.sender
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.
msg.value
The value associated to the transaction associated in tinybar.
tx.origin
The account ID paying for the transaction, regardless of depth.
tx.gasprice
Fixed (varies with the global fee schedule and exchange rate).
selfdestruct(address payable recipient)
Address will not be reusable due to Hedera’s account numbering policies.
<address>.code
Precompile contract addresses will report no code, including HTS System contract.
<address>.codehash
Precompile contract addresses will report the empty code hash.
PRNGSEED
This opcode returns a random number based on the n-3 record running hash.
delegateCall
Contracts may no longer use delegateCall()
to invoke system contracts. Contracts should instead use the call()
method.
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
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 (TokenBurnTransaction
) or mint (TokenMintTransaction
) a token.
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:
Hedera Token Service
Pseudo Random Number Generator (PRNG)
Exchange Rate
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.
Code deposit
200 * bytes
Max of Shanghai or Hedera
BALANCE
(cold account)
2600
2600
BALANCE
(warm account)
100
100
EXP
10 + 50/byte
10 + 50/byte
EXTCODECOPY
(cold account)
2600 + Mem
2600 + Mem
EXTCODECOPY
(warm account)
100 + Mem
100 + Mem
EXTCODEHASH
(cold account)
2600
2600
EXTCODEHASH
(warm account)
100
100
EXTCODESIZE
(cold account)
2600
2600
EXTCODESIZE
(warm account)
100
100
LOG0, LOG1, LOG2,
LOG3, LOG4
375 + 375*topics + data Mem
Max of Shanghai or Hedera
SLOAD
(cold slot)
2100
2100
SLOAD
(warm slot)
100
100
SSTORE
(new slot)
22,100
Max of Shanghai or Hedera
SSTORE
(existing slot,
cold access)
2,900
2,900
SSTORE
(existing slot,
warm access)
100
100
SSTORE
refund
Only transient storage slots
Only transient storage slots
CALL
et al.
(cold recipient)
2,600
2,600
CALL
et al.
(warm recipient)
100
100
CALL
et al.
Hbar/Eth Transfer Surcharge
9,000
9,000
CALL
et al.
New Account Surcharge
25,000
revert
SELFDESTRUCT
(cold beneficiary)
2600
2600
SELFDESTRUCT
(warm beneficiary)
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.
Deploy 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