-
Notifications
You must be signed in to change notification settings - Fork 20
Description
🧠 Advanced
This issue is well-suited for contributors who are very familiar with the
Hiero Swift SDK and enjoy working with its core abstractions and design patterns.
Advanced Issues often involve:
- Exploring and shaping SDK architecture
- Reasoning about trade-offs and long-term impact
- Working across multiple modules or systems
- Updating tests, examples, and documentation alongside code
The goal is to support thoughtful, high-impact contributions in a clear
and collaborative way.
🐞 Problem Description
The SDK needs to support hooks, programmable Hiero extension points that let users customize the behavior of their entities. This HIP introduces:
- EVM hooks: Hooks programmed in EVM bytecode that can access state or interact with external contracts
- Account allowance hooks: The first extension point, allowing custom allowance logic for transfers
Hooks enable users to customize native entities instead of migrating to EVM smart contracts, preserving performance and simplicity while enabling powerful customization.
Use cases:
- Custom fee enforcement on token transfers
- One-time passcode allowances for NFT distribution
- Receiver signature waivers for specific asset types
- Complex allowance rules without full smart contract migration
💡 Proposed / Expected Outcome
Implement the full hooks API as specified in HIP-1195, including new types, new transactions, and updates to existing transactions.
New Enums
enum HookExtensionPoint {
case accountAllowanceHook
}
enum FungibleHookType {
case preHookSender
case prePostHookSender
case preHookReceiver
case prePostHookReceiver
}
enum NftHookType {
case preHook
case prePostHook
}New Types
HookCreationDetails:
struct HookCreationDetails {
var extensionPoint: HookExtensionPoint
var hookId: Int64
var evmHook: EvmHook
var adminKey: Key?
}EvmHook:
struct EvmHook {
var contractId: ContractId
var storageUpdates: [EvmHookStorageUpdate]?
}EvmHookStorageUpdate (abstract with variants):
// Explicit storage slot
struct EvmHookStorageSlot {
var key: Data // 32-byte storage slot key
var value: Data // 32-byte value (empty to delete)
}
// Mapping entries
struct EvmHookMappingEntries {
var mappingSlot: Data
var entries: [EvmHookMappingEntry]
}
struct EvmHookMappingEntry {
var key: Data? // 32-byte key (one of key or preimage required)
var preimage: Data? // Bytes that hash to the mapping key
var value: Data // 32-byte value (empty to delete)
}HookCall and variants:
struct HookCall {
var hookId: Int64
var evmHookCall: EvmHookCall
}
struct FungibleHookCall {
var hookId: Int64
var evmHookCall: EvmHookCall
var hookType: FungibleHookType
}
struct NftHookCall {
var hookId: Int64
var evmHookCall: EvmHookCall
var hookType: NftHookType
}
struct EvmHookCall {
var data: Data
var gasLimit: UInt64
}HookId and HookEntityId:
struct HookId {
var entityId: HookEntityId
var hookId: Int64
}
struct HookEntityId {
var accountId: AccountId?
var contractId: ContractId?
}New Transaction
HookStoreTransaction:
class HookStoreTransaction: Transaction {
func setHookId(_ hookId: HookId) -> Self
func getHookId() -> HookId?
func addStorageUpdate(_ update: EvmHookStorageUpdate) -> Self
func setStorageUpdates(_ updates: [EvmHookStorageUpdate]) -> Self
func getStorageUpdates() -> [EvmHookStorageUpdate]
}Updated Transactions
AccountCreateTransaction:
extension AccountCreateTransaction {
func addHook(_ hook: HookCreationDetails) -> Self
func setHooks(_ hooks: [HookCreationDetails]) -> Self
func getHooks() -> [HookCreationDetails]
}AccountUpdateTransaction:
extension AccountUpdateTransaction {
func addHookToCreate(_ hook: HookCreationDetails) -> Self
func setHooksToCreate(_ hooks: [HookCreationDetails]) -> Self
func addHookToDelete(_ hookId: Int64) -> Self
func setHooksToDelete(_ hookIds: [Int64]) -> Self
func getHooksToCreate() -> [HookCreationDetails]
func getHooksToDelete() -> [Int64]
}ContractCreateTransaction:
extension ContractCreateTransaction {
func addHook(_ hook: HookCreationDetails) -> Self
func setHooks(_ hooks: [HookCreationDetails]) -> Self
func getHooks() -> [HookCreationDetails]
}ContractUpdateTransaction:
extension ContractUpdateTransaction {
func addHookToCreate(_ hook: HookCreationDetails) -> Self
func setHooksToCreate(_ hooks: [HookCreationDetails]) -> Self
func addHookToDelete(_ hookId: Int64) -> Self
func setHooksToDelete(_ hookIds: [Int64]) -> Self
func getHooksToCreate() -> [HookCreationDetails]
func getHooksToDelete() -> [Int64]
}TransferTransaction:
extension TransferTransaction {
func addHbarTransferWithHook(_ accountId: AccountId, _ amount: Hbar, _ hookCall: FungibleHookCall) -> Self
func addNftTransferWithHook(_ nftId: NftId, _ sender: AccountId, _ receiver: AccountId,
_ senderHookCall: NftHookCall?, _ receiverHookCall: NftHookCall?) -> Self
func addTokenTransferWithHook(_ tokenId: TokenId, _ accountId: AccountId, _ amount: Int64,
_ hookCall: FungibleHookCall) -> Self
}🧠 Implementation & Design Notes
Implementation Phases
Phase 1: Core Types
- Implement all enums (HookExtensionPoint, FungibleHookType, NftHookType)
- Implement utility types (EvmHook, EvmHookStorageUpdate variants, HookCreationDetails)
- Implement hook call types (HookCall, FungibleHookCall, NftHookCall, EvmHookCall)
- Implement identifier types (HookId, HookEntityId)
Phase 2: HookStoreTransaction
- New transaction for updating EVM hook storage
- Protobuf serialization/deserialization
- Unit tests
Phase 3: Account Transactions
- Update AccountCreateTransaction with hook creation
- Update AccountUpdateTransaction with hook create/delete
- Unit and integration tests
Phase 4: Contract Transactions
- Update ContractCreateTransaction with hook creation
- Update ContractUpdateTransaction with hook create/delete
- Unit and integration tests
Phase 5: TransferTransaction
- Add hook-aware transfer methods
- Handle FungibleHookCall and NftHookCall in transfers
- Unit and integration tests
Phase 6: Examples
- Create examples demonstrating hook creation and usage
Error Codes to Handle
| Error Code | Description |
|---|---|
INVALID_HOOK_CREATION_SPEC |
Hook creation missing required fields |
HOOK_ID_REPEATED_IN_CREATION_DETAILS |
Duplicate hook IDs in same transaction |
HOOK_ID_IN_USE |
Hook ID already exists on entity |
HOOK_NOT_FOUND |
Referenced hook doesn't exist |
HOOK_DELETED |
Attempting to delete already-deleted hook |
✅ Acceptance Criteria
A pull request for this issue should:
- Implement
HookExtensionPointenum - Implement
FungibleHookTypeandNftHookTypeenums - Implement
HookCreationDetailsstruct - Implement
EvmHookstruct - Implement
EvmHookStorageUpdatevariants (StorageSlot, MappingEntries) - Implement
HookCall,FungibleHookCall,NftHookCallstructs - Implement
EvmHookCallstruct - Implement
HookIdandHookEntityIdstructs - Implement
HookStoreTransaction - Update
AccountCreateTransactionwith hook methods - Update
AccountUpdateTransactionwith hook create/delete methods - Update
ContractCreateTransactionwith hook methods - Update
ContractUpdateTransactionwith hook create/delete methods - Update
TransferTransactionwith hook-aware transfer methods - Add unit tests (38 test cases per test plan)
- Add integration tests
- Add examples
- Follow existing architectural and Swift conventions
- Pass all CI checks
Test Plan Summary (38 test cases)
AccountCreateTransaction (5 tests):
1-5. Create accounts with hooks, storage updates, admin keys, error cases
AccountUpdateTransaction (9 tests):
6-14. Add/delete hooks, error cases for duplicates, missing hooks
ContractCreateTransaction (5 tests):
15-19. Create contracts with hooks, storage updates, admin keys, error cases
ContractUpdateTransaction (9 tests):
20-28. Add/delete hooks from contracts, error cases
HookStoreTransaction (3 tests):
29-31. Update storage, signature validation, missing hook errors
TransferTransaction (7 tests):
32-38. HBAR/token/NFT transfers with various hook types
📚 Additional Context, Links, or Prior Art
References
- HIP: https://hips.hedera.com/hip/hip-1195
- SDK Design Document: https://github.com/hiero-ledger/sdk-collaboration-hub/blob/main/proposals/hips/hip-1195.md
- HIP Status: Approved
- Reference Implementation: https://github.com/hiero-ledger/hiero-consensus-node/tree/hooks-poc
Example: Creating an Account with an EVM Hook
import Hiero
// Create initial storage updates
let storageSlot = EvmHookStorageSlot(
key: Data(repeating: 1, count: 32),
value: Data(repeating: 100, count: 32)
)
// Create EVM hook with storage
let evmHook = EvmHook(
contractId: ContractId.fromString("0.0.67890"),
storageUpdates: [.storageSlot(storageSlot)]
)
let hookDetails = HookCreationDetails(
extensionPoint: .accountAllowanceHook,
hookId: 1002,
evmHook: evmHook,
adminKey: adminKey.publicKey
)
// Create account with hook
let tx = try AccountCreateTransaction()
.key(.single(accountKey.publicKey))
.addHook(hookDetails)
.freezeWith(client)
.sign(accountKey)
let response = try await tx.execute(client)
let accountId = try await response.getReceipt(client).accountId!Example: Transfer with Hook
let hookCall = FungibleHookCall(
hookId: 1001,
evmHookCall: EvmHookCall(
data: Data([0x01, 0x02]),
gasLimit: 50000
),
hookType: .preHookSender
)
let tx = try TransferTransaction()
.addHbarTransferWithHook(senderAccountId, Hbar(-100), hookCall)
.addHbarTransfer(receiverAccountId, Hbar(100))
.freezeWith(client)
.sign(senderKey)
try await tx.execute(client)If you have questions, the community is happy to help:
https://discord.com/channels/905194001349627914/1337424839761465364
Metadata
Metadata
Assignees
Labels
Type
Projects
Status