Documentation Index
Fetch the complete documentation index at: https://hedera-0c6e0218-514-egress-ports.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Hooks are created by adding HookCreationDetails to account or contract creation and update transactions. Once attached, hooks can be deleted through update transactions and their storage can be modified via HookStoreTransaction. This page covers the utility classes, hook creation, update, and deletion across all supported transaction types.
Utility Classes
HookCreationDetails
Every hook requires a HookCreationDetails object that specifies the extension point, a unique hook ID, the EVM implementation contract, and an optional admin key.
| Property | Type | Required | Description |
|---|
| extensionPoint | HookExtensionPoint | Yes | The type of hook. Currently only ACCOUNT_ALLOWANCE_HOOK is supported. |
| hookId | long | Yes | A 64-bit identifier for the hook, unique within the owning entity. Does not need to be sequential. |
| evmHook | EvmHook | Yes | The hook implementation, including the deployed contract ID and optional initial storage updates. |
| adminKey | Key | No | If set, this key (in addition to the entity’s key) can authorize hook deletion, replacement, and HookStoreTransaction updates. |
HookExtensionPoint
enum HookExtensionPoint {
ACCOUNT_ALLOWANCE_HOOK
}
EvmHook
| Property | Type | Required | Description |
|---|
| contractId | ContractId | Yes | The ID of a previously deployed contract whose bytecode implements the hook’s logic. |
| storageUpdates | list<EvmHookStorageUpdate> | No | Initial storage slot values to set when the hook is created. |
EvmHookStorageUpdate
EvmHookStorageUpdate is an abstract type with two concrete implementations:
EvmHookStorageSlot
Directly sets a 32-byte key/value pair in the hook’s storage.
| Property | Type | Description |
|---|
| key | bytes | 32-byte storage slot key. |
| value | bytes | 32-byte storage slot value. Set to empty bytes to delete the slot. |
EvmHookMappingEntries
Updates entries within a Solidity mapping at a specific storage slot.
| Property | Type | Description |
|---|
| mappingSlot | bytes | The slot corresponding to the Solidity mapping declaration. |
| entries | list<EvmHookMappingEntry> | The entries to update in the mapping. |
EvmHookMappingEntry
| Property | Type | Required | Description |
|---|
| key | bytes | One of key or preimage | 32-byte key of the mapping entry. |
| preimage | bytes | One of key or preimage | The bytes whose Keccak256 hash forms the mapping key. Useful when block stream consumers need to follow the metaprotocol without inverting hashes. |
| value | bytes | Yes | 32-byte value of the mapping entry. Set to empty bytes to delete. |
HookId and HookEntityId
Used by HookStoreTransaction to identify a specific hook on a specific entity.
| Class | Property | Type | Description |
|---|
| HookId | entityId | HookEntityId | The entity that owns the hook. |
| HookId | hookId | long | The hook’s 64-bit identifier. |
| HookEntityId | accountId | AccountId (optional) | The account that owns the hook. One of accountId or contractId must be set. (JavaScript SDK currently only supports accountId.) |
| HookEntityId | contractId | ContractId (optional) | The contract that owns the hook. One of accountId or contractId must be set. (Not supported in the JavaScript SDK.) |
Creating Hooks with New Entities
Hooks can be attached at entity creation time using AccountCreateTransaction or ContractCreateTransaction.
AccountCreateTransaction Methods
| Method | Type | Description |
|---|
addHook(<hook>) | HookCreationDetails | Adds a hook to be created with the new account. |
setHooks(<hooks>) | list<HookCreationDetails> | Sets all hooks to be created with the new account. |
getHooks() | list<HookCreationDetails> | Returns the list of hooks to be created. In JavaScript, use the .hooks property accessor instead of calling getHooks(). |
ContractCreateTransaction Methods
| Method | Type | Description |
|---|
addHook(<hook>) | HookCreationDetails | Adds a hook to be created with the new contract. |
setHooks(<hooks>) | list<HookCreationDetails> | Sets all hooks to be created with the new contract. |
getHooks() | list<HookCreationDetails> | Returns the list of hooks to be created. In JavaScript, use the .hooks property accessor instead of calling getHooks(). |
Example: Create an Account with a Hook
import com.hedera.hashgraph.sdk.*;
// Step 1: Deploy the hook contract (standard ContractCreateTransaction)
ContractId contractId = /* ... your deployed hook contract ... */;
// Step 2: Define the EVM hook
EvmHook evmHook = new EvmHook(contractId);
// Step 3: Create hook details
HookCreationDetails hookDetails = new HookCreationDetails(
HookExtensionPoint.ACCOUNT_ALLOWANCE_HOOK,
1002L,
evmHook,
adminKey.getPublicKey()
);
// Step 4: Create the account with the hook attached
TransactionResponse response = new AccountCreateTransaction()
.setKey(accountKey.getPublicKey())
.setInitialBalance(Hbar.from(1))
.addHook(hookDetails)
.setMaxTransactionFee(new Hbar(10))
.freezeWith(client)
.sign(accountKey)
.execute(client);
AccountId accountId = response.getReceipt(client).accountId;
System.out.println("Account created with hook: " + accountId);
Example: Create an Account with a Hook and Initial Storage
You can initialize hook storage at creation time by including EvmHookStorageUpdate entries in the EvmHook.
import {
AccountCreateTransaction,
HookCreationDetails,
EvmHook,
EvmHookStorageSlot,
HookExtensionPoint,
Long,
} from "@hiero-ledger/sdk";
// Create initial storage: set slot key 0x01 to value 100 (0x64)
const storageUpdates = [
new EvmHookStorageSlot()
.setKey(new Uint8Array([0x01]))
.setValue(new Uint8Array([0x64])),
];
const evmHook = new EvmHook({
contractId,
storageUpdates,
});
const hookDetails = new HookCreationDetails({
extensionPoint: HookExtensionPoint.ACCOUNT_ALLOWANCE_HOOK,
hookId: Long.fromInt(1002),
evmHook: evmHook,
adminKey: adminKey.publicKey,
});
const response = await (
await new AccountCreateTransaction()
.setKeyWithoutAlias(accountKey.publicKey)
.setInitialBalance(new Hbar(1))
.addHook(hookDetails)
.setMaxTransactionFee(new Hbar(10))
.freezeWith(client)
.sign(accountKey)
).execute(client);
const { accountId } = await response.getReceipt(client);
console.log(`Account with initialized hook: ${accountId}`);
Adding and Deleting Hooks on Existing Entities
Use AccountUpdateTransaction or ContractUpdateTransaction to add new hooks or remove existing hooks from an entity.
AccountUpdateTransaction Methods
| Method | Type | Description |
|---|
addHookToCreate(<hook>) | HookCreationDetails | Adds a hook to be created on the existing account. |
setHooksToCreate(<hooks>) | list<HookCreationDetails> | Sets all hooks to be created on the existing account. |
addHookToDelete(<hookId>) | long | Marks a hook for deletion by its hook ID. |
setHooksToDelete(<hookIds>) | list<long> | Marks multiple hooks for deletion. |
getHooksToCreate() | list<HookCreationDetails> | Returns the list of hooks to be created. In JavaScript, use the .hooksToCreate property accessor instead of calling getHooksToCreate(). |
getHooksToDelete() | list<long> | Returns the list of hook IDs to be deleted. In JavaScript, use the .hooksToDelete property accessor instead of calling getHooksToDelete(). |
ContractUpdateTransaction Methods
| Method | Type | Description |
|---|
addHookToCreate(<hook>) | HookCreationDetails | Adds a hook to be created on the existing contract. |
setHooksToCreate(<hooks>) | list<HookCreationDetails> | Sets all hooks to be created on the existing contract. |
addHookToDelete(<hookId>) | long | Marks a hook for deletion by its hook ID. |
setHooksToDelete(<hookIds>) | list<long> | Marks multiple hooks for deletion. |
getHooksToCreate() | list<HookCreationDetails> | Returns the list of hooks to be created. In JavaScript, use the .hooksToCreate property accessor instead of calling getHooksToCreate(). |
getHooksToDelete() | list<long> | Returns the list of hook IDs to be deleted. In JavaScript, use the .hooksToDelete property accessor instead of calling getHooksToDelete(). |
Example: Add Hooks to an Existing Account
HookCreationDetails hook1 = new HookCreationDetails(
HookExtensionPoint.ACCOUNT_ALLOWANCE_HOOK,
1L,
new EvmHook(contractId),
adminKey.getPublicKey()
);
HookCreationDetails hook2 = new HookCreationDetails(
HookExtensionPoint.ACCOUNT_ALLOWANCE_HOOK,
2L,
new EvmHook(contractId),
adminKey.getPublicKey()
);
new AccountUpdateTransaction()
.setAccountId(accountId)
.addHookToCreate(hook1)
.addHookToCreate(hook2)
.setMaxTransactionFee(new Hbar(10))
.freezeWith(client)
.sign(accountKey)
.execute(client)
.getReceipt(client);
Example: Delete Hooks from an Account
A hook can only be deleted when it has zero storage slots. Clear all storage first using HookStoreTransaction (set values to empty bytes). If storage slots remain, the deletion fails with HOOK_DELETION_REQUIRES_EMPTY_STORAGE.An account cannot be deleted while it has hooks attached. CryptoDelete fails with TRANSACTION_REQUIRES_ZERO_HOOKS.
new AccountUpdateTransaction()
.setAccountId(accountId)
.addHookToDelete(1L)
.addHookToDelete(2L)
.setMaxTransactionFee(new Hbar(10))
.freezeWith(client)
.sign(accountKey)
.execute(client)
.getReceipt(client);
System.out.println("Successfully deleted hooks (IDs: 1, 2)");
Atomic Delete and Recreate
To support atomic hook updates (e.g., for compliance), you can delete and recreate a hook with the same ID in a single update transaction. Deletions are processed first, then creations.
await (
await (
await new AccountUpdateTransaction()
.setAccountId(accountId)
.addHookToDelete(Long.fromNumber(1)) // Processed first
.addHookToCreate(newHookDetailsWithId1) // Processed second
.setMaxTransactionFee(new Hbar(10))
.freezeWith(client)
.sign(accountKey)
).execute(client)
).getReceipt(client);
Transaction Signing Requirements
| Scenario | Required Signatures |
|---|
| Create hook on new account | Account key (from AccountCreateTransaction) + transaction payer |
| Create hook on existing account | Account key + transaction payer |
| Delete hook (no admin key) | Account/entity key + transaction payer |
| Delete hook (with admin key) | Admin key OR entity key + transaction payer |
Error Codes
| Status Code | Description |
|---|
HOOK_ID_REPEATED_IN_CREATION_DETAILS | The same hook ID appears more than once in the hook_creation_details list. |
HOOK_ID_IN_USE | An update transaction tried to create a hook with an ID already occupied on the entity. |
HOOK_NOT_FOUND | An update transaction tried to delete a hook ID that does not exist on the entity. |
HOOK_DELETED | Attempted to delete a hook that was already previously deleted. |
INVALID_HOOK_CREATION_SPEC | The hook creation details are invalid (e.g., missing contract ID). |
HOOK_DELETION_REQUIRES_EMPTY_STORAGE | Cannot delete a hook that still has storage slots in use. Clear storage first via HookStoreTransaction. |
TRANSACTION_REQUIRES_ZERO_HOOKS | Cannot delete an account or contract that still has hooks attached. Remove all hooks first. |