GuideHedera Smart Contract Service (HSCS)
Deploying Solidity on Hedera: what changes when you port from Ethereum
Most Solidity ports to Hedera compile and deploy with the same tools, then fail in testing on details that do not exist on Ethereum: native account IDs beside EVM addresses, two decimal scales for HBAR, token association, system contracts and a different block model. This guide sets out those differences roughly in the order teams meet them, then gives a test plan and a mainnet cut-over checklist.
On this page
- What usually ports unchanged
- Ethereum assumptions that change on Hedera
- Two decimal scales for one currency
- HTS tokens from Solidity, and the association rule
- Gas limits, fees and the per-transaction cap
- Ordering without a public mempool, and indexing without Ethereum blocks
- A test plan for the port
- Mainnet cut-over checklist for a ported contract
- Questions and answers
- Sources
What usually ports unchanged
Hedera's smart contract service runs the EVM, so Solidity source, compilers and most libraries carry over. Teams keep Hardhat or Foundry for builds and tests and keep Ethers.js, viem or Web3.js in their applications, reaching the network through the Hedera JSON-RPC relay, which accepts Ethereum-style requests and turns them into Hedera transactions. Standard ERC-20 and ERC-721 contracts deploy and behave as written.
The relay implements a subset of the Ethereum JSON-RPC methods, some of which return fixed values for compatibility, and historical state, logs and transaction details come from mirror nodes rather than from block state roots1. Tooling that relies on less common methods, or on debug tracing, is worth checking in the first week of a port.
Ethereum assumptions that change on Hedera
| Area | On Ethereum | On Hedera | What to change in the port |
|---|---|---|---|
| Account identity | One address derived from an ECDSA key | A native account ID plus an EVM address; accounts created without an ECDSA alias use a long-zero address derived from the ID2 | Use the EVM address an account reports and never derive addresses from keys yourself |
| Key types | ECDSA secp256k1 only | ED25519, ECDSA secp256k1, key lists and threshold keys3 | Use ECDSA accounts for EVM wallets; check ED25519 signers through the account service system contract, since ecrecover cannot2 |
| HBAR units | Wei, eighteen decimals | Tinybars, eight decimals, inside the EVM; the relay presents the transaction value and gas price with eighteen4 | Convert at one boundary and test with amounts that are not round numbers |
| Receiving tokens | Any address can receive an ERC-20 token | An account must be associated with an HTS token first, unless automatic association applies5 | Associate contracts at deployment and handle the transfer that fails |
| Gas charging | Pay for gas used, up to the limit | Since HIP-1249, gas used is charged and unused gas refunded, and each transaction is still capped6 | Set limits from measured usage, with headroom below the cap |
| Transaction ordering | Public mempool and block builders | No public mempool; transactions are ordered by consensus timestamp | Revisit front-running defences rather than deleting them |
| Blocks and history | Blocks with state roots, served by full nodes | Record files presented as blocks; history served by mirror nodes | Point indexers at mirror-node contract logs |
Summarised from Hedera's documentation at the time of review. Confirm limits and behaviour against the release notes for the network version you deploy to.
Two decimal scales for one currency
HTS tokens from Solidity, and the association rule
A ported ERC-20 contract keeps working as a contract-managed token. The alternative is to issue the token natively on the Hedera Token Service and use it from Solidity: each HTS token answers standard ERC-20 or ERC-721 calls at its own address7, and the token service system contract at a reserved address offers operations such as minting and association8. The trade-offs between the two models belong to the Hedera Token Service design.
Either way, the receiving side differs from Ethereum. An account or contract must be associated with an HTS token before it can hold it. Accounts created automatically from an EVM address or public key now default to unlimited automatic associations, while accounts created explicitly default to none5, so a contract that pays tokens out should expect some transfers to fail and report them clearly.
System-contract calls also signal failure differently. Token-service functions return a response code alongside their result8. Check it on every call and revert explicitly when it is not SUCCESS, instead of assuming a failed call reverts by itself.
Gas limits, fees and the per-transaction cap
Hedera sets its fees in US dollars and converts them to HBAR, which keeps the cost of a given operation predictable when the HBAR price moves. HIP-1249 removed the earlier minimum charge on unused gas, so a transaction now pays for gas actually used, and network throughput is throttled by operations per second rather than gas per second; per-transaction limits remain, for example 15 million gas6.
Set gas limits from usage measured on testnet with headroom, not from Ethereum estimates, because system-contract calls are priced differently from ordinary opcodes. Deployments or calls with unusually large call data may need Hedera-specific handling, such as the jumbo transactions introduced by HIP-10863.
Ordering without a public mempool, and indexing without Ethereum blocks
Hedera has no public mempool for bots to watch: transactions go to consensus nodes and are ordered by consensus timestamp. That removes the familiar pattern of a searcher seeing a pending swap and paying to be placed ahead of it. It does not make ordering irrelevant, so keep slippage limits, deadlines and commit-reveal schemes wherever outcomes depend on order.
Indexers need adjusting too. The relay presents each record file as a block, so block numbers and timestamps exist but follow Hedera's cadence, and historical events are read from mirror-node contract logs. Code that uses block numbers as a clock, or a block value as a source of randomness, should move to timestamps and to the PRNG system contract respectively8.
A test plan for the port
Inventory Ethereum assumptions
List every place the code touches value, addresses, signatures, tokens, block data or randomness, and mark each against the table above.
Run the existing suite on a local Hedera node
Fix decimal, address and association failures locally before spending time on testnet.
Add Hedera-specific tests
Cover failed token associations, system-contract response codes, ED25519 signers, odd HBAR amounts and transfers to accounts with no free association slots.
Compare behaviour on testnet
Replay a recorded set of transactions against the original deployment and the Hedera testnet deployment, then compare resulting state and events after normalising units and addresses.
Rehearse operations
Run deployment, admin actions, pausing and upgrades on testnet with the key custody the mainnet deployment will use.
Mainnet cut-over checklist for a ported contract
Questions and answers
Do OpenZeppelin contracts work on Hedera?
Generally, yes: they are ordinary Solidity and compile for the EVM unchanged. Check the parts that touch Hedera-specific behaviour, namely anything that sends or measures HBAR, signature checks that rely on ecrecover and so work only for ECDSA accounts, and token contracts that will interact with HTS tokens. Run the library's tests against a local node or testnet rather than assuming Ethereum results apply.
Is CREATE2 supported on Hedera?
Yes. HIP-329 added the CREATE2 opcode, and a contract deployed with it receives the address defined by EIP-1014 alongside its Hedera contract ID10. The address depends on the deploying contract's address, the salt and the init code, so you will reproduce an Ethereum address only if all three are identical on Hedera, which is rarely the case for factories deployed from different accounts.
How do we verify contract source code on Hedera?
Verification runs through Sourcify, and the HashScan explorer shows the result on the contract's page. Submit the Solidity sources together with the compiler metadata file: uploading source alone tends to give a partial match, where the bytecode matches but the metadata hash does not9. Build verification into the deployment pipeline so every release is verified the same way.
Do we have to move our token to HTS when porting?
No. An ERC-20 contract can stay as it is, which keeps identical code across chains and suits tokens whose logic is the product, such as custom transfer hooks. Moving to HTS makes sense when you want network-level controls managed with Hedera keys, such as freezing or custom fees. Whichever you choose, plan for association on the receiving side if the contract will handle HTS tokens.
Sources
- JSON-RPC relay and EVM tooling — Hedera documentation · checked 10 October 2026
- Accounts, signature verification and keys (ECDSA vs ED25519) — Hedera documentation · checked 10 October 2026
- For EVM developers migrating to Hedera — Hedera documentation · checked 10 October 2026
- Decimal handling (8 vs 18 decimals) — Hedera documentation · checked 10 October 2026
- HIP-904: Frictionless Airdrops (automatic token associations) — Hiero Improvement Proposals · checked 10 October 2026
- Gas and fees (HIP-1249 and per-transaction gas limits) — Hedera documentation · checked 10 October 2026
- HIP-218: Smart Contract interactions with Hedera Token Accounts — Hiero Improvement Proposals · checked 10 October 2026
- System smart contracts — Hedera documentation · checked 10 October 2026
- How to verify a smart contract on HashScan — Hedera documentation · checked 10 October 2026
- HIP-329: Support CREATE2 opcode — Hiero Improvement Proposals · checked 10 October 2026