DELEGATECALL runs Contract B’s code inside Contract A’s storage frame. It is Hedera’s adoption of Ethereum’s EIP-7702, defined for Hedera by HIP-1340 and rolled out as part of the Pectra hard fork.
Delegation unlocks smart-account use cases (transaction batching, sponsored gas, session keys, privilege de-escalation) without migrating funds to a new contract wallet; the EOA’s address, balance, NFTs, and tokens stay put.
How delegation is stored
TheAccount entity gains a new optional 20-byte field, delegation_address. When set, calls to the EOA’s address resolve to the code at delegation_address.
For Ethereum-tool compatibility, the Smart Contract Service exposes the delegation as a Delegation Indicator in the EOA’s code field:
- Before Pectra,
eth_getCode(eoa)always returned0x. - After Pectra, an EOA with delegation set returns the 23-byte
0xef0100...indicator. An EOA with no delegation still returns0x. - Regular contract bytecode cannot start with
0xef(per EIP-3541), so the prefix is unambiguous.
delegation_address of 0x0000000000000000000000000000000000000000 clears the delegation (the field becomes empty).
Two paths to configure delegation
You can set, change, or clear an EOA’s delegation through either an Ethereum-compatible Type 4 transaction or a native HAPICryptoCreate / CryptoUpdate. Both routes converge on the same delegation_address field on the account.
Path A: EVM (Type 4 EthereumTransaction)
A Type 4 transaction extends the standard RLP-encoded fields with anauthorization_list:
ecrecover, and the recovered account’s delegation_address is set to the entry’s address. A single Type 4 transaction can authorize delegations for many unrelated EOAs in one shot, and the transaction sender may be a third party (i.e., sponsored delegation setup, useful for onboarding flows).
Validity rules (per EIP-7702, enforced by Hedera):
- Signature must be valid
ecrecoverover(MAGIC ‖ rlp([chain_id, address, nonce])). chain_idmust be0(any chain) or match the network’s chain ID (296 testnet, 295 mainnet).noncemust match the authorizing account’s current nonce.- If the authorization list is empty, the transaction is invalid and rejected.
- Invalid entries are silently skipped (no revert).
- If multiple valid entries target the same EOA, only the last one is applied.
CryptoCreate (for a brand-new hollow account) or CryptoUpdate (for an existing account). These child records appear in the transaction’s record stream regardless of whether the parent EVM call reverts; the delegation persists even if the subsequent code execution fails.
JavaScript example (viem)
There are two common flows: self-submitted (the EOA pays for and sends its own delegation transaction) and sponsored (a third party pays; the EOA only signs the authorization). Self-submitted (the EOA owns the gas):JavaScript
JavaScript
eoa.address will execute the smart-account implementation’s code in the EOA’s storage context. To revoke, the EOA signs a new authorization with contractAddress: "0x0000000000000000000000000000000000000000".
Submitting via EthereumTransaction (Hedera SDK)
If you have a fully-signed Type 4 RLP payload, you submit it the same way as any other Ethereum transaction:
JavaScript
EthereumTransactionDataEip7702, which carries the standard EIP-1559-style fields plus accessList and an authorizationList of Authorization entries (chainId, address, nonce, yParity, r, s). Calling toBytes() on it produces the raw payload to pass to setEthereumData().
Path B: Native HAPI (CryptoCreate / CryptoUpdate)
HIP-1340 extends bothCryptoCreateTransactionBody and CryptoUpdateTransactionBody with a delegation_address field (bytes, 20 raw EVM address bytes, not the 0xef0100-prefixed indicator). The SDK lifts this onto AccountCreateTransaction and AccountUpdateTransaction as setDelegationAddress(), which accepts raw bytes, a hex string (with or without the 0x prefix), or an EvmAddress.
JavaScript
0x0000000000000000000000000000000000000000) or pass null on an AccountUpdateTransaction.
Native HAPI is the only path available to ED25519 accounts and ECDSA accounts with a long-zero alias, since those account types cannot sign EIP-7702 authorizations. See Account-type applicability.
What happens when a delegated EOA is called
When the Smart Contract Service processes a call whose target is an EOA address:- A top-level transaction (
transaction.to == eoa). - An inner
CALL/STATICCALLfrom another contract (address(eoa).call(...)). - Any of the legacy transaction types (0, 1, 2), not just Type 4.
Code queries
EXTCODESIZE, EXTCODECOPY, EXTCODEHASH, eth_getCode, and ContractGetBytecodeQuery against a delegated EOA all return the Delegation Indicator (0xef0100 ‖ delegation_address). For an undelegated EOA they return empty bytecode, as before.
Storage & logs
A delegated EOA can now hold mutable storage slots and emit EVM logs, because the delegated code runs in its context. Tooling implications:eth_getStorageAt(eoa, slot)returns the EOA’s storage.eth_getLogsreturns logs emitted from the EOA’s address.- Mirror Node
/api/v1/contracts/{eoa}/state,/results/logs,/call, and friends now work on EOA addresses too.
Chains & loops
Ifdelegation_address points to another EOA that itself has a delegation, only the first hop is resolved. The bytecode at the second hop is interpreted literally, and since 0xef is a banned opcode (EIP-3541), the call reverts. In practice this means don’t chain delegations: always delegate directly to a real contract.
No-op targets
Settingdelegation_address to any of the following is allowed, but the resulting call to the EOA is a no-op (value transfer only, no code executes):
- A non-existent account.
- A precompile address (
0x01–0x11). - A system contract (HTS at
0x167, HAS at0x16a, HSS at0x16b, Exchange Rate at0x168, PRNG at0x169). - A Hedera system account.
- Another EOA whose own code is empty.
HAS facade precedence
Calls that match a Hedera Account Service facade selector are always routed to HAS, even if the EOA has a delegation set. This preserves the user-facing behavior of pre-Pectra HAS calls.| HAS function | Selector |
|---|---|
hbarAllowance(address spender) | 0xbbee989e |
hbarApprove(address spender, int256 amount) | 0x86aff07c |
setUnlimitedAutomaticAssociations(bool enabled) | 0xf5677e99 |
- If the call selector matches a HAS facade function → HAS handles it. The user’s delegation is ignored for this call.
- Else if the EOA has a delegation → run the delegate contract’s code.
- Else → no-op (with any attached value transfer).
⚠️ Selector-collision warning. If your smart-account delegate defines a function whose selector happens to equal one of the HAS selectors above (e.g. you happen to write a hbarApprove(address,int256) method), that function will be unreachable; HAS will intercept the call first. Pick distinct signatures.
Account-type applicability
Whether you can use the EVM path depends on the account’s key type and alias scheme.| Account type | EVM path (Type 4) | HAPI path (CryptoCreate/Update) |
|---|---|---|
| ED25519 account | ❌ | ✅ |
ECDSA account, long-zero alias (0x0000…<accountNum>) | ❌ | ✅ |
| ECDSA account, public-key-derived alias | ✅ | ✅ |
delegation_address set runs the delegate code just like for any other account.
CryptoTransfer signature validation is unchanged. Hedera-native authorization (e.g., multi-sig threshold keys) continues to govern transfers initiated through HAPI.
Gas costs
Per EIP-7702, every entry in anauthorization_list costs gas, whether valid, invalid, or duplicate:
| Authorization outcome | Gas charged |
|---|---|
| Authorizes an existing account | 12,500 |
| Authorizes a new account (hollow account creation) | 25,000 + Hedera’s hollow-account creation cost |
| Invalid signature / wrong chain ID / wrong nonce | 12,500 (consumed, then silently skipped) |
| Duplicate entry for an EOA already authorized in the list | 12,500 (consumed, then skipped) |
gas_limit and the network’s operations-per-second throttle. For the calldata and execution sides of the gas calculation, see Gas and Fees.
Gas shortage on a valid authorization. If an otherwise-valid authorization can’t be processed because the transaction ran out of gas (for example, it would require creating a hollow account but thegas_limitis exhausted), Hedera still emits a childCryptoCreate/CryptoUpdaterecord with a failed status so the error surfaces in the record stream rather than being silently dropped.
Smart-account example (Solidity)
A minimal smart-account delegate that supports batched calls and an owner-only check:Solidity
ContractCreate. Then any number of EOAs can delegate to that deployed address, and they each get smart-account behavior without re-deploying.
Use namespaced storage (ERC-7201) in delegate contracts so the EOA can later switch delegates without colliding on storage slots written by the previous implementation.
Sponsored onboarding (batched approve + swap, gas paid by a sponsor)
This is the flagship EIP-7702 use case: a new user with zero HBAR gets smart-account behavior and executes a multi-step action in one transaction, while a sponsor pays the gas. The single Type 4 transaction does two things at once: it sets the EOA’s delegation and runs a batched call in the EOA’s context.JavaScript
eth_getCode(eoa.address) returns the Delegation Indicator, and the approve + swap have executed from the EOA’s own address.
Mirror Node surface
HIP-1340 extends the Mirror Node REST API:-
Accounts endpoints (
GET /api/v1/accounts,GET /api/v1/accounts/{idOrAliasOrEvmAddress}) include a newdelegation_addressfield per account. The value is0xwhen no delegation is set. -
Contract-result endpoints (
GET /api/v1/contracts/{id}/results/{timestamp},GET /api/v1/contracts/results,GET /api/v1/contracts/results/{txOrHash}) include a newauthorization_listfield for Type 4 transactions: -
EOA contract APIs.
/api/v1/contracts/{eoa}/state,/results/logs,/results,/results/{tx}/actions,/results/{tx}/opcodes, and/api/v1/contracts/callnow accept EOA addresses and return contract-style data when the EOA has a delegation set.
eth_getCode, eth_getStorageAt, and eth_getLogs work for delegated EOAs; the relay handles Type 4 transaction parsing and submission.
HTS / HSS proxy accounts
HIP-1340 also re-implements the long-standing HTS-token and HSS-schedule facade calls (HIP-218 / HIP-719 / HIP-755 / HIP-906) using the new Delegation Indicator format. Calls likeIERC20(tokenAddress).transfer(...) continue to work exactly as before, but ContractGetBytecode(tokenAddress) now returns a stable 0xef0100 ‖ <HTS-system-contract-address> indicator instead of a runtime-synthesized DELEGATECALL stub.
This is invisible to most users. Tools that introspect the bytecode of token-proxy or schedule-proxy accounts (e.g. block explorers, custom indexers) may need to update their parsing.
Caveats and edge cases
- An empty
authorization_listmakes a Type 4 transaction invalid. Don’t construct one and then drop entries client-side; either include at least one authorization or send a different type. - Authorizations persist even if the EVM execution reverts. They are processed before EVM code runs and committed independently; this is a feature (so onboarding flows still succeed even if the follow-up call fails), but it does mean a “rolled back” transaction can still leave delegations in place.
- Selector collisions with HAS make those functions unreachable on a delegated EOA. Pick non-colliding signatures.
- Storage migration. Switching delegation targets does not migrate storage. Use ERC-7201 namespaces in your delegates to avoid collisions.
msg.sender == tx.origininvariant no longer holds in deeper frames. Code historically usedmsg.sender == tx.originas a “no contracts” check. With delegation, the topmost frame on a Type 4 transaction can be a delegated EOA, meaningtx.originandmsg.senderalign in places they previously wouldn’t. Treat this check as advisory, not a security boundary.- No impact on hooks. A call to a delegated EOA inside a hook behaves the same as outside one. Hooks use a dedicated storage namespace, so delegate code writing to the EOA’s storage slots cannot collide with hook storage.
References
- HIP-1340: EOA Code Delegation (Hedera adoption)
- HIP-1341: Support for Ethereum Pectra Release
- EIP-7702: Set EOA Account Code
- EIP-3541: Reject
0xef-prefixed contract code - Hedera Account Service
EthereumTransaction- Gas and Fees