From 29478b124ac14674b480695ff3f5782b327459f3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Tue, 23 Jun 2026 07:53:59 +0200
Subject: [PATCH 01/23] HookOnv2
---
src/content/docs/docs/features/amendments.mdx | 4 ++++
.../docs/docs/hooks/concepts/hookon-field.mdx | 22 +++++++++++++++++++
.../ledger-objects-types/hook-definition.mdx | 13 +++++++----
.../ledger-data/ledger-objects-types/hook.mdx | 12 ++++++----
.../transaction-types/sethook.mdx | 22 ++++++++++---------
5 files changed, 55 insertions(+), 18 deletions(-)
diff --git a/src/content/docs/docs/features/amendments.mdx b/src/content/docs/docs/features/amendments.mdx
index d5b7b2b..a5f0dbe 100644
--- a/src/content/docs/docs/features/amendments.mdx
+++ b/src/content/docs/docs/features/amendments.mdx
@@ -175,6 +175,10 @@ Fixes issues with provisional double threading in transaction processing. Ensure
Fixes a bug that currently allows invalid flags to be provided to some transactions. While these invalid flags currently do nothing, they should actually produce a malformed error. After this fix is applied, invalid flags will produce a malformed error as expected. _(Introduced in 2025.10.27-release+2405)_
+##### HookOnV2
+
+Hooks may continue to specify `HookOn` with the existing behaviour, or optionally replace it with two separate fields: `HookOnIncoming` and `HookOnOutgoing`. Both use the same bitmask syntax as `HookOn` but differentiate between transactions originating from the Hook account (`HookOnOutgoing`) and transactions originating from another account (`HookOnIncoming`). Additionally, `HookCanEmit` may be specified to control which transaction types the Hook is allowed to emit, using the same syntax as `HookOn`. _(Introduced in 2026.6.21-release+3350)_
+
##### fixCronStacking
Fixes issues with Cron transaction stacking behavior.
diff --git a/src/content/docs/docs/hooks/concepts/hookon-field.mdx b/src/content/docs/docs/hooks/concepts/hookon-field.mdx
index eca806e..e988114 100644
--- a/src/content/docs/docs/hooks/concepts/hookon-field.mdx
+++ b/src/content/docs/docs/hooks/concepts/hookon-field.mdx
@@ -42,3 +42,25 @@ Examples (assuming a 256-bit unsigned integer type):
### HookOn Calculator
+
+### HookCanEmit Field
+
+_(Added by the [HookCanEmit amendment](/docs/features/amendments/#hookcanemit).)_
+
+`HookCanEmit` uses the same 256-bit bitmask syntax as `HookOn` but controls which transaction types a Hook is allowed to **emit**, rather than which types trigger it.
+
+- Uses the same active-low semantics as `HookOn`, with bit 22 (`ttHOOK_SET`) being active high.
+- If `HookCanEmit` is absent, the Hook may emit any transaction type, including `SetHook`.
+
+### HookOnV2: Incoming and Outgoing
+
+_(Added by the [HookOnV2 amendment](/docs/features/amendments/#hookonv2).)_
+
+Instead of specifying a single `HookOn` field, Hooks may optionally replace it with two separate fields that differentiate the direction of the triggering transaction:
+
+- **`HookOnIncoming`** — triggers the Hook on transactions **originating from another account** (the Hook account is not the initiator).
+- **`HookOnOutgoing`** — triggers the Hook on transactions **originating from the Hook account itself**.
+
+Both fields use the same bit-field syntax as `HookOn`. `HookOnIncoming` and `HookOnOutgoing` are mutually exclusive with `HookOn` — you must use either `HookOn` alone or the `HookOnIncoming`/`HookOnOutgoing` pair, not both. If only one of the pair is specified, the Hook will not fire on the unspecified direction.
+
+Using `HookOn` alone continues to work exactly as before.
diff --git a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook-definition.mdx b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook-definition.mdx
index 734463e..b27b23e 100644
--- a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook-definition.mdx
+++ b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook-definition.mdx
@@ -13,6 +13,9 @@ A `HookDefinition` object describes a hook, which is a piece of code that is exe
{
"HookHash": "49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0",
"HookOn": "0000000000000000000000000000000000000000000000000000000000000000",
+ "HookOnIncoming": "0000000000000000000000000000000000000000000000000000000000000000",
+ "HookOnOutgoing": "0000000000000000000000000000000000000000000000000000000000000000",
+ "HookCanEmit": "0000000000000000000000000000000000000000000000000000000000000000",
"HookNamespace": "0000000000000000000000000000000000000000000000000000000000000000",
"HookParameters": {
"HookParameter": {
@@ -37,10 +40,12 @@ A `HookDefinition` object has the following fields:
| Field | JSON Type | \[Internal Type]\[] | Required? | Description |
| ----------------- | --------- | ------------------- | --------- | ----------------------------------------------------------------------------------------------------------------- |
-| `HookHash` | String | Hash256 | Yes | The unique identifier of the hook. |
-| `HookOn` | String | Hash256 | Yes | The transaction/s on which the hook is triggered. |
-| `HookCanEmit` | String | Hash256 | No | The transaction/s which the hook can emit. |
-| `HookNamespace` | String | Hash256 | Yes | The namespace of the hook. |
+| `HookHash` | String | Hash256 | Yes | The unique identifier of the hook. |
+| `HookOn` | String | Hash256 | No | The transaction/s on which the hook is triggered. Mutually exclusive with `HookOnIncoming`/`HookOnOutgoing`. |
+| `HookOnIncoming` | String | Hash256 | No | _(HookOnV2)_ Same syntax as `HookOn`. Triggers the hook on transactions originating from another account. Mutually exclusive with `HookOn`. |
+| `HookOnOutgoing` | String | Hash256 | No | _(HookOnV2)_ Same syntax as `HookOn`. Triggers the hook on transactions originating from the Hook account itself. Mutually exclusive with `HookOn`. |
+| `HookCanEmit` | String | Hash256 | No | Same syntax as `HookOn`. Controls which transaction types the hook is allowed to emit. If absent, the hook may emit any transaction type. |
+| `HookNamespace` | String | Hash256 | Yes | The namespace of the hook. |
| `HookParameters` | String | Vector | Yes | The parameters that the hook accepts. |
| `HookApiVersion` | Number | UInt16 | Yes | The version of the hook API that the hook uses. |
| `CreateCode` | String | VL | Yes | The code that is executed when the hook is created. |
diff --git a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook.mdx b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook.mdx
index 7238950..717fdab 100644
--- a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook.mdx
+++ b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook.mdx
@@ -36,7 +36,7 @@ A `Hook` object has the following fields:
| `OwnerNode` | String | UInt64 | Yes | A hint indicating which page of the owner's directory links to this object, in case the directory consists of multiple pages. |
| `PreviousTxnID` | String | Hash256 | Yes | The ID of the transaction that most recently modified this object. |
| `PreviousTxnLgrSeq` | Number | UInt32 | Yes | The \[ledger index]\[] of the ledger that contains the transaction that most recently modified this object. |
-| `Hooks` | Array | Array | Yes | An array of hook objects. Each object has the following fields: `HookHash`, `CreateCode`, `HookGrants`, `HookNamespace`, `HookParameters`, `HookOn`, `HookApiVersion`, `Flags`. |
+| `Hooks` | Array | Array | Yes | An array of hook objects. Each object has the following fields: `HookHash`, `CreateCode`, `HookGrants`, `HookNamespace`, `HookParameters`, `HookOn`, `HookOnIncoming`, `HookOnOutgoing`, `HookCanEmit`, `HookApiVersion`, `Flags`. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0043`, mapped to the string `Hook`, indicates that this object is a Hook object. |
### Hook Fields
@@ -45,9 +45,13 @@ The following fields are used in the hook object:
| Field | JSON Type | Internal Type | Description |
| ---------------- | --------- | ------------- | ------------------------------ |
-| `HookHash` | String | Hash256 | The hash of the hook. |
-| `HookParameters` | Array | Array | The parameters of the hook. |
-| `Flags` | Number | UInt32 | Additional flags for the hook. |
+| `HookHash` | String | Hash256 | The hash of the hook. |
+| `HookParameters` | Array | Array | The parameters of the hook. |
+| `HookOn` | String | Hash256 | The transaction/s on which the hook is triggered. Mutually exclusive with `HookOnIncoming`/`HookOnOutgoing`. |
+| `HookOnIncoming` | String | Hash256 | _(HookOnV2)_ Same syntax as `HookOn`. Triggers the hook on transactions originating from another account. Mutually exclusive with `HookOn`. |
+| `HookOnOutgoing` | String | Hash256 | _(HookOnV2)_ Same syntax as `HookOn`. Triggers the hook on transactions originating from the Hook account itself. Mutually exclusive with `HookOn`. |
+| `HookCanEmit` | String | Hash256 | Same syntax as `HookOn`. Controls which transaction types the hook is allowed to emit. If absent, the hook may emit any transaction type. |
+| `Flags` | Number | UInt32 | Additional flags for the hook. |
#### Hook ID Format
diff --git a/src/content/docs/docs/protocol-reference/transactions/transaction-types/sethook.mdx b/src/content/docs/docs/protocol-reference/transactions/transaction-types/sethook.mdx
index bfc56ae..1e61f80 100644
--- a/src/content/docs/docs/protocol-reference/transactions/transaction-types/sethook.mdx
+++ b/src/content/docs/docs/protocol-reference/transactions/transaction-types/sethook.mdx
@@ -274,7 +274,7 @@ _All_ of the following conditions are met:
* `HookNamespace` is specified.
* `CreateCode` is absent.
* `HookHash` is absent.
-* `HookGrants`, `HookParameters`, `HookOn` and `HookApiVersion` are absent.
+* `HookGrants`, `HookParameters`, `HookOn`, `HookOnIncoming`, `HookOnOutgoing` and `HookApiVersion` are absent.
**Behaviour**:
@@ -308,15 +308,17 @@ The following fields are used in the hook object:
| Field | JSON Type | Internal Type | Description |
| ---------------- | --------- | ------------- | ------------------------------------------------- |
-| `HookHash` | String | Hash256 | The hash of the hook. |
-| `CreateCode` | String | Blob | The WebAssembly code for the hook. |
-| `HookGrants` | Array | Array | The grants associated with the hook. |
-| `HookNamespace` | String | Hash256 | The namespace of the hook. |
-| `HookParameters` | Array | Array | The parameters of the hook. |
-| `HookOn` | String | Hash256 | The transaction/s on which the hook is triggered. |
-| `HookCanEmit` | String | Hash256 | The transaction/s which the hook can emit. |
-| `HookApiVersion` | Number | UInt16 | The API version of the hook. |
-| `Flags` | Number | UInt32 | Additional flags for the hook. |
+| `HookHash` | String | Hash256 | The hash of the hook. |
+| `CreateCode` | String | Blob | The WebAssembly code for the hook. |
+| `HookGrants` | Array | Array | The grants associated with the hook. |
+| `HookNamespace` | String | Hash256 | The namespace of the hook. |
+| `HookParameters` | Array | Array | The parameters of the hook. |
+| `HookOn` | String | Hash256 | The transaction/s on which the hook is triggered. Mutually exclusive with `HookOnIncoming`/`HookOnOutgoing`. |
+| `HookOnIncoming` | String | Hash256 | _(Optional, HookOnV2)_ Same syntax as `HookOn`. Triggers the hook on transactions originating from **another account**. Mutually exclusive with `HookOn`. |
+| `HookOnOutgoing` | String | Hash256 | _(Optional, HookOnV2)_ Same syntax as `HookOn`. Triggers the hook on transactions originating from **the Hook account itself**. Mutually exclusive with `HookOn`. |
+| `HookCanEmit` | String | Hash256 | _(Optional)_ Same syntax as `HookOn`. Controls which transaction types the hook is allowed to emit. If absent, the hook may emit any transaction type. |
+| `HookApiVersion` | Number | UInt16 | The API version of the hook. |
+| `Flags` | Number | UInt32 | Additional flags for the hook. |
### Flags
From bf275aa37d2d2557133ab27b22b800100f312d2b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Tue, 23 Jun 2026 08:39:18 +0200
Subject: [PATCH 02/23] IOUClaim
---
src/content/docs/docs/features/amendments.mdx | 4 ++
.../network-features/balance-rewards.mdx | 23 ++++++
.../ledger-objects-types/ripple-state.mdx | 31 +++++++-
.../transaction-types/claimreward.mdx | 72 ++++++++++++++-----
4 files changed, 109 insertions(+), 21 deletions(-)
diff --git a/src/content/docs/docs/features/amendments.mdx b/src/content/docs/docs/features/amendments.mdx
index a5f0dbe..2691abc 100644
--- a/src/content/docs/docs/features/amendments.mdx
+++ b/src/content/docs/docs/features/amendments.mdx
@@ -179,6 +179,10 @@ Fixes a bug that currently allows invalid flags to be provided to some transacti
Hooks may continue to specify `HookOn` with the existing behaviour, or optionally replace it with two separate fields: `HookOnIncoming` and `HookOnOutgoing`. Both use the same bitmask syntax as `HookOn` but differentiate between transactions originating from the Hook account (`HookOnOutgoing`) and transactions originating from another account (`HookOnIncoming`). Additionally, `HookCanEmit` may be specified to control which transaction types the Hook is allowed to emit, using the same syntax as `HookOn`. _(Introduced in 2026.6.21-release+3350)_
+##### IOURewardClaim
+
+Expands the [ClaimReward](/docs/protocol-reference/transactions/transaction-types/claimreward) transaction type beyond genesis balance adjustments to issuers of other IOU currencies. The same reward logic (area under the curve of hold time vs. hold amount) is optionally applied to issuer currencies using the `ClaimCurrency` field. Reward counters are held within the trustline (`LowReward`/`HighReward` objects on the [RippleState](/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state) object) and do not affect genesis balance adjustments. The actual reward payout is handled by a Hook installed on the issuer account that fires on `ttCLAIM_REWARD`. _(Introduced in 2026.6.21-release+3350)_
+
##### fixCronStacking
Fixes issues with Cron transaction stacking behavior.
diff --git a/src/content/docs/docs/features/network-features/balance-rewards.mdx b/src/content/docs/docs/features/network-features/balance-rewards.mdx
index db51803..e6e56f0 100644
--- a/src/content/docs/docs/features/network-features/balance-rewards.mdx
+++ b/src/content/docs/docs/features/network-features/balance-rewards.mdx
@@ -18,3 +18,26 @@ A `ClaimReward` transaction allows an account to claim the rewards it has accumu
The `GenesisMint` transaction type is also associated with the Balance Rewards feature. This is an Emitted transaction that is executed through the Reward Hook every time a user claims balance rewards.
+
+### IOU Reward Claim
+
+_(Requires the [IOURewardClaim amendment](/docs/features/amendments/#iourewardclaim).)_
+
+The `IOURewardClaim` amendment extends the reward mechanic to IOU currencies issued by any account. The same area-under-the-curve calculation (hold time × hold amount) that governs XAH genesis rewards is applied to IOU token holders, with the issuer's Hook controlling payout logic.
+
+#### How it works
+
+1. **Opt-in**: A token holder submits a `ClaimReward` transaction with the `ClaimCurrency` field specifying the IOU. This initialises reward-tracking counters (`LowReward` or `HighReward`) directly on the trustline ([RippleState](/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state) ledger object).
+2. **Accumulation**: After every transaction that modifies the trustline balance, the ledger automatically updates the `TrustLineRewardAccumulator` field. This tracks the cumulative product of balance × ledgers elapsed since the last reset.
+3. **Claim**: When the holder submits another `ClaimReward` with `ClaimCurrency`, the ledger resets the counters and fires the issuer's Hook (which must be installed and must fire on `ttCLAIM_REWARD`). The Hook reads the accumulated value and emits a reward payment in whatever form the issuer chooses.
+
+#### Key differences from XAH genesis rewards
+
+| | XAH Genesis Rewards | IOU Rewards |
+|---|---|---|
+| Amendment | `BalanceRewards` | `IOURewardClaim` |
+| Counters stored on | AccountRoot | RippleState (trustline) |
+| Accumulator type | UInt64 (drops / 1,000,000) | Amount (in the token's units) |
+| Payout handled by | Genesis account Hook | Issuer account Hook |
+| Opt-out flag | `tfOptOut` (flag 1) | Not applicable |
+| Issuer restriction | Must be genesis account | Any account with a Hook on `ttCLAIM_REWARD`, except AMM accounts |
diff --git a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state.mdx b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state.mdx
index 5bb3e18..6c8df18 100644
--- a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state.mdx
+++ b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state.mdx
@@ -41,7 +41,17 @@ The "issuer" for the balance in a trust line depends on whether the balance is p
"currency": "USD",
"issuer": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
"value": "10"
- }
+ },
+ "LowReward": {
+ "RewardLgrFirst": 1000000,
+ "RewardLgrLast": 1001234,
+ "RewardTime": 744000000,
+ "TrustLineRewardAccumulator": {
+ "currency": "USD",
+ "issuer": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
+ "value": "500"
+ }
+ },
"index": "9CA88CDEDFF9252B3DE183CE35B038F57282BC9503CDFA1923EF9A95DF0D6F7B"
}
```
@@ -65,8 +75,23 @@ A `RippleState` object has the following fields:
| `LowQualityOut` | Number | UInt32 | No | The outbound quality set by the low account, as an integer in the implied ratio `LowQualityOut`:1,000,000,000. As a special case, the value 0 is equivalent to 1 billion, or face value. |
| `PreviousTxnID` | String | Hash256 | Yes | The identifying hash of the transaction that most recently modified this object. |
| `PreviousTxnLgrSeq` | Number | UInt32 | Yes | The \[index of the ledger]\[Ledger Index] that contains the transaction that most recently modified this object. |
-| `LockCount` | Number | UInt32 | No | The total number of lock balances on a RippleState ledger object |
-| `LockedBalance` | Object | Amount | No | The current amount of locked tokens for a specific trustline |
+| `LockCount` | Number | UInt32 | No | The total number of lock balances on a RippleState ledger object. |
+| `LockedBalance` | Object | Amount | No | The current amount of locked tokens for a specific trustline. |
+| `LowReward` | Object | STObject | No | _(IOURewardClaim)_ IOU reward-tracking counters for the low account. Present only after the low account opts in via `ClaimReward` with `ClaimCurrency`. Contains `RewardLgrFirst`, `RewardLgrLast`, `RewardTime`, and `TrustLineRewardAccumulator`. |
+| `HighReward` | Object | STObject | No | _(IOURewardClaim)_ IOU reward-tracking counters for the high account. Present only after the high account opts in via `ClaimReward` with `ClaimCurrency`. Contains `RewardLgrFirst`, `RewardLgrLast`, `RewardTime`, and `TrustLineRewardAccumulator`. |
+
+### LowReward / HighReward Fields
+
+_(Added by the [IOURewardClaim amendment](/docs/features/amendments/#iourewardclaim).)_
+
+Both `LowReward` and `HighReward` are inner objects with the same structure. Which one is present depends on the canonical high/low ordering of the two accounts in the trustline.
+
+| Field | JSON Type | Internal Type | Description |
+| ---------------------------- | --------- | ------------- | ---------------------------------------------------------------------------------------------------- |
+| `RewardLgrFirst` | Number | UInt32 | The ledger sequence when the account first opted in to IOU rewards for this trustline. |
+| `RewardLgrLast` | Number | UInt32 | The ledger sequence of the last time the reward accumulator was updated. |
+| `RewardTime` | Number | UInt32 | The ledger close time (Ripple epoch seconds) when the counters were last reset by a `ClaimReward` transaction. |
+| `TrustLineRewardAccumulator` | Object | Amount | The running total of `balance × ledgers elapsed` since the last `ClaimReward`. Expressed in the trustline's currency. This is the value the issuer's Hook reads to calculate the reward payout. |
### RippleState Flags
diff --git a/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx b/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx
index d836534..3e738b8 100644
--- a/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx
+++ b/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx
@@ -3,13 +3,15 @@ title: ClaimReward
description: >-
A ClaimReward transaction allows an account to claim the rewards it has
accumulated. The rewards can be claimed by the account owner or by a specified
- issuer. The account can also opt-out of rewards.
+ issuer. The account can also opt-out of rewards. With the IOURewardClaim
+ amendment, this transaction also supports claiming rewards for IOU currencies
+ issued by accounts with a reward Hook installed.
---
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/ClaimReward.cpp)]
_(Added by the \[BalanceRewards amendment]\[].)_
-### Opt-in + Claim
+### Opt-in + Claim (XAH genesis rewards)
```json
{
@@ -19,7 +21,7 @@ _(Added by the \[BalanceRewards amendment]\[].)_
}
```
-### Opt-out
+### Opt-out (XAH genesis rewards)
```json
{
@@ -29,34 +31,68 @@ _(Added by the \[BalanceRewards amendment]\[].)_
}
```
+### IOU Reward Claim
+
+_(Requires the \[IOURewardClaim amendment]\[].)_
+
+```json
+{
+ "TransactionType": "ClaimReward",
+ "Account": "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm",
+ "Issuer": "rIssuerAccountXXXXXXXXXXXXXXXXXXX",
+ "ClaimCurrency": {
+ "currency": "USD",
+ "issuer": "rIssuerAccountXXXXXXXXXXXXXXXXXXX"
+ }
+}
+```
+
### Fields
-| Field | JSON Type | \[Internal Type]\[] | Description |
-| --------- | --------- | ------------------- | ------------------------------------------------------- |
-| `Account` | String | AccountID | The address of the account that is claiming the reward. |
-| `Flags` | Number | UInt32 | _(Optional)_ Can have flag 1 set to opt-out of rewards. |
-| `Issuer` | String | AccountID | _(Optional)_ The genesis account. |
+| Field | JSON Type | \[Internal Type]\[] | Description |
+| --------------- | --------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `Account` | String | AccountID | The address of the account that is claiming the reward. |
+| `Flags` | Number | UInt32 | _(Optional)_ Can have flag 1 set to opt-out of XAH genesis rewards. |
+| `Issuer` | String | AccountID | _(Optional)_ The genesis account (XAH rewards) or the IOU issuer account (IOU rewards). |
+| `ClaimCurrency` | Object | Issue | _(Optional, IOURewardClaim)_ The IOU currency to claim rewards for, as `{"currency": "...", "issuer": "..."}`. Cannot be XAH. The issuer must not be the genesis account and must not equal `Account`. Requires a trustline to exist between `Account` and the issuer. |
### ClaimReward Flags
Transactions of the ClaimReward type support additional values in the `Flags` field, as follows:
-| Flag Name | Hex Value | Decimal Value | Description |
-| ---------- | ------------ | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `tfOptOut` | `0x00000001` | 1 | The `isOptOut` flag in the ClaimReward code is used to opt-out an account from rewards by removing reward-related fields from the account object in the ledger if the `sfFlags` field in the transaction is set to 1. |
+| Flag Name | Hex Value | Decimal Value | Description |
+| ---------- | ------------ | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `tfOptOut` | `0x00000001` | 1 | Opts the account out of XAH genesis rewards by removing reward-related fields from the account's ledger object. Not applicable when `ClaimCurrency` is specified. |
### Special Transaction Cost
The ClaimReward transaction has a standard transaction cost, which is the minimum transaction cost required for all transactions.
+### IOU Reward Behaviour
+
+_(Requires the \[IOURewardClaim amendment]\[].)_
+
+When `ClaimCurrency` is specified, the transaction follows the IOU reward path:
+
+1. The `Issuer` account must have a Hook installed that fires on `ttCLAIM_REWARD`. The Hook is responsible for calculating and distributing the reward payout.
+2. On first claim, a `LowReward` or `HighReward` reward-tracking object is initialised on the trustline ([RippleState](/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state) ledger object) between `Account` and the issuer. Which side is used depends on the canonical high/low ordering of the two accounts.
+3. After every subsequent transaction that changes the trustline balance, the ledger automatically updates `TrustLineRewardAccumulator` inside the tracking object using the same area-under-the-curve formula as genesis XAH rewards.
+4. When a `ClaimReward` with `ClaimCurrency` is submitted, the ledger resets the reward counters on the trustline and fires the issuer's Hook, which reads the accumulated value and emits a reward payment.
+
+The IOU reward counters are entirely independent of the genesis XAH reward fields on the AccountRoot object.
+
### Error Cases
Besides errors that can occur for all transactions, ClaimReward transactions can result in the following transaction result codes:
-| Error Code | Description |
-| ----------------- | ------------------------------------------------------------------------------------------------------- |
-| `temDISABLED` | Occurs if the feature is not enabled. |
-| `temINVALID_FLAG` | Occurs if the flag is set to a value other than 1. |
-| `temMALFORMED` | Occurs if the issuer is the same as the source account or if the flag and issuer are not correctly set. |
-| `tecNO_ISSUER` | Occurs if the issuer does not exist. |
-| `terNO_ACCOUNT` | Occurs if the sending account does not exist. |
+| Error Code | Description |
+| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |
+| `temDISABLED` | Occurs if the required amendment (`BalanceRewards` or `IOURewardClaim`) is not enabled. |
+| `temINVALID_FLAG` | Occurs if the flag is set to a value other than 1. _(Requires the \[fixRewardClaimFlags amendment]\[].)_ |
+| `temMALFORMED` | Occurs if `ClaimCurrency` is an MPT or XRP type, if the issuer equals `Account`, or if the transaction fields are otherwise incorrectly set. |
+| `temBAD_ISSUER` | Occurs if `ClaimCurrency` is set but the issuer is the genesis account, or if `Issuer` is the genesis account but `ClaimCurrency` is also set. |
+| `terNO_ACCOUNT` | Occurs if the sending account does not exist. |
+| `tecNO_ISSUER` | Occurs if the `Issuer` account does not exist. |
+| `tecNO_PERMISSION` | Occurs if the issuer account is an AMM account. AMM accounts cannot have reward Hooks. |
+| `tecNO_TARGET` | Occurs if the issuer account has no Hooks, or none of its Hooks fires on `ttCLAIM_REWARD`. |
+| `tecNO_LINE` | Occurs if no trustline exists between `Account` and the issuer for the specified `ClaimCurrency`. |
From b3d4869b0763421c036a7cfebde714105819a3ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Tue, 23 Jun 2026 08:58:15 +0200
Subject: [PATCH 03/23] Feature: HooksUpdate2
---
src/content/docs/docs/features/amendments.mdx | 4 +
.../hooks/concepts/emitted-transactions.mdx | 4 +-
.../functions/emitted-transaction/emit-1.mdx | 3 +
.../functions/emitted-transaction/emit.mdx | 76 ++++++++++++++++---
.../transaction-types/claimreward.mdx | 2 +-
5 files changed, 75 insertions(+), 14 deletions(-)
diff --git a/src/content/docs/docs/features/amendments.mdx b/src/content/docs/docs/features/amendments.mdx
index 2691abc..b2faaea 100644
--- a/src/content/docs/docs/features/amendments.mdx
+++ b/src/content/docs/docs/features/amendments.mdx
@@ -81,6 +81,10 @@ Core amendment enabling Hook smart contract functionality on Xahau. _(Added by t
Updates and improvements to the Hooks system.
+##### HooksUpdate2
+
+Adds the `prepare()` Hook API function. `prepare(write_ptr, write_len, read_ptr, read_len)` accepts a partial serialized transaction containing only transaction-type-specific fields and automatically injects all fields required for emission: `Account`, `Sequence`, `SigningPubKey`, `Fee`, `FirstLedgerSequence`, `LastLedgerSequence`, and `EmitDetails`. The output can be passed directly to `emit()`, eliminating the need to manually construct these boilerplate fields in hook code. _(Introduced in 2026.6.21-release+3350)_
+
##### Remit
Implements [XLS-55](https://github.com/XRPLF/XRPL-Standards/discussions/156). A new simple but powerful what-you-see-is-what-you-get push payment transaction type. Enables [Remit transactions](/docs/protocol-reference/transactions/transaction-types/remit) that allow paying multiple currencies and URITokens in the same transaction to the same destination. The transaction automatically pays to create missing trustlines, automatically pays the reserves on transferred tokens, and automatically pays to create the destination account if it doesn't exist. You can mint a receipt or bonus URIToken in-line within the transaction. Optionally inform a third party Hook about the transaction. No partial payments and no pathing.
diff --git a/src/content/docs/docs/hooks/concepts/emitted-transactions.mdx b/src/content/docs/docs/hooks/concepts/emitted-transactions.mdx
index 346d130..67a3776 100644
--- a/src/content/docs/docs/hooks/concepts/emitted-transactions.mdx
+++ b/src/content/docs/docs/hooks/concepts/emitted-transactions.mdx
@@ -18,13 +18,13 @@ The solution: **Emitted Transactions**. We allow the Originating Transaction to
Emitted Transactions are _new_ transactions created by the execution of a Hook and entered into consensus for processing in the next ledger. The transaction may be of any Transaction Type but must follow strict emission rules.
-To emit a transaction the Hook first prepares the serialized transaction then calls [emit](/docs/hooks/functions/emitted-transaction/emit-1).
+To emit a transaction the Hook first prepares the serialized transaction then calls [emit](/docs/hooks/functions/emitted-transaction/emit-1). With the [HooksUpdate2 amendment](/docs/features/amendments/#hooksupdate2), the [prepare()](/docs/hooks/functions/emitted-transaction/emit) API can build the complete emission-ready transaction automatically from a partial input, removing the need to manually set `Account`, `Sequence`, `SigningPubKey`, `Fee`, `FirstLedgerSequence`, `LastLedgerSequence`, and `EmitDetails`.
Because emitted transactions can trigger Hooks in the next ledger which in turn may emit more transactions, all emitted transactions carry a `burden` and a `generation` field in their `EmitDetails` block. The `EmitDetails` block replaces the signature field in a traditional transaction.
The `burden` and `generation` fields collectively prevent [Fork bomb](https://en.wikipedia.org/wiki/Fork_bomb) attacks on the ledger by exponentially increasing the cost of exponentially expanding emtited transactions.
-It is important to note that the Hooks API follows the strict rule of _no rewriting_. You _must_ present an emitted transaction in full, valid and canonically formed to xahaud for emission or it will be rejected. It is not xahaud's job to build your transaction for you. The Hook must do this itself.
+It is important to note that the Hooks API follows the strict rule of _no rewriting_. You _must_ present an emitted transaction in full, valid and canonically formed to xahaud for emission or it will be rejected. With the [HooksUpdate2 amendment](/docs/features/amendments/#hooksupdate2), the [`prepare()`](/docs/hooks/functions/emitted-transaction/emit) API automates this: the Hook provides only the transaction-type-specific fields and the runtime injects all required emission boilerplate. Without HooksUpdate2, the Hook must construct the complete transaction itself.
### Callbacks
diff --git a/src/content/docs/docs/hooks/functions/emitted-transaction/emit-1.mdx b/src/content/docs/docs/hooks/functions/emitted-transaction/emit-1.mdx
index 9db8215..721dfda 100644
--- a/src/content/docs/docs/hooks/functions/emitted-transaction/emit-1.mdx
+++ b/src/content/docs/docs/hooks/functions/emitted-transaction/emit-1.mdx
@@ -7,6 +7,7 @@ import { Tabs, TabItem, LinkButton } from '@astrojs/starlight/components';
### Concepts
Emitted Transactions
+prepare()
### Behaviour
@@ -16,6 +17,8 @@ import { Tabs, TabItem, LinkButton } from '@astrojs/starlight/components';
* Validate the transaction against the emission rules
* Emit the transaction into consensus when valid
* Write canonical transaction hash to `write_ptr`
+
+With the [HooksUpdate2 amendment](/docs/features/amendments/#hooksupdate2), use [`prepare()`](/docs/hooks/functions/emitted-transaction/emit) before `emit()` to automatically inject all required emission fields (`Account`, `Sequence`, `SigningPubKey`, `Fee`, `EmitDetails`, etc.) from a partial transaction.
diff --git a/src/content/docs/docs/hooks/functions/emitted-transaction/emit.mdx b/src/content/docs/docs/hooks/functions/emitted-transaction/emit.mdx
index 8c42d18..a5db7b4 100644
--- a/src/content/docs/docs/hooks/functions/emitted-transaction/emit.mdx
+++ b/src/content/docs/docs/hooks/functions/emitted-transaction/emit.mdx
@@ -1,16 +1,27 @@
---
title: prepare
-description: Prepares a JSON transaction for emission.
+description: Prepares a transaction for emission by automatically injecting all required emission fields.
---
import { Tabs, TabItem, LinkButton } from '@astrojs/starlight/components';
### Concepts
-Transactions
+Emitted Transactions
### Behaviour
+
+
+_(Requires the [HooksUpdate2 amendment](/docs/features/amendments/#hooksupdate2).)_
+
+* Reads a partial serialized transaction from `read_ptr`/`read_len`. The input must contain at minimum the `TransactionType` and all fields required by that transaction type, but **must not** include emission-specific fields.
+* Automatically injects all fields required for emission: `Account` (the Hook account), `Sequence` (0), `SigningPubKey` (all zeros), `Fee` (computed), `FirstLedgerSequence` (current ledger + 1), `LastLedgerSequence` (current ledger + 5), and `EmitDetails`.
+* Writes the complete, emission-ready transaction blob to `write_ptr`.
+* The output can be passed directly to [`emit()`](/docs/hooks/functions/emitted-transaction/emit-1).
+* `etxn_reserve()` must be called before `prepare()`.
+
+
* This function takes a transaction JSON object and prepares it for emission.
* The transaction must be complete except for the Account field, which should always be the Hook account.
@@ -20,6 +31,17 @@ import { Tabs, TabItem, LinkButton } from '@astrojs/starlight/components';
### Definition
+
+```c
+int64_t prepare (
+ uint32_t write_ptr,
+ uint32_t write_len,
+ uint32_t read_ptr,
+ uint32_t read_len
+);
+```
+
+
```javascript
function prepare(
@@ -29,11 +51,31 @@ function prepare(
-
-
### Example
+
+```c
+etxn_reserve(1);
+
+// Build a minimal payment transaction (TransactionType + required fields only)
+uint8_t tx[256];
+// ... populate tx with TransactionType, Destination, Amount ...
+int64_t tx_len = /* size of tx */;
+
+// prepare() fills in Account, Sequence, Fee, EmitDetails, etc.
+uint8_t prepared[512];
+int64_t prepared_len = prepare(prepared, sizeof(prepared), tx, tx_len);
+if (prepared_len < 0)
+ rollback("Prepare failed", 14, prepared_len);
+
+// emit() submits the fully-formed transaction
+uint8_t txid[32];
+if (emit(txid, 32, prepared, prepared_len) != 32)
+ rollback("Emit failed", 11, EMISSION_FAILURE);
+```
+
+
```javascript
const prepared_txn = prepare({
@@ -45,27 +87,39 @@ const prepared_txn = prepare({
-
-
### Parameters
-
+
+| Name | Type | Description |
+| ---------- | --------- | -------------------------------------------------------------------------------------------------------------------------------- |
+| `write_ptr` | uint32_t | Pointer to a buffer to receive the complete prepared transaction blob. |
+| `write_len` | uint32_t | Length of the write buffer. Must be large enough to hold the prepared transaction (input size + injected fields). |
+| `read_ptr` | uint32_t | Pointer to a partial serialized transaction. Must include `TransactionType` and all type-specific required fields. |
+| `read_len` | uint32_t | Length of the input transaction. |
+
+
+
+
Name
Type
Description
txJson
Record<string, any> | Transaction
The transaction JSON, must be a complete transaction except for Account (always the Hook account).
-
-
### Return Code
-
+
+| Type | Description |
+| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| int64_t | On success, the number of bytes written to `write_ptr` (the size of the prepared transaction blob). The result can be passed directly as `read_ptr`/`read_len` to `emit()`.
If negative, an error: `OUT_OF_BOUNDS` — pointers/lengths fall outside hook memory. `PREREQUISITE_NOT_MET` — `etxn_reserve()` must be called before `prepare()`. `INVALID_ARGUMENT` — the input blob is not a valid serialized transaction, or the transaction cannot be prepared (e.g. fee computation failed). `INTERNAL_ERROR` — failed to generate `EmitDetails` or re-serialize the transaction. |
+
+
+
+
Type
Description
ErrorCode | Record<string, any> | Transaction
Returns an ErrorCode if there is an error, or the prepared transaction JSON or Transaction object.
-
diff --git a/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx b/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx
index 3e738b8..305482e 100644
--- a/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx
+++ b/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx
@@ -89,7 +89,7 @@ Besides errors that can occur for all transactions, ClaimReward transactions can
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `temDISABLED` | Occurs if the required amendment (`BalanceRewards` or `IOURewardClaim`) is not enabled. |
| `temINVALID_FLAG` | Occurs if the flag is set to a value other than 1. _(Requires the \[fixRewardClaimFlags amendment]\[].)_ |
-| `temMALFORMED` | Occurs if `ClaimCurrency` is an MPT or XRP type, if the issuer equals `Account`, or if the transaction fields are otherwise incorrectly set. |
+| `temMALFORMED` | Occurs if `ClaimCurrency` is an non-currency or XAH type, if the issuer equals `Account`, or if the transaction fields are otherwise incorrectly set. |
| `temBAD_ISSUER` | Occurs if `ClaimCurrency` is set but the issuer is the genesis account, or if `Issuer` is the genesis account but `ClaimCurrency` is also set. |
| `terNO_ACCOUNT` | Occurs if the sending account does not exist. |
| `tecNO_ISSUER` | Occurs if the `Issuer` account does not exist. |
From 60f86576fb3e6bf329a850f96e85e39e3d2a15d0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Tue, 23 Jun 2026 09:45:09 +0200
Subject: [PATCH 04/23] PriceOracle
---
src/content/docs/docs/features/amendments.mdx | 4 +
.../get-aggregate-price.mdx | 103 +++++++++++++++++
.../public-api-methods.mdx | 8 ++
.../ledger-objects-types/oracle.mdx | 90 +++++++++++++++
.../transaction-types/oracledelete.mdx | 39 +++++++
.../transaction-types/oracleset.mdx | 107 ++++++++++++++++++
6 files changed, 351 insertions(+)
create mode 100644 src/content/docs/docs/features/http-websocket-apis/get-aggregate-price.mdx
create mode 100644 src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/oracle.mdx
create mode 100644 src/content/docs/docs/protocol-reference/transactions/transaction-types/oracledelete.mdx
create mode 100644 src/content/docs/docs/protocol-reference/transactions/transaction-types/oracleset.mdx
diff --git a/src/content/docs/docs/features/amendments.mdx b/src/content/docs/docs/features/amendments.mdx
index b2faaea..46c9c03 100644
--- a/src/content/docs/docs/features/amendments.mdx
+++ b/src/content/docs/docs/features/amendments.mdx
@@ -183,6 +183,10 @@ Fixes a bug that currently allows invalid flags to be provided to some transacti
Hooks may continue to specify `HookOn` with the existing behaviour, or optionally replace it with two separate fields: `HookOnIncoming` and `HookOnOutgoing`. Both use the same bitmask syntax as `HookOn` but differentiate between transactions originating from the Hook account (`HookOnOutgoing`) and transactions originating from another account (`HookOnIncoming`). Additionally, `HookCanEmit` may be specified to control which transaction types the Hook is allowed to emit, using the same syntax as `HookOn`. _(Introduced in 2026.6.21-release+3350)_
+##### PriceOracle
+
+A port of the XRPL PriceOracle (XLS-47d) standard. Enables on-chain price feeds by allowing accounts to publish asset price data as [Oracle ledger objects](/docs/protocol-reference/ledger-data/ledger-objects-types/oracle). Introduces two new transactions: [OracleSet](/docs/protocol-reference/transactions/transaction-types/oracleset) (create or update an Oracle) and [OracleDelete](/docs/protocol-reference/transactions/transaction-types/oracledelete) (remove an Oracle). Also adds the `get_aggregate_price` RPC method for querying aggregated prices across multiple oracles. Each Oracle object stores 1–10 asset/quote price pairs (1–5 pairs consume 1 owner reserve; 6–10 consume 2). Prices are stored as scaled integers (`AssetPrice × 10^(-Scale)`). _(Introduced in 2026.6.21-release+3350)_
+
##### IOURewardClaim
Expands the [ClaimReward](/docs/protocol-reference/transactions/transaction-types/claimreward) transaction type beyond genesis balance adjustments to issuers of other IOU currencies. The same reward logic (area under the curve of hold time vs. hold amount) is optionally applied to issuer currencies using the `ClaimCurrency` field. Reward counters are held within the trustline (`LowReward`/`HighReward` objects on the [RippleState](/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state) object) and do not affect genesis balance adjustments. The actual reward payout is handled by a Hook installed on the issuer account that fires on `ttCLAIM_REWARD`. _(Introduced in 2026.6.21-release+3350)_
diff --git a/src/content/docs/docs/features/http-websocket-apis/get-aggregate-price.mdx b/src/content/docs/docs/features/http-websocket-apis/get-aggregate-price.mdx
new file mode 100644
index 0000000..acbe380
--- /dev/null
+++ b/src/content/docs/docs/features/http-websocket-apis/get-aggregate-price.mdx
@@ -0,0 +1,103 @@
+---
+title: get_aggregate_price
+description: >-
+ Retrieves aggregated price statistics across multiple Price Oracle objects
+ for a given asset pair.
+---
+_(Added by the [PriceOracle amendment](/docs/features/amendments/#priceoracle).)_
+
+The `get_aggregate_price` method queries the price data stored in one or more [Oracle ledger objects](/docs/protocol-reference/ledger-data/ledger-objects-types/oracle) for a specified asset pair and returns aggregated statistics (mean, median, standard deviation). Optionally, outliers can be trimmed and a time window filter applied.
+
+### Request Format
+
+```json
+{
+ "command": "get_aggregate_price",
+ "ledger_index": "current",
+ "base_asset": "XAH",
+ "quote_asset": "USD",
+ "trim": 20,
+ "time_threshold": 300,
+ "oracles": [
+ {
+ "account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
+ "oracle_document_id": 1
+ },
+ {
+ "account": "rN7n3473SaZBCG4dFL83w7PB8LTfHBEDP",
+ "oracle_document_id": 2
+ }
+ ]
+}
+```
+
+### Request Parameters
+
+| Field | JSON Type | Required? | Description |
+| ---------------- | --------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `base_asset` | String | Yes | The currency code of the asset being priced (e.g. `"XAH"`, `"BTC"`). |
+| `quote_asset` | String | Yes | The currency code of the denomination (e.g. `"USD"`, `"EUR"`). |
+| `oracles` | Array | Yes | Array of up to **200** oracle references. Each entry must contain `account` (String, AccountID) and `oracle_document_id` (Number, UInt32). |
+| `trim` | Number | No | Percentage (1–50) of outliers to remove from both ends of the price distribution before computing `trimmed_set` statistics. |
+| `time_threshold` | Number | No | Maximum age in seconds for a price to be included. Prices with `LastUpdateTime < (latestTime - time_threshold)` are excluded. If omitted, all prices are included. |
+| `ledger_index` | String or Number | No | The ledger to query. Defaults to `"current"`. |
+
+### Response Format
+
+```json
+{
+ "result": {
+ "entire_set": {
+ "mean": "7.456",
+ "size": 5,
+ "standard_deviation": "0.12"
+ },
+ "trimmed_set": {
+ "mean": "7.45",
+ "size": 3,
+ "standard_deviation": "0.08"
+ },
+ "median": "7.46",
+ "time": 816348900,
+ "status": "success"
+ }
+}
+```
+
+### Response Fields
+
+| Field | JSON Type | Description |
+| ------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------ |
+| `entire_set.mean` | String | Mean price across all collected data points (as a decimal string). |
+| `entire_set.size` | Number | Number of price data points used to compute the statistics. |
+| `entire_set.standard_deviation` | String | Standard deviation of prices in the full set. |
+| `trimmed_set.mean` | String | Mean price after removing the top and bottom `trim%` outliers. Only present if `trim` was specified. |
+| `trimmed_set.size` | Number | Number of data points remaining after trimming. Only present if `trim` was specified. |
+| `trimmed_set.standard_deviation`| String | Standard deviation after trimming. Only present if `trim` was specified. |
+| `median` | String | Median price across the full set. |
+| `time` | Number | The most recent `LastUpdateTime` (Ripple Epoch) found across all queried Oracle objects. |
+
+### Algorithm
+
+1. Iterates through up to **200** oracle accounts and retrieves their `Oracle` ledger entries.
+2. For each Oracle, searches up to **3** historical transaction metadata entries to find a price for the requested `base_asset`/`quote_asset` pair.
+3. Applies the `time_threshold` filter: keeps only prices where `LastUpdateTime ≥ (latestTime - time_threshold)`.
+4. Computes mean, standard deviation, and median over the filtered set.
+5. If `trim` > 0: removes the top and bottom `trim%` by price value and recomputes statistics for `trimmed_set`.
+
+### Error Cases
+
+| Error Code | Description |
+| --------------------- | ---------------------------------------------------------------------------------------------- |
+| `rpcORACLE_MALFORMED` | An entry in `oracles` is missing or has an invalid `account` or `oracle_document_id`. |
+| `rpcINVALID_PARAMS` | Invalid parameter type, empty asset string, or `trim` outside the 1–50 range. |
+| `rpcOBJECT_NOT_FOUND` | No matching price data found for the requested asset pair across all queried Oracle objects. |
+| `rpcINTERNAL` | All data points were excluded by the `time_threshold` filter, leaving an empty result set. |
+
+### Limits
+
+| Parameter | Limit |
+| ------------- | -------------------------- |
+| `oracles` | Max 200 entries per request |
+| History depth | Max 3 historical metadata entries searched per oracle |
+| `trim` | 1–50 (%) |
diff --git a/src/content/docs/docs/features/http-websocket-apis/public-api-methods.mdx b/src/content/docs/docs/features/http-websocket-apis/public-api-methods.mdx
index 8c2e416..1c4dc0e 100644
--- a/src/content/docs/docs/features/http-websocket-apis/public-api-methods.mdx
+++ b/src/content/docs/docs/features/http-websocket-apis/public-api-methods.mdx
@@ -78,6 +78,14 @@ Interact directly with an xahaud server using public API methods. These methods
| server_state | Get server status in machine-readable format. |
| manifest | Retrieve public key details for a validator. |
+### Oracle Methods
+
+_(Requires the [PriceOracle amendment](/docs/features/amendments/#priceoracle).)_
+
+| Method | Description |
+| ----------------------- | ------------------------------------------------------------------------------------ |
+| [get_aggregate_price](/docs/features/http-websocket-apis/get-aggregate-price) | Retrieve aggregated price statistics across multiple Oracle objects for an asset pair. |
+
### Utility Methods
diff --git a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/oracle.mdx b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/oracle.mdx
new file mode 100644
index 0000000..e38437e
--- /dev/null
+++ b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/oracle.mdx
@@ -0,0 +1,90 @@
+---
+title: Oracle
+---
+\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/xrpld/app/tx/detail/SetOracle.cpp)]
+
+_(Added by the [PriceOracle amendment](/docs/features/amendments/#priceoracle).)_
+
+An `Oracle` ledger object represents a Price Oracle created by an account on the Xahau ledger. It stores one or more asset price data points and is identified by the owner account together with a document ID. Oracle objects are created and updated via [OracleSet transactions](/docs/protocol-reference/transactions/transaction-types/oracleset) and deleted via [OracleDelete transactions](/docs/protocol-reference/transactions/transaction-types/oracledelete).
+
+### Example JSON
+
+```json
+{
+ "LedgerEntryType": "Oracle",
+ "Owner": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
+ "OracleDocumentID": 1,
+ "Provider": "70726F7669646572",
+ "AssetClass": "63757272656E6379",
+ "LastUpdateTime": 816348759,
+ "PriceDataSeries": [
+ {
+ "PriceData": {
+ "BaseAsset": "XAH",
+ "QuoteAsset": "USD",
+ "AssetPrice": 74560,
+ "Scale": 4
+ }
+ },
+ {
+ "PriceData": {
+ "BaseAsset": "BTC",
+ "QuoteAsset": "USD",
+ "AssetPrice": 6800000,
+ "Scale": 2
+ }
+ }
+ ],
+ "URI": "697066733A2F2F",
+ "OwnerNode": "0000000000000000",
+ "PreviousTxnID": "5463C6E08862A1FAE5EDAC12D70ADB16546A1F674930521295BC082494B62924",
+ "PreviousTxnLgrSeq": 6,
+ "index": "49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0"
+}
+```
+
+### Fields
+
+An `Oracle` object has the following fields:
+
+| Field | JSON Type | \[Internal Type]\[] | Required? | Description |
+| ------------------- | --------- | ------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `Owner` | String | AccountID | Yes | The account that created and owns this Oracle. Only this account can update or delete it. |
+| `OracleDocumentID` | Number | UInt32 | Yes | The unique identifier for this Oracle within the owner account. |
+| `Provider` | String | Blob | Yes | Hex-encoded identifier of the data provider (e.g. the oracle service name). Max 256 bytes. |
+| `AssetClass` | String | Blob | Yes | Hex-encoded string describing the category of assets (e.g. `63757272656E6379` = "currency"). Max 16 bytes. |
+| `LastUpdateTime` | Number | UInt32 | Yes | Ripple Epoch timestamp (seconds since January 1, 2000) of the last price update. |
+| `PriceDataSeries` | Array | Array | Yes | Array of `PriceData` objects (1–10 entries). Entries are stored in canonical sorted order by `BaseAsset`/`QuoteAsset` pair. |
+| `URI` | String | Blob | No | Hex-encoded URI pointing to supplementary off-chain data (e.g. an IPFS CID). Max 256 bytes. |
+| `OwnerNode` | String | UInt64 | Yes | A hint indicating which page of the owner's directory links to this object. |
+| `PreviousTxnID` | String | Hash256 | Yes | The identifying hash of the transaction that most recently modified this object. |
+| `PreviousTxnLgrSeq` | Number | UInt32 | Yes | The ledger index of the ledger that contains the transaction that most recently modified this object. |
+| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0080`, mapped to the string `Oracle`, indicates this is an Oracle object. |
+
+### PriceData Object
+
+Each entry in `PriceDataSeries` contains a `PriceData` object:
+
+| Field | JSON Type | \[Internal Type]\[] | Required? | Description |
+| ------------ | --------- | ------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------ |
+| `BaseAsset` | String | Currency | Yes | The asset being priced (e.g. `"XAH"`, `"BTC"`). |
+| `QuoteAsset` | String | Currency | Yes | The denomination currency (e.g. `"USD"`, `"EUR"`). |
+| `AssetPrice` | Number | UInt64 | No | The price as a scaled integer. The effective price is `AssetPrice × 10^(-Scale)`. |
+| `Scale` | Number | UInt8 | No | Decimal exponent (0–10) used to derive the effective price. Example: `AssetPrice = 74560`, `Scale = 4` → effective price = 7.456. |
+
+### Reserve
+
+An Oracle object consumes owner reserves based on the number of `PriceData` pairs stored:
+
+| Pairs | Owner reserves consumed |
+| ----- | ----------------------- |
+| 1–5 | 1 |
+| 6–10 | 2 |
+
+### Oracle ID Format
+
+The ID of an `Oracle` object is the \[SHA-512Half]\[] of the following values, concatenated in order:
+
+* The Oracle space key (`0x0080`)
+* The AccountID of the `Owner`
+* The `OracleDocumentID` as a 32-bit unsigned integer
diff --git a/src/content/docs/docs/protocol-reference/transactions/transaction-types/oracledelete.mdx b/src/content/docs/docs/protocol-reference/transactions/transaction-types/oracledelete.mdx
new file mode 100644
index 0000000..9424cee
--- /dev/null
+++ b/src/content/docs/docs/protocol-reference/transactions/transaction-types/oracledelete.mdx
@@ -0,0 +1,39 @@
+---
+title: OracleDelete
+description: >-
+ An OracleDelete transaction removes an existing Price Oracle object from the
+ ledger, releasing the owner reserves held by it.
+---
+\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/xrpld/app/tx/detail/DeleteOracle.cpp)]
+
+_(Added by the [PriceOracle amendment](/docs/features/amendments/#priceoracle).)_
+
+### Example
+
+```json
+{
+ "TransactionType": "OracleDelete",
+ "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
+ "OracleDocumentID": 1
+}
+```
+
+### Fields
+
+| Field | JSON Type | \[Internal Type]\[] | Description |
+| ------------------ | --------- | ------------------- | -------------------------------------------------------------------------------------------- |
+| `Account` | String | AccountID | The address of the account that owns the Oracle. Only the owner can delete the object. |
+| `OracleDocumentID` | Number | UInt32 | The document ID of the Oracle object to delete. |
+
+### Special Transaction Cost
+
+OracleDelete transactions have the standard transaction cost.
+
+### Error Cases
+
+| Error Code | Description |
+| --------------- | -------------------------------------------------------------------- |
+| `temDISABLED` | The PriceOracle amendment is not enabled. |
+| `temINVALID_FLAG` | Invalid flags specified. |
+| `terNO_ACCOUNT` | The sending account does not exist. |
+| `tecNO_ENTRY` | No Oracle object exists for the given account and `OracleDocumentID`. |
diff --git a/src/content/docs/docs/protocol-reference/transactions/transaction-types/oracleset.mdx b/src/content/docs/docs/protocol-reference/transactions/transaction-types/oracleset.mdx
new file mode 100644
index 0000000..6fdbb5c
--- /dev/null
+++ b/src/content/docs/docs/protocol-reference/transactions/transaction-types/oracleset.mdx
@@ -0,0 +1,107 @@
+---
+title: OracleSet
+description: >-
+ An OracleSet transaction creates or updates a Price Oracle object on the
+ ledger, publishing one or more asset price data points for a given account.
+---
+\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/xrpld/app/tx/detail/SetOracle.cpp)]
+
+_(Added by the [PriceOracle amendment](/docs/features/amendments/#priceoracle).)_
+
+### Create
+
+```json
+{
+ "TransactionType": "OracleSet",
+ "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
+ "OracleDocumentID": 1,
+ "Provider": "70726F7669646572",
+ "AssetClass": "63757272656E6379",
+ "LastUpdateTime": 816348759,
+ "PriceDataSeries": [
+ {
+ "PriceData": {
+ "BaseAsset": "XAH",
+ "QuoteAsset": "USD",
+ "AssetPrice": 74560,
+ "Scale": 4
+ }
+ }
+ ]
+}
+```
+
+### Update
+
+```json
+{
+ "TransactionType": "OracleSet",
+ "Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
+ "OracleDocumentID": 1,
+ "LastUpdateTime": 816348900,
+ "PriceDataSeries": [
+ {
+ "PriceData": {
+ "BaseAsset": "XAH",
+ "QuoteAsset": "USD",
+ "AssetPrice": 74800,
+ "Scale": 4
+ }
+ }
+ ]
+}
+```
+
+### Fields
+
+| Field | JSON Type | \[Internal Type]\[] | Description |
+| ------------------ | --------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `Account` | String | AccountID | The address of the account creating or updating the Oracle. Only this account can later update or delete the object. |
+| `OracleDocumentID` | Number | UInt32 | A unique identifier for this Oracle within the owner account. Multiple Oracles can exist per account using different IDs. |
+| `Provider` | String | Blob | _(Optional on update; required on create)_ Hex-encoded identifier of the Oracle provider (e.g. Chainlink, Band). Max 256 bytes. |
+| `URI` | String | Blob | _(Optional)_ Hex-encoded URI referencing supplementary off-chain data for this Oracle (e.g. IPFS CID). Max 256 bytes. |
+| `AssetClass` | String | Blob | _(Optional on update; required on create)_ Hex-encoded category describing the type of assets (e.g. `63757272656E6379` = "currency"). Max 16 bytes. |
+| `LastUpdateTime` | Number | UInt32 | Ripple Epoch timestamp (seconds since January 1, 2000) of the last price update. Must be within ±300 seconds of the ledger close time and must be strictly greater than the current stored value on updates. |
+| `PriceDataSeries` | Array | Array | Array of `PriceData` objects. Must contain between 1 and 10 entries. On update, pairs without `AssetPrice` are deleted from the object. |
+
+### PriceData Object
+
+Each entry in `PriceDataSeries` is a `PriceData` object:
+
+| Field | JSON Type | \[Internal Type]\[] | Description |
+| ------------ | --------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `BaseAsset` | String | Currency | The asset being priced (e.g. `"XAH"`, `"BTC"`). |
+| `QuoteAsset` | String | Currency | The denomination currency (e.g. `"USD"`, `"EUR"`). Must differ from `BaseAsset`. |
+| `AssetPrice` | Number | UInt64 | _(Optional)_ The price as a scaled integer. The effective price is `AssetPrice × 10^(-Scale)`. Omit this field to **delete** an existing pair during an update. |
+| `Scale` | Number | UInt8 | _(Optional)_ Decimal exponent used to derive the effective price. Valid values: 0–10. Default: 0. Example: `AssetPrice = 74560`, `Scale = 4` → effective price = 7.456. |
+
+### Reserve
+
+OracleSet transactions consume owner reserves depending on the number of `PriceData` pairs stored:
+
+| Pairs | Owner reserves consumed |
+| ----- | ----------------------- |
+| 1–5 | 1 |
+| 6–10 | 2 |
+
+If an update changes the number of pairs across the 5-pair threshold, the owner count is adjusted automatically (±1).
+
+### Special Transaction Cost
+
+OracleSet transactions have the standard transaction cost.
+
+### Error Cases
+
+| Error Code | Description |
+| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `temDISABLED` | The PriceOracle amendment is not enabled. |
+| `temINVALID_FLAG` | Invalid flags specified. |
+| `temMALFORMED` | `Provider`, `URI`, or `AssetClass` is empty or exceeds max length; duplicate base/quote pairs in the same transaction; `BaseAsset` equals `QuoteAsset`; `Scale` > 10; `Provider` or `AssetClass` do not match stored values on update; `Provider` or `AssetClass` missing on create. |
+| `temARRAY_EMPTY` | `PriceDataSeries` is empty. |
+| `temARRAY_TOO_LARGE` | `PriceDataSeries` contains more than 10 entries in the transaction. |
+| `terNO_ACCOUNT` | The sending account does not exist. |
+| `tecINVALID_UPDATE_TIME` | `LastUpdateTime` is outside the ±300 second window from ledger close time, predates the XRP Ledger epoch (Jan 1 2000), or is not strictly greater than the stored value on an update. |
+| `tecTOKEN_PAIR_NOT_FOUND` | A pair specified for deletion (no `AssetPrice`) does not exist in the current Oracle object. |
+| `tecARRAY_EMPTY` | The result after applying all updates and deletions would leave `PriceDataSeries` empty. |
+| `tecARRAY_TOO_LARGE` | The result after applying all updates and additions would exceed 10 entries. |
+| `tecINSUFFICIENT_RESERVE` | The account does not have enough XAH to meet the reserve requirement for creating the Oracle object. |
From 7069cae93368d65fd2792d58ef209909fa80e21b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Tue, 23 Jun 2026 11:09:36 +0200
Subject: [PATCH 05/23] feature NamedHooks
---
src/content/docs/docs/features/amendments.mdx | 4 +
.../docs/docs/hooks/concepts/named-hooks.mdx | 105 ++++++++++++++++++
.../ledger-data/ledger-objects-types/hook.mdx | 3 +-
.../transaction-types/sethook.mdx | 1 +
4 files changed, 112 insertions(+), 1 deletion(-)
create mode 100644 src/content/docs/docs/hooks/concepts/named-hooks.mdx
diff --git a/src/content/docs/docs/features/amendments.mdx b/src/content/docs/docs/features/amendments.mdx
index 46c9c03..02d7856 100644
--- a/src/content/docs/docs/features/amendments.mdx
+++ b/src/content/docs/docs/features/amendments.mdx
@@ -81,6 +81,10 @@ Core amendment enabling Hook smart contract functionality on Xahau. _(Added by t
Updates and improvements to the Hooks system.
+##### NamedHooks
+
+Adds an optional `HookName` field (4–16 bytes, UTF-8) to the Hook slot in a [SetHook transaction](/docs/protocol-reference/transactions/transaction-types/sethook). When a hook installation carries a `HookName`, that hook will **only execute** if the incoming transaction also includes a matching top-level `HookName` field. Transactions without `HookName`, or with a different value, silently skip the named hook. `HookName` is also added as an optional common field on all transaction types so that submitters can target specific named hooks. This enables multiple hooks to coexist on an account with different entry points activated by different callers. _(Introduced in 2026.6.21-release+3350)_
+
##### HooksUpdate2
Adds the `prepare()` Hook API function. `prepare(write_ptr, write_len, read_ptr, read_len)` accepts a partial serialized transaction containing only transaction-type-specific fields and automatically injects all fields required for emission: `Account`, `Sequence`, `SigningPubKey`, `Fee`, `FirstLedgerSequence`, `LastLedgerSequence`, and `EmitDetails`. The output can be passed directly to `emit()`, eliminating the need to manually construct these boilerplate fields in hook code. _(Introduced in 2026.6.21-release+3350)_
diff --git a/src/content/docs/docs/hooks/concepts/named-hooks.mdx b/src/content/docs/docs/hooks/concepts/named-hooks.mdx
new file mode 100644
index 0000000..4889b93
--- /dev/null
+++ b/src/content/docs/docs/hooks/concepts/named-hooks.mdx
@@ -0,0 +1,105 @@
+---
+title: Named Hooks
+description: Selectively activate specific hooks on an account using a name-based execution gate.
+---
+
+_(Added by the [NamedHooks amendment](/docs/features/amendments/#namedhooks).)_
+
+### Overview
+
+By default, every installed hook on an account executes on every transaction type it has been configured for via `HookOn`. Named Hooks allow an installed hook to declare an **execution gate**: the hook only runs if the triggering transaction carries a matching `HookName` value.
+
+This enables multiple hooks to coexist on the same account, each serving a different use case, with callers selecting which hook to activate by including the appropriate `HookName` in their transaction.
+
+### How It Works
+
+**1. Name the hook at installation time**
+
+Set the `HookName` field inside the `Hook` slot of a [SetHook transaction](/docs/protocol-reference/transactions/transaction-types/sethook):
+
+```json
+{
+ "TransactionType": "SetHook",
+ "Account": "rHookOwner...",
+ "Hooks": [
+ {
+ "Hook": {
+ "HookHash": "A5663784D04ED1B4408C6B97193464D27C9C3334AAF8BBB4FA5EB8E557FC4A2C",
+ "HookOn": "0000000000000000",
+ "HookNamespace": "...",
+ "HookName": "6D795F68616E646C6572"
+ }
+ }
+ ]
+}
+```
+
+`HookName` is a hex-encoded UTF-8 string (e.g. `6D795F68616E646C6572` = `"my_handler"`). It is stored per-installation on the account's [Hook ledger object](/docs/protocol-reference/ledger-data/ledger-objects-types/hook) and is not shared with the [HookDefinition](/docs/protocol-reference/ledger-data/ledger-objects-types/hook-definition).
+
+**2. Activate the hook by name in a transaction**
+
+Any transaction type can include the top-level `HookName` field to target the named hook:
+
+```json
+{
+ "TransactionType": "Payment",
+ "Account": "rSender...",
+ "Destination": "rHookOwner...",
+ "Amount": "1000000",
+ "HookName": "6D795F68616E646C6572"
+}
+```
+
+When the ledger processes this transaction and reaches the hook chain on `rHookOwner`:
+
+- Hooks **without** a `HookName` set → execute normally (unchanged behaviour).
+- Hooks **with** a `HookName` that matches the transaction's `HookName` → execute.
+- Hooks **with** a `HookName` that does **not** match → silently skipped (no error).
+
+Transactions that carry **no** `HookName` field will skip all named hooks on the account.
+
+### HookName Constraints
+
+| Constraint | Value |
+| ---------- | ----- |
+| Minimum length | 4 bytes (8 hex chars in JSON) |
+| Maximum length | 16 bytes (32 hex chars in JSON) |
+| Encoding | Valid UTF-8 |
+| Remove name | Set to empty blob (`""`) in an update operation |
+
+### Removing a Name
+
+To remove a previously assigned name from a hook slot, submit an Update Operation with `HookName` set to an empty blob:
+
+```json
+{
+ "TransactionType": "SetHook",
+ "Account": "rHookOwner...",
+ "Hooks": [
+ {
+ "Hook": {
+ "HookName": ""
+ }
+ }
+ ]
+}
+```
+
+After removal, the hook reverts to unconditional execution (governed only by its `HookOn` / `HookOnIncoming` / `HookOnOutgoing` settings).
+
+### Fee Calculation
+
+Hook fee calculation respects the same gating logic: named hooks that would be skipped by a transaction (name mismatch or absent) are **not** counted when computing the hook execution fee for that transaction.
+
+### Error Cases
+
+| Error Code | Condition |
+| -------------- | --------- |
+| `temDISABLED` | `HookName` is present in a Hook slot but the `NamedHooks` amendment is not enabled. |
+| `temMALFORMED` | `HookName` present as a top-level transaction field but `featureHooks` or `featureNamedHooks` is not active; or the value fails UTF-8 / length validation. |
+
+### Use Cases
+
+- **Multi-purpose accounts**: install several specialised hooks (e.g. payment processor, governance handler, escrow manager), each gated by a different name.
+- **Selective invocation**: external contracts or users can selectively trigger only the hook relevant to their interaction without affecting others.
+- **Gradual migration**: deploy a new hook version under a different name and migrate callers incrementally without removing the old hook.
diff --git a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook.mdx b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook.mdx
index 717fdab..8b5b899 100644
--- a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook.mdx
+++ b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook.mdx
@@ -36,7 +36,7 @@ A `Hook` object has the following fields:
| `OwnerNode` | String | UInt64 | Yes | A hint indicating which page of the owner's directory links to this object, in case the directory consists of multiple pages. |
| `PreviousTxnID` | String | Hash256 | Yes | The ID of the transaction that most recently modified this object. |
| `PreviousTxnLgrSeq` | Number | UInt32 | Yes | The \[ledger index]\[] of the ledger that contains the transaction that most recently modified this object. |
-| `Hooks` | Array | Array | Yes | An array of hook objects. Each object has the following fields: `HookHash`, `CreateCode`, `HookGrants`, `HookNamespace`, `HookParameters`, `HookOn`, `HookOnIncoming`, `HookOnOutgoing`, `HookCanEmit`, `HookApiVersion`, `Flags`. |
+| `Hooks` | Array | Array | Yes | An array of hook objects. Each object has the following fields: `HookHash`, `CreateCode`, `HookGrants`, `HookNamespace`, `HookParameters`, `HookOn`, `HookOnIncoming`, `HookOnOutgoing`, `HookCanEmit`, `HookName`, `HookApiVersion`, `Flags`. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0043`, mapped to the string `Hook`, indicates that this object is a Hook object. |
### Hook Fields
@@ -51,6 +51,7 @@ The following fields are used in the hook object:
| `HookOnIncoming` | String | Hash256 | _(HookOnV2)_ Same syntax as `HookOn`. Triggers the hook on transactions originating from another account. Mutually exclusive with `HookOn`. |
| `HookOnOutgoing` | String | Hash256 | _(HookOnV2)_ Same syntax as `HookOn`. Triggers the hook on transactions originating from the Hook account itself. Mutually exclusive with `HookOn`. |
| `HookCanEmit` | String | Hash256 | Same syntax as `HookOn`. Controls which transaction types the hook is allowed to emit. If absent, the hook may emit any transaction type. |
+| `HookName` | String | Blob | _(NamedHooks)_ UTF-8 string (4–16 bytes, hex-encoded) assigned to this hook slot. When present, the hook only executes if the triggering transaction carries a matching top-level `HookName` field. |
| `Flags` | Number | UInt32 | Additional flags for the hook. |
#### Hook ID Format
diff --git a/src/content/docs/docs/protocol-reference/transactions/transaction-types/sethook.mdx b/src/content/docs/docs/protocol-reference/transactions/transaction-types/sethook.mdx
index 1e61f80..91368b9 100644
--- a/src/content/docs/docs/protocol-reference/transactions/transaction-types/sethook.mdx
+++ b/src/content/docs/docs/protocol-reference/transactions/transaction-types/sethook.mdx
@@ -317,6 +317,7 @@ The following fields are used in the hook object:
| `HookOnIncoming` | String | Hash256 | _(Optional, HookOnV2)_ Same syntax as `HookOn`. Triggers the hook on transactions originating from **another account**. Mutually exclusive with `HookOn`. |
| `HookOnOutgoing` | String | Hash256 | _(Optional, HookOnV2)_ Same syntax as `HookOn`. Triggers the hook on transactions originating from **the Hook account itself**. Mutually exclusive with `HookOn`. |
| `HookCanEmit` | String | Hash256 | _(Optional)_ Same syntax as `HookOn`. Controls which transaction types the hook is allowed to emit. If absent, the hook may emit any transaction type. |
+| `HookName` | String | Blob | _(Optional, NamedHooks)_ A UTF-8 string (4–16 bytes, hex-encoded) assigned to this hook installation. When set, the hook only executes if the incoming transaction carries a matching top-level `HookName` field. Set to an empty blob to remove a previously assigned name. |
| `HookApiVersion` | Number | UInt16 | The API version of the hook. |
| `Flags` | Number | UInt32 | Additional flags for the hook. |
From 6eb3f34e3c786fb256011cab1604ac73c92d09b9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Tue, 23 Jun 2026 11:36:41 +0200
Subject: [PATCH 06/23] Feature: HookAPISerializedType240
---
src/content/docs/docs/features/amendments.mdx | 4 +++
.../hooks/concepts/serialized-objects.mdx | 30 +++++++++++++++++++
2 files changed, 34 insertions(+)
diff --git a/src/content/docs/docs/features/amendments.mdx b/src/content/docs/docs/features/amendments.mdx
index 02d7856..48e86ce 100644
--- a/src/content/docs/docs/features/amendments.mdx
+++ b/src/content/docs/docs/features/amendments.mdx
@@ -81,6 +81,10 @@ Core amendment enabling Hook smart contract functionality on Xahau. _(Added by t
Updates and improvements to the Hooks system.
+##### HookAPISerializedType240
+
+Fixes incorrect parsing of `STPathSet` fields (used by `sfPaths` in Payment transactions) within all `sto_` Hook API functions ([sto_subfield](/docs/hooks/functions/serialization/sto_subfield), [sto_subarray](/docs/hooks/functions/serialization/sto_subarray), [sto_emplace](/docs/hooks/functions/serialization/sto_emplace), [sto_erase](/docs/hooks/functions/serialization/sto_erase), [sto_validate](/docs/hooks/functions/serialization/sto_validate)). Before this amendment, PathSet fields were incorrectly treated as VL-encoded data, causing the internal parser (`get_stobject_length`) to misread the field boundary and corrupt the parsing of all subsequent fields in the object. PathSet fields are self-delimiting (using `0xFF` path-separator bytes and a `0x00` end-of-set byte) and are now parsed correctly. Also raises the maximum supported serialized type from `STI_VECTOR256` (19) to `STI_CURRENCY` (26), adding correct support for `STI_ISSUE` (24), `STI_XCHAIN_BRIDGE` (25), and `STI_CURRENCY` (26) within all `sto_` functions. _(Introduced in 2026.6.21-release+3350)_
+
##### NamedHooks
Adds an optional `HookName` field (4–16 bytes, UTF-8) to the Hook slot in a [SetHook transaction](/docs/protocol-reference/transactions/transaction-types/sethook). When a hook installation carries a `HookName`, that hook will **only execute** if the incoming transaction also includes a matching top-level `HookName` field. Transactions without `HookName`, or with a different value, silently skip the named hook. `HookName` is also added as an optional common field on all transaction types so that submitters can target specific named hooks. This enables multiple hooks to coexist on an account with different entry points activated by different callers. _(Introduced in 2026.6.21-release+3350)_
diff --git a/src/content/docs/docs/hooks/concepts/serialized-objects.mdx b/src/content/docs/docs/hooks/concepts/serialized-objects.mdx
index 9c3df60..4d4b51d 100644
--- a/src/content/docs/docs/hooks/concepts/serialized-objects.mdx
+++ b/src/content/docs/docs/hooks/concepts/serialized-objects.mdx
@@ -2,6 +2,8 @@
title: Serialized Objects
description: Manipulate raw serialized xahaud objects!
---
+import { Aside } from '@astrojs/starlight/components';
+
### What are Serialized Objects?
Xahau has canonical [serialized](/docs/protocol-reference/binary-format) forms of all objects subject to consensus. When writing a Hook it is inevitable you will come across serialized objects. These manifest as buffers containing what might appear to the developer as opaque binary blobs. In fact you can read these with the [XRPL-Binary-Visualiser](https://richardah.github.io/xrpl-binary-visualizer/).
@@ -44,6 +46,34 @@ for (int i = 0; GUARD(3), i < 3; ++i)
}
```
+### PathSet Support and Supported Serialized Types
+
+
+
+With the [HookAPISerializedType240 amendment](/docs/features/amendments/#hookapiSerializedType240), the following serialized types are correctly handled by all `sto_` functions:
+
+| STI Type | Code | Examples |
+|---|---|---|
+| `STI_UINT16` | 1 | `sfTransactionType` |
+| `STI_UINT32` | 2 | `sfFlags`, `sfSequence` |
+| `STI_UINT64` | 3 | `sfOfferSequence` |
+| `STI_HASH128` | 4 | `sfEmailHash` |
+| `STI_HASH256` | 5 | `sfLedgerHash`, `sfTransactionHash` |
+| `STI_AMOUNT` | 6 | `sfAmount`, `sfFee` |
+| `STI_VL` | 7 | `sfPublicKey`, `sfMemos`, blobs |
+| `STI_ACCOUNT` | 8 | `sfAccount`, `sfDestination` |
+| `STI_OBJECT` | 14 | `sfTransaction`, inner objects |
+| `STI_ARRAY` | 15 | `sfHooks`, `sfSigners` |
+| `STI_UINT8` | 16 | `sfCloseResolution` |
+| `STI_UINT160` | 17 | `sfTakerPaysCurrency` |
+| `STI_PATHSET` | 18 | `sfPaths` _(fixed by HookAPISerializedType240)_ |
+| `STI_VECTOR256` | 19 | `sfHookNamespaces` |
+| `STI_ISSUE` | 24 | _(added by HookAPISerializedType240)_ |
+| `STI_XCHAIN_BRIDGE` | 25 | _(added by HookAPISerializedType240)_ |
+| `STI_CURRENCY` | 26 | _(added by HookAPISerializedType240)_ |
+
### Overlap with slots
You may notice some overlap between slot APIs and STO APIs. The key difference here is who _owns_ the underlying data:
From b8bb6969a75fcee382280300d53b18fb709ecd20 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Tue, 23 Jun 2026 14:35:26 +0200
Subject: [PATCH 07/23] HookOnv2Review
---
src/content/docs/docs/features/amendments.mdx | 2 +-
src/content/docs/docs/hooks/concepts/hookon-field.mdx | 6 ++++--
.../ledger-data/ledger-objects-types/hook-definition.mdx | 2 --
.../transactions/transaction-types/sethook.mdx | 2 +-
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/content/docs/docs/features/amendments.mdx b/src/content/docs/docs/features/amendments.mdx
index 48e86ce..dc027c0 100644
--- a/src/content/docs/docs/features/amendments.mdx
+++ b/src/content/docs/docs/features/amendments.mdx
@@ -189,7 +189,7 @@ Fixes a bug that currently allows invalid flags to be provided to some transacti
##### HookOnV2
-Hooks may continue to specify `HookOn` with the existing behaviour, or optionally replace it with two separate fields: `HookOnIncoming` and `HookOnOutgoing`. Both use the same bitmask syntax as `HookOn` but differentiate between transactions originating from the Hook account (`HookOnOutgoing`) and transactions originating from another account (`HookOnIncoming`). Additionally, `HookCanEmit` may be specified to control which transaction types the Hook is allowed to emit, using the same syntax as `HookOn`. _(Introduced in 2026.6.21-release+3350)_
+Hooks may continue to specify `HookOn` with the existing behaviour, or optionally replace it with two separate fields: `HookOnIncoming` and `HookOnOutgoing`. Both use the same bitmask syntax as `HookOn` but differentiate between transactions originating from the Hook account (`HookOnOutgoing`) and transactions originating from another account (`HookOnIncoming`). _(Introduced in 2026.6.21-release+3350)_
##### PriceOracle
diff --git a/src/content/docs/docs/hooks/concepts/hookon-field.mdx b/src/content/docs/docs/hooks/concepts/hookon-field.mdx
index e988114..ac8ff11 100644
--- a/src/content/docs/docs/hooks/concepts/hookon-field.mdx
+++ b/src/content/docs/docs/hooks/concepts/hookon-field.mdx
@@ -52,7 +52,7 @@ _(Added by the [HookCanEmit amendment](/docs/features/amendments/#hookcanemit).)
- Uses the same active-low semantics as `HookOn`, with bit 22 (`ttHOOK_SET`) being active high.
- If `HookCanEmit` is absent, the Hook may emit any transaction type, including `SetHook`.
-### HookOnV2: Incoming and Outgoing
+### HookOnIncoming and HookOnOutgoing Fields
_(Added by the [HookOnV2 amendment](/docs/features/amendments/#hookonv2).)_
@@ -61,6 +61,8 @@ Instead of specifying a single `HookOn` field, Hooks may optionally replace it w
- **`HookOnIncoming`** — triggers the Hook on transactions **originating from another account** (the Hook account is not the initiator).
- **`HookOnOutgoing`** — triggers the Hook on transactions **originating from the Hook account itself**.
-Both fields use the same bit-field syntax as `HookOn`. `HookOnIncoming` and `HookOnOutgoing` are mutually exclusive with `HookOn` — you must use either `HookOn` alone or the `HookOnIncoming`/`HookOnOutgoing` pair, not both. If only one of the pair is specified, the Hook will not fire on the unspecified direction.
+Both fields use the same bit-field syntax as `HookOn`. `HookOnIncoming` and `HookOnOutgoing` are mutually exclusive with `HookOn` — you must use either `HookOn` alone or the `HookOnIncoming`/`HookOnOutgoing` pair, not both. If only one of the pair is specified, the Hook will not fire on the unspecified direction.
+
+_Note: The `HookOnIncoming` and `HookOnOutgoing` cannot be configured with exactly the same settings. If you need a Hook to respond to both directions using identical criteria, use the `HookOn` field instead, as it provides a simpler and more appropriate way to define shared trigger behavior._
Using `HookOn` alone continues to work exactly as before.
diff --git a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook-definition.mdx b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook-definition.mdx
index b27b23e..47a5ab6 100644
--- a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook-definition.mdx
+++ b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook-definition.mdx
@@ -13,8 +13,6 @@ A `HookDefinition` object describes a hook, which is a piece of code that is exe
{
"HookHash": "49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0",
"HookOn": "0000000000000000000000000000000000000000000000000000000000000000",
- "HookOnIncoming": "0000000000000000000000000000000000000000000000000000000000000000",
- "HookOnOutgoing": "0000000000000000000000000000000000000000000000000000000000000000",
"HookCanEmit": "0000000000000000000000000000000000000000000000000000000000000000",
"HookNamespace": "0000000000000000000000000000000000000000000000000000000000000000",
"HookParameters": {
diff --git a/src/content/docs/docs/protocol-reference/transactions/transaction-types/sethook.mdx b/src/content/docs/docs/protocol-reference/transactions/transaction-types/sethook.mdx
index 91368b9..2ba7fc6 100644
--- a/src/content/docs/docs/protocol-reference/transactions/transaction-types/sethook.mdx
+++ b/src/content/docs/docs/protocol-reference/transactions/transaction-types/sethook.mdx
@@ -313,7 +313,7 @@ The following fields are used in the hook object:
| `HookGrants` | Array | Array | The grants associated with the hook. |
| `HookNamespace` | String | Hash256 | The namespace of the hook. |
| `HookParameters` | Array | Array | The parameters of the hook. |
-| `HookOn` | String | Hash256 | The transaction/s on which the hook is triggered. Mutually exclusive with `HookOnIncoming`/`HookOnOutgoing`. |
+| `HookOn` | String | Hash256 | _(Optional, HookOnV2)_ The transaction/s on which the hook is triggered. Mutually exclusive with `HookOnIncoming`/`HookOnOutgoing`. |
| `HookOnIncoming` | String | Hash256 | _(Optional, HookOnV2)_ Same syntax as `HookOn`. Triggers the hook on transactions originating from **another account**. Mutually exclusive with `HookOn`. |
| `HookOnOutgoing` | String | Hash256 | _(Optional, HookOnV2)_ Same syntax as `HookOn`. Triggers the hook on transactions originating from **the Hook account itself**. Mutually exclusive with `HookOn`. |
| `HookCanEmit` | String | Hash256 | _(Optional)_ Same syntax as `HookOn`. Controls which transaction types the hook is allowed to emit. If absent, the hook may emit any transaction type. |
From c87deb89a506af25b76cac120744167cc0f1b1dd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Tue, 23 Jun 2026 14:37:21 +0200
Subject: [PATCH 08/23] Update sethook.mdx
---
.../transactions/transaction-types/sethook.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/content/docs/docs/protocol-reference/transactions/transaction-types/sethook.mdx b/src/content/docs/docs/protocol-reference/transactions/transaction-types/sethook.mdx
index 2ba7fc6..71e50b7 100644
--- a/src/content/docs/docs/protocol-reference/transactions/transaction-types/sethook.mdx
+++ b/src/content/docs/docs/protocol-reference/transactions/transaction-types/sethook.mdx
@@ -102,7 +102,7 @@ _All_ of the following conditions are met:
**Behaviour**:
-* A reference counted `HookDefinition` object is created on the XRPL containing the fields in the HookSet Object, with all specified fields (Namespace, Parameters, HookOn) becoming defaults (but not Grants.)
+* A reference counted `HookDefinition` object is created on the Xahau containing the fields in the HookSet Object, with all specified fields (Namespace, Parameters, HookOn) becoming defaults (but not Grants.)
* A `Hooks` array is created on the executing account, if it doesn't already exist. (This is the structure that contains the Corresponding Hooks.)
* A `Hook` object is created at the Corresponding Hook position if one does not already exist.
* The `Hook` object points at the `HookDefinition`.
From 4eea0bf01c815955b5917fc6026ddf393d7e1619 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Tue, 23 Jun 2026 16:32:35 +0200
Subject: [PATCH 09/23] Emit/Prepare update
---
src/content/docs/docs/features/amendments.mdx | 2 +-
.../network-features/balance-rewards.mdx | 1 -
.../functions/emitted-transaction/emit-1.mdx | 114 ----------------
.../functions/emitted-transaction/emit.mdx | 83 +++++-------
.../functions/emitted-transaction/prepare.mdx | 125 ++++++++++++++++++
5 files changed, 162 insertions(+), 163 deletions(-)
delete mode 100644 src/content/docs/docs/hooks/functions/emitted-transaction/emit-1.mdx
create mode 100644 src/content/docs/docs/hooks/functions/emitted-transaction/prepare.mdx
diff --git a/src/content/docs/docs/features/amendments.mdx b/src/content/docs/docs/features/amendments.mdx
index dc027c0..b6e9f96 100644
--- a/src/content/docs/docs/features/amendments.mdx
+++ b/src/content/docs/docs/features/amendments.mdx
@@ -197,7 +197,7 @@ A port of the XRPL PriceOracle (XLS-47d) standard. Enables on-chain price feeds
##### IOURewardClaim
-Expands the [ClaimReward](/docs/protocol-reference/transactions/transaction-types/claimreward) transaction type beyond genesis balance adjustments to issuers of other IOU currencies. The same reward logic (area under the curve of hold time vs. hold amount) is optionally applied to issuer currencies using the `ClaimCurrency` field. Reward counters are held within the trustline (`LowReward`/`HighReward` objects on the [RippleState](/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state) object) and do not affect genesis balance adjustments. The actual reward payout is handled by a Hook installed on the issuer account that fires on `ttCLAIM_REWARD`. _(Introduced in 2026.6.21-release+3350)_
+Expands the [ClaimReward](/docs/protocol-reference/transactions/transaction-types/claimreward) transaction type beyond genesis balance adjustments to issuers of other IOU currencies. Reward counters are held within the trustline (`LowReward`/`HighReward` objects on the [RippleState](/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state) object) and do not affect genesis balance adjustments. The transaction triggers any Hook installed on the account specified by the `Issuer` field, allowing that Hook to process and optionally pay out the reward. The reward-paying account does not need to be the issuer of the IOU currency. _(Introduced in 2026.6.21-release+3350)_
##### fixCronStacking
diff --git a/src/content/docs/docs/features/network-features/balance-rewards.mdx b/src/content/docs/docs/features/network-features/balance-rewards.mdx
index e6e56f0..16fe578 100644
--- a/src/content/docs/docs/features/network-features/balance-rewards.mdx
+++ b/src/content/docs/docs/features/network-features/balance-rewards.mdx
@@ -39,5 +39,4 @@ The `IOURewardClaim` amendment extends the reward mechanic to IOU currencies iss
| Counters stored on | AccountRoot | RippleState (trustline) |
| Accumulator type | UInt64 (drops / 1,000,000) | Amount (in the token's units) |
| Payout handled by | Genesis account Hook | Issuer account Hook |
-| Opt-out flag | `tfOptOut` (flag 1) | Not applicable |
| Issuer restriction | Must be genesis account | Any account with a Hook on `ttCLAIM_REWARD`, except AMM accounts |
diff --git a/src/content/docs/docs/hooks/functions/emitted-transaction/emit-1.mdx b/src/content/docs/docs/hooks/functions/emitted-transaction/emit-1.mdx
deleted file mode 100644
index 721dfda..0000000
--- a/src/content/docs/docs/hooks/functions/emitted-transaction/emit-1.mdx
+++ /dev/null
@@ -1,114 +0,0 @@
----
-title: emit
-description: Emit a new transaction from the hook
----
-import { Tabs, TabItem, LinkButton } from '@astrojs/starlight/components';
-
-### Concepts
-
-Emitted Transactions
-prepare()
-
-### Behaviour
-
-
-
-* Read a transaction from `read_ptr`
-* Validate the transaction against the emission rules
-* Emit the transaction into consensus when valid
-* Write canonical transaction hash to `write_ptr`
-
-With the [HooksUpdate2 amendment](/docs/features/amendments/#hooksupdate2), use [`prepare()`](/docs/hooks/functions/emitted-transaction/emit) before `emit()` to automatically inject all required emission fields (`Account`, `Sequence`, `SigningPubKey`, `Fee`, `EmitDetails`, etc.) from a partial transaction.
-
-
-
-* This function emits the provided transaction JSON.
-* On success, it returns the number of emitted transaction hashes.
-* If there is an error, it returns an error code.
-
-
-
-### Definition
-
-
-
-```c
-int64_t emit (
- uint32_t write_ptr,
- uint32_t write_len,
- uint32_t read_ptr,
- uint32_t read_len
-);
-```
-
-
-
-
-
-```javascript
-function emit(
- txJson: Record | Transaction
- ): ErrorCode | ByteArray
-```
-
-
-
-
-
-### Example
-
-
-
-```c
-if (emit(tx, tx_len) < 0)
- rollback("Failed to emit!", 15, 1);
-```
-
-
-
-
-
-```javascript
-const emitResult = emit(txJson)
-if(typeof emitResult === 'number')
- rollback("Failed to emit!", 1)
-```
-
-
-
-
-
-### Parameters
-
-
-
-
Name
Type
Description
write_ptr
uint32_t
Pointer to a buffer to write the transaction hash to
write_len
uint32_t
The size of the buffer to write the transaction hash to (should be 32.)
read_ptr
uint32_t
Pointer to the transaction to emit
read_len
uint32_t
The length of the transaction
-
-
-
-
-
-
-
-
Name
Type
Description
txJson
Record<string, any> | Transaction
The TX JSON to emit.
-
-
-
-
-
-### Return Code
-
-
-
-
Type
Description
int64_t
On success, the number of bytes of transaction hash written (32), or:
If negative, an error: OUT_OF_BOUNDS - pointers/lengths specified outside of hook memory.
PREREQUISITE_NOT_MET - emit_reserve must be called first
TOO_MANY_EMITTED_TXN - the number of emitted transactions is now greater than the promise made when emit_reserve was called earlier
EMISSION_FAILURE - the transaction was malformed according to the emission rules.
-
-
-
-
-
-
-
-
Type
Description
ErrorCode | ByteArray
Returns an ErrorCode if there is an error, or an array of emitted transaction hashes on success.
-
-
-
diff --git a/src/content/docs/docs/hooks/functions/emitted-transaction/emit.mdx b/src/content/docs/docs/hooks/functions/emitted-transaction/emit.mdx
index a5db7b4..721dfda 100644
--- a/src/content/docs/docs/hooks/functions/emitted-transaction/emit.mdx
+++ b/src/content/docs/docs/hooks/functions/emitted-transaction/emit.mdx
@@ -1,30 +1,30 @@
---
-title: prepare
-description: Prepares a transaction for emission by automatically injecting all required emission fields.
+title: emit
+description: Emit a new transaction from the hook
---
import { Tabs, TabItem, LinkButton } from '@astrojs/starlight/components';
### Concepts
Emitted Transactions
+prepare()
### Behaviour
+* Read a transaction from `read_ptr`
+* Validate the transaction against the emission rules
+* Emit the transaction into consensus when valid
+* Write canonical transaction hash to `write_ptr`
-_(Requires the [HooksUpdate2 amendment](/docs/features/amendments/#hooksupdate2).)_
-
-* Reads a partial serialized transaction from `read_ptr`/`read_len`. The input must contain at minimum the `TransactionType` and all fields required by that transaction type, but **must not** include emission-specific fields.
-* Automatically injects all fields required for emission: `Account` (the Hook account), `Sequence` (0), `SigningPubKey` (all zeros), `Fee` (computed), `FirstLedgerSequence` (current ledger + 1), `LastLedgerSequence` (current ledger + 5), and `EmitDetails`.
-* Writes the complete, emission-ready transaction blob to `write_ptr`.
-* The output can be passed directly to [`emit()`](/docs/hooks/functions/emitted-transaction/emit-1).
-* `etxn_reserve()` must be called before `prepare()`.
+With the [HooksUpdate2 amendment](/docs/features/amendments/#hooksupdate2), use [`prepare()`](/docs/hooks/functions/emitted-transaction/emit) before `emit()` to automatically inject all required emission fields (`Account`, `Sequence`, `SigningPubKey`, `Fee`, `EmitDetails`, etc.) from a partial transaction.
-* This function takes a transaction JSON object and prepares it for emission.
-* The transaction must be complete except for the Account field, which should always be the Hook account.
+* This function emits the provided transaction JSON.
+* On success, it returns the number of emitted transaction hashes.
+* If there is an error, it returns an error code.
@@ -33,93 +33,82 @@ _(Requires the [HooksUpdate2 amendment](/docs/features/amendments/#hooksupdate2)
```c
-int64_t prepare (
+int64_t emit (
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len
);
```
+
+
```javascript
-function prepare(
+function emit(
txJson: Record | Transaction
- ): ErrorCode | Record | Transaction
+ ): ErrorCode | ByteArray
```
+
+
### Example
```c
-etxn_reserve(1);
-
-// Build a minimal payment transaction (TransactionType + required fields only)
-uint8_t tx[256];
-// ... populate tx with TransactionType, Destination, Amount ...
-int64_t tx_len = /* size of tx */;
-
-// prepare() fills in Account, Sequence, Fee, EmitDetails, etc.
-uint8_t prepared[512];
-int64_t prepared_len = prepare(prepared, sizeof(prepared), tx, tx_len);
-if (prepared_len < 0)
- rollback("Prepare failed", 14, prepared_len);
-
-// emit() submits the fully-formed transaction
-uint8_t txid[32];
-if (emit(txid, 32, prepared, prepared_len) != 32)
- rollback("Emit failed", 11, EMISSION_FAILURE);
+if (emit(tx, tx_len) < 0)
+ rollback("Failed to emit!", 15, 1);
```
+
+
```javascript
-const prepared_txn = prepare({
- TransactionType: "Payment",
- Destination: util_raddr(p1address_ns),
- Amount: parseFloat(drops_sent)*2
- })
+const emitResult = emit(txJson)
+if(typeof emitResult === 'number')
+ rollback("Failed to emit!", 1)
```
+
+
### Parameters
+
Name
Type
Description
write_ptr
uint32_t
Pointer to a buffer to write the transaction hash to
write_len
uint32_t
The size of the buffer to write the transaction hash to (should be 32.)
read_ptr
uint32_t
Pointer to the transaction to emit
read_len
uint32_t
The length of the transaction
-| Name | Type | Description |
-| ---------- | --------- | -------------------------------------------------------------------------------------------------------------------------------- |
-| `write_ptr` | uint32_t | Pointer to a buffer to receive the complete prepared transaction blob. |
-| `write_len` | uint32_t | Length of the write buffer. Must be large enough to hold the prepared transaction (input size + injected fields). |
-| `read_ptr` | uint32_t | Pointer to a partial serialized transaction. Must include `TransactionType` and all type-specific required fields. |
-| `read_len` | uint32_t | Length of the input transaction. |
-
Name
Type
Description
txJson
Record<string, any> | Transaction
The transaction JSON, must be a complete transaction except for Account (always the Hook account).
+
+
Name
Type
Description
txJson
Record<string, any> | Transaction
The TX JSON to emit.
+
+
### Return Code
+
Type
Description
int64_t
On success, the number of bytes of transaction hash written (32), or:
If negative, an error: OUT_OF_BOUNDS - pointers/lengths specified outside of hook memory.
PREREQUISITE_NOT_MET - emit_reserve must be called first
TOO_MANY_EMITTED_TXN - the number of emitted transactions is now greater than the promise made when emit_reserve was called earlier
EMISSION_FAILURE - the transaction was malformed according to the emission rules.
-| Type | Description |
-| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| int64_t | On success, the number of bytes written to `write_ptr` (the size of the prepared transaction blob). The result can be passed directly as `read_ptr`/`read_len` to `emit()`.
If negative, an error: `OUT_OF_BOUNDS` — pointers/lengths fall outside hook memory. `PREREQUISITE_NOT_MET` — `etxn_reserve()` must be called before `prepare()`. `INVALID_ARGUMENT` — the input blob is not a valid serialized transaction, or the transaction cannot be prepared (e.g. fee computation failed). `INTERNAL_ERROR` — failed to generate `EmitDetails` or re-serialize the transaction. |
-
Type
Description
ErrorCode | Record<string, any> | Transaction
Returns an ErrorCode if there is an error, or the prepared transaction JSON or Transaction object.
+
+
Type
Description
ErrorCode | ByteArray
Returns an ErrorCode if there is an error, or an array of emitted transaction hashes on success.
+
diff --git a/src/content/docs/docs/hooks/functions/emitted-transaction/prepare.mdx b/src/content/docs/docs/hooks/functions/emitted-transaction/prepare.mdx
new file mode 100644
index 0000000..4387d2c
--- /dev/null
+++ b/src/content/docs/docs/hooks/functions/emitted-transaction/prepare.mdx
@@ -0,0 +1,125 @@
+---
+title: prepare
+description: Prepares a transaction for emission by automatically injecting all required emission fields.
+---
+import { Tabs, TabItem, LinkButton } from '@astrojs/starlight/components';
+
+### Concepts
+
+Emitted Transactions
+
+### Behaviour
+
+
+
+
+_(Requires the [HooksUpdate2 amendment](/docs/features/amendments/#hooksupdate2).)_
+
+* Reads a partial serialized transaction from `read_ptr`/`read_len`. The input must contain at minimum the `TransactionType` and all fields required by that transaction type, but included emission-specific fields will be **overwritten**.
+* Automatically injects all fields required for emission: `Account` (the Hook account), `Sequence` (0), `SigningPubKey` (all zeros), `Fee` (computed), `FirstLedgerSequence` (current ledger + 1), `LastLedgerSequence` (current ledger + 5), and `EmitDetails`.
+* Writes the complete, emission-ready transaction blob to `write_ptr`.
+* The output can be passed directly to [`emit()`](/docs/hooks/functions/emitted-transaction/emit-1).
+* `etxn_reserve()` must be called before `prepare()`.
+
+
+
+* This function takes a transaction JSON object and prepares it for emission.
+* The transaction must be complete except for the Account field, which should always be the Hook account.
+
+
+
+### Definition
+
+
+
+```c
+int64_t prepare (
+ uint32_t write_ptr,
+ uint32_t write_len,
+ uint32_t read_ptr,
+ uint32_t read_len
+);
+```
+
+
+
+```javascript
+function prepare(
+ txJson: Record | Transaction
+ ): ErrorCode | Record | Transaction
+```
+
+
+
+### Example
+
+
+
+```c
+etxn_reserve(1);
+
+// Build a minimal payment transaction (TransactionType + required fields only)
+uint8_t tx[256];
+// ... populate tx with TransactionType, Destination, Amount ...
+int64_t tx_len = /* size of tx */;
+
+// prepare() fills in Account, Sequence, Fee, EmitDetails, etc.
+uint8_t prepared[512];
+int64_t prepared_len = prepare(prepared, sizeof(prepared), tx, tx_len);
+if (prepared_len < 0)
+ rollback("Prepare failed", 14, prepared_len);
+
+// emit() submits the fully-formed transaction
+uint8_t txid[32];
+if (emit(txid, 32, prepared, prepared_len) != 32)
+ rollback("Emit failed", 11, EMISSION_FAILURE);
+```
+
+
+
+```javascript
+const prepared_txn = prepare({
+ TransactionType: "Payment",
+ Destination: util_raddr(p1address_ns),
+ Amount: parseFloat(drops_sent)*2
+ })
+```
+
+
+
+### Parameters
+
+
+
+
+| Name | Type | Description |
+| ---------- | --------- | -------------------------------------------------------------------------------------------------------------------------------- |
+| `write_ptr` | uint32_t | Pointer to a buffer to receive the complete prepared transaction blob. |
+| `write_len` | uint32_t | Length of the write buffer. Must be large enough to hold the prepared transaction (input size + injected fields). |
+| `read_ptr` | uint32_t | Pointer to a partial serialized transaction. Must include `TransactionType` and all type-specific required fields. |
+| `read_len` | uint32_t | Length of the input transaction. |
+
+
+
+
+
+
Name
Type
Description
txJson
Record<string, any> | Transaction
The transaction JSON, must be a complete transaction except for Account (always the Hook account).
+
+
+
+### Return Code
+
+
+
+
+| Type | Description |
+| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| int64_t | On success, the number of bytes written to `write_ptr` (the size of the prepared transaction blob). The result can be passed directly as `read_ptr`/`read_len` to `emit()`.
If negative, an error: `OUT_OF_BOUNDS` — pointers/lengths fall outside hook memory. `PREREQUISITE_NOT_MET` — `etxn_reserve()` must be called before `prepare()`. `INVALID_ARGUMENT` — the input blob is not a valid serialized transaction, or the transaction cannot be prepared (e.g. fee computation failed). `INTERNAL_ERROR` — failed to generate `EmitDetails` or re-serialize the transaction. |
+
+
+
+
+
+
Type
Description
ErrorCode | Record<string, any> | Transaction
Returns an ErrorCode if there is an error, or the prepared transaction JSON or Transaction object.
+
+
From 32ac37bf1ec37b6745e5a0ecd7845ab7ebc05fba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Tue, 23 Jun 2026 19:25:54 +0200
Subject: [PATCH 10/23] Fixes
---
src/content/docs/docs/features/amendments.mdx | 2 +-
.../transactions/transaction-types/claimreward.mdx | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/content/docs/docs/features/amendments.mdx b/src/content/docs/docs/features/amendments.mdx
index b6e9f96..dba5819 100644
--- a/src/content/docs/docs/features/amendments.mdx
+++ b/src/content/docs/docs/features/amendments.mdx
@@ -197,7 +197,7 @@ A port of the XRPL PriceOracle (XLS-47d) standard. Enables on-chain price feeds
##### IOURewardClaim
-Expands the [ClaimReward](/docs/protocol-reference/transactions/transaction-types/claimreward) transaction type beyond genesis balance adjustments to issuers of other IOU currencies. Reward counters are held within the trustline (`LowReward`/`HighReward` objects on the [RippleState](/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state) object) and do not affect genesis balance adjustments. The transaction triggers any Hook installed on the account specified by the `Issuer` field, allowing that Hook to process and optionally pay out the reward. The reward-paying account does not need to be the issuer of the IOU currency. _(Introduced in 2026.6.21-release+3350)_
+Expands the [ClaimReward](/docs/protocol-reference/transactions/transaction-types/claimreward) transaction type beyond genesis balance adjustments to other IOU currencies. Reward counters are held within the trustline (`LowReward`/`HighReward` objects on the [RippleState](/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state) object) and do not affect genesis balance adjustments. The transaction triggers any Hook installed on the account specified by the `Issuer` field, allowing that Hook to process and optionally pay out the reward. The reward-paying account does not need to be the issuer of the IOU currency. _(Introduced in 2026.6.21-release+3350)_
##### fixCronStacking
diff --git a/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx b/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx
index 305482e..fd3b2ad 100644
--- a/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx
+++ b/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx
@@ -52,8 +52,8 @@ _(Requires the \[IOURewardClaim amendment]\[].)_
| Field | JSON Type | \[Internal Type]\[] | Description |
| --------------- | --------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Account` | String | AccountID | The address of the account that is claiming the reward. |
-| `Flags` | Number | UInt32 | _(Optional)_ Can have flag 1 set to opt-out of XAH genesis rewards. |
-| `Issuer` | String | AccountID | _(Optional)_ The genesis account (XAH rewards) or the IOU issuer account (IOU rewards). |
+| `Flags` | Number | UInt32 | _(Optional)_ Can have flag 1 set to opt-out rewards. |
+| `Issuer` | String | AccountID | _(Optional)_ The genesis account (XAH rewards) or an IOU account (IOU rewards). |
| `ClaimCurrency` | Object | Issue | _(Optional, IOURewardClaim)_ The IOU currency to claim rewards for, as `{"currency": "...", "issuer": "..."}`. Cannot be XAH. The issuer must not be the genesis account and must not equal `Account`. Requires a trustline to exist between `Account` and the issuer. |
### ClaimReward Flags
From 6991c1da176cb4f48c92e20c18425bc58014453d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Tue, 23 Jun 2026 20:35:48 +0200
Subject: [PATCH 11/23] reference links fixed
---
.../docs/docs/hooks/concepts/emitted-transactions.mdx | 6 +++---
src/content/docs/docs/hooks/concepts/serialized-objects.mdx | 4 ++--
.../docs/docs/hooks/functions/emitted-transaction/emit.mdx | 2 +-
.../docs/hooks/functions/emitted-transaction/prepare.mdx | 2 +-
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/content/docs/docs/hooks/concepts/emitted-transactions.mdx b/src/content/docs/docs/hooks/concepts/emitted-transactions.mdx
index 67a3776..138ba0d 100644
--- a/src/content/docs/docs/hooks/concepts/emitted-transactions.mdx
+++ b/src/content/docs/docs/hooks/concepts/emitted-transactions.mdx
@@ -18,13 +18,13 @@ The solution: **Emitted Transactions**. We allow the Originating Transaction to
Emitted Transactions are _new_ transactions created by the execution of a Hook and entered into consensus for processing in the next ledger. The transaction may be of any Transaction Type but must follow strict emission rules.
-To emit a transaction the Hook first prepares the serialized transaction then calls [emit](/docs/hooks/functions/emitted-transaction/emit-1). With the [HooksUpdate2 amendment](/docs/features/amendments/#hooksupdate2), the [prepare()](/docs/hooks/functions/emitted-transaction/emit) API can build the complete emission-ready transaction automatically from a partial input, removing the need to manually set `Account`, `Sequence`, `SigningPubKey`, `Fee`, `FirstLedgerSequence`, `LastLedgerSequence`, and `EmitDetails`.
+To emit a transaction the Hook first prepares the serialized transaction then calls [emit](/docs/hooks/functions/emitted-transaction/emit). With the [HooksUpdate2 amendment](/docs/features/amendments/#hooksupdate2), the [prepare()](/docs/hooks/functions/emitted-transaction/prepare) API can build the complete emission-ready transaction automatically from a partial input, removing the need to manually set `Account`, `Sequence`, `SigningPubKey`, `Fee`, `FirstLedgerSequence`, `LastLedgerSequence`, and `EmitDetails`.
Because emitted transactions can trigger Hooks in the next ledger which in turn may emit more transactions, all emitted transactions carry a `burden` and a `generation` field in their `EmitDetails` block. The `EmitDetails` block replaces the signature field in a traditional transaction.
The `burden` and `generation` fields collectively prevent [Fork bomb](https://en.wikipedia.org/wiki/Fork_bomb) attacks on the ledger by exponentially increasing the cost of exponentially expanding emtited transactions.
-It is important to note that the Hooks API follows the strict rule of _no rewriting_. You _must_ present an emitted transaction in full, valid and canonically formed to xahaud for emission or it will be rejected. With the [HooksUpdate2 amendment](/docs/features/amendments/#hooksupdate2), the [`prepare()`](/docs/hooks/functions/emitted-transaction/emit) API automates this: the Hook provides only the transaction-type-specific fields and the runtime injects all required emission boilerplate. Without HooksUpdate2, the Hook must construct the complete transaction itself.
+It is important to note that the Hooks API follows the strict rule of _no rewriting_. You _must_ present an emitted transaction in full, valid and canonically formed to xahaud for emission or it will be rejected. With the [HooksUpdate2 amendment](/docs/features/amendments/#hooksupdate2), the [`prepare()`](/docs/hooks/functions/emitted-transaction/prepare) API automates this: the Hook provides only the transaction-type-specific fields and the runtime injects all required emission boilerplate. Without HooksUpdate2, the Hook must construct the complete transaction itself.
### Callbacks
@@ -34,7 +34,7 @@ If an emitted transaction expires before it can be accepted into a ledger (for a
### Emission Rules
-The [emit](/docs/hooks/functions/emitted-transaction/emit-1) Hook API will enforce the following rules on a proposed (to be emitted) transaction.
+The [emit](/docs/hooks/functions/emitted-transaction/emit) Hook API will enforce the following rules on a proposed (to be emitted) transaction.
| # | Emission Rule | Explanation |
| - | ------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
diff --git a/src/content/docs/docs/hooks/concepts/serialized-objects.mdx b/src/content/docs/docs/hooks/concepts/serialized-objects.mdx
index 4d4b51d..f68630b 100644
--- a/src/content/docs/docs/hooks/concepts/serialized-objects.mdx
+++ b/src/content/docs/docs/hooks/concepts/serialized-objects.mdx
@@ -49,10 +49,10 @@ for (int i = 0; GUARD(3), i < 3; ++i)
### PathSet Support and Supported Serialized Types
-With the [HookAPISerializedType240 amendment](/docs/features/amendments/#hookapiSerializedType240), the following serialized types are correctly handled by all `sto_` functions:
+With the [HookAPISerializedType240 amendment](/docs/features/amendments/#hookapiserializedtype240), the following serialized types are correctly handled by all `sto_` functions:
| STI Type | Code | Examples |
|---|---|---|
diff --git a/src/content/docs/docs/hooks/functions/emitted-transaction/emit.mdx b/src/content/docs/docs/hooks/functions/emitted-transaction/emit.mdx
index 721dfda..1b2db7b 100644
--- a/src/content/docs/docs/hooks/functions/emitted-transaction/emit.mdx
+++ b/src/content/docs/docs/hooks/functions/emitted-transaction/emit.mdx
@@ -7,7 +7,7 @@ import { Tabs, TabItem, LinkButton } from '@astrojs/starlight/components';
### Concepts
Emitted Transactions
-prepare()
+prepare()
### Behaviour
diff --git a/src/content/docs/docs/hooks/functions/emitted-transaction/prepare.mdx b/src/content/docs/docs/hooks/functions/emitted-transaction/prepare.mdx
index 4387d2c..0484785 100644
--- a/src/content/docs/docs/hooks/functions/emitted-transaction/prepare.mdx
+++ b/src/content/docs/docs/hooks/functions/emitted-transaction/prepare.mdx
@@ -18,7 +18,7 @@ _(Requires the [HooksUpdate2 amendment](/docs/features/amendments/#hooksupdate2)
* Reads a partial serialized transaction from `read_ptr`/`read_len`. The input must contain at minimum the `TransactionType` and all fields required by that transaction type, but included emission-specific fields will be **overwritten**.
* Automatically injects all fields required for emission: `Account` (the Hook account), `Sequence` (0), `SigningPubKey` (all zeros), `Fee` (computed), `FirstLedgerSequence` (current ledger + 1), `LastLedgerSequence` (current ledger + 5), and `EmitDetails`.
* Writes the complete, emission-ready transaction blob to `write_ptr`.
-* The output can be passed directly to [`emit()`](/docs/hooks/functions/emitted-transaction/emit-1).
+* The output can be passed directly to [`emit()`](/docs/hooks/functions/emitted-transaction/emit).
* `etxn_reserve()` must be called before `prepare()`.
From 43717bb83a41e139ede88611f324d04739ec6bf4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Wed, 24 Jun 2026 06:37:37 +0200
Subject: [PATCH 12/23] Apply suggestion from @tequdev
Co-authored-by: tequ
---
.../transactions/transaction-types/claimreward.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx b/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx
index fd3b2ad..4ea8b4a 100644
--- a/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx
+++ b/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx
@@ -94,5 +94,5 @@ Besides errors that can occur for all transactions, ClaimReward transactions can
| `terNO_ACCOUNT` | Occurs if the sending account does not exist. |
| `tecNO_ISSUER` | Occurs if the `Issuer` account does not exist. |
| `tecNO_PERMISSION` | Occurs if the issuer account is an AMM account. AMM accounts cannot have reward Hooks. |
-| `tecNO_TARGET` | Occurs if the issuer account has no Hooks, or none of its Hooks fires on `ttCLAIM_REWARD`. |
+| `tecNO_TARGET` | Occurs if the issuer account has no Hooks, or none of its Hooks fires on `ClaimReward` transaction. |
| `tecNO_LINE` | Occurs if no trustline exists between `Account` and the issuer for the specified `ClaimCurrency`. |
From b57ceb6e8c3fe69ca204ec6788b88955ea1c5f1a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Wed, 24 Jun 2026 06:44:04 +0200
Subject: [PATCH 13/23] claimreward.mdx
---
.../transactions/transaction-types/claimreward.mdx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx b/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx
index 4ea8b4a..34685dc 100644
--- a/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx
+++ b/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx
@@ -62,7 +62,7 @@ Transactions of the ClaimReward type support additional values in the `Flags` fi
| Flag Name | Hex Value | Decimal Value | Description |
| ---------- | ------------ | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `tfOptOut` | `0x00000001` | 1 | Opts the account out of XAH genesis rewards by removing reward-related fields from the account's ledger object. Not applicable when `ClaimCurrency` is specified. |
+| `tfOptOut` | `0x00000001` | 1 | Opts the account out of rewards by removing reward-related fields from the account's ledger object. |
### Special Transaction Cost
@@ -74,7 +74,7 @@ _(Requires the \[IOURewardClaim amendment]\[].)_
When `ClaimCurrency` is specified, the transaction follows the IOU reward path:
-1. The `Issuer` account must have a Hook installed that fires on `ttCLAIM_REWARD`. The Hook is responsible for calculating and distributing the reward payout.
+1. The `Issuer` account must have a Hook installed that fires on `ClaimReward` transaction. The Hook is responsible for calculating and distributing the reward payout.
2. On first claim, a `LowReward` or `HighReward` reward-tracking object is initialised on the trustline ([RippleState](/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state) ledger object) between `Account` and the issuer. Which side is used depends on the canonical high/low ordering of the two accounts.
3. After every subsequent transaction that changes the trustline balance, the ledger automatically updates `TrustLineRewardAccumulator` inside the tracking object using the same area-under-the-curve formula as genesis XAH rewards.
4. When a `ClaimReward` with `ClaimCurrency` is submitted, the ledger resets the reward counters on the trustline and fires the issuer's Hook, which reads the accumulated value and emits a reward payment.
From 1db0ec8d958a3604818e62a129d32537f904f730 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Wed, 24 Jun 2026 06:46:55 +0200
Subject: [PATCH 14/23] Update balance-rewards.mdx
---
.../docs/docs/features/network-features/balance-rewards.mdx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/content/docs/docs/features/network-features/balance-rewards.mdx b/src/content/docs/docs/features/network-features/balance-rewards.mdx
index 16fe578..caaa1cf 100644
--- a/src/content/docs/docs/features/network-features/balance-rewards.mdx
+++ b/src/content/docs/docs/features/network-features/balance-rewards.mdx
@@ -29,7 +29,7 @@ The `IOURewardClaim` amendment extends the reward mechanic to IOU currencies iss
1. **Opt-in**: A token holder submits a `ClaimReward` transaction with the `ClaimCurrency` field specifying the IOU. This initialises reward-tracking counters (`LowReward` or `HighReward`) directly on the trustline ([RippleState](/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state) ledger object).
2. **Accumulation**: After every transaction that modifies the trustline balance, the ledger automatically updates the `TrustLineRewardAccumulator` field. This tracks the cumulative product of balance × ledgers elapsed since the last reset.
-3. **Claim**: When the holder submits another `ClaimReward` with `ClaimCurrency`, the ledger resets the counters and fires the issuer's Hook (which must be installed and must fire on `ttCLAIM_REWARD`). The Hook reads the accumulated value and emits a reward payment in whatever form the issuer chooses.
+3. **Claim**: When the holder submits another `ClaimReward` with `ClaimCurrency`, the ledger resets the counters and fires the issuer's Hook (which must be installed and must fire on `ClaimReward` transaction). The Hook reads the accumulated value and emits a reward payment in whatever form the issuer chooses.
#### Key differences from XAH genesis rewards
@@ -39,4 +39,4 @@ The `IOURewardClaim` amendment extends the reward mechanic to IOU currencies iss
| Counters stored on | AccountRoot | RippleState (trustline) |
| Accumulator type | UInt64 (drops / 1,000,000) | Amount (in the token's units) |
| Payout handled by | Genesis account Hook | Issuer account Hook |
-| Issuer restriction | Must be genesis account | Any account with a Hook on `ttCLAIM_REWARD`, except AMM accounts |
+| Issuer restriction | Must be genesis account | Any account with a Hook on `ClaimReward` transaction, except AMM accounts |
From d5e2d9445f9960c959021afde2c420815f1e62a6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Wed, 24 Jun 2026 07:19:11 +0200
Subject: [PATCH 15/23] trim valid range fix
---
.../docs/features/http-websocket-apis/get-aggregate-price.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/content/docs/docs/features/http-websocket-apis/get-aggregate-price.mdx b/src/content/docs/docs/features/http-websocket-apis/get-aggregate-price.mdx
index acbe380..6159dfa 100644
--- a/src/content/docs/docs/features/http-websocket-apis/get-aggregate-price.mdx
+++ b/src/content/docs/docs/features/http-websocket-apis/get-aggregate-price.mdx
@@ -38,7 +38,7 @@ The `get_aggregate_price` method queries the price data stored in one or more [O
| `base_asset` | String | Yes | The currency code of the asset being priced (e.g. `"XAH"`, `"BTC"`). |
| `quote_asset` | String | Yes | The currency code of the denomination (e.g. `"USD"`, `"EUR"`). |
| `oracles` | Array | Yes | Array of up to **200** oracle references. Each entry must contain `account` (String, AccountID) and `oracle_document_id` (Number, UInt32). |
-| `trim` | Number | No | Percentage (1–50) of outliers to remove from both ends of the price distribution before computing `trimmed_set` statistics. |
+| `trim` | Number | No | Percentage (1–25) of outliers to remove from both ends of the price distribution before computing `trimmed_set` statistics. |
| `time_threshold` | Number | No | Maximum age in seconds for a price to be included. Prices with `LastUpdateTime < (latestTime - time_threshold)` are excluded. If omitted, all prices are included. |
| `ledger_index` | String or Number | No | The ledger to query. Defaults to `"current"`. |
From a08ab831e02fa518c341d709b24c3b35f75b048a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Wed, 24 Jun 2026 07:29:31 +0200
Subject: [PATCH 16/23] STI_ARRAY update
---
src/content/docs/docs/hooks/concepts/serialized-objects.mdx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/content/docs/docs/hooks/concepts/serialized-objects.mdx b/src/content/docs/docs/hooks/concepts/serialized-objects.mdx
index f68630b..6ea0a75 100644
--- a/src/content/docs/docs/hooks/concepts/serialized-objects.mdx
+++ b/src/content/docs/docs/hooks/concepts/serialized-objects.mdx
@@ -62,10 +62,10 @@ With the [HookAPISerializedType240 amendment](/docs/features/amendments/#hookapi
| `STI_HASH128` | 4 | `sfEmailHash` |
| `STI_HASH256` | 5 | `sfLedgerHash`, `sfTransactionHash` |
| `STI_AMOUNT` | 6 | `sfAmount`, `sfFee` |
-| `STI_VL` | 7 | `sfPublicKey`, `sfMemos`, blobs |
+| `STI_VL` | 7 | `sfPublicKey`, blobs |
| `STI_ACCOUNT` | 8 | `sfAccount`, `sfDestination` |
| `STI_OBJECT` | 14 | `sfTransaction`, inner objects |
-| `STI_ARRAY` | 15 | `sfHooks`, `sfSigners` |
+| `STI_ARRAY` | 15 | `sfHooks`, `sfMemos`, `sfSigners` |
| `STI_UINT8` | 16 | `sfCloseResolution` |
| `STI_UINT160` | 17 | `sfTakerPaysCurrency` |
| `STI_PATHSET` | 18 | `sfPaths` _(fixed by HookAPISerializedType240)_ |
From ec84b40d847a27ef46ece630da27dc4a92fcce47 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Wed, 24 Jun 2026 07:38:29 +0200
Subject: [PATCH 17/23] emit/prepare link and example fix
---
.../docs/docs/hooks/functions/emitted-transaction/emit.mdx | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/content/docs/docs/hooks/functions/emitted-transaction/emit.mdx b/src/content/docs/docs/hooks/functions/emitted-transaction/emit.mdx
index 1b2db7b..997ac23 100644
--- a/src/content/docs/docs/hooks/functions/emitted-transaction/emit.mdx
+++ b/src/content/docs/docs/hooks/functions/emitted-transaction/emit.mdx
@@ -18,7 +18,7 @@ import { Tabs, TabItem, LinkButton } from '@astrojs/starlight/components';
* Emit the transaction into consensus when valid
* Write canonical transaction hash to `write_ptr`
-With the [HooksUpdate2 amendment](/docs/features/amendments/#hooksupdate2), use [`prepare()`](/docs/hooks/functions/emitted-transaction/emit) before `emit()` to automatically inject all required emission fields (`Account`, `Sequence`, `SigningPubKey`, `Fee`, `EmitDetails`, etc.) from a partial transaction.
+With the [HooksUpdate2 amendment](/docs/features/amendments/#hooksupdate2), use [`prepare()`](/docs/hooks/functions/emitted-transaction/prepare) before `emit()` to automatically inject all required emission fields (`Account`, `Sequence`, `SigningPubKey`, `Fee`, `EmitDetails`, etc.) from a partial transaction.
@@ -60,8 +60,9 @@ function emit(
```c
-if (emit(tx, tx_len) < 0)
- rollback("Failed to emit!", 15, 1);
+uint8_t emithash[32];
+if (emit(SBUF(emithash), SBUF(tx)) < 0)
+ rollback(SBUF("hook: emit failed"), __LINE__);
```
From 84d84612f8936546b8d72e7bb45e3066ecd61584 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Wed, 24 Jun 2026 07:41:22 +0200
Subject: [PATCH 18/23] Update oracle.mdx
---
.../ledger-data/ledger-objects-types/oracle.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/oracle.mdx b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/oracle.mdx
index e38437e..ad0138b 100644
--- a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/oracle.mdx
+++ b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/oracle.mdx
@@ -85,6 +85,6 @@ An Oracle object consumes owner reserves based on the number of `PriceData` pair
The ID of an `Oracle` object is the \[SHA-512Half]\[] of the following values, concatenated in order:
-* The Oracle space key (`0x0080`)
+* The Oracle space key (`0x0152`)
* The AccountID of the `Owner`
* The `OracleDocumentID` as a 32-bit unsigned integer
From 7559cf107952563f2875d5a85d7e792ab9437475 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Wed, 24 Jun 2026 07:54:13 +0200
Subject: [PATCH 19/23] Unix epoch
---
.../transactions/transaction-types/oracleset.mdx | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/content/docs/docs/protocol-reference/transactions/transaction-types/oracleset.mdx b/src/content/docs/docs/protocol-reference/transactions/transaction-types/oracleset.mdx
index 6fdbb5c..655ff08 100644
--- a/src/content/docs/docs/protocol-reference/transactions/transaction-types/oracleset.mdx
+++ b/src/content/docs/docs/protocol-reference/transactions/transaction-types/oracleset.mdx
@@ -17,7 +17,7 @@ _(Added by the [PriceOracle amendment](/docs/features/amendments/#priceoracle).)
"OracleDocumentID": 1,
"Provider": "70726F7669646572",
"AssetClass": "63757272656E6379",
- "LastUpdateTime": 816348759,
+ "LastUpdateTime": 1763033559,
"PriceDataSeries": [
{
"PriceData": {
@@ -38,7 +38,7 @@ _(Added by the [PriceOracle amendment](/docs/features/amendments/#priceoracle).)
"TransactionType": "OracleSet",
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"OracleDocumentID": 1,
- "LastUpdateTime": 816348900,
+ "LastUpdateTime": 1763033700,
"PriceDataSeries": [
{
"PriceData": {
@@ -61,7 +61,7 @@ _(Added by the [PriceOracle amendment](/docs/features/amendments/#priceoracle).)
| `Provider` | String | Blob | _(Optional on update; required on create)_ Hex-encoded identifier of the Oracle provider (e.g. Chainlink, Band). Max 256 bytes. |
| `URI` | String | Blob | _(Optional)_ Hex-encoded URI referencing supplementary off-chain data for this Oracle (e.g. IPFS CID). Max 256 bytes. |
| `AssetClass` | String | Blob | _(Optional on update; required on create)_ Hex-encoded category describing the type of assets (e.g. `63757272656E6379` = "currency"). Max 16 bytes. |
-| `LastUpdateTime` | Number | UInt32 | Ripple Epoch timestamp (seconds since January 1, 2000) of the last price update. Must be within ±300 seconds of the ledger close time and must be strictly greater than the current stored value on updates. |
+| `LastUpdateTime` | Number | UInt32 | Unix timestamp (seconds since January 1, 1970) of the last price update. Must be within ±300 seconds of the ledger close time and must be strictly greater than the current stored value on updates. |
| `PriceDataSeries` | Array | Array | Array of `PriceData` objects. Must contain between 1 and 10 entries. On update, pairs without `AssetPrice` are deleted from the object. |
### PriceData Object
@@ -100,7 +100,7 @@ OracleSet transactions have the standard transaction cost.
| `temARRAY_EMPTY` | `PriceDataSeries` is empty. |
| `temARRAY_TOO_LARGE` | `PriceDataSeries` contains more than 10 entries in the transaction. |
| `terNO_ACCOUNT` | The sending account does not exist. |
-| `tecINVALID_UPDATE_TIME` | `LastUpdateTime` is outside the ±300 second window from ledger close time, predates the XRP Ledger epoch (Jan 1 2000), or is not strictly greater than the stored value on an update. |
+| `tecINVALID_UPDATE_TIME` | `LastUpdateTime` is outside the ±300 second window from ledger close time, predates the UNIX timestamp (seconds since January 1, 1970), or is not strictly greater than the stored value on an update. |
| `tecTOKEN_PAIR_NOT_FOUND` | A pair specified for deletion (no `AssetPrice`) does not exist in the current Oracle object. |
| `tecARRAY_EMPTY` | The result after applying all updates and deletions would leave `PriceDataSeries` empty. |
| `tecARRAY_TOO_LARGE` | The result after applying all updates and additions would exceed 10 entries. |
From 84fb564a20d370ab90611c45a484fa98cd817638 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Wed, 24 Jun 2026 07:57:03 +0200
Subject: [PATCH 20/23] Update get-aggregate-price.mdx
---
.../docs/features/http-websocket-apis/get-aggregate-price.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/content/docs/docs/features/http-websocket-apis/get-aggregate-price.mdx b/src/content/docs/docs/features/http-websocket-apis/get-aggregate-price.mdx
index 6159dfa..3ebf982 100644
--- a/src/content/docs/docs/features/http-websocket-apis/get-aggregate-price.mdx
+++ b/src/content/docs/docs/features/http-websocket-apis/get-aggregate-price.mdx
@@ -90,7 +90,7 @@ The `get_aggregate_price` method queries the price data stored in one or more [O
| Error Code | Description |
| --------------------- | ---------------------------------------------------------------------------------------------- |
| `rpcORACLE_MALFORMED` | An entry in `oracles` is missing or has an invalid `account` or `oracle_document_id`. |
-| `rpcINVALID_PARAMS` | Invalid parameter type, empty asset string, or `trim` outside the 1–50 range. |
+| `rpcINVALID_PARAMS` | Invalid parameter type, empty asset string, or `trim` outside the 1–25 range. |
| `rpcOBJECT_NOT_FOUND` | No matching price data found for the requested asset pair across all queried Oracle objects. |
| `rpcINTERNAL` | All data points were excluded by the `time_threshold` filter, leaving an empty result set. |
From dab6d6c738203e2cbeefa5cf10b0eb2bb952de43 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Wed, 24 Jun 2026 09:43:22 +0200
Subject: [PATCH 21/23] Sublimator notes
---
src/content/docs/docs/features/amendments.mdx | 24 +++++++++----------
.../hooks/concepts/emitted-transactions.mdx | 2 +-
.../docs/docs/hooks/concepts/hookon-field.mdx | 4 ++--
.../docs/docs/hooks/concepts/named-hooks.mdx | 2 +-
.../hooks/concepts/serialized-objects.mdx | 4 ++--
.../functions/emitted-transaction/emit.mdx | 4 ++--
.../functions/emitted-transaction/prepare.mdx | 4 ++--
.../ledger-objects-types/hook-definition.mdx | 2 +-
.../ledger-data/ledger-objects-types/hook.mdx | 6 ++++-
.../ledger-objects-types/ripple-state.mdx | 2 +-
.../transaction-types/claimreward.mdx | 10 ++++----
.../transaction-types/sethook.mdx | 4 ++--
12 files changed, 36 insertions(+), 32 deletions(-)
diff --git a/src/content/docs/docs/features/amendments.mdx b/src/content/docs/docs/features/amendments.mdx
index dba5819..8bee947 100644
--- a/src/content/docs/docs/features/amendments.mdx
+++ b/src/content/docs/docs/features/amendments.mdx
@@ -93,6 +93,18 @@ Adds an optional `HookName` field (4–16 bytes, UTF-8) to the Hook slot in a [S
Adds the `prepare()` Hook API function. `prepare(write_ptr, write_len, read_ptr, read_len)` accepts a partial serialized transaction containing only transaction-type-specific fields and automatically injects all fields required for emission: `Account`, `Sequence`, `SigningPubKey`, `Fee`, `FirstLedgerSequence`, `LastLedgerSequence`, and `EmitDetails`. The output can be passed directly to `emit()`, eliminating the need to manually construct these boilerplate fields in hook code. _(Introduced in 2026.6.21-release+3350)_
+##### HookOnV2
+
+Hooks may continue to specify `HookOn` with the existing behaviour, or optionally replace it with two separate fields: `HookOnIncoming` and `HookOnOutgoing`. Both use the same bitmask syntax as `HookOn` but differentiate between transactions originating from the Hook account (`HookOnOutgoing`) and transactions originating from another account (`HookOnIncoming`). _(Introduced in 2026.6.21-release+3350)_
+
+##### PriceOracle
+
+A port of the XRPL PriceOracle (XLS-47d) standard. Enables on-chain price feeds by allowing accounts to publish asset price data as [Oracle ledger objects](/docs/protocol-reference/ledger-data/ledger-objects-types/oracle). Introduces two new transactions: [OracleSet](/docs/protocol-reference/transactions/transaction-types/oracleset) (create or update an Oracle) and [OracleDelete](/docs/protocol-reference/transactions/transaction-types/oracledelete) (remove an Oracle). Also adds the `get_aggregate_price` RPC method for querying aggregated prices across multiple oracles. Each Oracle object stores 1–10 asset/quote price pairs (1–5 pairs consume 1 owner reserve; 6–10 consume 2). The integer `AssetPrice`, together with `Scale`, encodes the price as `AssetPrice` × 10^(-`Scale`). _(Introduced in 2026.6.21-release+3350)_
+
+##### IOURewardClaim
+
+Expands the [ClaimReward](/docs/protocol-reference/transactions/transaction-types/claimreward) transaction type beyond genesis balance adjustments to other IOU currencies. Reward counters are held within the trustline (`LowReward`/`HighReward` objects on the [RippleState](/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state) object) and do not affect genesis balance adjustments. The transaction triggers any Hook installed on the account specified by the `Issuer` field, allowing that Hook to process and optionally pay out the reward. The reward-paying account does not need to be the issuer of the IOU currency. _(Introduced in 2026.6.21-release+3350)_
+
##### Remit
Implements [XLS-55](https://github.com/XRPLF/XRPL-Standards/discussions/156). A new simple but powerful what-you-see-is-what-you-get push payment transaction type. Enables [Remit transactions](/docs/protocol-reference/transactions/transaction-types/remit) that allow paying multiple currencies and URITokens in the same transaction to the same destination. The transaction automatically pays to create missing trustlines, automatically pays the reserves on transferred tokens, and automatically pays to create the destination account if it doesn't exist. You can mint a receipt or bonus URIToken in-line within the transaction. Optionally inform a third party Hook about the transaction. No partial payments and no pathing.
@@ -187,18 +199,6 @@ Fixes issues with provisional double threading in transaction processing. Ensure
Fixes a bug that currently allows invalid flags to be provided to some transactions. While these invalid flags currently do nothing, they should actually produce a malformed error. After this fix is applied, invalid flags will produce a malformed error as expected. _(Introduced in 2025.10.27-release+2405)_
-##### HookOnV2
-
-Hooks may continue to specify `HookOn` with the existing behaviour, or optionally replace it with two separate fields: `HookOnIncoming` and `HookOnOutgoing`. Both use the same bitmask syntax as `HookOn` but differentiate between transactions originating from the Hook account (`HookOnOutgoing`) and transactions originating from another account (`HookOnIncoming`). _(Introduced in 2026.6.21-release+3350)_
-
-##### PriceOracle
-
-A port of the XRPL PriceOracle (XLS-47d) standard. Enables on-chain price feeds by allowing accounts to publish asset price data as [Oracle ledger objects](/docs/protocol-reference/ledger-data/ledger-objects-types/oracle). Introduces two new transactions: [OracleSet](/docs/protocol-reference/transactions/transaction-types/oracleset) (create or update an Oracle) and [OracleDelete](/docs/protocol-reference/transactions/transaction-types/oracledelete) (remove an Oracle). Also adds the `get_aggregate_price` RPC method for querying aggregated prices across multiple oracles. Each Oracle object stores 1–10 asset/quote price pairs (1–5 pairs consume 1 owner reserve; 6–10 consume 2). Prices are stored as scaled integers (`AssetPrice × 10^(-Scale)`). _(Introduced in 2026.6.21-release+3350)_
-
-##### IOURewardClaim
-
-Expands the [ClaimReward](/docs/protocol-reference/transactions/transaction-types/claimreward) transaction type beyond genesis balance adjustments to other IOU currencies. Reward counters are held within the trustline (`LowReward`/`HighReward` objects on the [RippleState](/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state) object) and do not affect genesis balance adjustments. The transaction triggers any Hook installed on the account specified by the `Issuer` field, allowing that Hook to process and optionally pay out the reward. The reward-paying account does not need to be the issuer of the IOU currency. _(Introduced in 2026.6.21-release+3350)_
-
##### fixCronStacking
Fixes issues with Cron transaction stacking behavior.
diff --git a/src/content/docs/docs/hooks/concepts/emitted-transactions.mdx b/src/content/docs/docs/hooks/concepts/emitted-transactions.mdx
index 138ba0d..64aab2e 100644
--- a/src/content/docs/docs/hooks/concepts/emitted-transactions.mdx
+++ b/src/content/docs/docs/hooks/concepts/emitted-transactions.mdx
@@ -24,7 +24,7 @@ Because emitted transactions can trigger Hooks in the next ledger which in turn
The `burden` and `generation` fields collectively prevent [Fork bomb](https://en.wikipedia.org/wiki/Fork_bomb) attacks on the ledger by exponentially increasing the cost of exponentially expanding emtited transactions.
-It is important to note that the Hooks API follows the strict rule of _no rewriting_. You _must_ present an emitted transaction in full, valid and canonically formed to xahaud for emission or it will be rejected. With the [HooksUpdate2 amendment](/docs/features/amendments/#hooksupdate2), the [`prepare()`](/docs/hooks/functions/emitted-transaction/prepare) API automates this: the Hook provides only the transaction-type-specific fields and the runtime injects all required emission boilerplate. Without HooksUpdate2, the Hook must construct the complete transaction itself.
+It is important to note that the Hooks API follows the strict rule of _no rewriting_. You _must_ present an emitted transaction in full, valid and canonically formed to xahaud for emission or it will be rejected. With the [HooksUpdate2 amendment](/docs/features/amendments/#hooksupdate2), the [prepare()](/docs/hooks/functions/emitted-transaction/prepare) API automates this: the Hook provides only the transaction-type-specific fields and the runtime injects all required emission boilerplate. Without HooksUpdate2, the Hook must construct the complete transaction itself.
### Callbacks
diff --git a/src/content/docs/docs/hooks/concepts/hookon-field.mdx b/src/content/docs/docs/hooks/concepts/hookon-field.mdx
index ac8ff11..505fdd1 100644
--- a/src/content/docs/docs/hooks/concepts/hookon-field.mdx
+++ b/src/content/docs/docs/hooks/concepts/hookon-field.mdx
@@ -61,8 +61,8 @@ Instead of specifying a single `HookOn` field, Hooks may optionally replace it w
- **`HookOnIncoming`** — triggers the Hook on transactions **originating from another account** (the Hook account is not the initiator).
- **`HookOnOutgoing`** — triggers the Hook on transactions **originating from the Hook account itself**.
-Both fields use the same bit-field syntax as `HookOn`. `HookOnIncoming` and `HookOnOutgoing` are mutually exclusive with `HookOn` — you must use either `HookOn` alone or the `HookOnIncoming`/`HookOnOutgoing` pair, not both. If only one of the pair is specified, the Hook will not fire on the unspecified direction.
+Both fields use the same bit-field syntax as `HookOn`. `HookOnIncoming` and `HookOnOutgoing` are mutually exclusive with `HookOn` — you must use either `HookOn` alone or the `HookOnIncoming`/`HookOnOutgoing` pair, not both. If only one of the pair is specified, the Hook will not fire on the unspecified direction.
-_Note: The `HookOnIncoming` and `HookOnOutgoing` cannot be configured with exactly the same settings. If you need a Hook to respond to both directions using identical criteria, use the `HookOn` field instead, as it provides a simpler and more appropriate way to define shared trigger behavior._
+_Note: The `HookOnIncoming` and `HookOnOutgoing` fields cannot be configured with exactly the same settings. If you need a Hook to respond to both directions using identical criteria, use the `HookOn` field instead, as it provides a simpler and more appropriate way to define shared trigger behavior._
Using `HookOn` alone continues to work exactly as before.
diff --git a/src/content/docs/docs/hooks/concepts/named-hooks.mdx b/src/content/docs/docs/hooks/concepts/named-hooks.mdx
index 4889b93..d25bf81 100644
--- a/src/content/docs/docs/hooks/concepts/named-hooks.mdx
+++ b/src/content/docs/docs/hooks/concepts/named-hooks.mdx
@@ -96,7 +96,7 @@ Hook fee calculation respects the same gating logic: named hooks that would be s
| Error Code | Condition |
| -------------- | --------- |
| `temDISABLED` | `HookName` is present in a Hook slot but the `NamedHooks` amendment is not enabled. |
-| `temMALFORMED` | `HookName` present as a top-level transaction field but `featureHooks` or `featureNamedHooks` is not active; or the value fails UTF-8 / length validation. |
+| `temMALFORMED` | `HookName` present as a top-level transaction field but `Hooks` or `NamedHooks` is not active; or the value fails UTF-8 / length validation. |
### Use Cases
diff --git a/src/content/docs/docs/hooks/concepts/serialized-objects.mdx b/src/content/docs/docs/hooks/concepts/serialized-objects.mdx
index 6ea0a75..52543a8 100644
--- a/src/content/docs/docs/hooks/concepts/serialized-objects.mdx
+++ b/src/content/docs/docs/hooks/concepts/serialized-objects.mdx
@@ -57,8 +57,8 @@ With the [HookAPISerializedType240 amendment](/docs/features/amendments/#hookapi
| STI Type | Code | Examples |
|---|---|---|
| `STI_UINT16` | 1 | `sfTransactionType` |
-| `STI_UINT32` | 2 | `sfFlags`, `sfSequence` |
-| `STI_UINT64` | 3 | `sfOfferSequence` |
+| `STI_UINT32` | 2 | `sfFlags`, `sfSequence`, `sfOfferSequence` |
+| `STI_UINT64` | 3 | |
| `STI_HASH128` | 4 | `sfEmailHash` |
| `STI_HASH256` | 5 | `sfLedgerHash`, `sfTransactionHash` |
| `STI_AMOUNT` | 6 | `sfAmount`, `sfFee` |
diff --git a/src/content/docs/docs/hooks/functions/emitted-transaction/emit.mdx b/src/content/docs/docs/hooks/functions/emitted-transaction/emit.mdx
index 997ac23..51d6fed 100644
--- a/src/content/docs/docs/hooks/functions/emitted-transaction/emit.mdx
+++ b/src/content/docs/docs/hooks/functions/emitted-transaction/emit.mdx
@@ -23,7 +23,7 @@ With the [HooksUpdate2 amendment](/docs/features/amendments/#hooksupdate2), use
* This function emits the provided transaction JSON.
-* On success, it returns the number of emitted transaction hashes.
+* On success, it returns the emitted transaction hashes.
* If there is an error, it returns an error code.
@@ -101,7 +101,7 @@ if(typeof emitResult === 'number')
-
Type
Description
int64_t
On success, the number of bytes of transaction hash written (32), or:
If negative, an error: OUT_OF_BOUNDS - pointers/lengths specified outside of hook memory.
PREREQUISITE_NOT_MET - emit_reserve must be called first
TOO_MANY_EMITTED_TXN - the number of emitted transactions is now greater than the promise made when emit_reserve was called earlier
EMISSION_FAILURE - the transaction was malformed according to the emission rules.
+
Type
Description
int64_t
On success, the number of bytes of transaction hash written (32), or:
If negative, an error: OUT_OF_BOUNDS - pointers/lengths specified outside of hook memory.
PREREQUISITE_NOT_MET - etxn_reserve must be called first
TOO_MANY_EMITTED_TXN - the number of emitted transactions is now greater than the promise made when etxn_reserve was called earlier
EMISSION_FAILURE - the transaction was malformed according to the emission rules.
diff --git a/src/content/docs/docs/hooks/functions/emitted-transaction/prepare.mdx b/src/content/docs/docs/hooks/functions/emitted-transaction/prepare.mdx
index 0484785..ed51b35 100644
--- a/src/content/docs/docs/hooks/functions/emitted-transaction/prepare.mdx
+++ b/src/content/docs/docs/hooks/functions/emitted-transaction/prepare.mdx
@@ -24,7 +24,7 @@ _(Requires the [HooksUpdate2 amendment](/docs/features/amendments/#hooksupdate2)
* This function takes a transaction JSON object and prepares it for emission.
-* The transaction must be complete except for the Account field, which should always be the Hook account.
+* The transaction must be complete except for the Account, Sequence, SigningPubKey, Fee, FirstLedgerSequence, LastLedgerSequence, and EmitDetails fields.
@@ -114,7 +114,7 @@ const prepared_txn = prepare({
| Type | Description |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| int64_t | On success, the number of bytes written to `write_ptr` (the size of the prepared transaction blob). The result can be passed directly as `read_ptr`/`read_len` to `emit()`.
If negative, an error: `OUT_OF_BOUNDS` — pointers/lengths fall outside hook memory. `PREREQUISITE_NOT_MET` — `etxn_reserve()` must be called before `prepare()`. `INVALID_ARGUMENT` — the input blob is not a valid serialized transaction, or the transaction cannot be prepared (e.g. fee computation failed). `INTERNAL_ERROR` — failed to generate `EmitDetails` or re-serialize the transaction. |
+| int64_t | On success, the number of bytes written to `write_ptr` (the size of the prepared transaction blob). The returned value is the length of the prepared transaction. Pass the original buffer as `read_ptr` and the returned length as `read_len` when calling `emit()`.
If negative, an error: `OUT_OF_BOUNDS` — pointers/lengths fall outside hook memory. `PREREQUISITE_NOT_MET` — `etxn_reserve()` must be called before `prepare()`. `INVALID_ARGUMENT` — the input blob is not a valid serialized transaction, or the transaction cannot be prepared (e.g. fee computation failed). `INTERNAL_ERROR` — failed to generate `EmitDetails` or re-serialize the transaction. |
diff --git a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook-definition.mdx b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook-definition.mdx
index 47a5ab6..713e0c8 100644
--- a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook-definition.mdx
+++ b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook-definition.mdx
@@ -18,7 +18,7 @@ A `HookDefinition` object describes a hook, which is a piece of code that is exe
"HookParameters": {
"HookParameter": {
"HookParameterName": "DEADBEEF",
- "HookParameterValue": "DEADBEEF",
+ "HookParameterValue": "DEADBEEF"
}
},
"HookApiVersion": 1,
diff --git a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook.mdx b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook.mdx
index 8b5b899..31f2199 100644
--- a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook.mdx
+++ b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/hook.mdx
@@ -46,8 +46,12 @@ The following fields are used in the hook object:
| Field | JSON Type | Internal Type | Description |
| ---------------- | --------- | ------------- | ------------------------------ |
| `HookHash` | String | Hash256 | The hash of the hook. |
+| `CreateCode` | String | Blob | The hex-encoded WebAssembly binary (WASM) that defines the hook's logic. Present when the hook was installed with inline code rather than referencing an existing `HookDefinition` object. |
+| `HookGrants` | Array | Array | An array of grant objects specifying which accounts are permitted to set or modify this hook on the hook account's behalf. |
+| `HookNamespace` | String | Hash256 | A 32-byte (64 hex character) namespace that segregates this hook's state data from other hooks on the same account. Must be unique per hook slot. |
| `HookParameters` | Array | Array | The parameters of the hook. |
-| `HookOn` | String | Hash256 | The transaction/s on which the hook is triggered. Mutually exclusive with `HookOnIncoming`/`HookOnOutgoing`. |
+| `HookApiVersion` | Number | UInt16 | The version of the Hooks API used by this hook. Determines which hook API functions are available to the WASM binary at runtime. |
+| `HookOn` | String | Hash256 | The transaction type(s) on which the hook is triggered. Mutually exclusive with `HookOnIncoming`/`HookOnOutgoing`. |
| `HookOnIncoming` | String | Hash256 | _(HookOnV2)_ Same syntax as `HookOn`. Triggers the hook on transactions originating from another account. Mutually exclusive with `HookOn`. |
| `HookOnOutgoing` | String | Hash256 | _(HookOnV2)_ Same syntax as `HookOn`. Triggers the hook on transactions originating from the Hook account itself. Mutually exclusive with `HookOn`. |
| `HookCanEmit` | String | Hash256 | Same syntax as `HookOn`. Controls which transaction types the hook is allowed to emit. If absent, the hook may emit any transaction type. |
diff --git a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state.mdx b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state.mdx
index 6c8df18..990c6b5 100644
--- a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state.mdx
+++ b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state.mdx
@@ -84,7 +84,7 @@ A `RippleState` object has the following fields:
_(Added by the [IOURewardClaim amendment](/docs/features/amendments/#iourewardclaim).)_
-Both `LowReward` and `HighReward` are inner objects with the same structure. Which one is present depends on the canonical high/low ordering of the two accounts in the trustline.
+Both `LowReward` and `HighReward` are inner objects with the same structure. `LowReward` is present if the low account has opted in to IOU rewards for this trustline, and `HighReward` is present if the high account has opted in. Both can be present if both accounts have opted in. The canonical high/low ordering only determines which side an account maps to.
| Field | JSON Type | Internal Type | Description |
| ---------------------------- | --------- | ------------- | ---------------------------------------------------------------------------------------------------- |
diff --git a/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx b/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx
index 34685dc..541b65e 100644
--- a/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx
+++ b/src/content/docs/docs/protocol-reference/transactions/transaction-types/claimreward.mdx
@@ -5,7 +5,7 @@ description: >-
accumulated. The rewards can be claimed by the account owner or by a specified
issuer. The account can also opt-out of rewards. With the IOURewardClaim
amendment, this transaction also supports claiming rewards for IOU currencies
- issued by accounts with a reward Hook installed.
+ with a reward Hook installed.
---
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/ClaimReward.cpp)]
@@ -52,7 +52,7 @@ _(Requires the \[IOURewardClaim amendment]\[].)_
| Field | JSON Type | \[Internal Type]\[] | Description |
| --------------- | --------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Account` | String | AccountID | The address of the account that is claiming the reward. |
-| `Flags` | Number | UInt32 | _(Optional)_ Can have flag 1 set to opt-out rewards. |
+| `Flags` | Number | UInt32 | _(Optional)_ Can have flag 1 set to opt-out of rewards. |
| `Issuer` | String | AccountID | _(Optional)_ The genesis account (XAH rewards) or an IOU account (IOU rewards). |
| `ClaimCurrency` | Object | Issue | _(Optional, IOURewardClaim)_ The IOU currency to claim rewards for, as `{"currency": "...", "issuer": "..."}`. Cannot be XAH. The issuer must not be the genesis account and must not equal `Account`. Requires a trustline to exist between `Account` and the issuer. |
@@ -74,7 +74,7 @@ _(Requires the \[IOURewardClaim amendment]\[].)_
When `ClaimCurrency` is specified, the transaction follows the IOU reward path:
-1. The `Issuer` account must have a Hook installed that fires on `ClaimReward` transaction. The Hook is responsible for calculating and distributing the reward payout.
+1. The `Issuer` account must have a Hook installed that fires on a `ClaimReward` transaction. The Hook is responsible for calculating and distributing the reward payout.
2. On first claim, a `LowReward` or `HighReward` reward-tracking object is initialised on the trustline ([RippleState](/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state) ledger object) between `Account` and the issuer. Which side is used depends on the canonical high/low ordering of the two accounts.
3. After every subsequent transaction that changes the trustline balance, the ledger automatically updates `TrustLineRewardAccumulator` inside the tracking object using the same area-under-the-curve formula as genesis XAH rewards.
4. When a `ClaimReward` with `ClaimCurrency` is submitted, the ledger resets the reward counters on the trustline and fires the issuer's Hook, which reads the accumulated value and emits a reward payment.
@@ -89,10 +89,10 @@ Besides errors that can occur for all transactions, ClaimReward transactions can
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `temDISABLED` | Occurs if the required amendment (`BalanceRewards` or `IOURewardClaim`) is not enabled. |
| `temINVALID_FLAG` | Occurs if the flag is set to a value other than 1. _(Requires the \[fixRewardClaimFlags amendment]\[].)_ |
-| `temMALFORMED` | Occurs if `ClaimCurrency` is an non-currency or XAH type, if the issuer equals `Account`, or if the transaction fields are otherwise incorrectly set. |
+| `temMALFORMED` | Occurs if `ClaimCurrency` is a non-currency or XAH type, if the issuer equals `Account`, or if the transaction fields are otherwise incorrectly set. |
| `temBAD_ISSUER` | Occurs if `ClaimCurrency` is set but the issuer is the genesis account, or if `Issuer` is the genesis account but `ClaimCurrency` is also set. |
| `terNO_ACCOUNT` | Occurs if the sending account does not exist. |
| `tecNO_ISSUER` | Occurs if the `Issuer` account does not exist. |
| `tecNO_PERMISSION` | Occurs if the issuer account is an AMM account. AMM accounts cannot have reward Hooks. |
-| `tecNO_TARGET` | Occurs if the issuer account has no Hooks, or none of its Hooks fires on `ClaimReward` transaction. |
+| `tecNO_TARGET` | Occurs if the issuer account has no Hooks, or none of its Hooks fires on a `ClaimReward` transaction. |
| `tecNO_LINE` | Occurs if no trustline exists between `Account` and the issuer for the specified `ClaimCurrency`. |
diff --git a/src/content/docs/docs/protocol-reference/transactions/transaction-types/sethook.mdx b/src/content/docs/docs/protocol-reference/transactions/transaction-types/sethook.mdx
index 71e50b7..0201d81 100644
--- a/src/content/docs/docs/protocol-reference/transactions/transaction-types/sethook.mdx
+++ b/src/content/docs/docs/protocol-reference/transactions/transaction-types/sethook.mdx
@@ -98,11 +98,11 @@ _All_ of the following conditions are met:
* The Corresponding Hook does not exist _or_`FLAG_OVERRIDE` is specified.
* `CreateCode` field is specified and is not blank and contains the valid web assembly bytecode for a valid Hook.
-* No instance of the same web assembly bytecode already exists on the XRPL. (If it does and all other requirements are met then interpret as an Install Operation — see below.)
+* No instance of the same web assembly bytecode already exists on Xahau. (If it does and all other requirements are met then interpret as an Install Operation — see below.)
**Behaviour**:
-* A reference counted `HookDefinition` object is created on the Xahau containing the fields in the HookSet Object, with all specified fields (Namespace, Parameters, HookOn) becoming defaults (but not Grants.)
+* A reference counted `HookDefinition` object is created on Xahau containing the fields in the HookSet Object, with all specified fields (Namespace, Parameters, HookOn) becoming defaults (but not Grants.)
* A `Hooks` array is created on the executing account, if it doesn't already exist. (This is the structure that contains the Corresponding Hooks.)
* A `Hook` object is created at the Corresponding Hook position if one does not already exist.
* The `Hook` object points at the `HookDefinition`.
From 7d34f79c155c7c260a1c09e564247a54ff9fab16 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Wed, 24 Jun 2026 11:12:25 +0200
Subject: [PATCH 22/23] fixes
---
src/content/docs/docs/hooks/concepts/serialized-objects.mdx | 2 +-
.../ledger-data/ledger-objects-types/ripple-state.mdx | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/content/docs/docs/hooks/concepts/serialized-objects.mdx b/src/content/docs/docs/hooks/concepts/serialized-objects.mdx
index 52543a8..6fc0a96 100644
--- a/src/content/docs/docs/hooks/concepts/serialized-objects.mdx
+++ b/src/content/docs/docs/hooks/concepts/serialized-objects.mdx
@@ -58,7 +58,7 @@ With the [HookAPISerializedType240 amendment](/docs/features/amendments/#hookapi
|---|---|---|
| `STI_UINT16` | 1 | `sfTransactionType` |
| `STI_UINT32` | 2 | `sfFlags`, `sfSequence`, `sfOfferSequence` |
-| `STI_UINT64` | 3 | |
+| `STI_UINT64` | 3 | `sfHookOn` |
| `STI_HASH128` | 4 | `sfEmailHash` |
| `STI_HASH256` | 5 | `sfLedgerHash`, `sfTransactionHash` |
| `STI_AMOUNT` | 6 | `sfAmount`, `sfFee` |
diff --git a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state.mdx b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state.mdx
index 990c6b5..17a3b2e 100644
--- a/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state.mdx
+++ b/src/content/docs/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state.mdx
@@ -88,7 +88,7 @@ Both `LowReward` and `HighReward` are inner objects with the same structure. `Lo
| Field | JSON Type | Internal Type | Description |
| ---------------------------- | --------- | ------------- | ---------------------------------------------------------------------------------------------------- |
-| `RewardLgrFirst` | Number | UInt32 | The ledger sequence when the account first opted in to IOU rewards for this trustline. |
+| `RewardLgrFirst` | Number | UInt32 | The ledger sequence when the account first opted in to IOU rewards for this trustline. It gets updated every time `ClaimReward` is executed. The field will be deleted if the account opts out |
| `RewardLgrLast` | Number | UInt32 | The ledger sequence of the last time the reward accumulator was updated. |
| `RewardTime` | Number | UInt32 | The ledger close time (Ripple epoch seconds) when the counters were last reset by a `ClaimReward` transaction. |
| `TrustLineRewardAccumulator` | Object | Amount | The running total of `balance × ledgers elapsed` since the last `ClaimReward`. Expressed in the trustline's currency. This is the value the issuer's Hook reads to calculate the reward payout. |
From 9344d08f4d0a301ae74e0c7b02eb1014445eeacb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ekiserrep=C3=A9?=
<126416117+Ekiserrepe@users.noreply.github.com>
Date: Wed, 24 Jun 2026 11:55:30 +0200
Subject: [PATCH 23/23] Features page update for Price Oracles.
---
src/components/XahauFeatures.astro | 13 ++++++++++++-
src/data/features.json | 11 +++++++++++
src/i18n/featuresTranslations.ts | 8 ++++++++
3 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/src/components/XahauFeatures.astro b/src/components/XahauFeatures.astro
index 9ccaa54..594abd2 100644
--- a/src/components/XahauFeatures.astro
+++ b/src/components/XahauFeatures.astro
@@ -156,6 +156,16 @@ const t = featuresTranslations[locale] ?? featuresTranslations.en