Appearance
State APIs
This page documents the state Hook APIs: the functions that read and write a hook's persistent key/value storage, both on the hook's own account and — with an explicit grant — on other accounts.
All function signatures on this page match the Hook API.
Return codes reference the shared error table in Glossary, and the values quoted below match the Hook API's error definitions.
The implementation uses WASM-facing wrappers and a state cache.
What Hook State is
Hook State is a persistent key/value store attached to an account. Each stored entry is addressed by a triple:
- Account — whose ledger the entry lives on. For
state/state_setthis is always the account the hook is installed on (hook_account). For the_foreignvariants you name the account explicitly. - Namespace — a 32-byte (
uint256) tag that partitions an account's state. Each hook runs with a current namespace (sfHookNamespace).state/state_setand the_foreignvariants with a zero-length namespace use that current namespace; otherwise you pass a 32-byte namespace. - Key — a 32-byte key. Keys shorter than 32 bytes are accepted and zero-padded on the left to 32 bytes: the key
"key"is stored as 29 zero bytes followed by the three ASCII bytes. A key must be 1..32 bytes; 0 bytes returnsTOO_SMALLand more than 32 returnsTOO_BIG.
Each entry is a HookState ledger object (ltHOOK_STATE) identified by its account, key, and namespace.
Value size
A state value may be up to the scaled state-data limit.
- The base limit is 256 bytes.
- An account may raise it with
sfHookStateScale(1..16); the limit is256 * scale, i.e. up to 4096 bytes at scale 16. Accounts withoutsfHookStateScaleuse scale 1 (256 bytes).
Writing more than the limit returns TOO_BIG. The scale is read from the account object at write time.
State entries cost reserve
Creating a new state entry consumes owner reserve. The first time an account is touched in a hook execution, the implementation computes how many reserve increments the account can still afford:
availableForReserves = (balance - accountReserve(ownerCount)) / feeIncrementEach new entry consumes scale reserve positions. If the account cannot afford the next entry the write fails with RESERVE_INSUFFICIENT (-38). Overwriting an existing entry does not consume additional reserve. Deleting an entry (see state_set below) frees it.
Namespaces
An account may hold at most 256 namespaces.
Creating a state entry in a brand-new namespace counts against this limit and returns TOO_MANY_NAMESPACES (-45) if exceeded. The new-namespace accounting is gated behind the fixXahauV1 amendment.
Two distinct "too many modifications" limits
There are two separate limits on how much state a single transaction may change, and they are enforced at different points:
- Per-execution cache limit — 256. A write is rejected with
TOO_MANY_STATE_MODIFICATIONS(-44) once 256 entries have been modified within the current hook's state cache. - Combined-chain write limit. When state is finally flushed to the ledger, modified entries are counted across the combined hook chains, and the transaction returns
tecHOOK_REJECTEDif the count exceeds the 256-entry limit. TheTOO_MANY_STATE_MODIFICATIONS(-44) error is raised by this same 256-entry limit. Treat 256 as the operative figure for both mechanisms above.
Index
| Function | Purpose |
|---|---|
state | Read state under the hook account's current namespace. |
state_set | Write (or delete) state under the hook account's current namespace. |
state_foreign | Read state from a specified account and namespace. |
state_foreign_set | Write state on another account's namespace (requires a grant). |
Related documents
- ../../README — documentation index.
- Overview — hook execution model and lifecycle.
- Glossary — full error-code and term reference.
- Helper Macros —
SBUF,SVAR,UINT64_TO_BUF, and other helpers. - Best Practices — structuring state access and reserve budgets.
- Control APIs —
hook_account,accept/rollback, and namespaces context. - Transaction APIs — reading fields off the originating transaction.
- Slot APIs — slots and ledger info.
- Utility APIs —
util_keylet,util_accid, STO helpers. - State Counter — a persistent counter hook.
- Foreign State — cross-account state with grants.