Skip to main content
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.
PropertyTypeRequiredDescription
extensionPointHookExtensionPointYesThe type of hook. Currently only ACCOUNT_ALLOWANCE_HOOK is supported.
hookIdlongYesA 64-bit identifier for the hook, unique within the owning entity. Does not need to be sequential.
evmHookEvmHookYesThe hook implementation, including the deployed contract ID and optional initial storage updates.
adminKeyKeyNoIf 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

PropertyTypeRequiredDescription
contractIdContractIdYesThe ID of a previously deployed contract whose bytecode implements the hook’s logic.
storageUpdateslist<EvmHookStorageUpdate>NoInitial 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.
PropertyTypeDescription
keybytes32-byte storage slot key.
valuebytes32-byte storage slot value. Set to empty bytes to delete the slot.

EvmHookMappingEntries

Updates entries within a Solidity mapping at a specific storage slot.
PropertyTypeDescription
mappingSlotbytesThe slot corresponding to the Solidity mapping declaration.
entrieslist<EvmHookMappingEntry>The entries to update in the mapping.

EvmHookMappingEntry

PropertyTypeRequiredDescription
keybytesOne of key or preimage32-byte key of the mapping entry.
preimagebytesOne of key or preimageThe bytes whose Keccak256 hash forms the mapping key. Useful when block stream consumers need to follow the metaprotocol without inverting hashes.
valuebytesYes32-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.
ClassPropertyTypeDescription
HookIdentityIdHookEntityIdThe entity that owns the hook.
HookIdhookIdlongThe hook’s 64-bit identifier.
HookEntityIdaccountIdAccountId (optional)The account that owns the hook. One of accountId or contractId must be set.
HookEntityIdcontractIdContractId (optional)The contract that owns the hook. One of accountId or contractId must be set.

Creating Hooks with New Entities

Hooks can be attached at entity creation time using AccountCreateTransaction or ContractCreateTransaction.

AccountCreateTransaction Methods

MethodTypeDescription
addHook(<hook>)HookCreationDetailsAdds 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.

ContractCreateTransaction Methods

MethodTypeDescription
addHook(<hook>)HookCreationDetailsAdds 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.

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()
    .setContractId(contractId);

// Step 3: Create hook details
HookCreationDetails hookDetails = new HookCreationDetails()
    .setExtensionPoint(HookExtensionPoint.ACCOUNT_ALLOWANCE_HOOK)
    .setHookId(1002L)
    .setEvmHook(evmHook)
    .setAdminKey(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,
    EvmHookStorageUpdate,
    EvmHookStorageSlot,
    HookExtensionPoint,
    Long,
} from "@hashgraph/sdk";

// Create initial storage: set slot key 0x01 to value 100
const storageUpdates = [
    new EvmHookStorageUpdate().setStorageSlot(
        new EvmHookStorageSlot()
            .setKey(new Uint8Array(32).fill(1))     // slot key
            .setValue(new Uint8Array(32).fill(100))  // slot value
    ),
];

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

MethodTypeDescription
addHookToCreate(<hook>)HookCreationDetailsAdds 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>)longMarks 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.
getHooksToDelete()list<long>Returns the list of hook IDs to be deleted.

ContractUpdateTransaction Methods

MethodTypeDescription
addHookToCreate(<hook>)HookCreationDetailsAdds 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>)longMarks 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.
getHooksToDelete()list<long>Returns the list of hook IDs to be deleted.

Example: Add Hooks to an Existing Account

HookCreationDetails hook1 = new HookCreationDetails()
    .setExtensionPoint(HookExtensionPoint.ACCOUNT_ALLOWANCE_HOOK)
    .setHookId(1L)
    .setEvmHook(new EvmHook().setContractId(contractId))
    .setAdminKey(adminKey.getPublicKey());

HookCreationDetails hook2 = new HookCreationDetails()
    .setExtensionPoint(HookExtensionPoint.ACCOUNT_ALLOWANCE_HOOK)
    .setHookId(2L)
    .setEvmHook(new EvmHook().setContractId(contractId))
    .setAdminKey(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

ScenarioRequired Signatures
Create hook on new accountAccount key (from AccountCreateTransaction) + transaction payer
Create hook on existing accountAccount 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 CodeDescription
HOOK_ID_REPEATED_IN_CREATION_DETAILSThe same hook ID appears more than once in the hook_creation_details list.
HOOK_ID_IN_USEAn update transaction tried to create a hook with an ID already occupied on the entity.
HOOK_NOT_FOUNDAn update transaction tried to delete a hook ID that does not exist on the entity.
HOOK_DELETEDAttempted to delete a hook that was already previously deleted.
INVALID_HOOK_CREATION_SPECThe hook creation details are invalid (e.g., missing contract ID).
HOOK_DELETION_REQUIRES_EMPTY_STORAGECannot delete a hook that still has storage slots in use. Clear storage first via HookStoreTransaction.
TRANSACTION_REQUIRES_ZERO_HOOKSCannot delete an account or contract that still has hooks attached. Remove all hooks first.