This is the full developer documentation for Xahau Docs
# Xahau Documentation
Welcome to the Xahau Documentation. This is your comprehensive guide to understanding and working with Xahau. This documentation is divided into three main categories: Features, Infrastructure, and Technical.
Each category is designed to provide you with detailed insights and instructions about different aspects of Xahau.
### Features
[Section titled “Features”](#features)
The Features section is where you’ll find information about the unique aspects of Xahau. One of the key areas covered in this section is Developer Tooling.
Our Developer Tooling page covers Hooks Tools and Client Libraries, simplifying the process of interacting with Hooks and the Xahau Network. This section is designed to help you understand the functionality and capabilities of Xahau, with practical examples to help illustrate these features in action.
### Protocol Reference
[Section titled “Protocol Reference”](#protocol-reference)
The Protocol Reference section of Xahau’s documentation provides an in-depth look at the platform’s unique aspects, including various transaction types like AccountDelete, CheckCancel, and Payment, each with its own specific use and characteristics.
It also covers the different ledger objects integral to the network’s operation, such as AccountRoot and Amendments. This comprehensive overview aims to enhance the understanding of Xahau’s functionalities and capabilities, ensuring users can fully leverage the network’s features.
### Infrastructure
[Section titled “Infrastructure”](#infrastructure)
Infrastructure is the core of the Xahau Network. Servers running the xahaud software enable users to do things like submit, verify, and query transactions. The documentation in this section provides instructions for installing, updating, configuring, and building xahaud. Concepts, such as attesting to the identity of a given server or running xahaud as a validator, are also discussed.
**We hope this documentation provides you with the information you need to understand, use, and contribute to the Xahau Network. Happy exploring!**
# Responsible Disclosure
> Our Responsible Disclosure Policy provides clear guidelines for submitting reports through our support portal, ensuring confidentiality.
### Responsible Disclosure Policy
[Section titled “Responsible Disclosure Policy”](#responsible-disclosure-policy)
At Xahau, we believe that the security of our systems is extremely important.
Despite our concern for the security of our systems during product development and maintenance, there’s always the possibility of someone finding something we need to improve/update/change/fix /…
We appreciate you notifying us if you have found a weak point in one of our systems as soon as possible so we can immediately take measures to protect our customers and their data.
### How to Report
[Section titled “How to Report”](#how-to-report)
If you believe you have found a security-related bug, please notify us as soon as possible by emailing a **high level description of your finding and contact information (so someone can reach out)** to .
If the issue is related to **xahaud**, please refer to its security policy:
### Rules
[Section titled “Rules”](#rules)
This responsible disclosure policy is not an open invitation to actively scan our network and applications for vulnerabilities. Our continuous monitoring will likely detect your scan, and these will be investigated.
#### We ask you to:
[Section titled “We ask you to:”](#we-ask-you-to)
* Not share information about the security issue with others until the problem is resolved, and to immediately delete any confidential data acquired
* Not further abuse the problem, for example, by downloading more data than is necessary to demonstrate the leak or to view, delete, or amend the data of third parties
* Provide detailed information in order for us to reproduce, validate, and resolve the problem as quickly as possible. Include your test data, timestamps, and URL(s) of the system(s) involved
* Leave your contact details (e-mail address and/or phone number) so that we may contact you about the progress of the solution. We do accept anonymous reports.
* Do not use attacks on physical security, social engineering, distributed denial of service, spam, or applications of third parties
### Responsible Disclosure procedure(s)
[Section titled “Responsible Disclosure procedure(s)”](#responsible-disclosure-procedures)
#### When you report a security issue, we will act according to the following:
[Section titled “When you report a security issue, we will act according to the following:”](#when-you-report-a-security-issue-we-will-act-according-to-the-following)
* You will receive a confirmation of receipt from us within 4 working days after the report is made
* You will receive a response with the assessment of the security issue and an expected date of resolution within 4 working days after the confirmation of receipt is sent
* We will take no legal steps against you in relation to the report if you have kept to the conditions as set out above
* We will handle your report confidentially, and we will not share your details with third parties without your permission unless that is necessary in order to fulfill a legal obligation
#### This responsible disclosure scheme is not intended for:
[Section titled “This responsible disclosure scheme is not intended for:”](#this-responsible-disclosure-scheme-is-not-intended-for)
* Complaints
* Website unavailable reports
* Phishing reports
* Fraud reports
For these complaints or reports, please post a **high level description of your issue and contact information (so someone can reach out) on Github:** [**https://github.com/Xahau/xahaud/issues**](https://github.com/Xahau/xahaud/issues)
### Bug bounty program
[Section titled “Bug bounty program”](#bug-bounty-program)
Xahau encourages the reporting of security issues or vulnerabilities. We may make an appropriate reward for confidential disclosure of any design or implementation issue that could be used to compromise the confidentiality or integrity of our users’ data that was not yet known to us. We decide whether the report is eligible and the amount of the reward.
### Exclusions
[Section titled “Exclusions”](#exclusions)
#### The following types of security problems are excluded
[Section titled “The following types of security problems are excluded”](#the-following-types-of-security-problems-are-excluded)
* (D)DOS attacks
* Error messages or error pages without sensitive data
* Tests & sample data as publicly available in our repositories on Github
* Common issues like browser header warnings or DNS configuration, identified by vulnerability scans
* Vulnerability scan reports for the software we publicly use
* Security issues related to outdated OS’s, browsers, or plugins
* Reports for security problems that we have been notified of before
Please note: Reports that lack any proof (such as screenshots or other data), detailed information, or details on how to reproduce any unexpected result will be investigated but will not be eligible for any reward.
This policy is based on the National Cyber Security Centre’s Responsible Disclosure Guidelines and an [example by Floor Terra](https://responsibledisclosure.nl/).
# Security Audits
The Hooks amendment, integral to XRPL’s smart contract infrastructure, has passed a detailed security audit by FYEO. The audit examined the Hooks framework implementation, including the Hook API, helper functions, and execution environment.
With no severe security issues detected and all minor issues resolved, this audit serves as a testament to our commitment to security and the robustness of Hooks.
By enabling smart transaction logic directly on XRPL’s Layer 1, Hooks bring increased flexibility to tailor applications to their unique needs, inspiring further innovation within the XRPL ecosystem.
Developers now have robust tools for creating and deploying custom logic, accessible on our testnet.
### **Assurance of Ongoing Security**
[Section titled “Assurance of Ongoing Security”](#assurance-of-ongoing-security)
The audit’s successful completion is not just a milestone but a cornerstone for the ongoing security and sustainability of the Hooks network.
With all identified vulnerabilities addressed, the Hooks amendment is set to drive innovation securely on Xahau.
Note
The full security audit can be found [**here**](https://xrpl-labs.com/static/misc/Security%20Assessment%20of%20the%20XRP%20Labs%20Hooks%20Amendment%20v1.0.pdf).
To a brighter, more innovative future with Xahau!
# Data APIs
The primary Data API is located at
# Amendments
Amendments represent new features or other changes to transaction processing.
The amendment system uses the consensus process to approve any changes that affect transaction processing on Xahau. Fully-functional, transaction process changes are introduced as amendments; validators then vote on these changes. If an amendment receives more than 80% support for five days, the amendment passes and the change applies permanently to all subsequent ledger versions. Disabling a passed amendment requires a new amendment to do so.
**Note:** Bug fixes that change transaction processes also require amendments.
### Amendment Process
[Section titled “Amendment Process”](#amendment-process)
The Contributing Code to Xahau topic walks through the workflow to develop an amendment from an idea to activation on Xahau.
After the code for an amendment is built into a software release, the process to enable it happens within the Xahau network, which checks the status of amendments every *flag* ledger (typically about 15 minutes apart).
Every 256th ledger is called a **flag** ledger. The flag ledger doesn’t have special contents, but the amendment process happens around it.
1. **Flag Ledger -1:** When `xahaud` validators send validation messages, they also submit their amendment votes.
2. **Flag Ledger:** Servers interpret the votes from trusted validators.
3. **Flag Ledger +1:** Servers insert an `EnableAmendment` pseudo-transaction and flag based on what they think happened:
* The `tfGotMajority` flag means the amendment has more than 80% support.
* The `tfLostMajority` flag means support for the amendment has decreased to 80% or less.
* No flag means the amendment is enabled.
**Note:** It’s possible for an amendment to lose 80% support on the same ledger it reaches the required five day period to be enabled. In these cases, an `EnableAmendment` pseudo-transactions is added for both scenarios, but the amendment is ultimately enabled.
4. **Flag Ledger +2:** Enabled amendments apply to transactions on this ledger onwards.
### Amendment Voting
[Section titled “Amendment Voting”](#amendment-voting)
Each version of `xahaud` is compiled with a list of known amendments and the code to implement those amendments. Operators of `xahaud` validators configure their servers to vote on each amendment and can change it at any time. If the operator doesn’t choose a vote, the server uses a default vote defined by the source code.
**Note:** The default vote can change between software releases. \[Updated in: rippled 1.8.1]\[]
Amendments must maintain five days of support from more than 80% of trusted validators to be enabled. If support drops below 80%, the amendment is temporarily rejected, and the two week period restarts. Amendments can gain and lose a majority any number of times before they become permanently enabled.
Amendments that have had their source code removed without being enabled are considered **Vetoed** by the network.
### Amendment Blocked Servers
[Section titled “Amendment Blocked Servers”](#amendment-blocked-servers)
Amendment blocking is a security feature to protect the accuracy of Xahau’s data. When an amendment is enabled, servers running earlier versions of `xahaud` without the amendment’s source code no longer understand the rules of the network. Rather than guess and misinterpret ledger data, these servers become **amendment blocked** and can’t:
* Determine the validity of a ledger.
* Submit or process transactions.
* Participate in the consensus process.
* Vote on future amendments.
The voting configuration of a `xahaud` server has no impact on it becoming amendment blocked. A `xahaud` server always follows the amendments enabled by the rest of the network, so blockages are based solely on having the code to understand rule changes. This means you can also become amendment blocked if you connect your server to a parallel network with different amendments enabled. For example, the Xahau Testnet typically has experimental amendments enabled. If you are using the latest production release, your server likely won’t have the code for those experimental amendments.
You can unblock amendment blocked servers by upgrading to the newest version of `xahaud`.
### Retiring Amendments
[Section titled “Retiring Amendments”](#retiring-amendments)
When amendments are enabled, the source code for pre-amendment behaviors remain in `xahaud`. While there are use-cases for keeping old code, such as reconstructing ledger outcomes for verification, tracking amendments and legacy code adds complexity over time.
The [XRP Ledger Standard 11d](https://github.com/XRPLF/XRPL-Standards/discussions/19) defines a process for retiring old amendments and associated pre-amendment code. After an amendment has been enabled on the Mainnet for two years, it can be retired. Retiring an amendment makes it part of the core protocol unconditionally; it’s no longer tracked or treated as an amendment, and all pre-amendment code is removed.
### Known Amendments
[Section titled “Known Amendments”](#known-amendments)
The following amendments have been implemented or are in the process of being enabled on Xahau:
#### Feature Amendments
[Section titled “Feature Amendments”](#feature-amendments)
##### XahauGenesis
[Section titled “XahauGenesis”](#xahaugenesis)
Enables the genesis account to mint XAH and distribute it via [GenesisMint transactions](/docs/protocol-reference/transactions/transaction-types/genesismint-emitted-txn).
##### MultiSign
[Section titled “MultiSign”](#multisign)
Enables multi-signature functionality, allowing accounts to require multiple signatures for transactions. This amendment introduces [SignerListSet transactions](/docs/protocol-reference/transactions/transaction-types/signerlistset) and [SignerList ledger objects](/docs/protocol-reference/ledger-data/ledger-objects-types/signers-list) to support multi-signing.
##### DepositAuth
[Section titled “DepositAuth”](#depositauth)
Enables deposit authorization functionality, allowing accounts to require preauthorization before receiving payments. This amendment introduces [DepositPreauth transactions](/docs/protocol-reference/transactions/transaction-types/depositpreauth) and [DepositPreauth ledger objects](/docs/protocol-reference/ledger-data/ledger-objects-types/deposit-pre-auth) to manage preauthorizations.
##### Hooks
[Section titled “Hooks”](#hooks)
Core amendment enabling Hook smart contract functionality on Xahau. *(Added by the [Hooks amendment](/docs/features/amendments/#hooks).)*
##### HooksUpdate1
[Section titled “HooksUpdate1”](#hooksupdate1)
Updates and improvements to the Hooks system.
##### HookAPISerializedType240
[Section titled “HookAPISerializedType240”](#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
[Section titled “NamedHooks”](#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
[Section titled “HooksUpdate2”](#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)*
##### HookOnV2
[Section titled “HookOnV2”](#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
[Section titled “PriceOracle”](#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
[Section titled “IOURewardClaim”](#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
[Section titled “Remit”](#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.
##### ZeroB2M
[Section titled “ZeroB2M”](#zerob2m)
Disables the burn-to-mint path for XRP to XAH. Normal behaviour of the Import transaction remains, but burned XRP is not credited. B2M is still available for key synchronisation or to activate an account, but cannot be used to mint new assets.
##### Remarks
[Section titled “Remarks”](#remarks)
The Remarks amendment allows key-value pairs (similar to hook state) to be stored by object owners on those objects. This is akin to flipping over a document and hand-writing a note on it. Remarks can be anything and mean different things to different parties. Remarks can also be set to immutable. Remarks follow an object through changes of ownership and can be used to achieve novel use cases like dynamic NFTs and simplify some otherwise very complicated hook state operations. Enables [SetRemarks transactions](/docs/protocol-reference/transactions/transaction-types/setremarks).
##### Touch
[Section titled “Touch”](#touch)
This amendment ensures all accounts involved in a transaction (all transactional stakeholders) are forced to appear in its metadata by incrementing a “touch counter” even if nothing else on the account was changed. This is named for the unix file utility touch. This provides better audit consistency and ease of programming automated tools.
##### HookCanEmit
[Section titled “HookCanEmit”](#hookcanemit)
This amendment adds a new field to HookSet objects: `HookCanEmit` is syntactically identical to the `HookOn` field, except that it controls which transaction types the Hook is allowed to emit rather than which transaction types trigger the hook. Note that it uses the same active-low semantics as `HookOn` with `SetHook` being active high. However if the field is absent it’s taken to be that the Hook may emit any transaction including `SetHook`. Adds the `HookCanEmit` field to [HookDefinition](/docs/protocol-reference/ledger-data/ledger-objects-types/hook-definition) objects.
##### Clawback
[Section titled “Clawback”](#clawback)
Enables [Clawback transactions](/docs/protocol-reference/transactions/transaction-types/clawback) that allow issuers to revoke tokens that were previously issued by their account. This is a ported feature from the XRPL. *(Introduced in 2025.7.9-release+1951)*
##### DeepFreeze
[Section titled “DeepFreeze”](#deepfreeze)
Enables deep freeze functionality for trustlines and assets. This is a ported feature from the XRPL. *(Introduced in 2025.7.9-release+1951)*
##### IOUIssuerWeakTSH
[Section titled “IOUIssuerWeakTSH”](#iouissuerweaktsh)
Makes IOU issuers weak transactional stakeholders (TSH) in certain transaction types. Ensures that Currency Issuers have their hooks executed in third party transactions that touch or mention their currency, if they have opted into weak execution. See [Weak and Strong](/docs/hooks/concepts/weak-and-strong) for details. *(Introduced in 2025.7.9-release+1951)*
##### Cron
[Section titled “Cron”](#cron)
Enables scheduled Hook execution via [CronSet transactions](/docs/protocol-reference/transactions/transaction-types/cronset) and [Cron ledger objects](/docs/protocol-reference/ledger-data/ledger-objects-types/cron). This feature allows Hooks to schedule a series of future self-invocations (akin to a cronjob in Linux systems) which can assist Hook developers in writing complex governance structures, games and more. The maximum number of repeats is 256, however issuing a further `CronSet` transaction can extend this once the number of repeats crosses a desired minimum threshold. *(Introduced in 2025.10.27-release+2405)*
##### ExtendedHookState
[Section titled “ExtendedHookState”](#extendedhookstate)
Extends Hook state management capabilities, including the `HookStateScale` field for [AccountRoot](/docs/protocol-reference/ledger-data/ledger-objects-types/accountroot) objects to control when Hook state entries become stale. This feature expands the amount of data Hooks can store in their Hook State (key-value system for Hooks) to allow Hooks richer data storage when they need it. The scale (up to 16) affects both the maximum size of the value you may store in a single hook state, along with the number of reserve units that k-v pair consumes. A scale of 1 (default) means you pay 1 reserve for up-to 256 bytes stored per Hook State. A scale of 4 means you pay 4 reserve units for up-to 1024 bytes per Hook State. It’s important to note that you pay this rate (the scale rate) even if all of your Hook States contain only a single byte. It is possible to increase the scale after your Hook already has stored state, but not to decrease it. Decreasing the scale requires all HookState to be first deleted. *(Introduced in 2025.10.27-release+2405)*
#### Bug Fix Amendments
[Section titled “Bug Fix Amendments”](#bug-fix-amendments)
##### fixXahauV1
[Section titled “fixXahauV1”](#fixxahauv1)
Enforces a namespaces per account limit of 256. Various bug fixes with URIToken logic. Ensures that default (0) STAmounts are recorded in metadata. Ensures that OfferID can be used instead of OfferSequence when cancelling an offer. Fixes a bug where certain hooks cannot be deleted. Fixes a bug where the quorum required for a `ttIMPORT` is accidentally too high. Allows accounts to appear more than once in a GenesisMint transaction. Changes the Issuer of a URIToken from strong to weak TSH when a URIToken is being burned. Ensures TSHes on escrows created by emitted transactions are correctly triggered. Adds hook parameters size fee to all txns (1 drop per byte). *(Introduced in 2024.9.11-release+985)*
##### fixXahauV2
[Section titled “fixXahauV2”](#fixxahauv2)
Cleans up TSH logic and removes old redundant table. Adds informational flags to each member of `sfHookExecutions`, describing weak, strong etc. execution. Adds `sfEmitNonce` to each member of `sfHookEmissions`, so as to better disambiguate emitted txns. Additional sanity checks on emitted txns to ensure they are placed into the correct ledger.
##### fixXahauV3
[Section titled “fixXahauV3”](#fixxahauv3)
Further fixes for Xahau protocol implementation issues. This amendment ensures consistency and sensible outcomes for various edge cases. This amendment is set to default: *yes* voting. If validators wish to vote against this amendment they must manually change their vote to no. *(Introduced in 2025.2.6-release+1299)*
##### fixNSDelete
[Section titled “fixNSDelete”](#fixnsdelete)
Fixes the behaviour of Hook State namespace deletion to ensure ledger consistency. Introduces a new tes code: `tesPARTIAL`. `tesPARTIAL` is returned if the transaction was successful but should be resubmitted by the user under a new sequence number to complete amortized work until `tesSUCCESS` is returned.
##### fix240819
[Section titled “fix240819”](#fix240819)
Bug fix amendment from August 19, 2024.
##### fixPageCap
[Section titled “fixPageCap”](#fixpagecap)
Fixes issues related to page capacity limits.
##### fix240911
[Section titled “fix240911”](#fix240911)
Bug fix amendment from September 11, 2024.
##### fixFloatDivide
[Section titled “fixFloatDivide”](#fixfloatdivide)
Fixes issues with floating point division operations in Hooks. This amendment ensures proper handling of division by zero and edge cases in the `float_divide` function. Changes the behaviour of the `float_divide` hook API to correct a small error. This amendment is set to default: *yes* voting. See [float\_divide](/docs/hooks/functions/float/float_divide) for details. *(Introduced in 2024.11.18-release+1141)*
##### fixReduceImport
[Section titled “fixReduceImport”](#fixreduceimport)
Fixes issues related to Import transaction processing. This amendment ensures consistency and sensible outcomes for various edge cases. This amendment is set to default: *yes* voting. If validators wish to vote against this amendment they must manually change their vote to no. *(Introduced in 2025.2.6-release+1299)*
##### fix20250131
[Section titled “fix20250131”](#fix20250131)
Bug fix amendment from January 31, 2025. This amendment ensures consistency and sensible outcomes for various edge cases. This amendment is set to default: *yes* voting. If validators wish to vote against this amendment they must manually change their vote to no. *(Introduced in 2025.2.6-release+1299)*
##### fixRewardClaimFlags
[Section titled “fixRewardClaimFlags”](#fixrewardclaimflags)
Fixes issues with reward claim transaction flags.
##### fixProvisionalDoubleThreading
[Section titled “fixProvisionalDoubleThreading”](#fixprovisionaldoublethreading)
Fixes issues with provisional double threading in transaction processing. Ensures the correct PreviousTxnID and transaction metadata are maintained in double threading scenarios. *(Introduced in 2025.7.9-release+1951)*
##### fixInvalidTxFlags
[Section titled “fixInvalidTxFlags”](#fixinvalidtxflags)
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)*
##### fixCronStacking
[Section titled “fixCronStacking”](#fixcronstacking)
Fixes issues with Cron transaction stacking behavior.
### Amendment Status
[Section titled “Amendment Status”](#amendment-status)
For the most current status of amendments (enabled, voting, or vetoed), check the [xahaud repository](https://github.com/Xahau/xahaud) or query a running `xahaud` server using the `feature` command.
# Balance Adjustments
> How to claim a Balance Adjustment on Xahau
### Opt-in + Claim
[Section titled “Opt-in + Claim”](#opt-in--claim)
Opting into Balance Adjustments is the same transaction as claiming an adjustment. You must do this first to kick off the ability to claim later.
```json
{
"Account": "",
"TransactionType": "ClaimReward",
"Issuer": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"NetworkID": 21337
}
```
### Opt-out
[Section titled “Opt-out”](#opt-out)
To opt-out of Balance Adjustments, omit the Issuer field and set Flags to 1. Doing this will delete your average balance statistics. These will not be restored. If you opt-in again, they will be reset to a starting position.
```json
{
"Account": "",
"TransactionType": "ClaimReward",
"NetworkID": 21337,
"Flags": 1
}
```
### Technical Details
[Section titled “Technical Details”](#technical-details)
Balance Adjustments are implemented as a combination of two pieces of code:
1. BalanceRewards Amendment (native code)
2. Genesis Account’s Reward Hook (hook code).
BalanceRewards collect average balance statistics about the accounts they are activated on. These statistics are then passed to a target Hook when the user wishes to claim.
All interactions with this amendment are via the ClaimReward transaction:
```json
{
"Account": "",
"TransactionType": "ClaimReward",
"Issuer": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"NetworkID": 21337
}
```
When a ClaimReward transaction is successfully submitted with a **tesSUCCESS** error code, the account’s average balance statistics are reset. The only other thing the amendment does is invoke the Hooks on the specified Issuer’s account.
The *Issuer* field is the account responsible for fulfilling the claim. Depending on what’s installed on the Issuer account, several things can happen:
* If no Hook is installed on the Issuer’s account, then nothing is done, and the BalanceRewards statistics are simply reset.
* If a Hook is installed on the Issuer’s account and the Hook performs a rollback, then the transaction fails, and the statistics are *not* reset.
* If a Hook is installed on the Issuer’s account and the Hook performs accept, then the transaction succeeds, and the statistics are reset. In this case, the Hook should also emit a transaction back to the user’s account containing their reward.
In practice, on Xahau, the Issuer will probably always be the genesis account **rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh**.
Unless:
* Network Governance results in a different account being used for BalanceAdjustments.
* A non-Governance party runs its own BalanceRewards giveaway that the user wants to be involved with. Note that successful claims result in the average balance statistics being reset, so only one type of reward can be claimed per reset.
The average balance statistics exist as a collection of three new fields on the AccountRoot object. These are:
| Field | Type | Explanation |
| --------------------- | ------ | --------------------------------------------------------------------------------------------- |
| `sfRewardAccumulator` | UINT64 | The area under of the balance-time graph for your account since last ClaimReward transaction. |
| `sfRewardLgrFirst` | UINT32 | The ledger number of the last ClaimReward transaction. |
| `sfRewardLgrLast` | UINT32 | The ledger sequence number of the last transaction in or out of your account. |
| `sfRewardTime` | UINT32 | The ledger time the last reward was claimed. |
# Burn 2 Mint (B2M)
> Burn2Mint is a low-level inter-chain primitive and is intended for enterprise users to self-supply their own liquidity as needed for their own purposes.
Caution
Since the ZeroB2M amendment has been voted in at Xahau, Burn 2 Mint (B2M) is no longer available to mint new assets. B2M is still available, but just for **key synchonisation** or to activate an account based (for which the information & procedures below are still relevant)
## Burn2Mint Technical Manual (Xahau Testnet)
[Section titled “Burn2Mint Technical Manual (Xahau Testnet)”](#burn2mint-technical-manual-xahau-testnet)
Caution
**This process is deliberately non-trivial and not designed for end users.** Mistakes result in a burn not being able to turn into a mint.
This is a warning that will appear on the production version of this document. You may disregard it because you are burning free testnet XRP in this instance.
Burn2Mint is a low-level inter-chain primitive intended for enterprise users to self-supply their liquidity as needed for their purposes. Running your own nodes and performing this operation yourself on your nodes means you and you alone bear responsibility for the outcome of the procedure.
The generation & collection of XPOPs fundamentally relies on collecting validation messages on the overlay network, which are ephemeral by nature. If your nodes are not reliably connected, or if your hardware, network connection, or operating system fails at the wrong point in time, then the XPOP for a Burn Transaction might not be generated or might not be generated correctly. This can lead to loss of funds as the Burn Transaction’s XPOP was not captured in time, and it’s possible the validation messages are lost forever, making a Mint Transaction impossible despite a successful Burn Transaction.
If you are not comfortable with taking these technical risks or do not understand what you are doing, or are not an enterprise user, then please source your liquidity via other friendly alternatives.
### Setup
[Section titled “Setup”](#setup)
To perform B2M, *two* XRPL protocol nodes should be operated by the user:
1. **Obtain xPOP from burn**
* xPOP Collector & Server (easier)
Run this (e.g., using Docker Compose; see repo Docs)\
[**https://github.com/Xahau/Validation-Ledger-Tx-Store-to-xPOP**](https://github.com/Xahau/Validation-Ledger-Tx-Store-to-xPOP)
* The service listens for XRPL validation messages, closed ledgers, and transactions.
* It stores this data in an organized file system.
* It is essential for generating xPOPs, as XRPL validation messages are ephemeral; without storing them, a transaction burn can’t be turned into a mint.
* **How it Works**:
* A watcher connects to multiple XRPL nodes and listens for specific data.
* The captured data is then saved, organized, and used to generate xPOPs
Simply fetch the xPOP now from:\
`http[s]://{your-host}:{your-port}/xpop/{tx-hash}`
You can easily fetch/create xPOPs from a node using the repo above using this NPM package:
[**https://www.npmjs.com/package/xpop**](https://www.npmjs.com/package/xpop)
* or: dedicated "Burning Node"
**Burn Node**, comprising:
* A modified Rippled instance (modified to record XPOPs)
* Universal linux binary here:
*
* Running a with a rippled.cfg that has:
* an **\[xpop\_dir]** stanza specifying an output directory for generated XPOPs.
* a **\[network\_id]** stanza specifying network\_id: 1
* (in production this would be network 0)
* a `validators.txt` containing:\\
```plaintext
[validator_list_sites]
https://vl.altnet.rippletest.net
[validator_list_keys]
ED264807102805220DA0F312E71FC2C69E1552C9C5790F6C25E3729DEB573D5860
```
2. **Mint**
* In this test scenario, you will connect directly to the Xahau. You do not need to run your own node. In the production scenario, you will need to run a Mint node, which is just a stock node for the target network. This is because public nodes will probably opt out of accepting Import transactions due to legal risk.
* Connect to **wss\://xahau-test.net**
* Or download download/run: [**https://github.com/Xahau/Xahau-Testnet-Docker**](https://github.com/Xahau/Xahau-Testnet-Docker)
## Sample (nodejs)
[Section titled “Sample (nodejs)”](#sample-nodejs)
This example creates a testnet account, burns 10 XRP & then imports this on Xahau Testnet, using the xPOP fetched using the tools mentioned above.
```js
import { derive, utils, signAndSubmit } from 'xrpl-accountlib'
import { TxData } from 'xrpl-txdata'
import { XrplClient } from 'xrpl-client'
import { xpop, setEndpoints as xpopEndpoints } from 'xpop'
import fetch from 'node-fetch'
// The above needs:
// npm install xrpl-accountlib xrpl-txdata xrpl-client xpop node-fetch
console.log('Obtaining XRPL Testnet account (faucet)')
const faucet = await (await fetch('https://faucet.altnet.rippletest.net/accounts', { method: 'POST' })).json()
console.log(' -->', faucet.account.address)
const account = derive.familySeed(faucet.account.secret)
xpopEndpoints((await (await fetch('https://xrpl.ws-stats.com/xpop/list?json=true')).json()).bestguess)
const nodes = {
testnet: [
new XrplClient('wss://s.altnet.rippletest.net:51233'),
new XrplClient('wss://testnet.xrpl-labs.com'),
],
xahau: [
new XrplClient('wss://xahau-test.net'),
]
}
console.log('Waiting for network connections to be ready')
await Promise.all(Object.keys(nodes).map(k => Promise.race(nodes[k].map(n => n.ready()))))
console.log('Waiting for faucet account funding & obtaining network values...')
await new Promise(resolve => setTimeout(resolve, 4000)) // Wait till ledger is closed
const [
testnetParams,
xahauParams,
] = await Promise.all([
Promise.race(nodes.testnet.map(n => utils.accountAndLedgerSequence(n, account))),
Promise.race(nodes.xahau.map(n => utils.accountAndLedgerSequence(n, account))),
])
const testnetTx = {
...testnetParams.txValues,
TransactionType: 'AccountSet',
Fee: String(10_000_000),
OperationLimit: xahauParams.txValues.NetworkID,
NetworkID: undefined, // Testnet has a NetworkID < 1024, so none should be provided
}
console.log('Submitting burn...', testnetTx)
const testnetSubmitted = await Promise.race(nodes.testnet.map(n => signAndSubmit(testnetTx, n, account)))
console.log('Submitted burn to testnet')
console.log(' -->', 'https://testnet.xrpl.org/transactions/' + testnetSubmitted.tx_id)
console.log('Obtaining burn tx data...')
const txdata = new TxData(nodes.testnet.map(n => n.getState().server.uri), {
AllowNoFullHistory: true,
EndpointTimeoutMs: 2_000,
OverallTimeoutMs: 10_000,
})
const appliedtx = await txdata.getOne(testnetSubmitted.tx_id)
console.log(' -->', 'Burn validated in ledger', appliedtx?.result?.ledger_index)
console.log('Waiting for closed ledger before fetching xPOP...')
await new Promise(resolve => setTimeout(resolve, 4000)) // Wait till ledger is closed
console.log('Fetching xPOP...')
const Blob = await xpop(testnetSubmitted.tx_id, appliedtx?.result?.ledger_index, 1)
console.log(' -->', 'xPOP fetched, hex strlen:', Blob.length)
const hooksTx = {
...xahauParams.txValues,
TransactionType: 'Import',
Fee: '0',
Blob,
}
console.log('Submitting for mint of xPOP...')
const b2mSubmitted = await Promise.race(nodes.xahau.map(n => signAndSubmit(hooksTx, n, account)))
console.log(' -->', 'B2M submitted! TX on Xahau Testnet:')
console.log(' -->', 'https://test.xahauexplorer.com/explorer/' + b2mSubmitted?.tx_id)
console.log(' -->', b2mSubmitted.response.engine_result, b2mSubmitted.response.engine_result_message)
// Closing connections
Object.keys(nodes).map(k => nodes[k].map(n => n.close()))
```
[Source](https://gist.github.com/WietseWind/cd8a7a8c88f218fe7b768f59a665685d)
## Technical Summary of B2M’s procedure
[Section titled “Technical Summary of B2M’s procedure”](#technical-summary-of-b2ms-procedure)
#### New Transaction Type: `Import`
[Section titled “New Transaction Type: Import”](#new-transaction-type-import)
Xahau Testnet (*network\_id=21338*) introduces a new transaction type called ***Import***, which accepts an XPOP from the Ripple testnet chain (*network\_id=1*) and provides for a “burn-to-mint” unidirectional value transfer and key / account synchronization.
### Burn Transaction
[Section titled “Burn Transaction”](#burn-transaction)
A ***Burn Transaction*** is a transaction that burns XRP on a source XRPL chain, which would be used as proof (XPOP) to mint on a destination XRPL chain.
The following are supported transaction types:
* AccountSet
* SetRegularKey
* SignerListSet.
Caution
Tickets ***are not accepted*** in **any** Burn Transactions and would lead to a Burn Transaction being invalid for minting. To protect against spam, transactions must be validated with a real, natural sequence number.
Note that other transaction types are not currently supported and cannot be used to mint on Xahau Testnet. (However, this may change).
All three transaction types can be used for minting. This means the ***Fee*** burned by the Burn Transaction is subsequently minted on Xahau Testnet after a successful `Import`.
If `SetRegularKey` or `SignerListSet` is used, then key synchronization occurs according to the standard rules of the transaction type. If `AccountSet` it is used, then no key synchronization occurs on the destination XRPL chain (Xahau Testnet).
A field called ***OperationLimit*** must be present on the Burn Transaction to be the destination chain’s Network ID. This field is to prevent replay attacks on other B2M-integrated chains.
The Burn Transaction may be used for Minting if it has either a **tesSUCCESS** transaction code or *any* of the **tec** transaction codes. Meaning *if* the fee was burnt, then the transaction can be used for minting. However, key synchronization *only* occurs when the Burn Transaction result was tesSUCCESS.
Example Burn Transaction:
```json
{
"TransactionType": "AccountSet",
"Fee": 10000000,
"OperationLimit": 21338
}
```
### XPOP Collection
[Section titled “XPOP Collection”](#xpop-collection)
Before submitting the Burn Transaction, ensure your Burn Node is synchronized with the testnet chain (Network ID: `1`).
After checking your Burn Node’s state, submit the signed Burn Transaction to the Burn Node.
The Burn Node watches closed ledgers for transactions containing the **OperationLimit** field and uses collected validation messages to generate an XPOP (Proof Of Burn). These are written to a file under the directory specified in **\[xpop\_dir]** stanza in the Burn Node’s `rippled.cfg`.
Wait for the ledger to close, then browse through the xpop\_dir for the Burn Transaction’s XPOP according to its TXID. The file contains a JSON document, which is the XPOP that you’ll be relaying to the destination XRPL chain (HooksV3).
Take the raw contents of this file and encode it as HEX. This will become the contents of the \**Blob* field in the `Import` transaction.
### Mint Transaction
[Section titled “Mint Transaction”](#mint-transaction)
Your binary codec will be missing the necessary fields to construct the `Import` (Mint) transaction. If you are using ripple-binary-codec, you can update its `definitions.json` file in the following way:
1. Change directory into `node_modules`
2. Run `find . | grep 'dist/enums/definitions.json'` to locate the relevant file to update
3. Connect to **wss\://hooks-testnet-v3.xrpl-labs.com**
4. Request: `{"command":"server_definitions"}`
5. Dump the contents of the `"result"` key into `definitions.json` from step 2.
The `Import` transaction type takes only one non-common field ***Blob.***. This must contain the HEX-encoded XPOP from the XPOP Collection phase.
* You can do this with `cat xpopjsonfile | xxd -p | tr -d '\n'`
The `Account` and `SigningPubKey` field (or Signers array) must match exactly between the Burn Transaction and the Mint Transaction. Users can only mint to the same account, which they burned from.
If the `Account` field specifies an account that does not yet exist on Xahau Testnet, and it will be created. In this case, use 0 for the `Sequence` field on the Mint Transaction. If the account already exists on Xahau Testnet, then use the next available Sequence number on the account on Xahau Testnet.
Example Import:
```json
{
"Account": "",
"TransactionType": "Import",
"Blob": "",
"Sequence": 0
}
```
IMPORTANT: **The Mint Transaction must be signed exactly the same way and by the same account as the Burn Transaction!**
Encode and sign the transaction appropriately, yielding a signed transaction blob (hex).
If you are not running your own Mint node:
* Connect to **wss\://xahau-testn.et**
* Submit the transaction to the node:
```json
{
"command": "submit",
"tx_blob": ""
}
```
Or, if you are running your own Mint node:
* Ensure the Mint Node is running and synchronised to Network ID 21338.
* Use the `submit` RPC call to submit the Mint Transaction.
* You can do this from command line using `./hooksv3d submit `
### Considerations
[Section titled “Considerations”](#considerations)
If the Account is to be created on Xahau Testnet but the keying for the account is unclear from the context of the Burn Transaction, then the Account is created in a blackholed mode. It can be subsequently rekeyed using either keying transaction type.
If the Burn Transaction is either a `SignerListSet` or a `SetRegularKey` transaction, then provided it had a tesSUCCESS transaction result on the source XRPL chain (testnet), that same keying operation is now applied to that same account on the destination XRPL chain (Xahau Testnet).
During testing, Accounts on Xahau Testnet *can* be deleted, however, on the production Hooks-enabled chain, they will not be able to be deleted.
Accounts on Xahau Testnet have an optional ***ImportSequence*** field in the AccountRoot. If **Import** has ever been used on that account on Xahau Testnet, this field is present and is populated with the most recently imported Burn Transaction’s Sequence number. This is to prevent replay attacks, but it also means that you should never submit your Burn2Mints out of sequence, otherwise the skipped transactions will never be accepted for Minting.
# Client Libraries
These client libraries simplify some of the common work of accessing and processing XAH Ledger data and present it in a form that matches the native conventions of their respective programming languages.
For other programming languages, you can access the XAH Ledger through the HTTP APIs.
| Language | Library Name | Get Started | Protocol | Source Code |
| ------------------------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------- |
| **Python** | `xahau-py` | [Get Started](https://github.com/Xahau/xahau-py) | XAH / XRP | [Repo](https://github.com/Xahau/xahau-py) |
| **JavaScript** / **TypeScript** | `xahau.js` | [Get Started](https://github.com/Xahau/xahau.js) | XAH / XRP | [Repo](https://github.com/Xahau/xahau.js) |
| **JavaScript** / **TypeScript** | [`xrpl-accountlib`](https://www.npmjs.com/package/xrpl-accountlib) | [Get started](https://www.npmjs.com/package/xrpl-accountlib) [Sample](https://github.com/WietseWind/xrpl-accountlib/blob/master/samples/prefill-sign-and-submit.mjs) | XAH / XRP | [Repo](https://github.com/WietseWind/xrpl-accountlib) |
**Tip:** To add a client library not listed here, please suggest changes to this page!
# Curated Tooling
These tools simplify some of the common work of accessing and processing Hooks.
| Tool | Reference Link |
| --------------------- | ---------------------------------------------------------------- |
| **Hooks Builder** | [Builder Link](https://builder.xahau.network/develop) |
| **Hooks Toolkit** | [Toolkit Link](https://hooks-toolkit.com/) |
| **Xpop Toolkit** | [Toolkit Link](https://github.com/Transia-RnD/xpop-toolkit) |
| **Hooks Blog** | [Blog Link](https://dev.to/t/xrplhooks/top/infinity) |
| **XFL Tools** | [Tool Link](https://richardah.github.io/xfl-tools/) |
| **Binary Visualizer** | [Tool Link](https://richardah.github.io/xrpl-binary-visualizer/) |
| **Keylet Tools** | [Tool Link](https://richardah.github.io/xrpl-keylet-tools/) |
| **CTID Visualizer** | [Tool Link](https://transia-rnd.github.io/xrpl-ctid-visualizer/) |
| **C Hook Tx Builder** | [Tool Link](https://transia-rnd.github.io/xrpl-tt-visualizer/) |
# Developer Tricks
## Wildcard signing
[Section titled “Wildcard signing”](#wildcard-signing)
To easily test & replay, use `NetworkID` with value `65535` (config: `[network_id]`) to disable signature verification.
Added:
## Server Definitions
[Section titled “Server Definitions”](#server-definitions)
Server definitions can easily be fetched from public nodes. These definitions include binary codec information and other network-specific data needed for transaction serialization and deserialization.
### Mainnet
[Section titled “Mainnet”](#mainnet)
* [`https://xahau.network/server_definitions.json`](https://xahau.network/server_definitions.json)
### Testnet
[Section titled “Testnet”](#testnet)
* [`https://xahau-test.net/server_definitions.json`](https://xahau-test.net/server_definitions.json)
### JSHooks-Testnet
[Section titled “JSHooks-Testnet”](#jshooks-testnet)
* [`https://jshooks.xahau-test.net/server_definitions.json`](https://jshooks.xahau-test.net/server_definitions.json)
These server definitions are essential for:
* Binary codec operations
* Transaction serialization
* Field type definitions
* Network-specific constants
You can use these definitions in your applications to properly encode and decode transactions for the Xahau network.
# Faucet & Explorers
The Xahau Faucet & Explorers can be found here:
## Testnet
[Section titled “Testnet”](#testnet)
* **Faucet:** [**https://xahau-test.net**](https://xahau-test.net)
* To automate funding accounts on testnet, HTTP POST to:\
\
Empty body: new account (prefunded)\
JSON body with `destination` property: fund the mentioned `destination` account.
* **Explorers:**
* **Xahauexplorer:** [**https://test.xahauexplorer.com**](https://test.xahauexplorer.com)
* **InFTF:** [**https://explorer.xahau-test.net**](https://explorer.xahau-test.net)
* **XRPL.org:** [**https://xahau-testnet.xrpl.org**](https://xahau-testnet.xrpl.org)
* **XRPLWin:** [**https://xahau-testnet.xrplwin.com**](https://xahau-testnet.xrplwin.com/)
## Mainnet
[Section titled “Mainnet”](#mainnet)
* **Homepage:** [**https://xahau.network**](https://xahau.network/)
* **Explorers:**
* **Xahauexplorer:** [**https://xahauexplorer.com**](https://xahauexplorer.com/)
* **Xahscan:** [**https://xahscan.com/**](https://xahscan.com/)
* **InFTF:** [**https://explorer.xahau.network**](https://explorer.xahau.network/)
* **XRPL.org:** [**https://xahau.xrpl.org**](https://xahau.xrpl.org)
* **XRPLWin:** [**https://xahau.xrplwin.com**](https://xahau.xrplwin.com/)
# Governance Game
> The Governance Game is an innovative governance mechanism within the Xahau ecosystem to ensure a community-centric approach towards decision-making.
### Overview
[Section titled “Overview”](#overview)
The Xahau Governance Game allows up to 400 stakeholders to democratically participate in the management of the Xahau network via the Governance Hook installed on the Genesis Account.
### Layer 1
[Section titled “Layer 1”](#layer-1)
The game consists of a “Layer 1” table at which there are 20 seats. A Xahau account (r-address) may fill each seat, or it may be empty. When a seat is filled, it is said that a member of the table sits there.
To play the game, the members of the table cast votes. The votes are for one of three types of topics:
* Seat topics
* Hook topics
* Reward topics.
Seat topics are S00 through S19 and represent a vote for who (if anyone) currently sits in that seat. A vote of 80% is sufficient to make a change. The voting process is continuous, with the final vote that crosses the threshold actioning the change.
Hook topics are H0 through H9 and represent which Hooks, including the Governance Hook itself, are installed on the table’s account. These topics require 100% of the members seated at that table to agree before a change can be made. This allows the Governance Game to be updated and for more Genesis account features to be added over time.
Reward topics are RR and RD, which stand for Reward-Rate and Reward-Delay, respectively. These topics also require 100% of the members at the table to agree in order to make a change. These parameters affect the BalanceAdjustments system: how much each active user on the network can claim and how often.
### Layer 2
[Section titled “Layer 2”](#layer-2)
The members who fill seats on the Layer 1 table are Xahau accounts (r-addresses). The governance game is designed to be structurally recursive, such that one of these accounts may itself be a table consisting of another 20 seats. This is called a Layer 2 table, and the seats are Layer 2 seats.
Within a Layer 2 table, the same seat voting and hook voting topics exist, with the same voting rules as the Layer 1 table. This allows a table to govern its own membership and the hooks that run there.
In addition to these topics, a Layer 2 table may also, by a 51% vote, raise a vote to the Layer 1 table. This is a vote on behalf of the r-address that the Layer 2 table exists on and counts as a single vote at the Layer 1 table.
The Layer 2 table vote may fall below 51%, in which case the vote originally raised to the Layer 1 table is **not** retracted. Only a new (different) vote attaining 51% can change the table’s vote at Layer 1.
Layer 2 tables can only vote on Reward topics via a vote raised to Layer 1.
In summary, Layer 2 members can vote for:
* Seats and Hooks for their own table, and
* Seats, Hooks, and Reward topics for the L1 table via the Layer 1 seat their Layer 2 table resides in.
### Game Constraints
[Section titled “Game Constraints”](#game-constraints)
* Any table may have at least 2 members and at most 20 members.
* A single r-address can only occupy one seat at a given table but may occupy one seat at each of many different tables.
* The Governance Game is not designed to recurse beyond two layers. There’s no technical infeasibility in implementing a Layer 3 table, but the current Governance Hook does not support it.
### Validator Rewards
[Section titled “Validator Rewards”](#validator-rewards)
Validator rewards are an incentive for running a validator on the network. The rewards are generated by the network and granted to the intersection of Layer 1 members and active UNL validators. To qualify for validator rewards within a given block of 256 ledgers, the following must be true:
* The validator is on the Xahau UNL.
* The validator validates successfully in the eyes of other UNL validators.
* When the validator’s master public key is converted to an r-address, that account sits at the L1 Table.
Rewards are ad-hoc and based on Xahau users’ Balance Adjustments. When a user performs a Balance Adjustment, an amount equal to their adjustment divided by 20 is sent to the r-address of each of the active validators that meet the above criteria.
## Technical Specification
[Section titled “Technical Specification”](#technical-specification)
The Governance Hook is installed on the genesis account by the XahauGenesis amendment several ledgers after ledger 1 on a new network. This is the L1 table. To create an L2 table, install the Hook on a different account, then seat that account at the L1 table.
### Governance Hook Parameters
[Section titled “Governance Hook Parameters”](#governance-hook-parameters)
When the Governance Hook is installed, it is installed with a set of HookParameters. These specify the initial composition of the table.
Each HookParameter has a 3-byte name consisting of either 3 Ascii characters or 2 Ascii characters and an identifier as below. LE = Little Endian.
```plaintext
Parameter Name: {'I', 'R', 'R'}
Parameter Value: Initial Reward Rate <8 byte XFL fraction between 0 and 1, LE>
Parameter Name: {'I', 'R', 'D'}
Parameter Value: Initial Reward Delay <8 byte LE XFL seconds between rewards>
Parameter Name: {'I', 'M', 'C'}
Parameter Value: Initial Member Count <1 byte>
Parameter Name: {'I', 'S', 0x00}
Parameter Value: Initial seat #0's member's 20 byte Account ID.
Parameter Name: {'I', 'S', 0x01}
Parameter Value: Initial seat #1's member's 20 byte Account ID.
... etc ... up to at most Seat 19.
```
To kick-off the game, an Invoke transaction must be sent to the Hook. This may be sent by any account. No Blob or HookParameters are required. This Invoke transaction triggers the Hook for the first time and prompts it to create state entries for each initial seat, reward rate, and reward delay.
### Governance Hook State
[Section titled “Governance Hook State”](#governance-hook-state)
The Hook State of the Governance Hook is stored in the zero namespace: `0000000000000000000000000000000000000000000000000000000000000000.`
There are several types of state entry. The first is what are referred to as forward and reverse member keys. These map each seat number to the member who sits there and each member to the seat they sit at.
```plaintext
Key: 0x0000000000000000000000000000000000000000000000000000000000000005
Val: <20 byte AccountID of the member at seat 5 or all 0's or absent.>
Key: <20 byte AccountID of the member at seat 3>
Val: 0x03
```
Next, there are some singleton state entries. Member Count, Reward Rate, and Reward Delay, respectively:
```plaintext
Key in Ascii: MC
Key: 0x0000000000000000000000000000000000000000000000000000000000004D43
Val: <1 byte member count (how many seats are occupied)>
Key in Ascii: RR
Key: 0x0000000000000000000000000000000000000000000000000000000000005252
Val: <8 byte LE XFL reward rate (between 0 and 1 (1 being 100%))>
Key in Ascii: RD
Key: 0x0000000000000000000000000000000000000000000000000000000000005244
Val: <8 byte LE XFL reward delay in seconds>
```
Finally, votes and vote counters are also stored in Hook state. When a vote is cast by a seat it is recorded in Hook state as follows:
```plaintext
Vote key is 32 bytes comprising:
'V' (0x56) - vote
'H' (0x48) or 'R' (0x52) or 'S' (0x53) - topic type
'R' (0x52) or 'D' (0x44) or 0 (0x00) to 19 (0x13) - topic detail
1 (0x01) or 2 (0x02) - target layer for this vote
0x00 00 00 00 00 00 00 00 - 8 bytes of padding
20 byte Account ID - the voter
Vote data:
20 byte Account ID or 8 byte XFL
```
When a vote is cast, it increments a vote counter-state entry. This counter keeps track of how many votes there currently are for this topic-data pair and allows the Hook to action the vote when voting crosses the required threshold. The counter state is as follows:
```plaintext
Counter key is 32 bytes comprising:
'C' (0x43) - count
'H' (0x48) or 'R' (0x52) or 'S' (0x53) - topic type
'R' (0x52) or 'D' (0x44) or 0 (0x00) to 19 (0x13) - topic detail
1 (0x01) or 2 (0x02) - target layer for this vote
0's for padding
vote data or left-truncated vote data
```
### Governance Hook Transactions
[Section titled “Governance Hook Transactions”](#governance-hook-transactions)
The Governance Hook is interacted with by its members using ttINVOKE transactions. In addition to this, the Hook may also emit its own ttINVOKE transactions if it is an L2 table raising a vote to the L1 table.
A vote transaction contains a HookParameters array at the top level of the transaction:
```plaintext
{
Account: ,
TransactionType: Invoke,
NetworkID: 21337,
Destination: ,
HookParameters:
[
{
HookParameter:
{
HookParameterName: "4C", // L - the target layer
HookParameterValue: "01", // 01 for L1 table, 02 for L2 table
// note: this is the table the vote is
// intended for, not the table you're at
// i.e. for a L2 table you can vote on
// your own membership or on L1's
}
},
{
HookParameter:
{
HookParameterName: "54", // T - topic type
HookParameterValue: "4801", // H [0x00-0x09] or
// S [0x00-0x13] or
// RR or RD
}
},
{
HookParameter:
{
HookParameterName: "56", // V - vote data
HookParameterValue: <32 or 20 or 8 bytes of vote data>
}
}
]
}
```
### Clearing a Vote
[Section titled “Clearing a Vote”](#clearing-a-vote)
There is no way to “delete a vote” per se. You can change your vote back to reflect the current position instead.
So, for example, if no one sits at seat 8 and you have voted for account A to sit there, and then you change your mind, you can make a vote to vacate seat 8 (even though it’s already vacant) thus aligning your vote with the current state of the seat.
To do this, you vote with all 0’s in the vote data, to the same length as the vote topic normally requires. So, for a seat vote, this is 20 bytes of 0.
# Admin API Methods
These methods are intended exclusively for trusted personnel responsible for maintaining xahaud server operations.
### Key Generation Methods
[Section titled “Key Generation Methods”](#key-generation-methods)
| Method | Description |
| ------------------ | --------------------------------------------------------------------------------------------------------------- |
| validation\_create | Generate a formatted key pair for xhaud nodes. (Validators should use tokens instead of keys from this method.) |
| wallet\_propose | Generate keys for a new account. |
### Logging and Data Management Methods
[Section titled “Logging and Data Management Methods”](#logging-and-data-management-methods)
| Method | Description |
| --------------- | --------------------------------------------------------------- |
| can\_delete | Enable online deletion of ledgers up to a specified ledger. |
| download\_shard | Download a specific shard of ledger history. |
| ledger\_cleaner | Set up the ledger cleaner to detect and resolve corrupted data. |
| ledger\_request | Query a peer server for a specific ledger version. |
| log\_level | View or change log verbosity levels. |
| logrotate | Reopen the log file. |
| node\_to\_shard | Transfer data from the ledger store to the shard store. |
### Server Control Methods
[Section titled “Server Control Methods”](#server-control-methods)
| Method | Description |
| -------------- | ------------------------------------------------- |
| ledger\_accept | Close and advance the ledger in stand-alone mode. |
| stop | Shut down the xahaud server. |
### Signing Methods
[Section titled “Signing Methods”](#signing-methods)
| Method | Description |
| --------- | ------------------------------------- |
| sign | Cryptographically sign a transaction. |
| sign\_for | Contribute to a multi-signature. |
### Peer Management Methods
[Section titled “Peer Management Methods”](#peer-management-methods)
| Method | Description |
| ------------------------ | -------------------------------------------------- |
| connect | Force the server to connect to a specific peer. |
| peer\_reservations\_add | Add or update a reserved slot for a specific peer. |
| peer\_reservations\_del | Remove a reserved slot for a specific peer. |
| peer\_reservations\_list | View all reserved peer slots. |
| peers | Retrieve information about connected peers |
### Status/Debugging Methods
[Section titled “Status/Debugging Methods”](#statusdebugging-methods)
| Method | Description |
| ---------------------- | ----------------------------------------------------------- |
| consensus\_info | View the current state of the consensus process. |
| feature | Retrieve information about protocol amendments. |
| fetch\_info | Check the server’s synchronization status with the network. |
| get\_counts | View statistics about server internals and memory usage. |
| manifest | Retrieve public key details for a known validator. |
| print | Access information about internal subsystems. |
| validator\_info | Get the server’s validator configuration details. |
| validator\_list\_sites | View sites that publish validator lists. |
| validators | Retrieve information about the current validators. |
# Considerations
## Markers
[Section titled “Markers”](#markers)
Some methods return more data than can fit efficiently into a single response. When the results exceed the response limit, a `marker` field is included in the response. This field allows you to retrieve additional pages of data through subsequent requests. To continue fetching data, include the `marker` value from the previous response in your next request. If a response does not include a `marker`, it means you have reached the end of the data set.
The format of the `marker` field is intentionally unspecified. Each server can define the `marker` as needed, meaning it could be a string, a nested object, or another type. The `marker` format may vary between servers and even between methods on the same server. Each `marker` is temporary and may become invalid after approximately 10 minutes.
## Rate Limit
[Section titled “Rate Limit”](#rate-limit)
The `xahaud` server enforces rate limits on API clients using public APIs to prevent excessive requests. Rate limiting is applied based on the client’s IP address, meaning multiple clients sharing a [network address translation (NAT)](https://en.wikipedia.org/wiki/Network_address_translation) will share the same rate limit associated with their public IP.
When a client is nearing the rate limit, the server includes a `"warning": "load"` field at the top level of an API response. This warning does not appear on every response but may be sent several times before the server disconnects the client. Clients connected as an admin are exempt from rate limiting.
If a client exceeds the rate limit, the server disconnects the client and temporarily blocks further requests from that IP address. The WebSocket and JSON-RPC APIs handle disconnects differently, as described below.
# get_aggregate_price
> 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
[Section titled “Request Format”](#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
[Section titled “Request Parameters”](#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–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"`. |
### Response Format
[Section titled “Response Format”](#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
[Section titled “Response Fields”](#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
[Section titled “Algorithm”](#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
[Section titled “Error Cases”](#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–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. |
### Limits
[Section titled “Limits”](#limits)
| Parameter | Limit |
| ------------- | ----------------------------------------------------- |
| `oracles` | Max 200 entries per request |
| History depth | Max 3 historical metadata entries searched per oracle |
| `trim` | 1–50 (%) |
# Public API Methods
Interact directly with an xahaud server using public API methods. These methods are not necessarily intended for general public use but are accessible to any client connected to the server.
### Account Methods
[Section titled “Account Methods”](#account-methods)
| Method | Description |
| ------------------- | ---------------------------------------------------------------------- |
| account\_channels | List payment channels where the account is the channel source. |
| account\_currencies | List currencies the account can send or receive. |
| account\_info | Retrieve basic information about an account. |
| account\_lines | Access trust line information for an account. |
| account\_objects | Retrieve all ledger objects owned by an account. |
| account\_offers | View an account’s currency exchange offers. |
| account\_tx | Retrieve transaction history for an account. |
| gateway\_balances | Calculate total issued amounts for an account. |
| noripple\_check | Suggest changes to an account’s Default Ripple and No Ripple settings. |
### Ledger Methods
[Section titled “Ledger Methods”](#ledger-methods)
| Method | Description |
| --------------- | -------------------------------------------------- |
| ledger | Get information about a specific ledger version. |
| ledger\_closed | Retrieve the most recently closed ledger version. |
| ledger\_current | Retrieve the current working ledger version. |
| ledger\_data | Access raw ledger content. |
| ledger\_entry | Retrieve a specific element from a ledger version. |
### Transaction Methods
[Section titled “Transaction Methods”](#transaction-methods)
| Method | Description |
| ------------------- | ---------------------------------------------------------- |
| submit | Submit a transaction to the network. |
| submit\_multisigned | Submit a multi-signed transaction. |
| transaction\_entry | Retrieve details about a transaction in a specific ledger. |
| tx | Retrieve transaction information across all ledgers. |
| sign | (Admin) Cryptographically sign a transaction. |
| sign\_for | (Admin) Contribute to a multi-signature. |
### Order Book Methods
[Section titled “Order Book Methods”](#order-book-methods)
| Method | Description |
| ------------------- | ----------------------------------------------------------- |
| book\_offers | View offers for exchanging two currencies. |
| deposit\_authorized | Check if one account can send payments directly to another. |
### Payment Channel Methods
[Section titled “Payment Channel Methods”](#payment-channel-methods)
| Method | Description |
| ------------------ | ----------------------------------------- |
| channel\_authorize | Sign a claim for a payment channel |
| channel\_verify | Verify a payment channel claim signature. |
### Subscription Methods
[Section titled “Subscription Methods”](#subscription-methods)
| Method | Description |
| ----------- | ------------------------------- |
| subscribe | Listen for updates on a subject |
| unsubscribe | Stop receiving updates |
### Server Info Methods
[Section titled “Server Info Methods”](#server-info-methods)
| Method | Description |
| ------------- | --------------------------------------------- |
| fee | Retrieve information about transaction costs. |
| server\_info | Get server status in human-readable format. |
| server\_state | Get server status in machine-readable format. |
| manifest | Retrieve public key details for a validator. |
### Oracle Methods
[Section titled “Oracle Methods”](#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
[Section titled “Utility Methods”](#utility-methods)
| Method | Description |
| ------ | ---------------------------------------------------------------------- |
| json | Proxy for running commands with JSON parameters. *(Commandline only.)* |
| ping | Verify server connectivity. |
| random | Generate random numbers. |
# Request Formatting Guide
### Public Servers
[Section titled “Public Servers”](#public-servers)
* wss\://xahau.network or (Mainnet)
* wss\://xahau-test.net or (Testnet)
### Sample Requests
[Section titled “Sample Requests”](#sample-requests)
To send a sample request to the API, use the following commands.
### Websocket
[Section titled “Websocket”](#websocket)
```plaintext
{
"id": 3,
"command": "account_info",
"account": "rhBDFMmr3jSjgsWMqBAYaATLy3PuXy395y",
"strict": true,
"ledger_index": "validated",
"api_version": 1
}
```
### WebSocket Request Structure
[Section titled “WebSocket Request Structure”](#websocket-request-structure)
Once you establish a WebSocket connection to the `xahaud` server, you can send commands as JSON objects with these fields:
| Field | Type | Description |
| ------------ | ---------- | ----------------------------------------------- |
| command | String | The name of the API method |
| id | (Multiple) | *(Optional)* Unique identifier for the request. |
| api\_version | Number | *(Optional)* Specifies the API version. |
### JSON-RPC
[Section titled “JSON-RPC”](#json-rpc)
```plaintext
POST https://xahau.network/
Content-Type: application/json
{
"method": "account_info",
"params": [
{
"account": "rhBDFMmr3jSjgsWMqBAYaATLy3PuXy395y",
"strict": true,
"ledger_index": "validated",
"api_version": 1
}
]
}
```
### JSON-RPC Request Structure
[Section titled “JSON-RPC Request Structure”](#json-rpc-request-structure)
| Field | Type | Description |
| ------ | ------ | ----------------------------------------------------------------------------------------- |
| method | String | The name of the API method |
| params | Array | *(Optional)* A one-item array containing a JSON object with the parameters of the method. |
### Comandline
[Section titled “Comandline”](#comandline)
```plaintext
xahaud account_info rhBDFMmr3jSjgsWMqBAYaATLy3PuXy395y validated strict
```
### Commandline Request Structure
[Section titled “Commandline Request Structure”](#commandline-request-structure)
| Field | Description |
| ------ | -------------------------------- |
| xahaud | Start calling the service xahaud |
| method | The name of the API method |
| params | (Optional) |
# Response Formatting Guide
Responses are structured differently based on whether the request is made through the WebSocket, JSON-RPC, or Commandline interfaces. The JSON-RPC and Commandline interfaces share the same format, as the Commandline interface internally uses JSON-RPC.
### Fields
[Section titled “Fields”](#fields)
| Field | Type | Description |
| ------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | (Varies) | (For WebSocket) The ID from the original request. |
| status | String | (For WebSocket) Indicates `success` when the request was received and processed correctly. |
| result.status | String | (For JSON-RPC and Commandline) Indicates `success` when the request was successfully processed. |
| type | String | (For WebSocket) The value `response` is used for direct replies to API requests. Asynchronous notifications use other values, such as `ledgerClosed` or `transaction`. |
| result | Object | Contains the query result, with content that varies by command. |
| warning | String | *(Optional)* If present, the value is `load`, indicating the client is nearing the rate limit threshold where the server may disconnect. |
| warnings | Array | *(Optional)* A list of **Warning Objects** with important server warnings. For more details, see API Warnings. |
| forwarded | Boolean | *(Optional)* `true` indicates the request was forwarded from a Reporting Mode server to a P2P server to fulfill the request. Default is `false`. |
API Warnings
When a response contains a `warnings` array, each entry represents a specific warning from the server. Each **Warning Object** includes the following fields:
| Field | Type | Description |
| ------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | Number | A unique numeric code identifying this warning message. |
| message | String | A human-readable explanation of the warning. Avoid writing code that relies on the content of this field; use the `id` (and `details`, if available) to interpret the warning instead. |
| details | Object | *(Optional)* Additional context about the warning. The content varies by warning type. |
# Account Managment
The Account Management features in the Xahau network are a crucial component for users to manage their accounts effectively.
This includes several transaction types that enable users to perform various operations on their accounts.
### Transaction Types
[Section titled “Transaction Types”](#transaction-types)
#### AccountSet
[Section titled “AccountSet”](#accountset)
The `AccountSet` transaction type allows users to modify the properties of their accounts. This includes settings such as transfer rate, account flags, and more.
[AccountSet ](/docs/protocol-reference/transactions/transaction-types/accountset)
#### AccountDelete
[Section titled “AccountDelete”](#accountdelete)
The `AccountDelete` transaction type enables users to delete their accounts from the Xahau network. This operation is irreversible and should be used with caution.
[AccountDelete ](/docs/protocol-reference/transactions/transaction-types/accountdelete)
#### SetRegularKey
[Section titled “SetRegularKey”](#setregularkey)
The `SetRegularKey` transaction type allows users to set a regular key pair for their account. This key pair can be used as an alternative to the master key pair for signing transactions.
[SetRegularKey ](/docs/protocol-reference/transactions/transaction-types/setregularkey)
#### SignerListSet
[Section titled “SignerListSet”](#signerlistset)
The `SignerListSet` transaction type enables users to set a list of signers for their account. This is particularly useful for multi-signature accounts where multiple parties are required to sign off on transactions.
[SignerListSet ](/docs/protocol-reference/transactions/transaction-types/signerlistset)
#### Import
[Section titled “Import”](#import)
The `Import` transaction type is used to import transactions from other networks. This feature is especially useful for issuers who need to import transactions for their asset holders. It’s recommended to key your accounts first before attempting to import transactions.
Please note that the process of importing for the issuer involves specific transaction types and requires careful configuration. Always ensure that the hooks are correctly set up and that the transactions are valid for the intended operations.
[Import ](/docs/protocol-reference/transactions/transaction-types/import)
These transaction types provide users with a comprehensive set of tools for managing their accounts on the Xahau network. As with all operations, users should ensure they understand the implications of each transaction type before use.
# Balance Rewards
The Balance Rewards feature is a unique aspect of the Xahau network that allows users to accumulate and claim rewards based on their account balance. This feature is implemented through a combination of native code (BalanceRewards Amendment) and hook code (Genesis Account’s Reward Hook).
### Transaction Types
[Section titled “Transaction Types”](#transaction-types)
#### ClaimReward
[Section titled “ClaimReward”](#claimreward)
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 by setting the Flags field to 1.
[ClaimReward ](/docs/protocol-reference/transactions/transaction-types/claimreward)
#### GenesisMint
[Section titled “GenesisMint”](#genesismint)
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.
[GenesisMint - (Emitted Txn) ](/docs/protocol-reference/transactions/transaction-types/genesismint-emitted-txn)
### IOU Reward Claim
[Section titled “IOU Reward Claim”](#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
[Section titled “How it works”](#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 `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
[Section titled “Key differences from XAH genesis rewards”](#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 |
| Issuer restriction | Must be genesis account | Any account with a Hook on `ClaimReward` transaction, except AMM accounts |
# Check
The Check feature in the Xahau network is a deferred payment system that allows for the creation, cancellation, and cashing of checks within the ledger. This feature is designed to facilitate secure and efficient transactions between parties.
### Transaction Types
[Section titled “Transaction Types”](#transaction-types)
#### CheckCreate
[Section titled “CheckCreate”](#checkcreate)
The `CheckCreate` transaction is used to create a Check object in the ledger. This represents a deferred payment that can be cashed by its intended destination.
[CheckCreate ](/docs/protocol-reference/transactions/transaction-types/checkcreate)
#### CheckCancel
[Section titled “CheckCancel”](#checkcancel)
The `CheckCancel` transaction is used to cancel a Check that has been created but not yet cashed. This allows the sender to stop the payment from being processed if necessary.
[CheckCancel ](/docs/protocol-reference/transactions/transaction-types/checkcancel)
#### CheckCash
[Section titled “CheckCash”](#checkcash)
The `CheckCash` transaction is used to cash a Check that has been created. This allows the recipient to receive the funds that have been deferred.
[CheckCash ](/docs/protocol-reference/transactions/transaction-types/checkcash)
# Escrow
The Escrow feature is a crucial part of the Xahau network. It provides a secure and trustless method for transactions between parties. The Escrow feature ensures that the assets involved in a transaction are held securely until all the conditions of the transaction are met.
### Transaction Types
[Section titled “Transaction Types”](#transaction-types)
The Escrow feature includes three types of transactions:
#### EscrowCreate
[Section titled “EscrowCreate”](#escrowcreate)
The `EscrowCreate` transaction is used to create a new escrow agreement. This transaction specifies the terms of the escrow, including the parties involved, the assets to be held in escrow, and the conditions under which the assets will be released.
[EscrowCreate ](/docs/protocol-reference/transactions/transaction-types/escrowcreate)
#### EscrowFinish
[Section titled “EscrowFinish”](#escrowfinish)
The `EscrowFinish` transaction is used to complete an escrow agreement. This transaction is executed when all the conditions of the escrow are met. Upon execution, the assets held in escrow are released to the appropriate party.
[EscrowFinish ](/docs/protocol-reference/transactions/transaction-types/escrowfinish)
#### EscrowCancel
[Section titled “EscrowCancel”](#escrowcancel)
The `EscrowCancel` transaction is used to cancel an escrow agreement. This transaction can be executed if the conditions of the escrow are not met within a specified time frame. Upon cancellation, the assets held in escrow are returned to the party that initiated the escrow.
[EscrowCancel ](/docs/protocol-reference/transactions/transaction-types/escrowcancel)
# Hooks
Hooks are a powerful feature of the XRPL network, providing robust smart contract functionality. They are small, efficient WebAssembly modules designed specifically for the XRPL, and can be referred to as Smart Contracts for the XRP Ledger Protocol. Hooks can be written in any language that is compilable with WebAssembly, allowing for a wide range of business logic and smart contract concepts to be implemented.
### Transaction Types
[Section titled “Transaction Types”](#transaction-types)
The Hooks feature includes two types of transactions:
**SetHook**
This transaction type is used to set up a hook on an account.
[SetHook ](/docs/protocol-reference/transactions/transaction-types/sethook)
**Invoke**
This transaction type is used to call or invoke the functionality of a hook.
[Invoke ](/docs/protocol-reference/transactions/transaction-types/invoke)
# Offer
The Offer feature in the Xahau network is a crucial component of the decentralized exchange system. It allows users to create and cancel offers, facilitating a dynamic and responsive trading environment.
### Transaction Types
[Section titled “Transaction Types”](#transaction-types)
#### OfferCreate
[Section titled “OfferCreate”](#offercreate)
The `OfferCreate` transaction is used to place an offer in the decentralized exchange.
[OfferCreate ](/docs/protocol-reference/transactions/transaction-types/offercreate)
#### OfferCancel
[Section titled “OfferCancel”](#offercancel)
The `OfferCancel` transaction is used to cancel an existing offer. The documentation for this transaction type is referenced in the Xahau Documentation but not provided in the given context.
[OfferCancel ](/docs/protocol-reference/transactions/transaction-types/offercancel)
# Payments
The Payments feature in the Xahau network is a crucial component that enables the transfer of assets and funds within the network. This feature is designed to facilitate seamless transactions, ensuring a smooth and efficient operation of the network.
### Transaction Types
[Section titled “Transaction Types”](#transaction-types)
The Payments feature comprises several transaction types, each serving a unique purpose in the network. Here’s a brief overview of each transaction type:
**DepositPreauth**
This transaction type allows an account to preauthorize incoming transactions from a specified source. It’s a way to whitelist accounts, ensuring that only authorized transactions are processed.
[DepositPreauth ](/docs/protocol-reference/transactions/transaction-types/depositpreauth)
**TrustSet**
This transaction type allows users to create a trust line with another account. It’s a way to establish trust between two accounts, enabling them to transact with each other.
[TrustSet ](/docs/protocol-reference/transactions/transaction-types/trustset)
**Payment**
This is the basic transaction type that allows the transfer of assets between accounts. It’s the fundamental transaction type for any payment operation in the network.
[Payment ](/docs/protocol-reference/transactions/transaction-types/payment)
**PaymentChannelCreate**
This transaction type allows the creation of a payment channel between two accounts. Payment channels are off-ledger scalability solutions that enable high-frequency, low-cost transactions between two parties.
[PaymentChannelCreate ](/docs/protocol-reference/transactions/transaction-types/paymentchannelcreate)
**PaymentChannelFund**
This transaction type allows an account to fund an existing payment channel. It’s a way to add more assets to a payment channel, enabling more transactions to take place.
[PaymentChannelFund ](/docs/protocol-reference/transactions/transaction-types/paymentchannelfund)
**PaymentChannelClaim**
This transaction type allows an account to claim the funds from a payment channel. It’s a way to close a payment channel and retrieve the remaining assets.
[PaymentChannelClaim ](/docs/protocol-reference/transactions/transaction-types/paymentchannelclaim)
# URIToken
URITokens are the Non-Fungible Token (NFT) implementation native to the Xahau network. They exist as first-class on-ledger objects, uniquely identified by the hash of their issuer and Uniform Resource Identifier (URI). URITokens can point to any digital content, with only one object per URI per account existing on the ledger.
The issuer has the ability to set a flag to enable the burning of the object in the future. Each owner’s reserve is locked up as well upon ownership of the URIToken.
### Transaction Types
[Section titled “Transaction Types”](#transaction-types)
#### URITokenMint
[Section titled “URITokenMint”](#uritokenmint)
The URITokenMint transaction mints a new URIToken and assigns ownership to the specified account. The minted URIToken represents a unique digital asset that can be used in various applications. The issuer can choose to allow the minted URIToken to be destroyed in the future.
[URITokenMint ](/docs/protocol-reference/transactions/transaction-types/uritokenmint)
#### URITokenBurn
[Section titled “URITokenBurn”](#uritokenburn)
The URITokenBurn transaction is used to burn a URIToken in Xahau. Burning a URIToken permanently removes it from circulation. The transaction does not have any special transaction cost requirements. The account that owns the URIToken to be burned is required for this transaction.
[URITokenBurn ](/docs/protocol-reference/transactions/transaction-types/uritokenburn)
#### URITokenBuy
[Section titled “URITokenBuy”](#uritokenbuy)
The URITokenBuy transaction allows a user to buy a URIToken from the issuer. This transaction is used to transfer ownership of a URIToken from the issuer to the buyer. The buyer’s account, the unique identifier of the URIToken to be bought, and the amount of currency to pay for the URIToken are required for this transaction.
[URITokenBuy ](/docs/protocol-reference/transactions/transaction-types/uritokenbuy)
[URITokenCreateSellOffer ](/docs/protocol-reference/transactions/transaction-types/uritokencreateselloffer)
[URITokenCancelSellOffer ](/docs/protocol-reference/transactions/transaction-types/uritokencancelselloffer)
# Public Nodes (RPC)
> Running your own node: amazing. Hit the ground running? Use the public Xahau RPC nodes.
## Mainnet (network 21337)
[Section titled “Mainnet (network 21337)”](#mainnet-network-21337)
* Websocket
* `wss://xahau.network`
* `wss://xahau.org` (alias, some ad-blockers block .network)
* HTTP POST RPC
* `https://xahau.network`
* `https://xahau.org` (alias, some ad-blockers block .network)
* Network Definitions (Binary Codec, …)
* [`https://xahau.network/server_definitions.json`](https://xahau.network/server_definitions.json)
## Testnet (network 21338)
[Section titled “Testnet (network 21338)”](#testnet-network-21338)
* Websocket
* `wss://xahau-test.net`
* HTTP POST RPC
* `https://xahau-test.net`
* Network Definitions (Binary Codec, …)
* [`https://xahau-test.net/server_definitions.json`](https://xahau-test.net/server_definitions.json)
## JSHooks-Testnet (network 31338)
[Section titled “JSHooks-Testnet (network 31338)”](#jshooks-testnet-network-31338)
* Websocket
* `wss://jshooks.xahau-test.net`
* HTTP POST RPC
* `https://jshooks.xahau-test.net`
* Network Definitions (Binary Codec, …)
* [`https://jshooks.xahau-test.net/server_definitions.json`](https://jshooks.xahau-test.net/server_definitions.json)
# Transaction Signing
> As Hooks-enabled networks require specific transaction fields & offer more transaction types, not all clients will work out of the box. `xrpl-accountlib`
## Main differences
[Section titled “Main differences”](#main-differences)
1. Hooks-enabled networks allow getting network definitions dynamically. Allowing clients to adapt available transaction types, ledger objects, properties, and value types. When implemented correctly, signing and encoding libraries don’t have to be updated when the network adds transaction/object types/properties. ***The libraries below implement this and will handle this for you.***
2. Hooks-enabled networks require a **NetworkID** with every transaction to prevent transaction replay on another chain. The **NetworkID** will also be returned by a `server_info` RPC command in the `network_id` field (e.g. **`21338`** for Hooks V3 testnet)
3. Transactions on a Hooks-enabled network may need higher fees to deliver a transaction to another account, based on the Hooks that will be executed sending out of the sending account and receiving on the destination account. A reasonable fee to satisfy the Hooks execution can be dynamically fetched from a node by issuing the `fee` command while providing a transaction as `tx_blob`. ***The libraries below implement this and will handle this for you.***
## JavaScript/Typescript
[Section titled “JavaScript/Typescript”](#javascripttypescript)
The [**npm package `xrpl-accountlib`**](https://www.npmjs.com/package/xrpl-accountlib) can sign transactions for Hooks-enabled networks, as it offers full dynamic network feature support fetching network definitions at runtime.
The [**npm package `xrpl-client`**](https://www.npmjs.com/package/xrpl-client) integrates nicely with `xrpl-accountlib` (and comes as a dependency) to dynamically fetch the aforementioned network definitions and account values, helping submit the transaction.
### Code Sample
[Section titled “Code Sample”](#code-sample)
```javascript
import {
derive,
utils,
signAndSubmit,
} from "xrpl-accountlib"
const wss = 'wss://xahau-test.net'
const account = derive.familySeed("s...")
const networkInfo = await utils.txNetworkAndAccountValues(wss, account)
const tx = {
TransactionType: "SetHook",
Hooks: [ { Hook: {
CreateCode: "0061736D01000000011C0460057F7F7F7F7F017E60037F7F7E017E60027F7F017F60017F017E02230303656E76057472616365000003656E7606616363657074000103656E76025F670002030201030503010002062B077F0141B088040B7F004180080B7F0041A6080B7F004180080B7F0041B088040B7F0041000B7F0041010B07080104686F6F6B00030AC4800001C0800001017F230041106B220124002001200036020C41920841134180084112410010001A410022002000420010011A41012200200010021A200141106A240042000B0B2C01004180080B254163636570742E633A2043616C6C65642E00224163636570742E633A2043616C6C65642E22",
Flags: 1,
HookApiVersion: 0,
HookNamespace: "F".repeat(64),
HookOn: "F".repeat(58) + "BFFFFE",
}
}],
...networkInfo.txValues,
// ^^ This adds autmatically fetched values for you:
// Sequence, Account, LastLedgerSequence,
// Fee (Hooks enabled: autodetect (from ledger))
}
/**
* Note: the code above and `signAndSubmit` results in automatically
* fetching and setting a fee for you. If you want to check the fee
* for min/max/..., get your own fee (string in drops) using:
* utils.networkTxFee(wss, tx)
*
* e.g.
* const Fee = await utils.networkTxFee(wss, tx)
* assert(Number(Fee) < 50_000, "Auto fee above 50k drops, abort")
* Object.assign(tx, { Fee, })
*/
const submitted = await signAndSubmit(tx, wss, account)
console.log(submitted)
```
# Transaction Fees
> Xahau smart contracts (Hooks) need transaction & destination specific fees. You can easily get the required fee from the `fee` RPC command.
While libraries may deal with fee determination for you, when building your own integrations with the Xahau Network, you may have to implement dynamic fee determination based on the transaction, source & destination account.
As the sender of a transaction will have to pay for the fees required for the invoked Hooks for the specific transaction type, where Hooks can live both on the source & destination account, you can send a TX Blob (signed with a dummy account) to the `fee` command, after which Xahau will return the specific fees required for the specific transaction.
### Fee RPC Helper
[Section titled “Fee RPC Helper”](#fee-rpc-helper)
Transaction fees on a ledger with the Hooks Amendment enabled become non-trivial to compute for end-users and/or wallet applications. This is because strong hooks must be paid for by the originator of a transaction, and there may be as many as 4 strong hooks on the sending account and 4 on the receiving account, as well as any other strong transactional stakeholders involved (as can be the case with some exotic transaction types). Further, if the transaction is a SetHook then the size of the parameters, the size of the code and whether it is a *create* operation or an *install* operation all determine the size of the fee.
Therefore it is highly recommended that **all** transactions be run through the updated fee RPC call before they are submitted to the ledger.
#### To invoke the RPC call:
[Section titled “To invoke the RPC call:”](#to-invoke-the-rpc-call)
1. Open a websocket connection to the Hooks node you will be working with.
2. Compose the serialized transaction you wish to know the fee for with the following:
* `Fee: 0`
* `SigningPubKey: ""` (That is: 0 byte VL of type 0x73. In hex:`0x7300`.)
* Do **not** sign the transaction.
3. Submit it as a hex blob to the RPC as follows:
```json
{"command":"fee", "tx_blob":""}
```
For HTTP POST RPC submit it as follows:
```json
{"method":"fee", "params": [{"tx_blob":""}] }
```
The response should look something like
```json
{
result: {
drops: {
base_fee: '130520',
},
//...
},
type: 'response'
}
```
Take the base fee and set it as the `Fee` field in the transaction. Now sign and submit it as per the normal transaction submission process.
If there is an invalid value for `tx_blob` or `tx_blob` is missing, a regular JSON result will be returned with a `base_fee` of 10.
# Versioning Process
> This document outlines our versioning workflow on GitHub, to streamline the development, testing, and deployment of new features and fixes.
This document outlines the versioning process we use in our GitHub repository. We use a three-branch workflow: `dev`, `candidate`, and `release`. This process ensures that all new features and fixes are thoroughly tested before release.
### Dev Branch
[Section titled “Dev Branch”](#dev-branch)
The dev branch is the main branch for ongoing development. All new features, bug fixes, and improvements are merged into this branch. This is the most active branch, and it’s where developers should base their work.
To contribute to the dev branch, follow these steps:
1. Fork the repository to your own GitHub account.
2. Clone the forked repository to your local machine.
3. Create a new branch for your feature or bug fix.
4. Make your changes and commit them to your branch.
5. Push your branch to your forked repository on GitHub.
6. Create a pull request from your branch to the dev branch in the main repository.
Caution
All merges into the dev branch must be squashed
Code maintainers will review your pull request and provide feedback. Once the code is approved, it will be merged into the dev branch.
### Candidate Branches
[Section titled “Candidate Branches”](#candidate-branches)
Once the features in the `dev` branch are ready for testing, they are merged into a `candidate` branch. This branch serves as a staging area for code that is almost ready for release.
The code in the `candidate` branch is thoroughly tested. Any bugs or issues found are fixed in the `dev` branch and then merged back into the `candidate` branch.
The `candidate` branch is typically in this testing phase for about 2 weeks. However, this period can be longer or shorter, depending on the urgency of the fixes or the size of the new features.
1. Create a new branch `candidate` from `dev`.
2. Create a PR from the `candidate` branch to the `release` branch with a name like “Proposed.”
3. Update the “High Level Overview of Change” to include the Pull Requests from `candidate`. Update the “Context of Change” to include any additional notes about the PR’s
### Release Branch
[Section titled “Release Branch”](#release-branch)
After the code in the `candidate` branch has been thoroughly tested and all issues have been addressed, it is merged into the `release` branch. This is the final step before the code is released.
The `release` branch contains the code that is currently in production or is about to be released. Only fully tested and stable code should be in this branch.
Once the code is in the `release` branch, it is tagged with a version number. This version number is used to track the release and is also used when creating release notes.
In the `release` branch, a binary is built and published at . This binary is the final product that is delivered to the end users.
To release the code, follow these steps:
1. Merge the `candidate` pull request into the release branch.
2. Delete the `candidate` branch.
Caution
All merges into the release branch must be done with \`git merge —ff-only candidate\`
### Summary
[Section titled “Summary”](#summary)
This three-branch workflow ensures that all code is thoroughly tested before release. It allows us to catch and fix issues before they reach production, and it provides a clear path for moving code from development to release. The use of a custom LAN for testing and profiling metrics ensures that our code is not only functional but also efficient and performant.
# Hooks
> Introducing Hooks: The Smart Contract Functionality for Xahau.
Note
Hooks are small, efficient WebAssembly modules designed specifically for Xahau.
Hooks can be written in any language (compilable with WebAssembly), and most business logic and smart contract concepts can be implemented in a hook.
[**Development by XRPL Labs**](https://xrpl-labs.com/#team)
### What are Hooks?[](#what-are-hooks)
[Section titled “What are Hooks? ”](#what-are-hooks)
Hooks allow the creation of customized logic and automation within the Xahau, making transactions smarter and more convenient. These small, efficient modules add custom on-ledger functionality, such as creating custom triggers for specific events on the ledger.
These triggers can be used to send on-ledger actions or execute other actions in response to the specified event. Hooks are currently available on the [Xahau network](https://xahau.network/).
> *To learn more about the theoretical concepts of Hooks you can visit the* [*Concepts*](/docs/hooks/concepts/introduction) *section.*
> *To learn how to code Hooks in C and its functions, visit* [*Hooks C-Functions*](/docs/hooks/functions/overview/hook-api-conventions/)*.*
> *There is a* [*Hooks Builder site*](https://builder.xahau.network/) *where you can develop, test, debug, and deploy your own Hooks on testnet in your browser, using our examples or building your own from scratch.*
> *[Hookstore](https://hookstore.xahau.network/) provides a platform for discovering, sharing, and managing Hooks. Use the [Hookstore Console](https://console.hookstore.xahau.network/) to manage your Hooks and explore the ecosystem.*
> There is an upcoming development to allow writing Hooks in JavaScript, also known as JSHooks. At the moment it can be tested using [JSHooks](https://github.com/Xahau/jshooks-alpha) repo.
### Why are Hooks a Big Deal?[](#why-are-hooks-a-big-deal)
[Section titled “Why are Hooks a Big Deal? ”](#why-are-hooks-a-big-deal)
Simply put, Hooks add a robust smart contract functionality to Xahau, empowering you to construct and deploy applications with bespoke functionalities aligning with your specific needs and requirements.
Hooks provide a versatile platform as they can be used for implementing a broad spectrum of business logic and smart contract paradigms. Once a hook is set up on an account, it enables you to do the following:
* Block or allow transactions to and from the account.
* Change and keep track of the hook’s internal state and logic to inform programmatic choices.
* Autonomously initiate new transactions on the account’s behalf.
Hooks can be written in C or any other preferred language and then compiled into WebAssembly.

*Using Hooks Builder, you can develop, test, debug and deploy your own Hooks on our testnet, using our examples or building your own from scratch.*
The Hooks Builder serves as an integrated development environment, facilitating the crafting, testing, debugging, and deployment of your Hooks on our testnet.
Whether you’re utilizing our examples or building from scratch, Hooks Builder provides a helpful environment for honing and deploying your smart contract solutions.
### Some Examples of specific Hooks and Use Cases[](#some-examples-of-specific-hooks)
[Section titled “Some Examples of specific Hooks and Use Cases ”](#some-examples-of-specific-hooks-and-use-cases)
Showcasing the potential of Hooks with these concrete examples, each illustrating a unique application of smart contract functionality on Xahau:
* **Auto-Savings Hook**: Automate savings by configuring a Hook to transfer a set amount of XAH to a separate savings account on the ledger. This could be done to help save a portion of XAH and build up savings at specified intervals—daily, weekly, or monthly. This recurring transfer mechanism can be a base for developing personal finance applications or subscription-based models.
* **Carbon-Offset Hook**: Each transaction triggers an additional transfer of 1% of the amount to a carbon offset account managed by a trusted non-governmental organization (NGO) using the money for a good cause. This feature can be used as a base for building applications that contribute to environmental sustainability with every transaction made.
* **Firewall Hook**: By filtering incoming and outgoing transactions. The Firewall Hook can block malicious transactions originating from known scam accounts or containing suspicious memos. By retrieving an updated blocklist from a Hook on a different account, the firewall maintains a robust defense against fraud without the need for manual intervention. Additionally, implementing spending limits to deny high-value unauthorized withdrawals could be a crucial feature for financial applications.
### **Distinguishing Hooks from Ethereum Virtual Machine (EVM)**
[Section titled “Distinguishing Hooks from Ethereum Virtual Machine (EVM)”](#distinguishing-hooks-from-ethereum-virtual-machine-evm)
Xahau Hooks and the EVM allow developers to build and deploy custom logic and automation within their platforms. However, some key differences between these two technologies set them apart.
* **Platform Compatibility**: Hooks are tailored for Xahau, while EVM smart contracts are designed for Ethereum-based blockchains.
* **Execution Efficiency**: Hooks utilize WebAssembly (WASM), outperforming the bytecode used by the EVM in terms of speed and efficiency.
* **Predictable Execution Time**: Xahau Hooks use guards to ensure maximum execution time is well-bounded and known ahead of time, improving efficiency.
### Alternatives to Hooks on the XRPL ecosystem
[Section titled “Alternatives to Hooks on the XRPL ecosystem”](#alternatives-to-hooks-on-the-xrpl-ecosystem)
Ripple and Peersyst announced that an EVM-compatible sidechain is now live [on the company’s devnet](https://opensource.ripple.com/docs/evm-sidechain/intro-to-evm-sidechain/). This sidechain functions as an autonomous blockchain, complete with its unique consensus protocol and transaction rules. The EVM sidechain is an alternative to Hooks, adding smart contract functionality to the ecosystem.
However, it’s essential to note that EVM sidechain contracts function on Layer 2, which requires a two-step process where XRP is transitioned onto the sidechain for contract execution and then back to the main ledger. Once on the sidechain, then again on the XRPL, meaning Layer 2 smart contracts cannot influence the flow. Hooks can decide if a transaction is allowed in the first place. Layer 2 can make a retroactive decision, but the initial transaction has already happened.
Hooks are more closely integrated with XRPL, operating directly on Xahau, an Layer 1 XRPL-core fork, so they are more tightly integrated with the underlying blockchain technology than the EVM-compatible sidechain to take advantage of the specific features and capabilities of the XRPL platform. With the inherent scalability and performance of WebAssembly, Hooks are optimal to enhance Xahau’s functionality.
### Hooks Will Expand the On-ledger Functionality and Help Xahau Grow
[Section titled “Hooks Will Expand the On-ledger Functionality and Help Xahau Grow”](#hooks-will-expand-the-on-ledger-functionality-and-help-xahau-grow)
Hooks add native smart contract capabilities to Xahau, enabling the crafting of custom applications that meet the unique needs of users, bringing new functionalities, and opening up whole new domains of functionality. With Hooks, the possibilities are virtually unlimited.
As Xahau continues to grow, there is no doubt that Hooks will play a significant role in driving further innovation and adoption of the platform by retail and enterprise users.
# Chaining
> Chain multiple hooks together to do more useful tasks
Hook Design Philosophy
*Each Hook should do one thing, and do it really well.*
### History
[Section titled “History”](#history)
In the early days of Hooks it was only possible to install one Hook per account. This meant users were forced to produce omnibus Hooks if they wanted to do more than one thing: for example offset carbon and firewall at the same time.
This was counter to the Hook Design Philosophy, so Hook Chaining was introduced.
### Chaining
[Section titled “Chaining”](#chaining)
A Hook Chain is a sequence of up to **10** Hooks installed on an Xahau account.
* A Hook Chain executes successfully when every Hook in the chain has been individually executed and subsequently calls [accept](/docs/hooks/functions/control/accept).
* Each chain’s execution starts at chain position 0 and ends at chain position 9. If a position is blank (because it was never filled or because the hook that was installed there has been removed) then that position is skipped and treated as successful.
* In order for a transaction to succeed, both ends of the transaction (sending side and receiving side) must have executed successfully. This means if there is a Hook Chain installed on both sides, then both Hook Chains must execute successfully for the transaction to succeed.
Hooks are installed into the chain using the [SetHook Transaction](/docs/hooks/concepts/sethook-transaction). When they are installed, the installer may specify install-time [Parameters](/docs/hooks/concepts/parameters) which may change the behaviour of the installed Hook.

*Example: Execution flow for a transaction passing through two Hook Chains*
### Chain Manipulation
[Section titled “Chain Manipulation”](#chain-manipulation)
In addition to the *install-time* operations specified in the [SetHook Transaction](/docs/hooks/concepts/sethook-transaction), Hooks have some runtime control over chain execution:
* A Hook may determine its own `HookHash` by calling [hook\_hash](/docs/hooks/functions/hook-context/hook_hash).
* A Hook may determine its location in the Hook Chain using [hook\_pos](/docs/hooks/functions/hook-context/hook_pos).
* A Hook may skip (or re-enable) another Hook further down the chain using [hook\_skip](/docs/hooks/functions/hook-context/hook_skip).
* A Hook may modify the [Parameters](/docs/hooks/concepts/parameters) of a Hook further down the chain using [hook\_param\_set](/docs/hooks/functions/hook-context/hook_param_set).
### Weak Executions
[Section titled “Weak Executions”](#weak-executions)
Hook Chains are [Strongly Executed](/docs/hooks/concepts/weak-and-strong). However any Hook in any chain may flag that it requires a second, Weak Execution by calling [hook\_again](/docs/hooks/functions/hook-context/hook_again). If all Hook Chains execute successfully then the originating transaction is applied. Once the originating transaction has been applied any Weak Executions may happen, in the following order:
1. `cbak` execution if this was an Emitted Transaction.
2. Weak Transactional Stake Holders who have opted in to allow a [Collect Call](/docs/hooks/concepts/collect-call). Execution order is first-come first-serve according to the event that caused the TSH to be flagged (such as pathing).
3. Any *Again as Weak* (AAW) Hooks. Execution order for AAW is first numerically according to Account ID then numerically according to Hook position.
# Collect Call
Hook Design Philosophy
*Every party affected by a transaction should have the opportunity to have their hooks executed.*
When hooks are not Strongly Executed it is unfair to bill the originating transaction for their execution. For example an *OfferCreate* which crosses 20 offers on the DEX should not be forced to pay for the execution of each of those account’s Hooks.
Therefore during typical Weak execution the fee for the execution is collected from the owner of the Hook. To enable this:
* The Hook owner must have set `asfTshCollect` on their Xahau account using the AccountSet transaction.
* The Hook owner must have set `hsfCollect` on the specific Hook they wish to be called as a Weak TSH.
### Fee Responsibility Table
[Section titled “Fee Responsibility Table”](#fee-responsibility-table)
| Type of Weak Execution | Fee |
| ------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Again As Weak** - Happens when a Strongly Executed Hook calls [hook\_again](/docs/hooks/functions/hook-context/hook_again) | Free (already paid by the Strong Execution). |
| **Callback** - Happens when an emitted transaction either makes it into a ledger or is flagged as being impossible to ever make it into a ledger. | Free (already paid during Emission). |
| **Weak Transactional Stakeholder** - Happens if a transaction in some way mildly affects your account. | Paid for by your account (not by the originating transaction) if and only if both your account is marked with `asfTshCollect` flag and your Hook is marked with the `hsfCollect` flag. |
Caution
This is an advanced feature most Hook Developers will probably not use.
# Compiling Hooks
### Constraints
[Section titled “Constraints”](#constraints)
All Hooks are compiled to a single [webassembly module](https://webassembly.github.io/spec/core/syntax/modules.html) before they can be set onto an Xahau account.
A Hook always implements and exports exactly one or both of the following functions:
`int64_t hook(uint32_t ctx) { ... }` *required*
* Executed whenever a transaction comes into or leaves from the account the Hook is set on (`ctx = 0`) or
* Executed when executed as a [Weak Transactional Stakeholder](/docs/hooks/concepts/weak-and-strong) (`ctx > 0`).
`int64_t cbak(uint32_t ctx) { ... }` *optional*
* Executed when an emitted transaction is successfully accepted into a ledger (`ctx = 0`) or
* Executed when an emitted transaction cannot be accepted into any ledger (`ctx = 1`).
Hooks are not allowed to specify other functions. Instead they must make clever use of macros to do all their computation within these two functions. This is part of a computational restriction on hooks to keep their runtime predictable.
Additionally Hooks are afforded no *heap* memory. All required memory must be reserved and used on the stack.
### Example
[Section titled “Example”](#example)
Here is an example Hook written in C. The Hook prints 0…3 to the trace log before accepting the originating transaction.
```c
#include
#define GUARD(maxiter) _g(__LINE__, (maxiter)+1)
extern int32_t _g (uint32_t id, uint32_t maxiter);
extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
extern int64_t trace_num (uint32_t read_ptr, uint32_t read_len, int64_t number);
int64_t hook(uint32_t ctx)
{
for (int i = 0; GUARD(3), i < 3; ++i)
{
trace_num("test", 4, i);
}
accept (0,0,0);
return 0;
}
```
Tip
For educational purposes the above example deliberately does not include `hookapi.h` (which developers would typically use.)
### Compilation
[Section titled “Compilation”](#compilation)
A [variety of compilers](https://www.google.com/search?q=webassembly+compiler+C) will generate valid webassembly from a C source file. Once compiled, a Hook exists as a binary `.wasm` file. This contains a webassembly module. Using `wasmcc` to compile and the `wasm2wat` tool to convert to human readable webassembly this binary form can be rendered to the human readable form. Below appears the compilation result of the above example.
```plaintext
(module
(type (;0;) (func (param i32 i32) (result i32)))
(type (;1;) (func (param i32 i32 i64) (result i64)))
(type (;2;) (func))
(type (;3;) (func (param i32) (result i64)))
(import "env" "_g" (func $_g (type 0)))
(import "env" "trace_num" (func $trace_num (type 1)))
(import "env" "accept" (func $accept (type 1)))
(func $__wasm_call_ctors (type 2))
(func $cbak (type 3) (param i32) (result i64)
(local i32 i32 i32 i64)
global.get 0
local.set 1
i32.const 16
local.set 2
local.get 1
local.get 2
i32.sub
local.set 3
i64.const 0
local.set 4
local.get 3
local.get 0
i64.store offset=8
local.get 4
return)
(func $hook (type 3) (param i32) (result i64)
(local i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i64 i32 i32 i32 i64 i32 i32 i32)
global.get 0
local.set 1
i32.const 16
local.set 2
local.get 1
local.get 2
i32.sub
local.set 3
local.get 3
global.set 0
i32.const 0
local.set 4
local.get 3
local.get 0
i64.store offset=8
local.get 3
local.get 4
i32.store offset=4
block ;; label = @1
loop ;; label = @2
i32.const 3
local.set 5
i32.const 14
local.set 6
i32.const 4
local.set 7
local.get 6
local.get 7
call $_g
drop
local.get 3
i32.load offset=4
local.set 8
local.get 8
local.set 9
local.get 5
local.set 10
local.get 9
local.get 10
i32.lt_s
local.set 11
i32.const 1
local.set 12
local.get 11
local.get 12
i32.and
local.set 13
local.get 13
i32.eqz
br_if 1 (;@1;)
i32.const 1024
local.set 14
i32.const 4
local.set 15
local.get 3
i32.load offset=4
local.set 16
local.get 16
local.set 17
local.get 17
i64.extend_i32_s
local.set 18
local.get 14
local.get 15
local.get 18
call $trace_num
drop
local.get 3
i32.load offset=4
local.set 19
i32.const 1
local.set 20
local.get 19
local.get 20
i32.add
local.set 21
local.get 3
local.get 21
i32.store offset=4
br 0 (;@2;)
end
end
i64.const 0
local.set 22
i32.const 0
local.set 23
local.get 23
local.get 23
local.get 22
call $accept
drop
i32.const 16
local.set 24
local.get 3
local.get 24
i32.add
local.set 25
local.get 25
global.set 0
local.get 22
return)
(table (;0;) 1 1 funcref)
(memory (;0;) 2)
(global (;0;) (mut i32) (i32.const 66576))
(global (;1;) i32 (i32.const 1029))
(global (;2;) i32 (i32.const 1024))
(global (;3;) i32 (i32.const 66576))
(global (;4;) i32 (i32.const 1024))
(export "memory" (memory 0))
(export "__wasm_call_ctors" (func $__wasm_call_ctors))
(export "__data_end" (global 1))
(export "__global_base" (global 2))
(export "__heap_base" (global 3))
(export "__dso_handle" (global 4))
(export "cbak" (func $cbak))
(export "hook" (func $hook))
(data (;0;) (i32.const 1024) "test\00"))
```
The average Hook developer will never need to examine webassembly directly. However it is a useful conceptual exercise to review the contents of the sample Hook.
Above we can see:
* Three functions are imported from the Hooks API (`_g`, `accept`, `trace_num`)
* Two functions are defined by the hook (`cbak`, `hook`)
* Two functions are exported by the hook (again: `cbak`, `hook`)
* Some static (constant) data is recorded in the hook (see `data` at the bottom).
It is very important to note that a Hook *must only* import functions available to it from the Hooks API and *must* only export the `cbak` and `hook` functions. In additional all hooks must import `_g` from the Hooks API, which is the `guard` function.
Tip
Webassembly is a platform-independent general computation `bytecode` language. It has a one-to-one mapping with a human readable equivalent. These are used interchangeably.
### Unwanted Exports
[Section titled “Unwanted Exports”](#unwanted-exports)
Most webassembly compilers (including the one above) produce additional exports for their own linking purposes. In many cases the generation of these is difficult or impossible to disable.
Unwanted exports will lead to an otherwise valid Hook being rejected. Therefore after compilation developers should use the [Hook Cleaner Utility](https://github.com/XRPLF/hook-cleaner-c) to strip out these out. Failure to do so will lead to your Hook being rejected.
Caution
Don’t forget to use the [Hook Cleaner Utility](https://github.com/XRPLF/hook-cleaner-c) or your Hooks will be rejected.
# Debugging Hooks
> How to print "hello world" from your Hook!
### How can I debug a Hook?
[Section titled “How can I debug a Hook?”](#how-can-i-debug-a-hook)
The Hook API provides a set of functions in the namespace `trace` which write output to the `xrpld` log file when xrpld is configured with the *trace* log-level. These functions, generally speaking, allow you to see the value of variables, buffers and otherwise trace the execution and state of a Hook at runtime.
Tip
At time of writing there is no interactive Hook Debugger. You must use the trace functions.
### Trace APIs
[Section titled “Trace APIs”](#trace-apis)
The following `trace` functions are available in the Hooks API
| Hook API | What it does |
| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| [trace](/docs/hooks/functions/trace-debug/trace) | Print a utf-8 message, followed by a user-specified buffer (this last optionally as hex.) |
| [trace\_num](/docs/hooks/functions/trace-debug/trace_num) | Print a utf-8 message, followed by an integer. |
| [trace\_float](/docs/hooks/functions/trace-debug/trace_float) | Print a utf-8 message, followed by an XFL Floating point number. |
### Example
[Section titled “Example”](#example)
The following code will print a single trace line then accept the Originating Transaction.
```c
#include "../hookapi.h"
int64_t hook(int64_t reserved)
{
trace_num(SBUF("A number"), 10);
accept(0,0,0);
return 0;
}
```
An example of the log-line produced by `xahaud` when a payment is sent out of or into the Hook Account:
```plaintext
2021-Apr-13 13:59:11.083700726 UTC View:TRC
HookTrace[rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh-rE3SfnjwfzZFL3JK9cLVfJuy8Ar1XnCqPw]:
A number 10
```
The above appears in the log as all-one-line, but split here for visibility.
Use testnet
The [Xahau Testnet](https://xahau-test.net/) is the perfect place to test your Hooks.
### Log format
[Section titled “Log format”](#log-format)
A breakdown of the log format appears in the table below
| Part | Description | # |
| ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | - |
| 2021-Apr-13 13:59:11.083700726 UTC View:TRC | `xahaud`’s prefix to the log line | 1 |
| HookTrace | This is a trace initiated by the Hook itself not some other information about the Hook. Other information is available on tags `HookError`, `HookEmit` and `HookInfo`. | 2 |
| \[rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh | The first account in the square brackets is the Hook Account. | 3 |
| -rE3SfnjwfzZFL3JK9cLVfJuy8Ar1XnCqPw]: | The second account in the square brackets is the Originating Account. | 4 |
| A number | This is the message the Hook was told to deliver before the trace payload | 5 |
| 10 | This is the trace payload | 6 |
Tip
`Xahaud` produces a lot of output. It is therefore generally advisible to grep logs for the account/s you are interested in.
For example use: `tail -f log | grep HookTrace | grep `
# Emitted Transactions
> Your Hook can do a lot more than just block or allow transactions!
### Background
[Section titled “Background”](#background)
**All** changes made to Xahau *must* be the result of applying a valid transaction to the ledger. Thus if some change *X* is made then some transaction *Y* is responsible.
When designing the Hooks API we needed a way for Hooks to make changes to the ledger *beyond* simply accepting or rejecting a transaction. However attaching these changes to the Originating Transaction was confusing and resulted in a large increase in the general complexity of the system.
Suppose for example that a Hook needs to send you some funds… the send operation would be effectively enacted onto the ledger by the Originating Transaction which might have been something completely unrelated such as an Account Set transaction. Additionally this send operation would need to be able to potentially trigger another Hook on the receiving end of a payment.
The solution: **Emitted Transactions**. We allow the Originating Transaction to do exactly what the contents of the Transaction say it will do. If our Hook needs to make an additional change to the ledger such as sending a payment, it creates and then *emits* a brand new transaction.
### What are Emitted Transactions?
[Section titled “What are Emitted Transactions?”](#what-are-emitted-transactions)
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). 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/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
[Section titled “Callbacks”](#callbacks)
As introduced in [Introduction and Terminology](/docs/hooks/concepts/terminology) emitted transactions trigger callbacks when they are accepted into a ledger. Due to the decentralised nature of consensus acceptance into a ledger of an emitted transaction is **not a guarantee**, although it is usually all-but guaranteed.
If an emitted transaction expires before it can be accepted into a ledger (for any number of reasons: the ledgers may be full, the fee may be too high for the emitted transaction or the emitted transaction may be somehow invalid) then a *pseudo transaction* is created in the ledger to clean up the emitted transaction. This pseudo transaction also calls the callback of your hook, with `parameter = 1` to indicate the emitted transaction indeed failed.
### Emission Rules
[Section titled “Emission Rules”](#emission-rules)
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 |
| - | ------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1 | `sfSequence` = 0 | Emitted Transactions *do not* increase the sequence number of the Hook Account. This must always be set to zero. |
| 2 | `sfPubSigningKey` = 0 | Emitted Transactions are not signed but this is a required field for xrpld processing. It must be set to all zeros. |
| 3 | `sfEmitDetails` present and valid | Emitted Transactions require an `sfEmitDetails` block and this must be correctly filled. See EmitDetails section below. |
| 4 | `sfSignature` absent | This field must be absent in the emitted transaction because if it were not then the transaction would be ambiguous. |
| 5 | `LastLedgerSequence` valid and in the future | All emitted transactions must have a last ledger sequence set so that the Hook knows if the emitted transaction failed (since it did not get a callback in time). This is currently set to a maximum of 5 ledgers after the current ledger. |
| 6 | `FirstLedgerSequence` valid and set to the next ledger | All emitted transactions must have a first ledger sequence set to the next ledger (after the current ledger) so that Hooks do not recursively cascade within a single ledger. This is currently enforced to be the next ledger after the current ledger. |
| 7 | Fee appropirately computed and set | The fee is dependent on the size of the emtited transaction and the burden on the network (i.e. whether this emitted transaction was the result of another emitted transaction.) |
| 8 | Generation cap not exceeded | An emitted transaction can produce other emitted transactions, and these can form a chain. The length of the chain is the `sfEmitGeneration`. This is currently capped at 10. |
### EmitDetails block
[Section titled “EmitDetails block”](#emitdetails-block)
All emitted transactions must contain an `sfEmitDetails` object correctly populated with the fields in the table below.
| Field | Required Value | Description |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| sfEmitGeneration | If the Originating Transaction was itself an emitted transaction then one more than the `sfEmitGeneration` of that transaction. If the Originating Transaction was not an emitted transaction then `1`. This should be populated using [etxn\_generation](/docs/hooks/functions/emitted-transaction/etxn_generation). | This field keeps track of a chain of emitted transactions that in turn cause other transactions to be emitted. |
| sfEmitBurden | If the Originating Transaction was itself an emitted transaction then the `burden` of the Originating Transaction multiplied by the maximum number of transactions the Hook has declared it will emit using [etxn\_reserve](/docs/hooks/functions/emitted-transaction/etxn_reserve). If the Originating Transaction was not an emitted transaction then `1`. This should be populated using [etxn\_burden](/docs/hooks/functions/emitted-transaction/etxn_burden). | This field is a heuristic for detecting forkbombs. Fees are based on burden and will increase exponentially when a chain reaction is started to prevent the network becoming overun by self-reinforcing emitted transactions. |
| sfEmitParentTxnID | The transaction ID of the Originating Transaction | The Hook Execution that emitted the transaction is connected to the Originating Transaction. Therefore this field is always required for the efficient tracing of behaviour. |
| sfEmitNonce | A special deterministic nonce produced by a call to [nonce](/docs/hooks/functions/emitted-transaction/etxn_nonce) | Emitted Transactions would be identical with the same fields and therefore have identical transaction hashes if a nonce were not used. However every node on the network needs to agree on the nonce, so a special Hook API to produce a deterministic nonce is made available. |
| sfEmitCallback | The 20 byte Hook Account ID | This field is used by xahaud when it needs to intitate a callback, such that it knows which Hook and account to initate the callback on. Callbacks happen when an emitted transaction is accepted into a ledger. |
Check the examples
The [Example Hooks](https://github.com/XRPL-Labs/xrpld-hooks/tree/hooks-ssvm/hook-api-examples), in particular Peggy, Carbon and Doubler, demonstrate how to emit both simple and more complicated transactions.
# Execution Metadata
> What to expect when your Hook runs.
When Hooks execute they leave behind information about the status of that execution. This appears in the Originating Transaction metadata as an `sfHookExecutions` block. This block contains the following fields:
| Field | Description |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| sfHookResult | Hooks can end in three ways: `accept`, `rollback` and `error`. This is *not* the same as sfHookReturnCode! |
| sfHookHash | The SHA512H of the Hook at the time it was executed. |
| sfHookAccount | The account the Hook ran on. |
| sfHookReturnCode | The integer returned as the third parameter of `accept` or `rollback`. |
| sfHookReturnString | The string returned in the first two parameters of `accept` or `rollback`, if any. |
| sfHookInstructionCount | The total number of webassembly instructions that were executed when the Hook ran. |
| sfHookEmitCount | The total number of [Emitted Transactions](/docs/hooks/concepts/emitted-transactions) produced by the Hook. |
| sfHookExecutionIndex | The order in which the Hook was executed (as distinct from other Hook Executions on the same Originating Transaction.) |
| sfHookStateChangeCount | The number of [Hook State](/docs/hooks/concepts/state-management) changes the Hook made during execution. |
# Floating Point Numbers (XFL)
> High precision calculations are native to Hooks.
### Background
[Section titled “Background”](#background)
[Floating point numbers](https://en.wikipedia.org/wiki/Floating-point_arithmetic) are widely used in computer science to do calculation of finite precision but arbitrary scale numbers.
Most modern CPUs are capable of performing fast floating point operations using the [IEEE binary floating point standard](https://en.wikipedia.org/wiki/Double-precision_floating-point_format) however `xahaud` does **not** use this format. Instead Xahau uses a [bespoke decimal floating point standard](/docs/protocol-reference/binary-format).
This custom format has three basic properties:
1. The format is inherently decimal, expressed as a decimal `mantissa` multipled by `10` to the power of an `exponent`.
2. All values expressed have 16 significant (decimal) figures.
3. The range of exponents is `-96` to `+80`
When serialized the mantissa is 54 bits, and the exponent is 8 bits, with a final sign bit bringing the total size of the serialized floating point to 63 bits.
### What is XFL?
[Section titled “What is XFL?”](#what-is-xfl)
[XLS-17d](https://github.com/XRPLF/XRPL-Standards/discussions/39) is an XRPL standards proposal that defines an efficient way to pack and store xrpld floating point numbers (as described above).
XFLs store the bits of the floating point number within an *enclosing number*. This is always an `int64_t`. Negative enclosing numbers represent invalid XFLs (for example as a result of division by zero.)
Tip
Use the XFL-tool [here](https://richardah.github.io/xfl-tools/) to compose and decompose XFLs in your browser!
Some example XFLs follow
| loating Point Value | Enclosing Number | Representation |
| ------------------- | ------------------- | ----------------------------- |
| -1 | 1478180677777522688 | -1000000000000000 \* 10^(-15) |
| 0 | 0 | 0 (*canonical zero*) |
| 1 | 6089866696204910592 | +1000000000000000 \* 10^(-15) |
| *PI* | 6092008288858500385 | +3141592653589793 \* 10^(-15) |
| -*PI* | 1480322270431112481 | -3141592653589793 \* 10^(-15) |
This format is very convenient for Hooks, as Hooks can only exchange *integer* values with xrpld. By enclosing the floating point inside an integer in a well defined way it becomes possible to do complex floating point computations from a Hook. This is useful for computing exchange rates.
### Canonical Zero
[Section titled “Canonical Zero”](#canonical-zero)
Floating point regimes typically have a number of different ways to express zero, which can be a problem for testing for zero. For example `0 x 10 ^ 1` is zero and `0 x 10 ^ 2` is also zero. For this reason there is a canonical zero enforced by the standard and the Hook API. The canonical zero is also enclosing number zero (`0`).
### Hook Float API
[Section titled “Hook Float API”](#hook-float-api)
Once you have an XFL you can use the Float API to do various computations. The Float API appears in the table below. Each API takes one or more XFL enclosing numbers and returns an XFL enclosing number. Negative return values *always* represent a computational error (such as division by zero). There are no valid negative enclosing numbers.
| Hook API | What it does |
| ------------------------------------------------------------- | --------------------------------------------------------------------- |
| [float\_set](/docs/hooks/functions/float/float_set) | Create a float from an exponent and mantissa |
| [float\_multiply](/docs/hooks/functions/float/float_multiply) | Multiply two XFL numbers together |
| [float\_mulratio](/docs/hooks/functions/float/float_mulratio) | Multiply an XFL floating point by a non-XFL numerator and denominator |
| [float\_negate](/docs/hooks/functions/float/float_negate) | Negate an XFL floating point number |
| [float\_compare](/docs/hooks/functions/float/float_compare) | Perform a comparison on two XFL floating point numbers |
| [float\_sum](/docs/hooks/functions/float/float_sum) | Add two XFL numbers together |
| [float\_sto](/docs/hooks/functions/float/float_sto) | Output an XFL as a serialized object |
| [float\_sto\_set](/docs/hooks/functions/float/float_sto_set) | Read a serialized amount into an XFL |
| [float\_invert](/docs/hooks/functions/float/float_invert) | Divide one by an XFL floating point number |
| [float\_divide](/docs/hooks/functions/float/float_divide) | Divide an XFL by another XFL floating point number |
| [float\_one](/docs/hooks/functions/float/float_one) | Return the number 1 represented in an XFL enclosing number |
| [float\_exponent](/docs/hooks/functions/float/float_exponent) | Get the exponent of an XFL enclosing number |
| [float\_mantissa](/docs/hooks/functions/float/float_mantissa) | Get the mantissa of an XFL enclosing number |
| [float\_sign](/docs/hooks/functions/float/float_sign) | Get the sign of an XFL enclosing number |
| float\_exponent\_set | Set the exponent of an XFL enclosing number |
| float\_mantissa\_set | Set the mantissa of an XFL enclosing number |
| float\_sign\_set | Set the sign of an XFL enclosing number |
| [float\_int](/docs/hooks/functions/float/float_int) | Convert an XFL floating point into an integer floor |
| [float\_root](/docs/hooks/functions/float/float_root) | Compute the nth root of an XFL |
| [float\_log](/docs/hooks/functions/float/float_log) | Compute the decimal log of an XFL |
Caution
You should never do any direct math or comparison on the *enclosing number*. This will almost always result in incorrect computations.
The *sole exception* is checking for canonical zero.
### Example
[Section titled “Example”](#example)
In the below example an exchange rate conversion is performed, followed by a high precision fraction multiplication.
```c
int64_t max_vault_pusd =
float_multiply(vault_xrp, exchange_rate);
max_vault_pusd =
float_mulratio(max_vault_pusd, 0,
NEW_COLLATERALIZATION_NUMERATOR, NEW_COLLATERALIZATION_DENOMINATOR);
```
Tip
If a float API returns a negative value and you do not check for negatives, then passing that negative value into another float API will also produce a negative value. In this way, errors are propagated much like `NaN` (not a number) is propagated in other languages.
If you ever end up with a negative enclosing number, an error occurred somewhere in your floating point calculations.
# Grants
> Hook Grants
Caution
Most Hook Developers will rarely need to use HookGrants, and should exercise extreme caution when granting state mutation permission to foreign Hooks and accounts.
While a HookGrant cannot be used to directly steal funds, intentional external modification of a Hook’s State may lead a Hook to behave in an unintended way, which in some cases could lead to a theft.
If you think you need to use a Grant, please re-check your design first to ensure you actually need to use one before continuing.
### Grants
[Section titled “Grants”](#grants)
Grants provide a way for a Hook Installer to assign [State Management](/docs/hooks/concepts/state-management) permissions to a *foreign* Hook on other Xahau accounts.
A [SetHook Transaction](/docs/hooks/concepts/sethook-transaction) may specify a `HookGrants` array within any `Hook` object in its `Hooks` array. The `HookGrants` array contains one or more `HookGrant` objects (up to 8).
Unlike [Parameters](/docs/hooks/concepts/parameters), the `HookGrants` array is always set exactly as specified in the [SetHook Transaction](/docs/hooks/concepts/sethook-transaction). Therefore if you wish to update a particular `HookGrant` whilst retaining multiple other `HookGrant` entires that were previously set, you must first obtain the old `HookGrants` array, modify it, and then resubmit the entire array in an [*Update* Operation](/docs/hooks/concepts/sethook-transaction).
To delete all Grants submit an empty `HookGrants` array.
Caution
Unlike [Parameters](/docs/hooks/concepts/parameters), the `HookGrants` array is always set exactly as specified in the [SetHook Transaction](/docs/hooks/concepts/sethook-transaction).
A Grant permits a foreign XRPL account or Hook to modify the Hook State within the namespace of the specific Hook for which the Grant is defined.
The HookGrant must specify at least:
* `HookHash`\
And may also specify an account:
* `Authorize`
Only the Hook specified by HookHash may modify the Hook State within the namespace of the Hook for which the HookGrant is specified. If `Authorize` is specified then this permission is tightened further to only the Hook specified by the HookHash when it is installed on the account specified by `Authorize`.
Tip
Grants only apply to external Hooks and never limit the operation of Hooks with respect to the Hook State on the account they are installed on.
### Example
[Section titled “Example”](#example)
```json
Account: "rALicebv3hMYNBWtu1VEEWkToArgYsYERs",
TransactionType: "SetHook",
Hooks:
[
{
Hook: {
...,
HookNamespace: "3963ADEB1B0E8934C0963680531202FD511FF1E16D5864402C2DA63861C420A8",
HookGrants:
[
{
HookGrant: // first grant
{
HookHash: "78CAF69EEE950A6C55A450AC2A980DE434D624CD1B13148E007E28B7B6461CC8"
},
HookGrant: // second grant
{
Authorize: "rCLairev2ma2gNZdcHJeTk7fCQ1ki84vr9",
HookHash: "A5B8D62154DA1C329BE13582086B52612476720CEBD097EB85CEE1455E1C70A6"
}
},
]
}
}
],
...
```
The *first grant* above allows:
* any instance of the Hook whose code that hashes to `78CAF69EEE950A6C55A450AC2A980DE434D624CD1B13148E007E28B7B6461CC8`
* executing on **any account**
* to modify the Hook State of account `rALicebv3hMYNBWtu1VEEWkToArgYsYERs`
* inside the Namespace `3963ADEB1B0E8934C0963680531202FD511FF1E16D5864402C2DA63861C420A8`
The *second grant* above allows:
* any instance of the Hook whose code that hashes to `A5B8D62154DA1C329BE13582086B52612476720CEBD097EB85CEE1455E1C70A6`
* but only when executed on account `rCLairev2ma2gNZdcHJeTk7fCQ1ki84vr9`
* to modify the Hook State of account `rALicebv3hMYNBWtu1VEEWkToArgYsYERs`
* inside the Namespace `3963ADEB1B0E8934C0963680531202FD511FF1E16D5864402C2DA63861C420A8`
### Using the Grant
[Section titled “Using the Grant”](#using-the-grant)
To make use of a grant, a Hook modifies State objects on a foreign account by calling [state\_foreign\_set](/docs/hooks/functions/state/state_foreign_set).
# Hook Fees
> What to expect when your Hook runs.
### Hook Creation Fees
[Section titled “Hook Creation Fees”](#hook-creation-fees)
SetHook transactions are charged per byte of created webassembly. The rate is 500 drops per byte. Thus a 1kib Hook will cost 0.5 XAH to create.
### Hook Execution Fees
[Section titled “Hook Execution Fees”](#hook-execution-fees)
When Hooks are [Strongly Executed](/docs/hooks/concepts/weak-and-strong) the originating transaction must pay for the Strong Executions in the originating transaction’s fee.
Hook Execution fees are charged at a rate of 1 drop per web assembly instruction in the worst-case execution of the function `hook` (or `cbak` in the case of a callback). Thus a small Hook with a lot of looping may end up attracting high runtime fees.
### Fee RPC Helper
[Section titled “Fee RPC Helper”](#fee-rpc-helper)
Transaction fees on a ledger with the Hooks Amendment enabled become non-trivial to compute for end-users and/or wallet applications. This is because strong hooks must be paid for by the originator of a transaction, and there may be as many as 4 strong hooks on the sending account and 4 on the receiving account, as well as any other strong transactional stakeholders involved (as can be the case with some exotic transaction types). Further, if the transaction is a SetHook then the size of the parameters, the size of the code and whether it is a *create* operation or an *install* operation all determine the size of the fee.
Therefore it is highly recommended that **all** transactions be run through the updated fee RPC call before they are submitted to the ledger.
To invoke the RPC call:
1. Open a websocket connection to the Hooks node you will be working with.
2. Compose the serialized transaction you wish to know the fee for with the following:
* `Fee: "0"`
* `SigningPubKey: ""` (That is: 0 byte VL of type 0x73. In hex:`0x7300`.)
* Do **not** sign the transaction.
3. Submit it as a hex blob to the RPC as follows:
```json
{"command":"fee", "tx_blob":""}
```
For HTTP POST RPC submit it as follows:
```json
{"method":"fee", "params": [{"tx_blob":""}] }
```
The response should look something like
```json
{
result: {
drops: {
base_fee: '130520',
},
//...
},
type: 'response'
}
```
Take the base fee and set it as the `Fee` field in the transaction. Now sign and submit it as per the normal transaction submission process.
If there is an invalid value for `tx_blob` or `tx_blob` is missing, a regular JSON result will be returned with a `base_fee` of 10.
### Emission Fees
[Section titled “Emission Fees”](#emission-fees)
Hooks have access to the same computation the *Fee RPC Helper* does. To use this simply call [etxn\_fee\_base](/docs/hooks/functions/emitted-transaction/etxn_fee_base) with a buffer containing the serialised transaction as the arguments. As with the RPC call, you must ensure that the `Fee` field is present in the serialised transaction. The value is irrelevant.
When `etxn_fee_base` returns the recommended fee you may use [sto\_emplace](/docs/hooks/functions/serialization/sto_emplace) to emplace it into the serialised transaction before emission. The relevant field is `sfFee`.
# HookOn Field
> Specify which transaction types a Hook should be triggered on
### Understanding the HookOn field
[Section titled “Understanding the HookOn field”](#understanding-the-hookon-field)
Each bit in this unsigned 256-bit integer indicates whether the Hook should execute on a particular transaction type. All bits are *active low* **except** bit 22 which is *active high*. Since 22 is ttHOOK\_SET this means the default value of all 0’s will not fire on a SetHook transaction but will fire on every other transaction type. This is a deliberate design choice to help people avoid bricking their Xahau account with a misbehaving hook.
Bits are numbered from right to left:
* bit 0 - right most, i.e. the least significant bit.
* bit 63 - the left-most, i.e. the most significant bit.
Examples (assuming a 256-bit unsigned integer type):
1. If we want to completely disable the hook:
```c
~(1ULL << 22) /* every bit is 1 except bit 22 which is 0 */
```
2. If we want to disable the hook on everything except ttPAYMENT:
```c
~(1ULL << 22) & ~(1ULL)
```
3. If we want to enable the hook on everything except ttHOOK\_SET
```c
0
```
4. If we want to enable hook firing on ttHOOK\_SET (dangerous) and every other transaction type:
```c
(1ULL << 22)
```
### HookOn Calculator
[Section titled “HookOn Calculator”](#hookon-calculator)
[HookOn Calculator ](https://richardah.github.io/xrpl-hookon-calculator/)
### HookCanEmit Field
[Section titled “HookCanEmit Field”](#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`.
### HookOnIncoming and HookOnOutgoing Fields
[Section titled “HookOnIncoming and HookOnOutgoing Fields”](#hookonincoming-and-hookonoutgoing-fields)
*(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.
*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.
# Introduction
Hooks add smart contract functionality to the Xahau: *layer one* custom code to influence the behaviour and flow of transactions. Hooks are small, efficient pieces of code being defined on an Xahau account, allowing logic to be executed before and/or after Xahau transactions.
Note
Please note: you’re reading the **technical documentation** of Hooks. This documentation is highly technical & assumes prior knowledge of programming and the Xahau Network. If you are looking for examples on what Hooks are, will bring to the Xahau Network and what they could do, please [check this page](/docs/hooks/concepts/introduction/example-usage).
Xahau is known and is being appreciated for its transaction throughput, speed and the low fees. Combined with available advanced transaction types like multi sign, escrows, payment channels and even a decentralized exchange (all on ledger, out of the box, without requiring smart contracts) Xahau has a lot to offer businesses and creative developers.
Hooks add smart contract functionality to Xahau: *layer one* custom code to influence the behaviour and flow of transactions. Hooks are small, efficient pieces of code being defined on an Xahau account, allowing logic to be executed before and/or after Xahau transactions. These Hooks can be really simple, like: “reject payments < 10 XAH”, or “for all outgoing payments, send 10% to my savings account” or more advanced.

*Hooks high level concept*
By allowing Hooks to not only execute efficient logic but also to store small, simple data objects, one could define a Hook like: “for incoming payments transactions, check if the sending account is in a list maintained by another Hook, and if present: reject the transaction”.
Hooks are deliberately not Turing-Complete. While often touted as the holy grail of smart contracts, Turing-Completeness is actually inappropriate for smart contracts. (See [Blog 2](https://dev.to/wietse/hooked-2-hooks-security-smart-contracts-on-the-xrp-ledger-83e).)
Hooks are currently live on a public testnet. It’s time for testing, coding, having fun & breaking things, so a future amendment to add Hooks to Xahau livenet can be drafted with confidence.
### Resources
[Section titled “Resources”](#resources)
* [Xahau Testnet](https://xahau-test.net/)
* [Xahau Testnet Explorer](https://explorer.xahau-test.net/)
* [Examples (source code)](https://github.com/XRPL-Labs/xrpld-hooks/tree/hooks-ssvm/hook-api-examples)
* [Blogs concepts](https://dev.to/t/xrplhooks/top/infinity)
# Example Usage
Please read [the introduction of Hooks in this blog](https://coil.com/p/XUMM/XRPL-Labs-is-working-on-the-transaction-HOOKS-amendment-for-the-XRP-Ledger-Supporting-business-logic/kEmqhoqMW).
While working on Hooks we published a number of blogs on our progress, insights & Hooks concepts. You can [read all about that in our blogs on Dev.to](https://dev.to/t/xrplhooks/top/infinity)
### Examples (scenarios)
[Section titled “Examples (scenarios)”](#examples-scenarios)
#### 1. Receiving Hook executes additional logic
[Section titled “1. Receiving Hook executes additional logic”](#1-receiving-hook-executes-additional-logic)

#### 2. Receiving Hook blocks incoming transaction
[Section titled “2. Receiving Hook blocks incoming transaction”](#2-receiving-hook-blocks-incoming-transaction)

#### 3. Sending Hook blocks outgoing transaction
[Section titled “3. Sending Hook blocks outgoing transaction”](#3-sending-hook-blocks-outgoing-transaction)

#### 4. Hook controls an institutional account
[Section titled “4. Hook controls an institutional account”](#4-hook-controls-an-institutional-account)

# Loops and Guarding
> Guards are needed to perform loops in a Hook.
### What are guards?
[Section titled “What are guards?”](#what-are-guards)
Hooks are deliberately not [Turing Complete](https://en.wikipedia.org/wiki/Turing_completeness). This means arbitrary looping is forbidden. Instead you must *guard* your loops against a hard “maximum iteration” boundary.
A guard is a marker placed in your code at the top of each loop. The marker informs the Xahau what the upper bound of your loop will be *in every possible scenario*. Thus if your loop usually executes twice but sometimes executes *500* times, then your guard will say 500.
Guards are used by the Xahau to determine the *worst case execution time* (in instructions) of your Hook before execution. This is the basis for the fee the Xahau charges for the execution of a Hook and makes execution times predictable and controllable.
Tip
Existing developers migrating from other smart contract platforms may find guards to be annoying at first, but once you get used to them they are no harder to use than a normal for-loop.
### The guard function
[Section titled “The guard function”](#the-guard-function)
The guard function tells the ledger the **maximum number of iterations** a loop will make. Specifically the function takes two arguments:
```c
int32_t _g (uint32_t id, uint32_t maxiter);
```
The first argument `id` is the identifier for this guard. This is a unique constant chosen by the developer, typically the line number in the source file is used.
The second argument `maxiter` is a promise the developer makes to the ledger that this guard will not be *hit* more than `maxiter` times during the execution of the Hook. If the guard call is executed more than this many times the Hook will automatically rollback with a `GUARD_VIOLATION` ([Hook API return codes](/docs/hooks/functions/overview/return-codes)). Because the guard will be hit *before* the loop condition is checked, it is important to add one to the total number of expected iterations. (Note: The GUARD() macro already adds one).
Caution
Guards must be set using numerical literals. You cannot use a variable or runtime value in a Guard.
### Guard enforcement
[Section titled “Guard enforcement”](#guard-enforcement)
Consider the following for-loop in C:
```c
#define GUARD(maxiter) _g(__LINE__, (maxiter)+1)
for (int i = 0; GUARD(3), i < 3; ++i)
{
...
}
```
In C, the comma operator executes each expression in a list of expressions (e.g. `A, B, C`) and returns the last expression (e.g. `C`). Thus the condition above is still `i < 3`, but the guard is called before the condition is checked. This is the only way to satisify the *guard rule* when using a for-loop in C.
The Guard Rule
A call to `_g` (the guard function) must be the first branch instruction after a loop instruction.
Below appears the webassembly output when the above is compiled. Note the guard function being called at the start of the loop. The only instructions allowed before this call are non-branch instructions (typically manipulating constants.)
```plaintext
block ;; label = @1
loop ;; label = @2
i32.const 3
i32.const 14
=====> call $_g <=====
drop
...
```
### Nested Loops
[Section titled “Nested Loops”](#nested-loops)
When using nested loops the `maxiter` argument must reflect the total number of times the guard will be *hit*. This means you must multiply the nestings together.
Consider the example below:
```c
#define GUARD(maxiter) _g(__LINE__, (maxiter)+1)
for (int i = 0; GUARD(3), i < 3; ++i)
{
for (int j = 0; GUARD(15), j < 5; ++j)
{
...
}
}
```
Notice the inner-loop’s guard is set to **15**. You must multiply the loops together to compute the maximum number of times an inner guard will be hit during Hook execution.
### No recursion
[Section titled “No recursion”](#no-recursion)
Calls to non-Hook API functions are disallowed in the Hooks ammendment. All user code must fit within the two allowed Hook functions `cbak` and `hook`.
Caution
Failure to use guards correctly will cause an attempted `SetHook` transaction to be rejected.
# Named Hooks
> Selectively activate specific hooks on an account using a name-based execution gate.
*(Added by the [NamedHooks amendment](/docs/features/amendments/#namedhooks).)*
### Overview
[Section titled “Overview”](#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
[Section titled “How It Works”](#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
[Section titled “HookName Constraints”](#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
[Section titled “Removing a Name”](#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
[Section titled “Fee Calculation”](#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
[Section titled “Error Cases”](#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 `Hooks` or `NamedHooks` is not active; or the value fails UTF-8 / length validation. |
### Use Cases
[Section titled “Use Cases”](#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.
# Namespaces
> Prevent state clobbering by using the correct namespace
### Namespaces
[Section titled “Namespaces”](#namespaces)
To avoid two or more Hooks installed on the same account unintentionally clobbering each-other’s [Hook State](/docs/hooks/concepts/state-management), a 32 byte namespace must be provided when creating or installing each Hook.
The namespace may be any arbitrary 32 byte value the developer chooses. Provided the namespace is unique in the Hook chain no state clobbering will occur.
We strongly recommended using `SHA256` over the developer’s working name for the Hook. SHA256 is one of the two hashing algorithms used in the derivation of Xahau addresses (from an account master key), and, as such, it should be readily available to the developer.
The `HookNamespace` field is supplied as a 32 byte *hex* blob inside each `Hook` object in a `Hooks` array when [executing a SetHook transaction](/docs/hooks/concepts/sethook-transaction).
The configured Namespace a Hook operates under alters the [Keylets](/docs/hooks/concepts/slots-and-keylets) its [State](/docs/hooks/concepts/state-management) is stored under. Therefore two Hooks under two different Namespaces installed on the same Xahau account may use the same state key to refer to different state objects. Conversely, two different Hooks using the same Namespace on the same Xahau account can access and modify eachother’s state objects using the same state keys.
### Example
[Section titled “Example”](#example)
In javascript, importing the `ripple-address-codec` yields access to SHA256.\
(It is also possible to use `crypto.subtle` in browser, or `crypto.createHash` in node to access this hash algorithm.)
```js
HookNamespace: addr.codec.sha256('carbon').toString('hex')
```
### Default Namespace
[Section titled “Default Namespace”](#default-namespace)
The first user to [set a novel Hook](/docs/hooks/concepts/sethook-transaction) defines a `HookNamespace` which becomes the *Default Namespace* for that Hook. This means any subsequent users who [reference the same *HookDefinition*](/docs/hooks/concepts/reference-counted-hook-definitions) will receive this originally set Namespace by default.
The subsequent user may specify their own Namespace, overriding the Default Namespace for their installation only.
### Hook APIs Affected
[Section titled “Hook APIs Affected”](#hook-apis-affected)
Choice of HookNamespace affects the behaviour of the following Hook APIs:
* [state](/docs/hooks/functions/state/state)
* [state\_set](/docs/hooks/functions/state/state_set)
### Namespace API Helper
[Section titled “Namespace API Helper”](#namespace-api-helper)
See [account\_info](/docs/hooks/functions/websocket-apis/account_info) and [account\_namespace](/docs/hooks/functions/websocket-apis/account_namespace) for information about how to query the ledger regarding namespaces.
# Parameters
> Install-time parameters allow Hooks to be generic and flexible
### Parameters
[Section titled “Parameters”](#parameters)
Hook developers may opt to use *install-time* parameters (called Hook Parameters) in their Hook. This allows subsequent installers of the Hook to change certain behaviours the programmer defines without recompiling or re-uploading the Hook (assuming at least one account still [references](/docs/hooks/concepts/reference-counted-hook-definitions) the existing Hook Definition.)
Hook Parameters are a set of Key-Value pairs set during the [SetHook Transaction](/docs/hooks/concepts/sethook-transaction) and retrievable by the Hook during runtime. Both the `ParameterName` key and the `ParameterValue` are set as *hex* blobs, and have a maximum length of 32 bytes and 256 bytes respectively.
A [SetHook Transaction](/docs/hooks/concepts/sethook-transaction) may define up to *16* Hook Parameters per installed Hook.
### Setting Parameters
[Section titled “Setting Parameters”](#setting-parameters)
The `HookParameters` array is optionally defined inside each `Hook` in the `Hooks` array as shown below:
```json
TransactionType: "SetHook",
Hooks:
[
{
Hook: {
...,
HookParameters:
[
{
HookParameter:
{
HookParameterName: "ABCDEF12",
HookParameterValue: "12345678"
}
},
... // optionally up to 15 more Hook Parameters
]
}
}
],
...
```
### Default Parameters
[Section titled “Default Parameters”](#default-parameters)
The first user to [set a novel Hook](/docs/hooks/concepts/sethook-transaction) may define Hook Parameters which then become the *Default Parameters* for that Hook. This means any subsequent users who [references the same *HookDefinition*](/docs/hooks/concepts/reference-counted-hook-definitions) will receive these originally set Hook Parameters by default.
The subsequent user may specify their own Parameters, overriding the Default Parameters for their installation.
To erase a Parameter in a subsequent installation, specify the `ParameterName` key without specifying a `ParameterValue` key.
### Using Parameters in Hooks
[Section titled “Using Parameters in Hooks”](#using-parameters-in-hooks)
Parameters can be read by the Hooks they are set on using [hook\_param](/docs/hooks/functions/hook-context/hook_param).
If more than one Hook is installed in a Hook Chain, then [hook\_param\_set](/docs/hooks/functions/hook-context/hook_param_set) can be used in limited circumstances to modify the Hook Parameters of a Hook further down the chain on the same account.
### Runtime Parameters
[Section titled “Runtime Parameters”](#runtime-parameters)
On Xahau and the Xahau testnet, HookParameters may also be included at the top level of any transaction type according to the foregoing rules and size limits. These parameters can be accessed inside a hook using the [otxn\_param](/docs/hooks/functions/originating-transaction/otxn_param) API.
# Reference Counted Hook Definitions
> Avoid re-uploading the same bytecode to the ledger
When a novel Hook’s web assembly byte-code is uploaded to Xahau, a significant storage burden is imposed on the network. This storage burden is reflected in the [Hook Fees](/docs/hooks/concepts/hook-fees) charged by the network.
To avoid this burden (and high fees for end users) reference counting is used:
* The first time a novel Hook is installed, the [SetHook Transaction](/docs/hooks/concepts/sethook-transaction) must provide a significant fee.
* The Hook’s web assembly byte-code becomes an unowned and reference counted object on the ledger (called a `HookDefinition`).
* Subsequent installations by the same or other users for an identical Hook (i.e. with identical byte-code) increment the reference count. These installations point at the same object on the ledger. These transactions are billed in a similar way to setting a Trust Line, as the storage burden for the Hook was already paid for in the original Set Hook transaction.
* While the reference count on the Hook Definition is greater than zero (meaning one or more accounts still have the Hook installed) the object remains on the ledger.

# Serialized Objects
> Manipulate raw serialized xahaud objects!
### What are Serialized Objects?
[Section titled “What are Serialized Objects?”](#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/).
For example an `sfAmount` field serializes to a collection of bytes like `61D50F26109A32B7EC`
### Serialized Object API
[Section titled “Serialized Object API”](#serialized-object-api)
To assist Hook developers in working with serialized objects the `sto` namespace was created within the Hooks API. These functions manipulate pointers within a Hook-provided buffer. See table below.
| Hook API | at it does |
| ----------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| [sto\_subfield](/docs/hooks/functions/serialization/sto_subfield) | Index into a xrpld serialized object and return the location and length of a subfield |
| [sto\_subarray](/docs/hooks/functions/serialization/sto_subarray) | Index into a xrpld serialized array and return the location and length of an index |
| [sto\_emplace](/docs/hooks/functions/serialization/sto_emplace) | Emplace a field into an existing STObject at its canonical placement |
| [sto\_erase](/docs/hooks/functions/serialization/sto_erase) | Remove a field from an STObject |
| [sto\_validate](/docs/hooks/functions/serialization/sto_validate) | Validate an STObject |
Where applicable these APIs return an *offset* and a *length* encoded into a single int64\_t. See individual documentation for details.
### Example
[Section titled “Example”](#example)
At typical scenario in which you would use the STO API is in processing memos on an Originating Transaction. Since you will likely need access to the whole memo anyway, an efficient way to process a set of memos is simply to dump the whole `sfMemos` field into a buffer then index around within it. While it is also possible to use the slot API to do this by slotting the Originating Transaction it would result in additional code and additional copying.
```c
#define SUB_OFFSET(x) ((int32_t)(x >> 32))
#define SUB_LENGTH(x) ((int32_t)(x & 0xFFFFFFFFULL))
#define SBUF(str) (uint32_t)(str), sizeof(str)
uint8_t memos[2048];
int64_t memos_len = otxn_field(SBUF(memos), sfMemos);
for (int i = 0; GUARD(3), i < 3; ++i)
{
int64_t memo_lookup = sto_subarray(memos, memos_len, i);
if (memo_lookup < 0)
rollback(SBUF("Memo lookup error"), 1);
uint8_t* memo_ptr = SUB_OFFSET(memo_lookup) + memos;
uint32_t memo_len = SUB_LENGTH(memo_lookup);
// the above now point at the memo ... do something here
}
```
### PathSet Support and Supported Serialized Types
[Section titled “PathSet Support and Supported Serialized Types”](#pathset-support-and-supported-serialized-types)
PathSet parsing bug (pre-HookAPISerializedType240)
Without the [HookAPISerializedType240 amendment](/docs/features/amendments/#hookapiserializedtype240), all `sto_` functions incorrectly parse `sfPaths` (STPathSet fields, used in Payment transactions with cross-currency routing). The internal parser misreads the PathSet boundary, corrupting the results for any field that appears after `sfPaths` in the serialized object. Hook developers processing Payment transactions with cross-currency paths must ensure this amendment is enabled.
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`, `sfOfferSequence` |
| `STI_UINT64` | 3 | `sfHookOn` |
| `STI_HASH128` | 4 | `sfEmailHash` |
| `STI_HASH256` | 5 | `sfLedgerHash`, `sfTransactionHash` |
| `STI_AMOUNT` | 6 | `sfAmount`, `sfFee` |
| `STI_VL` | 7 | `sfPublicKey`, blobs |
| `STI_ACCOUNT` | 8 | `sfAccount`, `sfDestination` |
| `STI_OBJECT` | 14 | `sfTransaction`, inner objects |
| `STI_ARRAY` | 15 | `sfHooks`, `sfMemos`, `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
[Section titled “Overlap with slots”](#overlap-with-slots)
You may notice some overlap between slot APIs and STO APIs. The key difference here is who *owns* the underlying data:
* If you are using *slots* then xrpld owns the object you are interacting with.
* If you are using the *STO API* then the **Hook** owns the buffer you are interacting with.
Both sets of functions index into a Serialized Object without unnecessary copying.
# SetHook Transaction
### SetHook Transaction
[Section titled “SetHook Transaction”](#sethook-transaction)
Hook web assembly bytecode is installed onto an Xahau account using the `SetHook` transaction.
An example appears below:
```js
{
Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
TransactionType: "SetHook",
Fee: "2000000",
Hooks:
[
{
Hook: {
CreateCode: fs.readFileSync('accept.wasm').toString('hex').toUpperCase(),
HookOn: '0000000000000000',
HookNamespace: addr.codec.sha256('accept').toString('hex').toUpperCase(),
HookApiVersion: 0
}
}
]
}
```
The transaction is deceptively simple, but hides significant complexity, described below.
### Hooks Array
[Section titled “Hooks Array”](#hooks-array)
The main body of the SetHook transaction is the hooks array:
```js
{
Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
TransactionType: "SetHook",
Hooks: // This is the Hooks Array
[
{ Hook: { ... } }, // HookSet Object (position 0)
{ Hook: { ... } },
{ Hook: { ... } },
{ Hook: { ... } }. // HookSet Object (position 3)
]
}
```
This array *mirrors* the [Hook Chain](/docs/hooks/concepts/chaining) installed on the account:
* Position 0 in the array *corresponds* to position 0 in the Hook Chain.
* Position 3 in the array *corresponds* to position 3 in the Hook Chain, etc.
### HookSet Object and Corresponding Hook
[Section titled “HookSet Object and Corresponding Hook”](#hookset-object-and-corresponding-hook)
Each entry in the Hooks Array (in the SetHook Transaction) is called a *HookSet Object*, and its corresponding Hook in the account’s Hook Chain is called the *Corresponding Hook*.

*Example: A user performs an operation on each Hook in his/her Hook chain with a SetHook transaction.*
### HookDefinition
[Section titled “HookDefinition”](#hookdefinition)
Each Corresponding Hook is an object containing a *reference* (pointer) to a `HookDefinition` object.
The HookDefinition object is an unowned reference-counted ledger object that provides for de-duplication of identical web assembly bytecode. Two users using an identical hook will both point to the same HookDefinition.

*Example: Hook Definitions on Xahau*
For more information see: [Reference Counting](/docs/hooks/concepts/reference-counted-hook-definitions)
### Hook Defaults
[Section titled “Hook Defaults”](#hook-defaults)
When a `HookDefinition` is created it contains the initial [Parameters](/docs/hooks/concepts/parameters), [Namespace](/docs/hooks/concepts/namespaces) and [Grants](/docs/hooks/concepts/grants) supplied by the user. These become the Hook Defaults. Any Hook referencing this Hook Definition will use these defaults *unless* the SetHook Transaction that creates that reference explicitly overrides those defaults, or a subsequent Update Operation overrides them.
### HookSet Operations
[Section titled “HookSet Operations”](#hookset-operations)
There are six possible operations: No Operation, Create, Update, Delete, Install and Namespace Delete
Each operation is specified by the inclusion or omission of certain HookSet Object fields. This might seem confusing at first but by working through a few examples the reader should find it intuitive; Essentially HookSet operations are a type of **diff** between a specific Hook’s *defaults*, *existing* and newly specified fields.
Achieving each type of operation is explained in a subsection below.
### No Operation
[Section titled “No Operation”](#no-operation)
**Occurs when**:
* The HookSet Object is empty
**Behaviour**:
* No change of any kind is made.
**Example**:
```json
{
Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
TransactionType: "SetHook",
Fee: "2000000",
Hooks:
[
{
Hook: {}
}
]
}
```
### Create Operation
[Section titled “Create Operation”](#create-operation)
**Occurs when**:
*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 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 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`.
* The `Hook` object contains no fields except `HookHash` which points at the created `HookDefinition`.
* If `hsfNSDELETE` flag is specified then any HookState entires in the destination namespace are deleted if they currently exist.
**Example**:
```json
{
Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
TransactionType: "SetHook",
Fee: "2000000",
Hooks:
[
{
Hook: {
CreateCode: fs.readFileSync('accept.wasm').toString('hex').toUpperCase(),
HookOn: '0000000000000000',
HookNamespace: addr.codec.sha256('accept').toString('hex').toUpperCase(),
HookApiVersion: 0
}
}
]
}
```
### Install Operation
[Section titled “Install Operation”](#install-operation)
**Occurs when**:
*All* of the following conditions are met:
* The Corresponding Hook does not exist *or*`FLAG_OVERRIDE` is specified.
* `HookHash` field is specified and is not blank and contains the hash of a Hook that already exists as a `HookDefinition` on the ledger *or* `CreateCode` field is specified and is not blank and contains the valid web assembly bytecode for a valid hook that already exists on the ledger as a `HookDefinition`.
**Behaviour**:
* The reference count of the `HookDefinition` object is incremented.
* 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`.
* The `Hook` object contains all the fields in the HookSet Object, except and unless:
* A field or key-pair within a field is identical to the Hook Defaults set on the `HookDefinition`, in which case it is omitted due to defaults.
* If `hsfNSDELETE` flag is specified then any HookState entires in the destination namespace are deleted if they currently exist.
**Example**:
```json
{
Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
TransactionType: "SetHook",
Fee: "2000000",
Hooks:
[
{
Hook: {
HookHash: "A5663784D04ED1B4408C6B97193464D27C9C3334AAF8BBB4FA5EB8E557FC4A2C",
HookOn: '0000000000000000',
HookNamespace: addr.codec.sha256('accept').toString('hex').toUpperCase(),
}
}
]
}
```
### Update Operation
[Section titled “Update Operation”](#update-operation)
**Occurs when**:
*All* of the following conditions are met:
* The Corresponding Hook exists.
* `HookHash` is absent.
* `CreateCode` is absent.
* One or more of `HookNamespace`, `HookParameters` or `HookGrants` is present.
**General Behaviour**:
* The Corresponding Hook is updated in such a way that the desired changes are reflected in the Corresponding Hook.
**Specific Behaviour**:
If `HookNamespace` is specified and differs from the Corresponding Hook’s Namespace:
* the Corresponding Hook’s `HookNamespace` is updated, and
* if the `hsfNSDELETE` flag is specified all HookState entires in the old namespace are deleted.
If `HookParameters` is specified, then for each entry:
* If `HookParameterName` exists but `HookParameterValue` is absent and the Corresponding Hook’s Parameters (either specifically or via defaults) contains this `HookParameterName` then the parameter is marked as deleted on the Corresponding Hook.
* If `HookParameterName` exists and `HookParameterValue` exists then the Corresponding Hook’s Parameters are modified to include the new or updated parameter.
If `HookGrants` is specified then:
* The Corresponding Hook’s `HookGrants` array is replaced with the array.
**Example**:
```json
{
Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
TransactionType: "SetHook",
Fee: "2000000",
Hooks:
[
{
Hook: {
HookNamespace: addr.codec.sha256('new_accept').toString('hex').toUpperCase(),
}
}
]
}
```
### Delete Operation
[Section titled “Delete Operation”](#delete-operation)
**Occurs when**:
*All* of the following conditions are met:
* The Corresponding Hook exists.
* `hsfOVERRIDE` is specified.
* optionally `hsfNSDELETE` is also specified.
* `HookHash` is absent.
* `CreateCode` is present but empty.
**Behaviour**:
* The reference count of the `HookDefinition` object is decremented.
* If the reference count is now zero the `HookDefintion` is removed from the ledger.
* The `Hook` object in the Corresponding Hook position is deleted, leaving an empty position.
* If `hsfNSDELETE` is specified the namespace and all HookState entries are also deleted.
**Example**:
```json
{
Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
TransactionType: "SetHook",
Fee: "2000000",
Hooks:
[
{
Hook: {
CreateCode: "",
Flags: 1,
}
}
]
}
```
### Namespace Reset
[Section titled “Namespace Reset”](#namespace-reset)
**Occurs when**:
*All* of the following conditions are met:
* `flags` is present and `hsfNSDELETE` is set. `hsfOVERRIDE` can optionally also be specified if the Hook at this position is to be deleted.
* `HookNamespace` is specified.
* `CreateCode` is absent.
* `HookHash` is absent.
* `HookGrants`, `HookParameters`, `HookOn` and `HookApiVersion` are absent.
**Behaviour**:
* If the Corresponding Hook exists, it remains, nothing happens to it.
* A subset of HookState objects and the HookState directory for the specified namespace are removed from the ledger, up to the defined limit of 512. Further transactions are needed to continue the deletion process until all relevant records are removed.
**Example**:
```json
{
Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
TransactionType: "SetHook",
Fee: "2000000",
Hooks:
[
{
Hook: {
HookNamespace: addr.codec.sha256('accept').toString('hex').toUpperCase(),
Flags: 3,
}
}
]
}
```
# Slots and Keylets
> Inspect and manipulate on-ledger objects.
### Background
[Section titled “Background”](#background)
Xahau contains numerous heterogenous object types which a Hook has read-access to. For example: *transactions*, *accounts*, *ledgers*, and the subcomponents of each of these, to name just a few.
It is very easy to carelessly program a computer to do a lot of needless copy operations when disciplined access to the same underlying data (i.e. through a view) would suffice. The deliberate avoidance of copy operations in programming is referred to as [Zero copy](https://en.wikipedia.org/wiki/Zero-copy) in programming.
With Hooks the same principle applies. We want to avoid copying where possible. In particular we want to avoid as much as possible needlessly copying large objects such as whole ledgers, we also want to avoid serializaing and unserializing these where possible.
### What are slots?
[Section titled “What are slots?”](#what-are-slots)
Slots are part of the Hook API and provide a zero-copy *heterogenous* access system for on-ledger objects and transactions.
* Each Hook has access to 255 slots during runtime.
* Each slot may be empty or may contain a *slotted* object.
* The slot API allows traversal into inner objects, and allows these inner objects themselves to be slotted.
* The slot API allows slotted objects to be dumped to a buffer or otherwise read by the Hook.
The avilable slot APIs are:
| Hook API | What it does |
| ---------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| [slot](/docs/hooks/functions/slot/slot) | Serialize and output a slotted object |
| [slot\_clear](/docs/hooks/functions/slot/slot_clear) | Free up a currently occupied slot |
| [slot\_count](/docs/hooks/functions/slot/slot_count) | Count the elements of an array object in a slot |
| slot\_id | Compute the canonical hash of the slotted object and return it |
| [slot\_set](/docs/hooks/functions/slot/slot_set) | Locate an object based on its keylet and place it into a slot |
| [slot\_subarray](/docs/hooks/functions/slot/slot_subarray) | Index into a slotted array and assign a sub-object to another slot |
| [slot\_subfield](/docs/hooks/functions/slot/slot_subfield) | Index into a slotted object and assign a sub-object to another slot |
| [slot\_type](/docs/hooks/functions/slot/slot_type) | Retrieve the field code of an object in a slot and, optionally, some other information |
| [slot\_float](/docs/hooks/functions/slot/slot_float) | Parse the STI\_AMOUNT in the specified slot and return it as an XFL enclosed number |
| [slot\_size](/docs/hooks/functions/slot/slot_size) | Compute the serialized size of an object in a slot |
### What are keylets?
[Section titled “What are keylets?”](#what-are-keylets)
Keylets are used to locate (point to) on-ledger objects. In brief they are a *hash* of identifying information from the object, which is the canonical *handle* for that object.
Hooks use a serialized 34 byte keylet format which can be derrived using the important [util\_keylet](/docs/hooks/functions/utilities/util_keylet) function. Without this looking up and slotting objects would be generally impossible.
Tip
The Hook APIs which accept a 34 byte keylet will also generally accept a 32 byte canonical transaction hash.
### Example
[Section titled “Example”](#example)
In the following example a 34 byte keylet for a `signers` object is used to slot that object.
```c
uint8_t keylet[34];
if (util_keylet(SBUF(keylet), KEYLET_SIGNERS, SBUF(hook_accid), 0, 0, 0, 0) != 34)
rollback(SBUF("Notary: Internal error, could not generate keylet"), 10);
// then requesting XRPLD slot that keylet into a new slot for us
int64_t slot_no = slot_set(SBUF(keylet), 0);
if (slot_no < 0)
rollback(SBUF("Notary: Could not set keylet in slot"), 10);
```
# State Management
> Hooks can read and save small pieces of on-ledger data 🚀
### What is Hook State?
[Section titled “What is Hook State?”](#what-is-hook-state)
[State](https://en.wikipedia.org/wiki/State_\(computer_science\)) in computer science describes information held by a system between executions (as distinct from inputs and outputs.) For example your browser leaves you logged in to a website even after you close and reopen it. The login cookie is held in the browser’s *state*.
**Hook State** refers to a key-value mapping that logically exists for each account on Xahau whether or not any keys are currently present. The keys are always 32 bytes (unsigned 256 bit integer) and the values are variable length with a maximum size determined by validator voting, at time of writing 256 bytes.
State Management is achieved using
* [state](/docs/hooks/functions/state/state)
* [state\_set](/docs/hooks/functions/state/state_set)
* [state\_foreign](/docs/hooks/functions/state/state_foreign)
### Storing and fetching
[Section titled “Storing and fetching”](#storing-and-fetching)
The below example uses the [state\_set](/docs/hooks/functions/state/state_set) Hook API to assign the value `0xC001CAFE` to the key `0x0..000001` (uint256 = 1) in the Hook State of the Hook Account.
```c
uint8_t key[32] = {
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U
};
uint8_t value[4] = { 0xC0U, 0x01U, 0xCAU, 0xFEU };
if (state_set(value, 4, key, 32) == 4)
{
// ... state successfully saved
}
```
In a subsequent Hook execution this value can now be retrieved using the same key:
```c
uint8_t value[4];
uint8_t key[32] = {
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U
};
if (state(value, 4, key, 32) < 0)
{
// ... state fetch failed
}
```
After the above code has run the `value` buffer will be populated with the value found at the key.
Tip
The buffer that `state()` reads into (`writeptr`) must be large enough to store the value currently held at that key. If it isn’t, the Hook API returns with a `TOO_SMALL` error.
### Foreign state
[Section titled “Foreign state”](#foreign-state)
From time to time it may be advantageous for one Hook running on one account to read the Hook State of another Hook running on another account. The [state\_foreign](/docs/hooks/functions/state/state_foreign) Hook API does exactly this. Because the ledger is public there is no reasonable expectation of privacy anyway. Any Hook may therefore *read* (but not write) the Hook State of any other Hook.
### Namespaces and querying
[Section titled “Namespaces and querying”](#namespaces-and-querying)
Please see [Namespaces](/docs/hooks/concepts/namespaces)
# Terminology
> Welcome to Hooks 👋
### What are Hooks?
[Section titled “What are Hooks?”](#what-are-hooks)
Hooks are small, efficient web assembly modules designed specifically for Xahau. Hooks can be written in any language (compilable to WebAssembly) and most business logic and most smart contract concepts can be implemented in a hook. Typically Hooks are written in C.
Hooks are set onto an Xahau account using a `SetHook` transaction. Once installed on an account, a hook can:
1. Block or allow incoming and outgoing transactions on the account,
2. Modify and maintain internal state and logic specific to the hook on that account, and
3. Emit new transactions on behalf of the account.
### Glossary
[Section titled “Glossary”](#glossary)
This Hooks documentation and the Hooks API use a set of unfamiliar terms. Use the lookup table below if you find yourself lost.
| Term | Explanation |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Hook | *This term refers to a range of things depending on context* 1. A webassembly binary uploadable to Xahau with the [SetHook Transaction](/docs/hooks/concepts/sethook-transaction) type. 2. A webassembly binary already uploaded to and set or configured onto an Xahau account. 3. The [source code](/docs/hooks/concepts/compiling-hooks) of such a binary. |
| Originating Transaction | The transaction that triggered the Hook to fire. This could be either a transaction sent out of or into an account with a Hook set on it. |
| Originating Account | The account that sent an Originating Transaction. |
| Hook Account | The account where the currently executing Hook lives. This is the account that owns the Hook, the account that performed the [SetHook Transaction](/docs/hooks/concepts/sethook-transaction) which created the Hook and the account to whom belongs the Hook State for the currently executing Hook. |
| Installer | The account which is currently installing a Hook using the SetHook transaction. |
| Emitted Transaction | A new transaction created by a Hook during the Hook’s execution that is not the Originating Transaction. These are typically used for sending funds back to the Originating Account. See: [Emitted Transactions](/docs/hooks/concepts/emitted-transactions). |
| State | A per-account key-value map of 32 byte keys to arbitrary data. All Hooks present on an account have access to the same Hook State and can modify it. Note that the Hook State lives on the Hook Account **not** on the Originating Account. See: [State Management](/docs/hooks/concepts/state-management). |
| SetHook | A new Transaction Type introduced in the Hooks ammendment which sets a Hook onto an Xahau account. See: [SetHook Transaction](/docs/hooks/concepts/sethook-transaction). |
| Guards | A special control mechanism you need to use if you write a loop into in a Hook. See: [Loops and Guarding](/docs/hooks/concepts/loops-and-guarding). |
| Grants | Special permission a Hook Installer can give another account or a specific Hook (regardless of where it is installed) to modify Hook State on the Installer’s account. |
| Namespace | A unique 32 byte code delineating one set of state keys from another. The same state key may be used by two different Hooks without interfering with each-other if the namespaces set on the Hooks are different. |
| Parameters | Install-time parameters that can be optionally set on a Hook. |
| Reference Counting | An unowned object on the ledger may be reference counted, meaning it is deleted when the final account which referenced (used) it removes their reference to it. |
| XFL or Floating Point | A way to do high precision math in Hooks such as for exchange rate computation. See: [Floating Point Numbers (XFL)](/docs/hooks/concepts/floating-point-numbers-xfl). |
| Serialized Objects (STO) | The way xahaud transmits and stores ledger objects. See: [Serialized Objects](/docs/hooks/concepts/serialized-objects). |
| Slots and Keylets | Slots can contain ledger objects and keylets identify those objects. See: [Slots and Keylets](/docs/hooks/concepts/slots-and-keylets). |
| Trace | A way to print a log line to the xrpld output from a Hook. See: [Debugging Hooks](/docs/hooks/concepts/debugging-hooks). |
# Weak and Strong
> Which Hooks are allowed to run and when?
Hook Design Philosophy
Every party affected by a transaction should have the opportunity to have their Hooks executed.
Transactional Stake Holders (TSH) are parties that somehow have a stake in or are otherwise affected by a transaction. Their particular stake may be a *weak* or *strong*. The degree of connection with the transaction dictates whether the party has the right to have their Hooks executed and who has to pay for that execution.
For example:
* In a conventional direct XAH **Payment** transaction the two TSH are the *originating account* and the *destination account*.
* In a **SetSignerList** transaction the TSH are the *originating account* and each account whose address appears in the signer list, where such accounts are active on the ledger.
* In an **OfferCreate** transaction, other account’s offers which are crossed by the originating transaction are all weak TSH and may opt for weak execution.
* With the **IOUIssuerWeakTSH** amendment, currency issuers have their hooks executed in third-party transactions that touch or mention their currency, if they have opted into weak execution.
Due to the heterogenous nature of transactions on Xahau, TSH come in all shapes and sizes and can be exotic and non-intuitive. This becomes more true as time passes and more transaction types are added to the Ledger.
### Weak and Strong
[Section titled “Weak and Strong”](#weak-and-strong)
Each TSH has either a weak or a strong connection to the transaction.
A **Strong** connection means:
1. The originating transaction must pay the fee for the execution of the TSH Hook Chain
2. The TSH has the right to rollback the whole transaction by calling `rollback()` from their Hook during execution.
A **Weak** connection means:
1. The originating transaction **does not** pay for the execution of the TSH Hook Chain.
2. The TSH pays for the execution of their own Hook Chain through a feature called [Collect Call Hooks](/docs/hooks/concepts/collect-call).
3. The TSH must have set an account flag `asfTshCollect` prior to the execution of the originating transaction.
4. The TSH **does not** have the right to rollback the whole transaction by calling `rollback()` from their Hook during execution (but can still modify their own Hook state and Emit transactions.)
### Before or After
[Section titled “Before or After”](#before-or-after)
Strong TSHes have their hooks executed *before* the originating transaction is applied to the ledger. This means they have the ability to [rollback](/docs/hooks/functions/control/rollback) the transaction (because it hasn’t yet been applied.) This gives strongly executed hooks the ability to completely block a transaction from occurring.
Weak TSHes have their hooks executed *after* the originating transaction has been applied to the ledger. This means they have access to the [transaction metadata](/docs/hooks/functions/originating-transaction/meta_slot) but cannot prevent the transaction from occurring.
Tip
Strongly executed hooks can call [hook\_again](ref:hook_again) to be executed a second time as a weak execution after the originating transaction has been applied.
### Execution Context
[Section titled “Execution Context”](#execution-context)
The `uint32_t` parameter in `hook(uint32_t)` and `cbak(uint32_t)` carries important context information from the Hooks Amendment to your Hook.
During the execution of `hook`:
* 0 means the Hook is being executed *strongly*
* 1 means the Hook is being executed *weakly*
* 2 means the Hook is being executed *weakly* after being executed *strongly* due to a [hook\_again](/docs/hooks/functions/hook-context/hook_again) call.
During the execution of `cbak`:
* 0 means the Hook is being called back after a transaction it emitted was successfully accepted into a ledger.
* 1 means the Hook is being called back after a transaction it emitted was marked as never able to be applied to any ledger (EmitFailure).
### Reference Table
[Section titled “Reference Table”](#reference-table)
If a Transaction Type does not appear in the table then it has no TSHes **other than its originating account.**
| Transaction Type | TSH Type | Who is the TSH |
| ----------------------- | ------------- | -------------------------------------------------------------------------------------------- |
| AccountDelete | Strong | Destination account funds are paid out to after deletion |
| AccountSet | None | N/A |
| CheckCancel | Weak | Destination account |
| CheckCash | None | N/A |
| CheckCreate | Strong | Destination account |
| ClaimReward | Strong | Issuer Account |
| DepositPreauth | Strong | Authorized account |
| EscrowCancel | Weak | Destination account |
| EscrowCreate | Strong | Destination account |
| EscrowFinish | Strong | Destination account |
| GenesisMint | Weak | Each Destination in the GenesisMints Array |
| Import | Strong | Issuer Account |
| Invoke | Strong | Destination account |
| OfferCancel | None | N/A |
| OfferCreate | Weak | Accounts whose offers were crossed by this action. |
| Payment | Strong + Weak | Strong: Destination account. Weak: Any non-issuer the payment is rippled through. |
| PaymentChannelClaim | Weak | Destination account |
| PaymentChannelCreate | Strong | Destination account |
| PaymentChannelFund | Weak | Destination account |
| SetHook | None | N/A |
| SetRegularKey | Strong | The account whose address is being set as the key. |
| SignerListSet | Strong | Accounts whose addresses are set as signing keys (if they exist and have Hooks set on them). |
| TicketCreate | None | N/A |
| TrustSet | Weak | Issuer account |
| URITokenCancelSellOffer | None | N/A |
| URITokenCreateSellOffer | Strong | Destination account, Issuer if tfBurnable Flag is set |
| URITokenBurn | Strong | Issuer if tfBurnable Flag is set |
| URITokenBuy | Strong | Owner account, Issuer if tfBurnable Flag is set |
| URITokenMint | None | N/A |
**AccountSet**
| OTXN | TSH | AccountSet |
| ------- | ------- | ---------- |
| Account | Account | Strong |
**AccountDelete**
| OTXN | TSH | AccountDelete |
| ------- | ----------- | ------------- |
| Account | Account | None |
| Account | Beneficiary | Strong |
**Check**
| OTXN | TSH | CheckCancel | CheckCreate | CheckCash |
| ----------- | ----------- | ----------- | ----------- | --------- |
| Account | Account | Strong | Strong | None |
| Account | Destination | Weak | Strong | None |
| Destination | Destination | Strong | None | Strong |
| Destination | Account | Weak | None | Weak |
**ClaimReward**
| OTXN | TSH | ClaimReward |
| ------- | ------- | ----------- |
| Account | Account | Strong |
| Account | Issuer | Strong |
**DepositPreauth**
| OTXN | TSH | DepositPreauth |
| ------- | ---------- | -------------- |
| Account | Account | Strong |
| Account | Authorized | Strong |
**Escrow**
| OTXN | TSH | EscrowCancel | EscrowCreate | EscrowFinish |
| ----------- | ----------- | ------------ | ------------ | ------------ |
| Account | Account | Strong | Strong | Strong |
| Account | Destination | Weak | Strong | Weak |
| Destination | Destination | Strong | None | Strong |
| Destination | Account | Weak | None | Weak |
**GenesisMint**
| OTXN | TSH | GenesisMint |
| ------- | ----------- | ----------- |
| Account | Account | Strong |
| Account | Destination | Strong |
| Account | Beneficiary | Weak |
**Import**
| OTXN | TSH | Import |
| ------- | ------- | ------ |
| Account | Account | Strong |
| Account | Issuer | Strong |
**Invoke**
| OTXN | TSH | Invoke |
| ------- | ----------- | ------ |
| Account | Account | Strong |
| Account | Destination | Weak |
**Offer**
| OTXN | TSH | OfferCancel | OfferCreate |
| ------- | ------- | ----------- | ----------- |
| Account | Account | Strong | Strong |
| Account | Crossed | None | Weak |
**Payment**
| OTXN | TSH | Payment |
| ------- | ----------- | ------- |
| Account | Account | Strong |
| Account | Destination | Strong |
| Account | Crossed | Weak |
**PaymentChannel**
| OTXN | TSH | PaymentChannelClaim | PaymentChannelCreate | PaymentChannelFund |
| ----------- | ----------- | ------------------- | -------------------- | ------------------ |
| Account | Account | Strong | Strong | Strong |
| Account | Destination | Weak | Strong | Weak |
| Destination | Destination | Strong | None | None |
| Destination | Account | Weak | None | None |
**SetHook**
| OTXN | TSH | SetHook |
| ------- | ------- | ------- |
| Account | Account | Strong |
**SetRegularKey**
| OTXN | TSH | SetRegularKey |
| ------- | ---------- | ------------- |
| Account | Account | Strong |
| Account | RegularKey | Strong |
**SignerListSet**
| OTXN | TSH | SignerListSet |
| ------- | ------- | ------------- |
| Account | Account | Strong |
| Account | Signer | Strong |
**Ticket**
| OTXN | TSH | TicketCreate |
| ------- | ------- | ------------ |
| Account | Account | Strong |
**TrustSet**
| OTXN | TSH | TrustSet |
| ------- | ------- | -------- |
| Account | Account | Strong |
| Account | Issuer | Weak |
**URIToken**
| OTXN | Burnable | TSH | Mint | Burn | Buy | Sell | Cancel |
| ------ | -------- | ------ | ------ | ------ | ------ | ------ | ------ |
| Owner | False | Owner | None | Strong | Strong | Strong | Strong |
| Owner | False | Issuer | None | Weak | Weak | Weak | None |
| Owner | False | Buyer | None | None | None | Strong | Weak |
| Owner | True | Buyer | None | None | None | Strong | Weak |
| Owner | True | Owner | None | Strong | Strong | Strong | Strong |
| Owner | True | Issuer | None | Weak | Strong | Strong | None |
| Issuer | False | Owner | None | None | None | None | None |
| Issuer | False | Issuer | Strong | None | None | None | None |
| Issuer | False | Buyer | Weak | None | None | None | None |
| Issuer | True | Owner | None | Weak | None | None | None |
| Issuer | True | Issuer | Strong | Strong | None | None | None |
| Issuer | True | Buyer | Weak | None | None | None | None |
| Buyer | True | Buyer | None | None | Strong | None | None |
| Buyer | True | Owner | None | None | Weak | None | None |
# accept
> Accept the originating transaction and commit any changes the hook made.
### Concepts
[Section titled “Concepts”](#concepts)
[Introduction ](/docs/hooks/concepts/introduction/)[Execution Metadata](/docs/hooks/concepts/execution-metadata)
### Behaviour
[Section titled “Behaviour”](#behaviour)
End the execution of the hook with status: success.
* Record a return string and return code in transaction metadata.
* Commit all state changes.
* Submit all `emit()` transactions.
* Allow originating transaction to continue.
Caution
If the originating transaction is stopped for some other reason then this accept becomes a rollback. See: Execution Order.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t accept (
uint32_t read_ptr,
uint32_t read_len,
uint64_t error_code
);
```
* JavaScript
```javascript
function accept(msg: string, code: number): number
```
### Example
[Section titled “Example”](#example)
* C
```c
accept("Success", 7, 100);
```
* JavaScript
```javascript
accept('Success', 100)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ----------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| read\_ptr | uint32\_t | Pointer to a return string to be stored in execution metadata. This is any string the hook-developer wishes to return with the acceptance. *May be null.* |
| read\_len | uint32\_t | The length of the return string. At most 32. *May be null.* |
| error\_code | uint64\_t | A return code specific to this hook to be stored in execution metadata. Similar to the return code of an application on a \*nix system. By convention success is zero. |
* JavaScript
| Name | Type | Description |
| ---- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| msg | string | String to be stored in execution metadata. This is any string the hook-developer wishes to return with the acceptance. *May be null.* |
| code | number | A return code specific to this hook to be stored in execution metadata. Similar to the return code of an application on a \*nix system. By convention success is zero. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | Accept ends the hook, therefore no value is returned to the caller. By convention all Hook APIs return `int64_t`, but in this case nothing is returned. |
* JavaScript
| Type | Description |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| number | Accept ends the hook, therefore no value is returned to the caller. By convention all Hook APIs return `a number`, but in this case nothing is returned. |
# rollback
### Concepts
[Section titled “Concepts”](#concepts)
[Introduction ](/docs/hooks/concepts/introduction/)[Execution Metadata](/docs/hooks/concepts/execution-metadata)
### Behaviour
[Section titled “Behaviour”](#behaviour)
End the execution of the hook with status: reject.
* Record a return string and return code in transaction metadata.
* Discard all state changes.
* Discard all `emit()` transactions.
* Disallow originating transaction to continue.
Caution
The originating transaction will fail with `tecHOOK_REJECTED` and a fee will be charged. See: Execution Order.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t rollback (
uint32_t read_ptr,
uint32_t read_len,
uint64_t error_code
);
```
* JavaScript
```javascript
function rollback(error_msg: string, error_code: number): number
```
### Example
[Section titled “Example”](#example)
* C
```c
rollback("Rejected!", 9, 100);
```
* JavaScript
```javascript
rollback('Rejected!', 100)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ----------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| read\_ptr | uint32\_t | Pointer to a return string to be stored in execution metadata. This is any string the hook-developer wishes to return with the acceptance. *May be null.* |
| read\_len | uint32\_t | The length of the return string. At most 32. *May be null.* |
| error\_code | uint64\_t | A return code specific to this hook to be stored in execution metadata. Similar to the return code of an application on a \*nix system. By convention non-success is non-zero. |
* JavaScript
| Name | Type | Description |
| ----------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| error\_msg | string | String to be stored in execution metadata. This is any string the hook-developer wishes to return with the acceptance. *May be null.* |
| error\_code | number | A return code specific to this hook to be stored in execution metadata. Similar to the return code of an application on a \*nix system. By convention non-success is non-zero. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | Rollback ends the hook, therefore no value is returned to the caller. By convention all Hook APIs return `int64_t`, but in this case nothing is returned. |
* JavaScript
| Type | Description |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| number | Rollback ends the hook, therefore no value is returned to the caller. By convention all Hook APIs return `number`, but in this case nothing is returned. |
# cbak / Callback
> The callback function of your hook
### Concepts
[Section titled “Concepts”](#concepts)
[Compiling Hooks](/docs/hooks/concepts/compiling-hooks)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* `cbak` is a user defined function called by `xahaud` in order to inform your hook about the status of a previously emitted transaction
* State changes and further emit calls can be made from cbak but it cannot `rollback` a transaction.
* When cbak is executed the emitted transaction to which the callback relates is now the originating transaction.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t cbak (
uint32_t what
)
```
* JavaScript
```javascript
type Callback = (reserved: number) => number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t cbak(uint32_t reserved)
{
return 0;
}
```
* JavaScript
```javascript
const Callback = (reserved: number) => {
return 0
}
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| -------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| reserved | uint32\_t | if `0`: - the emittted transaction to which this callback relates was successfully accepted into a ledger. If `1` - the emitted transaction to which the callback relates was NOT successfully accepted into a ledger before it expired. |
* JavaScript
| Name | Type | Description |
| -------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| reserved | number | if `0`: - the emittted transaction to which this callback relates was successfully accepted into a ledger. If `1` - the emitted transaction to which the callback relates was NOT successfully accepted into a ledger before it expired. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | -------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | An arbitrary return code you wish to return from your hook. This will be present in the metadata of the originating transaction. |
* JavaScript
| Type | Description |
| ------ | -------------------------------------------------------------------------------------------------------------------------------- |
| number | An arbitrary return code you wish to return from your hook. This will be present in the metadata of the originating transaction. |
# hook
> The main function of your hook
### Concepts
[Section titled “Concepts”](#concepts)
[Compiling Hooks](/docs/hooks/concepts/compiling-hooks)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* `hook` is a user defined function called by `xahaud` in order to fire your hook.
* Your `hook` function calls either `accept` or `reject` to pass or reject the originating transaction.
* If execution reaches the end of the function it is implicitly an `accept`.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t hook (
uint32_t reserved
)
```
* JavaScript
```javascript
type Hook = (reserved: number) => number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t hook(uint32_t reserved)
{
return 0;
}
```
* JavaScript
```javascript
const Hook = (reserved: number) => {
return 0
}
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| -------- | --------- | ------------------------ |
| reserved | uint32\_t | Reserved for future use. |
* JavaScript
| Name | Type | Description |
| -------- | ------ | ------------------------ |
| reserved | number | Reserved for future use. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | -------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | An arbitrary return code you wish to return from your hook. This will be present in the metadata of the originating transaction. |
* JavaScript
| Type | Description |
| ------ | -------------------------------------------------------------------------------------------------------------------------------- |
| number | An arbitrary return code you wish to return from your hook. This will be present in the metadata of the originating transaction. |
# emit
> Emit a new transaction from the hook
### Concepts
[Section titled “Concepts”](#concepts)
[Emitted Transactions ](/docs/hooks/concepts/emitted-transactions)[prepare()](/docs/hooks/functions/emitted-transaction/prepare)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* 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/prepare) before `emit()` to automatically inject all required emission fields (`Account`, `Sequence`, `SigningPubKey`, `Fee`, `EmitDetails`, etc.) from a partial transaction.
* JavaScript
* This function emits the provided transaction JSON.
* On success, it returns the emitted transaction hashes.
* If there is an error, it returns an error code.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t emit (
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len
);
```
* JavaScript
```javascript
function emit(
txJson: Record | Transaction
): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
* C
```c
uint8_t emithash[32];
if (emit(SBUF(emithash), SBUF(tx)) < 0)
rollback(SBUF("hook: emit failed"), __LINE__);
```
* JavaScript
```javascript
const emitResult = emit(txJson)
if(typeof emitResult === 'number')
rollback("Failed to emit!", 1)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| 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 |
* JavaScript
| Name | Type | Description |
| ------ | ----------------------------------- | -------------------- |
| txJson | Record\ \| Transaction | The TX JSON to emit. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| 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. |
* JavaScript
| Type | Description |
| ---------------------- | ------------------------------------------------------------------------------------------------ |
| ErrorCode \| ByteArray | Returns an ErrorCode if there is an error, or an array of emitted transaction hashes on success. |
# etxn_burden
> Get the burden of a hypothetically emitted transaction
### Concepts
[Section titled “Concepts”](#concepts)
[Emitted Transactions](/docs/hooks/concepts/emitted-transactions)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* Return the burden an emitted transaction will carry.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t etxn_burden (
void
);
```
* JavaScript
```javascript
function etxn_burden(): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t burden = etxn_burden();
```
* JavaScript
```javascript
const burden = etxn_burden()
```
### Parameters
[Section titled “Parameters”](#parameters)
None
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------ |
| int64\_t | The burden an emitted transaction will need in order to be successfully passed to `emit()` |
* JavaScript
| Type | Description |
| ------ | -------------------------------------------------------------------------- |
| number | An ErrorCode if there is an error, or the current burden value on success. |
# etxn_details
> Produce an sfEmitDetails suitable for a soon-to-be emitted transaction
### Concepts
[Section titled “Concepts”](#concepts)
[Emitted Transactions](/docs/hooks/concepts/emitted-transactions)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Generate and write a 105 byte sfEmitDetails object into the `write_ptr` if cbak is not defined
* Generate and write a 127 byte sfEmitDetails object into the `write_ptr` if cbak is defined.
* JavaScript
* This function provides detailed information about the transaction.
* Returns an ErrorCode if there is an error, or an array of transaction details on success.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t etxn_details (
uint32_t write_ptr,
uint32_t write_len
);
```
* JavaScript
```javascript
function etxn_details(): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
* C
```c
uint8_t emitdet[105];
int64_t result =
etxn_details(emitdet, 105);
if (result != 105)
rollback("Etxndetails failed.", 19, 1);
```
* JavaScript
```javascript
const emitdet = etxn_details()
if (typeof emitdet === 'string || emitdet.length != 105)
rollback("Etxndetails failed.", 1)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | -------------------------------------------------------- |
| write\_ptr | uint32\_t | Pointer to the buffer receiving the sfEmitDetails record |
| write\_len | uint32\_t | Length of the buffer |
* JavaScript
No parameters for JavaScript
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The number of bytes written. If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `TOO_SMALL` - Buffer isn’t large enough to receive record `PREREQUISITE_NOT_MET` - The hook failed to call `etxn_reserve(n)` first `FEE_TOO_LARGE` - The burden would be too high for the network to allow. `INTERNAL_ERROR` - A generic error in which rippled had trouble generating the required field. |
* JavaScript
| Type | Description |
| --------- | ----------- |
| ErrorCode | ByteArray |
# etxn_fee_base
Caution
Fees on a Hooks-enabled ledger are non trivial. See: [Hook Fees](/docs/hooks/concepts/hook-fees) for details.
### Concepts
[Section titled “Concepts”](#concepts)
[Emitted Transactions](/docs/hooks/concepts/emitted-transactions)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* Return the amount of the fee in drops recommended for a to-be emitted transaction.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t etxn_fee_base (
uint32_t read_ptr,
uint32_t read_len
);
```
* JavaScript
```javascript
function etxn_fee_base(txblob: ByteArray | HexString): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t fee_to_pay =
etxn_fee_base(tx_blob, tx_blob_len);
```
* JavaScript
```javascript
const fee_to_pay = etxn_fee_base(tx_blob)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| --------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| read\_ptr | uint32\_t | Pointer to the buffer containing the serialized transaction you intend to emit. The fee field is required but ignored (you may use zero). Use the output of this function to populate the fee field correctly. |
| read\_len | uint32\_t | The length of the tx blob. |
* JavaScript
| Name | Type | Description |
| ------ | ---------------------- | ------------------------------------------------------------------- |
| txblob | ByteArray \| HexString | The transaction blob, which can be an array of numbers or a string. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The smallest number of drops that an emitted txn would need to be accepted. If negative, an error: `OUT_OF_BOUNDS` - The provided buffer is not validly within the hook memory. `PREREQUISITE_NOT_MET` - `etxn_reserve` has not been called first. `INVALID_TXN` - The provided buffer did not contain a valid serialized transaction. (Deserialization failed, or a required field was missing.) |
* JavaScript
| Type | Description |
| ------ | ------------------------------------------------------------------------- |
| number | An ErrorCode if there is an error, or the calculated base fee on success. |
# etxn_generation
> Get the generation of a hypothetically emitted transaction
### Concepts
[Section titled “Concepts”](#concepts)
[Emitted Transactions](/docs/hooks/concepts/emitted-transactions)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* Return the generation an emitted transaction will carry.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t etxn_generation (
void
);
```
* JavaScript
```javascript
function etxn_generation(): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t generation =
etxn_generation();
```
* JavaScript
```javascript
const generation = etxn_generation()
```
### Parameters
[Section titled “Parameters”](#parameters)
None
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ---------------------------------------------------------------------------------------------- |
| int64\_t | The generation an emitted transaction will need in order to be successfully passed to `emit()` |
* JavaScript
| Type | Description |
| ------ | --------------------------------------------------------------------------------------------------- |
| number | Returns An ErrorCode if there is an error, or a number indicating the generation result on success. |
# etxn_nonce
> Generate a 32 byte nonce for use in an emitted transaction
### Concepts
[Section titled “Concepts”](#concepts)
[Emitted Transactions](/docs/hooks/concepts/emitted-transactions)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Write the 32 byte Hash to the write\_ptr
* JavaScript
* Returns an ErrorCode if there is an error, or an array containing the nonce value on success.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t etxn_nonce (
uint32_t write_ptr,
uint32_t write_len
);
```
* JavaScript
```javascript
function etxn_nonce(): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
* C
```c
uint8_t n[32];
int64_t bytes_written =
etxn_nonce(n, 32);
```
* JavaScript
```javascript
const nonce = etxn_nonce()
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | ---------------------------------------------------------------------------------------- |
| write\_ptr | uint32\_t | Pointer to a buffer of a suitable size to store the output. Should be at least 32 bytes. |
| write\_len | uint32\_t | Length of the output buffer. |
* JavaScript
No parameters
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ----------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The number of bytes written If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. |
* JavaScript
| Type | Description |
| ---------------------- | --------------------------------------------------------------------------------------------- |
| ErrorCode \| ByteArray | Returns an ErrorCode if there is an error, or an array containing the nonce value on success. |
# etxn_reserve
> Estimate the required fee for a txn to be emitted successfully
### Concepts
[Section titled “Concepts”](#concepts)
[Emitted Transactions](/docs/hooks/concepts/emitted-transactions)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* Specifies a number of emitted transactions this hook might emit during execution.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t etxn_fee_base (
uint32_t count
);
```
* JavaScript
```javascript
function etxn_reserve(count: number): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
etxn_reserve(2);
```
* JavaScript
```javascript
etxn_reserve(2)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ----- | --------- | ------------------------------------------------------------------------------------------- |
| count | uint32\_t | The largest number of transactions this hook might emit during the course of one execution. |
* JavaScript
| Name | Type | Description |
| ----- | ------ | ---------------------------------------------------------------- |
| count | number | The maximum amount of transactions this Hook is allowed to emit. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The maximum number of emitted transactions this hook may emit. This will always be the same as the `count` parameter or an error as below. If negative, an error: `ALREADY_SET` - The hook already called this function earlier. `TOO_BIG` - The specified number of emitted transactions is too large. |
* JavaScript
| Type | Description |
| ------ | ---------------------------------------------------------------------------------- |
| number | An ErrorCode if there is an error, or the configured transaction count on success. |
# prepare
> Prepares a transaction for emission by automatically injecting all required emission fields.
### Concepts
[Section titled “Concepts”](#concepts)
[Emitted Transactions](/docs/hooks/concepts/emitted-transactions)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
*(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).
* `etxn_reserve()` must be called before `prepare()`.
* JavaScript
* This function takes a transaction JSON object and prepares it for emission.
* The transaction must be complete except for the Account, Sequence, SigningPubKey, Fee, FirstLedgerSequence, LastLedgerSequence, and EmitDetails fields.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t prepare (
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len
);
```
* JavaScript
```javascript
function prepare(
txJson: Record | Transaction
): ErrorCode | Record | Transaction
```
### Example
[Section titled “Example”](#example)
* C
```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
```javascript
const prepared_txn = prepare({
TransactionType: "Payment",
Destination: util_raddr(p1address_ns),
Amount: parseFloat(drops_sent)*2
})
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| 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. |
* JavaScript
| Name | Type | Description |
| ------ | ----------------------------------- | -------------------------------------------------------------------------------------------------- |
| txJson | Record\ \| Transaction | The transaction JSON, must be a complete transaction except for Account (always the Hook account). |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 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. |
* JavaScript
| Type | Description |
| ------------------------------------------------ | -------------------------------------------------------------------------------------------------- |
| ErrorCode \| Record\ \| Transaction | Returns an ErrorCode if there is an error, or the prepared transaction JSON or Transaction object. |
# float_compare
> Perform a comparison on two XFL floating point numbers
### Concepts
[Section titled “Concepts”](#concepts)
[Floating Point Numbers (XFL)](/docs/hooks/concepts/floating-point-numbers-xfl)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Evaluate a comparison of two XFL floating point numbers
* Return the result of the comparison as a boolean encoded in an int64\_t.
* JavaScript
* Evaluate a comparison of two XFL floating point numbers
* Returns an error code or the comparison result as a number.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t float_compare (
int64_t float1,
int64_t float2,
uint32_t mode
);
```
* JavaScript
```javascript
function float_compare(
f1: bigint,
f2: bigint,
mode: number
): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
if (float_compare(pusd_to_send, 0, COMPARE_LESS) == 1)
{
// pusd_to_send is less than 0
}
```
* JavaScript
```javascript
if (float_compare(pusd_to_send, 0n, COMPARE_LESS) == 1)
{
// pusd_to_send is less than 0
}
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ------ | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| float1 | int64\_t | An XFL floating point enclosing number representing the first operand to the comparison |
| float2 | int64\_t | An XFL floating point enclosing number representing the second operand to the comparison |
| mode | uint32\_t | A bit-flag field consisting of any of (or any logically valid combination of) the following flags: `COMPARE_EQUAL` `1` `COMPARE_LESS` `2` `COMPARE_GREATER` `4` Valid combinations are: `COMPARE_LESS` \| `COMPARE_GREATER` - Not equal `COMPARE_LESS` \| `COMPARE_EQUAL` - Less than or equal to `COMPARE_GREATER` \| `COMPARE_EQUAL` - Greater than or equal to |
Caution
Always verify the function returned `1` rather than `non-zero`, as negative error codes will be classed as `non-zero`.
* JavaScript
| Name | Type | Description |
| ---- | ------ | -------------------------------------------------------------- |
| f1 | bigint | The first float to compare. |
| f2 | bigint | The second float to compare. |
| mode | number | The comparison mode (e.g., less than, equal to, greater than). |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| int64\_t | `0` if the comparison was logically false. `1` if the comparison was logically true. If negative, an error: `INVALID_FLOAT` - one of the supplied parameters was not a valid XFL enclosing number `INVALID_ARGUMENT` - invalid combination of supplied comparison flags. |
* JavaScript
| Type | Description |
| ------------------- | ----------------------------------------------------------- |
| ErrorCode or number | Returns an error code or the comparison result as a number. |
# float_divide
> Divide an XFL by another XFL floating point number
### Concepts
[Section titled “Concepts”](#concepts)
[Floating Point Numbers (XFL)](/docs/hooks/concepts/floating-point-numbers-xfl)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Divide an XFL by another XFL
* Return a new XFL as an int64\_t
* JavaScript
* Divides one float representation by another.
* An error code or the quotient as a bigint.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t float_divide (
int64_t float1,
int64_t float2
);
```
* JavaScript
```javascript
function float_divide(f1: bigint, f2: bigint): ErrorCode | bigint
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t still_one =
float_divide(float_one(), float_one());
```
* JavaScript
```javascript
const still_one =
float_divide(float_one(), float_one())
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ------ | -------- | ------------------------------------------------------------ |
| float1 | int64\_t | An XFL floating point enclosing number to act as numerator |
| float2 | int64\_t | An XFL floating point enclosing number to act as denominator |
* JavaScript
| Name | Type | Description |
| ---- | ------ | ------------------- |
| f1 | bigint | The dividend float. |
| f2 | bigint | The divisor float. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The XFL (xls17) enclosing number If negative, an error: `INVALID_FLOAT` - the supplied parameter was not a valid XFL enclosing number or the division resulted in an XFL that cannot be represented. `DIVISION_BY_ZERO` - the supplied parameter was zero. |
* JavaScript
| Type | Description |
| ------------------- | ------------------------------------------ |
| bigint or ErrorCode | An error code or the quotient as a bigint. |
# float_exponent
> Get the exponent of an XFL enclosing number
* C
Replaced by macro
This function was replaced by a macro. Please use the macro below in your code instead. To check the validity of the XFL please use float\_mantissa in conjunction with this macro.
### Concepts
[Section titled “Concepts”](#concepts)
[Floating Point Numbers (XFL)](/docs/hooks/concepts/floating-point-numbers-xfl)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Return the exponent part of an XFL as a signed integer
### Definition
[Section titled “Definition”](#definition)
* C
Because exponents can be negative, and because negatives are reserved for error states, exponents cannot be returned from functions. Therefore this function has become a macro as shown below.
```c
#define float_exponent(f)\
(((int32_t)(((f) >> 54U) & 0xFFU)) - 97)
```
* JavaScript
```javascript
const float_exponent = (f) => (Number(((f) >> 54n) & 0xFFn) - 97)
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t exponent =
float_exponent(float_one());
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ------ | -------- | -------------------------------------- |
| float1 | int64\_t | An XFL floating point enclosing number |
# float_int
> Convert an XFL floating point into an integer (floor)
### Concepts
[Section titled “Concepts”](#concepts)
[Floating Point Numbers (XFL)](/docs/hooks/concepts/floating-point-numbers-xfl)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Left shift (multiply by 10) the XFL by the number of specified decimal places
* Convert the resulting XFL to an integer, discarding any remainder
* Return the integer
* JavaScript
* Converts a float representation to an integer with specified decimal places.
* An error code or the resulting integer as a number.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t float_int (
int64_t float1,
uint32_t decimal_places,
uint32_t absolute
);
```
* JavaScript
```javascript
function float_int(
f1: bigint,
decimal_places: number,
abs: number
): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t drops =
float_int(xahbalance, 6, 0);
```
* JavaScript
```javascript
const drops =
float_int(xahbalance, 6, 0);
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| --------------- | --------- | -------------------------------------------------------------------------------------------------------- |
| float1 | int64\_t | An XFL floating point enclosing number representing the first operand to the addition |
| decimal\_places | uint32\_t | The number of places to shift the decimal to the right before computing the floor of the floating point. |
| absolute | uint32\_t | If `1` also take the absolute of the value before returning it. |
Tip
Negative return values are reserved for error codes. Therefore if you need to execute this function against a negative XFL you should use `absolute = 1`
* JavaScript
| Name | Type | Description |
| --------------- | ------ | --------------------------------------------- |
| f1 | bigint | The float to convert |
| decimal\_places | number | The number of decimal places to consider. |
| abs | number | Indicates whether to take the absolute value. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The computed positive integer If negative, an error: `INVALID_FLOAT` - one of the supplied parameters was not a valid XFL enclosing number `INVALID_ARGUMENT` - attempted to specify more than 15 decimal places. `CANT_RETURN_NEGATIVE` - attempted to return a negative integer but this is not allowed, use `absolute = 1` |
* JavaScript
| Type | Description |
| ------------------- | ----------------------------------------------------------- |
| number or ErrorCode | Returns an error code or the resulting integer as a number. |
# float_invert
> Divide one by an XFL floating point number
### Concepts
[Section titled “Concepts”](#concepts)
[Floating Point Numbers (XFL)](/docs/hooks/concepts/floating-point-numbers-xfl)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Inverts a float representation.
* Return a inverted float as a bigint or an ErrorCode
* JavaScript
* Divide `1` by an XFL
* Return a new XFL as an int64\_t
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t float_invert (
int64_t float1
);
```
* JavaScript
```javascript
function float_invert(f1: bigint): ErrorCode | bigint
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t still_one =
float_invert(float_one());
```
* JavaScript
```javascript
const still_one =
float_invert(float_one())
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ------ | -------- | -------------------------------------- |
| float1 | int64\_t | An XFL floating point enclosing number |
* JavaScript
| Name | Type | Description |
| ---- | ----- | ------------------- |
| f1 | float | The float to invert |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The XFL (xls17) enclosing number If negative, an error: `INVALID_FLOAT` - the supplied parameter was not a valid XFL enclosing number or the division resulted in an XFL that cannot be represented. `DIVISION_BY_ZERO` - the supplied parameter was zero. |
* JavaScript
| Type | Description |
| ------------------- | ------------------------------------------------ |
| ErrorCode \| bigint | An error code or the inverted float as a bigint. |
# float_log
> Compute the decimal log of an XFL
### Concepts
[Section titled “Concepts”](#concepts)
[Floating Point Numbers (XFL)](/docs/hooks/concepts/floating-point-numbers-xfl)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Compute a the decimal logarithm of an XFL number
* Return the new XFL
Caution
Due to speed constraints,`float_log` converts the argument to an IEEE base-2 double precision floating point before applying base 10 log. Therefore the returned result will often contain less precision than expected.
* JavaScript
* Calculates the logarithm of a float representation.
* Returns an error code or the logarithm as a bigint.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t float_log (
int64_t float1
);
```
* JavaScript
```javascript
function float_log(f1: bigint): ErrorCode | bigint
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t zero =
float_log(float_one());
```
Caution
If a negative number is passed the function will return `COMPLEX_NOT_SUPPORTED` if the root is an even root.
* JavaScript
```javascript
const zero =
float_log(float_one())
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ------ | -------- | ------------------------------------------------------------------------------------------------------ |
| float1 | int64\_t | An XFL floating point enclosing number representing the floating point number to take the logarithm of |
* JavaScript
| Name | Type | Description |
| ---- | ------ | ---------------------------------------- |
| f1 | bigint | The float to calculate the logarithm of. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| int64\_t | The computed logarithm If negative, an error: `INVALID_FLOAT` - the supplied parameter was not a valid XFL enclosing number `COMPLEX_NOT_SUPPORTED` - the supplied parameter was a negative number which would result in a complex return value. |
* JavaScript
| Type | Description |
| ------------------- | --------------------------------------------------- |
| bigint or ErrorCode | Returns an error code or the logarithm as a bigint. |
# float_mantissa
> Get the mantissa of an XFL enclosing number
### Concepts
[Section titled “Concepts”](#concepts)
[Floating Point Numbers (XFL)](/docs/hooks/concepts/floating-point-numbers-xfl)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Return the mantissa part of an XFL as an unsigned integer
* JavaScript
* Retrieves the mantissa of a float representation.
* An error code or the mantissa as a bigint.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t float_mantissa (
int64_t float1
);
```
* JavaScript
```javascript
function float_mantissa(f1: bigint): ErrorCode | bigint
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t mantissa =
float_mantissa(float_one());
```
Tip
The mantissa of a negative XFL is always positive. Use `float_sign` to determine the sign of the number.
* JavaScript
```javascript
const mantissa =
float_mantissa(float_one());
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---- | ------ | ---------------------------------------- |
| f1 | bigint | The float to retrieve the mantissa from. |
* JavaScript
| Name | Type | Description |
| ------ | -------- | -------------------------------------- |
| float1 | int64\_t | An XFL floating point enclosing number |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ---------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The mantissa of the XFL If negative, an error: `INVALID_FLOAT` - the supplied parameter was not a valid XFL enclosing number |
* JavaScript
| Type | Description |
| ------------------- | ------------------------------------------ |
| bigint or ErrorCode | An error code or the mantissa as a bigint. |
# float_mulratio
> Multiply an XFL floating point by a non-XFL numerator and denominator
### Concepts
[Section titled “Concepts”](#concepts)
[Floating Point Numbers (XFL)](/docs/hooks/concepts/floating-point-numbers-xfl)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Compute the multiplication of an XFL (xls17) floating point number and the quotient of two integers
* Return a new XFL as an int64\_t
* JavaScript
* Multiplies a float by a ratio defined by a numerator and denominator.
* Returns an error code or new XFL as a bigint.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t float_mulratio (
int64_t float1,
uint32_t round_up,
uint32_t numerator,
uint32_t denominator
);
```
* JavaScript
```javascript
function float_mulratio(
f1: bigint,
round_up: number,
numerator: number,
denominator: number
): ErrorCode | bigint
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t max_vault_pusd =
float_mulratio(max_vault_pusd, 0,
COLLATERALIZATION_NUMERATOR, COLLATERALIZATION_DENOMINATOR);
```
* JavaScript
```javascript
const max_vault_pusd =
float_mulratio(max_vault_pusd, 0,
COLLATERALIZATION_NUMERATOR, COLLATERALIZATION_DENOMINATOR);
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ----------- | --------- | ------------------------------------------------------------------------------------------- |
| float1 | int64\_t | An XFL floating point enclosing number representing the first operand to the multiplication |
| round\_up | uint32\_t | If non-zero all computations will be rounded up |
| numerator | uint32\_t | The numerator of the quotient that the float will be multiplied by |
| denominator | uint32\_t | The denominator of the quotient that the float will be multiplied by |
Caution
Certain multiplications may overflow, which return with an `INVALID_FLOAT` error. However an **underflow** returns as XFL Canonical Zero (i.e. enclosing number = 0).
* JavaScript
| Name | Type | Description |
| ----------- | ------ | ------------------------------------------------------------------------------------------- |
| f1 | bigint | An XFL floating point enclosing number representing the first operand to the multiplication |
| round\_up | number | If non-zero all computations will be rounded up |
| numerator | number | The numerator of the quotient that the float will be multiplied by |
| denominator | number | The denominator of the quotient that the float will be multiplied by |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The XFL (xls17) enclosing number If negative, an error: `INVALID_FLOAT` - one of the supplied parameters was not a valid XFL enclosing number `OVERFLOW` - the result of the multiplication was too large to store in an XFL. `DIVISION_BY_ZERO` - the supplied denominator was zero. |
* JavaScript
| Type | Description |
| ------------------- | ----------------------------------------------------------- |
| ErrorCode or bigint | Returns an error code or tThe XFL (xls17) enclosing number. |
# float_multiply
> Multiply two XFL numbers together
### Concepts
[Section titled “Concepts”](#concepts)
[Floating Point Numbers (XFL)](/docs/hooks/concepts/floating-point-numbers-xfl)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Compute the multiplication of two XFL (xls17) floating point numbers
* Return a new XFL as an int64\_t
* JavaScript
* Compute the multiplication of two XFL (xls17) floating point numbers
* Return n error code or new XFL as a bigint.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t float_multiply (
int64_t float1,
int64_t float2
);
```
* JavaScript
```javascript
function float_multiply(f1: bigint, f2: bigint): ErrorCode | bigint
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t max_vault_pusd =
float_multiply(vault_xrp, exchange_rate);
```
* JavaScript
```javascript
const max_vault_pusd =
float_multiply(vault_xrp, exchange_rate)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ------ | -------- | -------------------------------------------------------------------------------------------- |
| float1 | int64\_t | An XFL floating point enclosing number representing the first operand to the multiplication |
| float2 | int64\_t | An XFL floating point enclosing number representing the second operand to the multiplication |
Caution
Certain multiplications may overflow, which return with an `INVALID_FLOAT` error. However an **underflow** returns as XFL Canonical Zero (i.e. enclosing number = 0).
* JavaScript
| Name | Type | Description |
| ---- | ------ | -------------------------------------------------------------------------------------------- |
| f1 | bigint | An XFL floating point enclosing number representing the first operand to the multiplication |
| f2 | bigint | An XFL floating point enclosing number representing the second operand to the multiplication |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The XFL (xls17) enclosing number If negative, an error: `INVALID_FLOAT` - one of the supplied parameters was not a valid XFL enclosing number `OVERFLOW` - the result of the multiplication was too large to store in an XFL. |
* JavaScript
| Type | Description |
| ------------------ | ------------------------------------------------- |
| Errorcor or bigint | An error code or The XFL (xls17) enclosing number |
# float_negate
> Negate an XFL floating point number
### Concepts
[Section titled “Concepts”](#concepts)
[Floating Point Numbers (XFL)](/docs/hooks/concepts/floating-point-numbers-xfl)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Multiply an XFL by `-1`
* Return a new XFL as an int64\_t
* JavaScript
* Negates a float representation.
* Returns an error code or the negated float as a bigint.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t float_negate (
int64_t float1
);
```
* JavaScript
```javascript
function float_negate(f1: bigint): ErrorCode | bigint
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t negative_one =
float_negate(float_one());
```
Special case
The negation of Canonical Zero is Canonical Zero. Unlike some floating point standards (such as IEEE) there is no “negative zero” in XFL.
* JavaScript
```javascript
const negative_one =
float_negate(float_one());
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ------ | -------- | -------------------------------------- |
| float1 | int64\_t | An XFL floating point enclosing number |
* JavaScript
| Name | Type | Description |
| ---- | ------ | -------------------- |
| f1 | bigint | The float to negate. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The XFL (xls17) enclosing number If negative, an error: `INVALID_FLOAT` - one of the supplied parameters was not a valid XFL enclosing number |
* JavaScript
| Type | Description |
| ------------------- | -------------------------------------------------- |
| ErrorCode or bigint | An error code or The XFL (xls17) enclosing number. |
# float_one
> Return the number 1 represented in an XFL enclosing number
### Concepts
[Section titled “Concepts”](#concepts)
[Floating Point Numbers (XFL)](/docs/hooks/concepts/floating-point-numbers-xfl)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Return one(`1`) as an XFL int64\_t
* JavaScript
* Retrieves the float representation of a number.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t float_one();
```
* JavaScript
```javascript
function float_one(): ErrorCode | bigint
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t one =
float_one();
```
* JavaScript
```javascript
const one = float_one()
```
### Parameters
[Section titled “Parameters”](#parameters)
This function has no parameters.
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | -------------------------------- |
| int64\_t | The XFL (xls17) enclosing number |
* JavaScript
| Type | Description |
| ------------------- | -------------------------------- |
| ErrorCode \| bigint | The XFL (xls17) enclosing number |
# float_root
> Compute the nth root of an XFL
### Concepts
[Section titled “Concepts”](#concepts)
[Floating Point Numbers (XFL)](/docs/hooks/concepts/floating-point-numbers-xfl)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Compute a the `nth` root of an XFL number
* Return the new XFL
Caution
Due to speed constraints,`float_root` converts the argument to an IEEE base-2 double precision floating point before applying n-th root. Therefore the returned result will often contain less precision than expected. If you need better precision you should consider dividing your XFL into a high and a low product then individually take the square roots of those products and multiply the results together.
* JavaScript
* Calculates the nth root of a float representation.
* An error code or the resulting root as a bigint.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t float_root (
int64_t float1,
uint32_t n
);
```
* JavaScript
```javascript
function float_root(f1: bigint, n: number): ErrorCode | bigint
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t three =
float_root(nine, 2);
```
Caution
If a negative number is passed the function will return `COMPLEX_NOT_SUPPORTED` if the root is an even root.
* JavaScript
```javascript
const three =
float_root(nine, 2)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ------ | --------- | -------------------------------------------------------------------------------------------------------- |
| float1 | int64\_t | An XFL floating point enclosing number representing the floating point number to take the square root of |
| n | uint32\_t | The root to compute, for example `2` is a square root. |
* JavaScript
| Name | Type | Description |
| ---- | ------ | ------------------------------------ |
| f1 | bigint | The float to calculate the root of. |
| n | number | The degree of the root to calculate. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The computed nth root If negative, an error: `INVALID_FLOAT` - the supplied parameter was not a valid XFL enclosing number `COMPLEX_NOT_SUPPORTED` - the supplied parameter was a negative number which would result in a complex root. |
* JavaScript
| Type | Description |
| ------------------- | -------------------------------------------------------- |
| bigint or ErrorCode | Returns an error code or the resulting root as a bigint. |
# float_set
> Create a float from an exponent and mantissa
### Concepts
[Section titled “Concepts”](#concepts)
[Floating Point Numbers (XFL)](/docs/hooks/concepts/floating-point-numbers-xfl)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Compute an XFL (xls17) floating point from the provided exponent and mantissa
* Return that XFL as an int64\_t
* JavaScript
* Sets the exponent and mantissa for a float representation.
* Returns an error code or a new XFL as a bigint.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t float_set (
int32_t exponent,
int64_t mantissa
);
```
* JavaScript
```javascript
function float_set(exponent: number, mantissa: number): ErrorCode | bigint
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t small_amount =
float_set(-81, 1);
```
* JavaScript
```javascript
const small_amount = float_set(-81, 1);
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| -------- | -------- | --------------------------------------------------------------- |
| exponent | int32\_t | An exponent in the range `-96` to `80` |
| mantissa | int64\_t | A mantissa. If negative then the sign of the float is negative. |
Caution
When setting a mantissa that is greater or fewer than 16 decimal digits the exponent will be adjusted to ensure the mantissa is exactly 16 digits. This adjustment may result in an `INVALID_FLOAT` in some circumstances.
Special case
XFL canonical 0 is also 0 in the enclosing number. Thus there is never a need to call `float_set(0,0);`
* JavaScript
| Name | Type | Description |
| -------- | ------ | --------------------------------------------------------------- |
| exponent | bigint | An exponent in the range `-96` to `80` |
| mantissa | bigint | A mantissa. If negative then the sign of the float is negative. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The XFL (xls17) enclosing number If negative, an error: `INVALID_FLOAT` - The adjustment of the mantissa to 16 digits produced an under or overflow. |
* JavaScript
| Type | Description |
| ------------------- | -------------------------------------------------- |
| ErrorCode \| bigint | An error code or the XFL (xls17) enclosing number. |
# float_sign
> Get the sign of an XFL enclosing number
### Concepts
[Section titled “Concepts”](#concepts)
[Floating Point Numbers (XFL)](/docs/hooks/concepts/floating-point-numbers-xfl)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Return `1` if the XFL is negative, otherwise return 0
* JavaScript
* Return 1 if the XFL is negative, otherwise return 0
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t float_sign (
int64_t float1
);
```
* JavaScript
```javascript
function float_sign(f1: bigint): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t sign =
float_sign(float_one());
```
Tip
The sign bit inside the XFL is the `0` when the XFL is negative, however this function follows the standard computing convention to return `1` if it is negative.
* JavaScript
```javascript
const sign =
float_sign(float_one());
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ------ | -------- | -------------------------------------- |
| float1 | int64\_t | An XFL floating point enclosing number |
* JavaScript
| Name | Type | Description |
| ---- | ------ | ---------------------------------------- |
| f1 | bigint | The float to retrieve the mantissa from. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The sign of the XFL: `0` if positive, `1` if negative. If negative, an error: `INVALID_FLOAT` - the supplied parameter was not a valid XFL enclosing number |
* JavaScript
| Type | Description |
| ------------------- | ------------------------------------------ |
| bigint or ErrorCode | An error code or the mantissa as a bigint. |
# float_sto
> Output an XFL as a serialized object
### Concepts
[Section titled “Concepts”](#concepts)
[Floating Point Numbers (XFL) ](/docs/hooks/concepts/floating-point-numbers-xfl)[Serialized Objects](/docs/hooks/concepts/serialized-objects)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Read an XFL floating point number and optionally a field code and currency code
* Write a serialized amount to `write_ptr` according to the parameters provided
* JavaScript
* Stores a float representation into a specified field.
* Returns an error code or the updated value as an array of numbers.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t float_sto (
uint32_t write_ptr,
uint32_t write_len,
uint32_t cread_ptr,
uint32_t cread_len,
uint32_t iread_ptr,
uint32_t iread_len,
int64_t float1,
uint32_t field_code
);
```
* JavaScript
```javascript
function float_sto(
currency: ByteArray | HexString | undefined,
issuer: ByteArray | HexString | undefined,
f1: bigint,
field_code: number
): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
* C
```c
#define SBUF(str) (uint32_t)(str), sizeof(str)
uint8_t amt_out[48];
if (float_sto(SBUF(amt_out),
SBUF(currency), SBUF(hook_accid), pusd_to_send, -1) < 0)
rollback(SBUF("Peggy: Could not dump pusd amount into sto"), 1);
```
* JavaScript
```javascript
const amt_out = float_sto(currency, hook_accid, pusd_to_send, -1)
if (typeof amt_out === 'number')
rollback("Peggy: Could not dump pusd amount into sto", 1)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ----------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| write\_ptr | uint32\_t | Pointer to a buffer of a suitable size to store the serialized amount field. Recommend at least 48 bytes. |
| write\_len | uint32\_t | The length of the output buffer. |
| cread\_ptr | uint32\_t | Pointer to a buffer contianing the currency code to serialize into the output. *May be null.* |
| cread\_len | uint32\_t | The length of the currency code. This must be 20 or 3 or 0 (null). |
| iread\_ptr | uint32\_t | Pointer to a buffer containing the issuer’s Account ID to serialize into the output. *May be null.* |
| iread\_len | uint32\_t | The length of the issuer’s Account ID. This must be either 20 or 0 (null). |
| float1 | int64\_t | An XFL floating point enclosing number to serialize. |
| field\_code | uint32\_t | The `sf` field code to prefix the serialized amount with. E.g. `sfAmount`. If this field is `0xFFFFFFFFU` (i.e. `(uint32_t)(-1)`) then no field code is prepended to the output, and no issuer or currency code is appended, but serialization proceeds as a floating point amount. If this field is 0 no field code is prepended to the output, and no issuer or currency code is appended, but serialization proceeds as though the amount is an XRP native amount rather than a floating point. |
Tip
To output an `XAH` amount prepopulate the field code in the output buffer then pass the output buffer incremented to the new start and `0` as field\_code
* JavaScript
| Name | Type | Description |
| ----------- | ----------------------------------- | ---------------------------------------------------------- |
| currency | ByteArray \| HexString \| undefined | The current value to store into. |
| issuer | ByteArray \| HexString \| undefined | The value to store. |
| f1 | bigint | The field code indicating where to store the float. |
| field\_code | number | An error code or the updated value as an array of numbers. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The number of bytes written to the output buffer. If negative, an error: `INVALID_FLOAT` - the supplied float was not a valid XFL enclosing number `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `INVALID_ARGUMENT` - If instructed to output as `XRP` or without `field code` then all non-write pointers and lengths should be 0 (null). `TOO_SMALL` - The output buffer was too small to receive the serialized object. `XFL_OVERFLOW` - Expressing the output caused an overflow during normalization. |
* JavaScript
| Type | Description |
| ---------------------- | ------------------------------------------------------------------ |
| ErrorCode \| ByteArray | Returns an error code or the updated value as an array of numbers. |
# float_sto_set
> Read a serialized amount into an XFL
### Concepts
[Section titled “Concepts”](#concepts)
[Floating Point Numbers (XFL) ](/docs/hooks/concepts/floating-point-numbers-xfl)[Serialized Objects](/docs/hooks/concepts/serialized-objects)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Read a serialized floating point number.
* If there are more fields/data after the serialized floating pointer number then ignore them.
* Return it as an XFL enclosing number
* JavaScript
* Sets the buffer for storing float representations.
* Returns ErrorCode or the result as a number.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t float_sto_set (
uint32_t read_ptr,
uint32_t read_len
);
```
* JavaScript
```javascript
function float_sto_set(buf: ByteArray | HexString): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t vault_pusd = float_sto_set(vault, 8);
if (vault_pusd < 0)
rollback("Failed to parse serialized float.", 33, 1);
```
* JavaScript
```javascript
const vault_pusd = float_sto_set(vault)
if (typeof vault_pusd === 'string')
rollback("Failed to parse serialized float.", 1)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| --------- | --------- | ----------------------------------------------------------------- |
| read\_ptr | uint32\_t | Pointer to a buffer contianing the serialized XFL. *May be null.* |
| read\_len | uint32\_t | The length of the buffer. |
* JavaScript
| Name | Type | Description |
| ---- | ---------------------- | ------------------ |
| buf | ByteArray \| HexString | The buffer to set. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The number of bytes written to the output buffer. If negative, an error: `NOT_AN_OBJECT` - the supplied buffer did not contain a valid serialized floating point number `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. |
* JavaScript
| Type | Description |
| ------------------- | ---------------------------------------- |
| ErrorCode or number | An error code or the result as a number. |
# float_sum
> Add two XFL numbers together
### Concepts
[Section titled “Concepts”](#concepts)
[Floating Point Numbers (XFL)](/docs/hooks/concepts/floating-point-numbers-xfl)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Compute the addition of two XFL (xls17) floating point numbers
* Return a new XFL as an int64\_t
* JavaScript
* Sums two float representations.
* Returns an error code or the sum as a bigint.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t float_sum (
int64_t float1,
int64_t float2
);
```
* JavaScript
```javascript
function float_sum(f1: bigint, f2: bigint): ErrorCode | bigint
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t two =
float_sum(float_one(), float_one());
```
* JavaScript
```javascript
const two =
float_sum(float_one(), float_one());
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ------ | -------- | -------------------------------------------------------------------------------------- |
| float1 | int64\_t | An XFL floating point enclosing number representing the first operand to the addition |
| float2 | int64\_t | An XFL floating point enclosing number representing the second operand to the addition |
Tip
To subtract two floats use `float_negate` on the second float then use `float_sum`.
* JavaScript
| Name | Type | Description |
| ---- | ------ | ------------------------ |
| f1 | bigint | The first float to sum. |
| f2 | bigint | The second float to sum. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The XFL (xls17) enclosing number If negative, an error: `INVALID_FLOAT` - one of the supplied parameters was not a valid XFL enclosing number `OVERFLOW` - the result of the addition was too large to store in an XFL. |
* JavaScript
| Type | Description |
| ------------------- | ------------------------------------- |
| ErrorCode or bigint | An error code or the sum as a bigint. |
# hook_account
> Retreive the 20 byte Account ID the Hook is executing on
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Write the 20 byte Account ID to the write\_ptr
* JavaScript
* Retrieve the 20 byte Account ID the Hook is executing on.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t hook_account (
uint32_t write_ptr,
uint32_t write_len
);
```
* JavaScript
“JavaScript function hook\_account(): ErrorCode | ByteArray
````plaintext
### Example
```c
uint8_t hook_acc_id[20];
int64_t bytes_written =
hook_account(hook_acc_id, 20);
````
* JavaScript
```javascript
const hook_acc_id =hook_account()
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | ---------------------------------------------------------------------------------------- |
| write\_ptr | uint32\_t | Pointer to a buffer of a suitable size to store the output. Should be at least 20 bytes. |
| write\_len | uint32\_t | Length of the output buffer. |
* JavaScript
No parameters
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ----------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The number of bytes written If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. |
* JavaScript
| Type | Description |
| ---------------------- | ----------------------------------------------------------------------------------------- |
| ErrorCode or ByteArray | Returns the Account ID the Hook is executing on, or an error code if the retrieval fails. |
# hook_again
> Returns the position in the hook chain the currently executing hook occupies
### Behaviour
[Section titled “Behaviour”](#behaviour)
* If the hook is being strongly executed then flag this specific hook in the chain for [Again As Weak Execution](/docs/hooks/concepts/weak-and-strong).
* If the originating transaction successfully is applied then the hook will be called again in a second, Weak Execution.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t hook_again(void);
```
* JavaScript
```javascript
function hook_again(): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t result =
hook_again();
```
* JavaScript
```javascript
const result = hook_again()
```
### Parameters
[Section titled “Parameters”](#parameters)
This API has no parameters
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| int64\_t | `1` iff successfully flagged for Again As Weak. `PREREQUISITE_NOT_MET` - This hook is already being executed weakly at the time of the call. `ALREADY_SET` - The function was already called this execution. |
* JavaScript
| Type | Description |
| ------ | ------------------------------------------------------------- |
| number | Returns a status code indicating the result of the operation. |
# hook_hash
> Retreive the 32 byte namespace biased SHA512H of the currently executing Hook
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Look up the hash of the hook installed on hook account at position `hook_no`
* Write the 32 byte hash to `write_ptr`
* JavaScript
* Look up the hash of the hook installed on the hook account at the specified position.
* The Namespace biased SHA512H of the currently executing Hook, or an error code if the lookup fails.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t hook_hash (
uint32_t write_ptr,
uint32_t write_len,
int32_t hook_no
);
```
* JavaScript
```javascript
function hook_hash(hookno: number): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
* C
```c
uint8_t hash[32];
int64_t bytes_written =
hook_hash(hash, 32, -1);
```
* JavaScript
```javascript
const hash = hook_hash(hookno)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | ---------------------------------------------------------------------------------------------- |
| write\_ptr | uint32\_t | Pointer to a buffer of a suitable size to store the output. Should be at least 32 bytes. |
| write\_len | uint32\_t | Length of the output buffer. |
| hook\_no | int32\_t | The position in the hook chain the hook is located at, or -1 for the currently executing hook. |
* JavaScript
| Name | Type | Description |
| -------- | ------ | ---------------------------------------------------------------------------------------------- |
| hook\_no | number | The position in the hook chain the hook is located at, or -1 for the currently executing hook. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| int64\_t | The number of bytes written If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `DOESNT_EXIST` - The specified hook sequence number doesn’t exist in the hook chain. |
* JavaScript
| Type | Description |
| ---------------------- | ----------------------------------------------------------------------------------------------------------- |
| ByteArray or ErrorCode | Returns the Namespace biased SHA512H of the currently executing Hook, or an error code if the lookup fails. |
# hook_param
> Retrieve the parameter value for a named hook parameter
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Look up the value for a named parameter specified in `read_ptr`
* Write the parameter’s value to `write_ptr`
* JavaScript
* Retrieve the value of a parameter associated with the specified key.
* Returns the value associated with the key, or an error code if the retrieval fails.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t hook_param (
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len
);
```
* JavaScript
```javascript
function hook_param(key: ByteArray | HexString): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
* C
```c
uint8_t pname[] = {0xCAU, 0xFEU};
uint8_t pvalue[32];
int64_t value_len =
hook_param(pvalue, 32, pname, 2);
```
* JavaScript
```javascript
const pname = [0xCA, 0xFE]
const pvalue = hook_param(pname)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | ---------------------------------------------------------------------------------------- |
| write\_ptr | uint32\_t | Pointer to a buffer of a suitable size to store the output. Should be at least 32 bytes. |
| write\_len | uint32\_t | Length of the output buffer. |
| read\_ptr | uint32\_t | Pointer to a buffer containing the parameter’s name |
| read\_len | uint32\_t | Length of the parameter’s name |
* JavaScript
| Name | Type | Description |
| ---- | ---------------------- | -------------------------------------------------- |
| key | ByteArray or HexString | The key for which to retrieve the parameter value. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| int64\_t | The number of bytes written If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `DOESNT_EXIST` - The specified paramater doesn’t exist or is null `TOO_SMALL` - The parameter name can’t be null `TOO_BIG` - The parameter name is greater than 32 bytes |
* JavaScript
| Type | Description |
| ---------------------- | ----------------------------------------------------------------------------------- |
| ByteArray or ErrorCode | Returns the value associated with the key, or an error code if the retrieval fails. |
# hook_param_set
> Set or delete a parameter on a hook on the same account further down the execution chain
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Search the hook chain on the hook account for a 32 byte hash indicated by `hread_ptr`
* If found: set a parameter:
* With the parameter name indicated by `kread_ptr` and
* The parameter value indicated by `read_ptr`
* JavaScript
* Set a parameter for the hook with the specified value and key, and associate it with a hash.
* Returns a status code indicating the result of the operation.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t hook_param_set (
uint32_t read_ptr,
uint32_t read_len,
uint32_t kread_ptr,
uint32_t kread_len,
uint32_t hread_ptr,
uint32_t hread_len
);
```
* JavaScript
```javascript
function hook_param_set(
val: ByteArray | HexString,
key: ByteArray | HexString,
hash: ByteArray | HexString
): number
```
### Example
[Section titled “Example”](#example)
* C
```c
uint8_t pvalue[] = "some parameter value";
uint8_t pname[] = "paramname";
uint8_t phash[] = { 0x19U, 0xFEU, 0x69U, 0xF1U, 0x53U, 0x66U, 0x4EU, 0x8CU,
0x97U, 0xF4U, 0x4CU, 0x5CU, 0x3CU, 0x65U, 0x63U, 0x79U,
0xC2U, 0xD0U, 0x26U, 0xE7U, 0x90U, 0xEFU, 0x38U, 0xF7U,
0xEDU, 0x73U, 0xE9U, 0xCEU, 0x9CU, 0x9DU, 0xBFU, 0x03U };
int64_t result =
hook_param_set(pvalue, sizeof(pvalue),
pname, sizeof(pname),
phash, sizeof(phash));
```
* JavaScript
```javascript
const pvalue = "some parameter value"
const pname = "paramname"
const phash = [ 0x19, 0xFE, 0x69, 0xF1, 0x53, 0x66, 0x4E, 0x8C,
0x97, 0xF4, 0x4C, 0x5C, 0x3C, 0x65, 0x63, 0x79,
0xC2, 0xD0, 0x26, 0xE7, 0x90, 0xEF, 0x38, 0xF7,
0xED, 0x73, 0xE9, 0xCE, 0x9C, 0x9D, 0xBF, 0x03 ]
const result = hook_param_set(str2hex(pvalue), str2hex(pname), phash)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | ------------------------------- |
| read\_ptr | uint32\_t | Pointer to parameter value |
| read\_len | uint32\_t | Length of the parameter value |
| kread\_ptr | uint32\_t | Pointer to the parameter name |
| kread\_len | uint32\_t | Length of the parameter name |
| hread\_ptr | uint32\_t | Pointer to hook hash |
| hread\_len | uint32\_t | Length of hook hash (always 32) |
* JavaScript
| Name | Type | Description |
| ---- | ---------------------- | ----------------------------------------- |
| val | ByteArray or HexString | The value to set for the parameter. |
| key | ByteArray or HexString | The key associated with the parameter. |
| hash | ByteArray or HexString | The hash to associate with the parameter. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The length of the parameter value successfully set If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `TOO_SMALL` - The parameter name can’t be null `TOO_BIG` - The parameter name is greater than 32 bytes |
* JavaScript
| Type | Description |
| ------ | ------------------------------------------------------------- |
| number | Returns a status code indicating the result of the operation. |
# hook_pos
> Returns the position in the hook chain the currently executing hook occupies
### Behaviour
[Section titled “Behaviour”](#behaviour)
* Returns the position in the hook chain the currently executing hook occupies.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t hook_pos(void);
```
* JavaScript
```javascript
hook_pos()
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t pos =
hook_pos();
```
* JavaScript
```javascript
const pos = hook_pos()
```
### Parameters
[Section titled “Parameters”](#parameters)
This API has no parameters
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ----------------------------------------------------------------------------------------- |
| int64\_t | The position in the chain the currently executing hook occupies. The first position is 0. |
* JavaScript
| Type | Description |
| ------ | ---------------------------------------------------------------------------------------- |
| number | Returns the current position in the hook chain, or an error code if the retrieval fails. |
# hook_skip
> Skip a hook that appears later in the hook chain on the hook account
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Search the hook chain for a hook identified by the hook hash at `read_ptr`
* Mark it as disabled for this chain execution
* JavaScript
* Skip the execution of a hook based on the provided hash and flag.
* Returns a status code indicating the result of the operation.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t hook_skip (
uint32_t read_ptr,
uint32_t read_len,
uint32_t flags
);
```
* JavaScript
```javascript
function hook_skip(
hash: ByteArray | HexString,
flag: number
): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
uint8_t phash[] = { 0x19U, 0xFEU, 0x69U, 0xF1U, 0x53U, 0x66U, 0x4EU, 0x8CU,
0x97U, 0xF4U, 0x4CU, 0x5CU, 0x3CU, 0x65U, 0x63U, 0x79U,
0xC2U, 0xD0U, 0x26U, 0xE7U, 0x90U, 0xEFU, 0x38U, 0xF7U,
0xEDU, 0x73U, 0xE9U, 0xCEU, 0x9CU, 0x9DU, 0xBFU, 0x03U };
int64_t result =
hook_skip(phash, 32, 0);
```
* JavaScript
```javascript
const phash = [ 0x19, 0xFE, 0x69, 0xF1, 0x53, 0x66, 0x4E, 0x8C,
0x97, 0xF4, 0x4C, 0x5C, 0x3C, 0x65, 0x63, 0x79,
0xC2, 0xD0, 0x26, 0xE7, 0x90, 0xEF, 0x38, 0xF7,
0xED, 0x73, 0xE9, 0xCE, 0x9C, 0x9D, 0xBF, 0x03 ]
const result = hook_skip(phash, 0);
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| --------- | --------- | ----------------------------------------------------------------------------------------- |
| read\_ptr | uint32\_t | Pointer to a buffer containing the hook hash |
| read\_len | uint32\_t | Length of the hook hash (always 32) |
| flags | uint32\_t | If 0: - add the hash to the hook skip list If 1 - remove the hash from the hook skip list |
* JavaScript
| Name | Type | Description |
| ---- | ---------------------- | --------------------------------------------------- |
| hash | ByteArray or HexString | The hash of the hook to skip. |
| flag | number | A flag indicating the reason for skipping the hook. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | If successful `1` If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `DOESNT_EXIST` - The specified paramater doesn’t exist or is null `INVALID_ARGUMENT` - Hash is not 32 bytes |
* JavaScript
| Type | Description |
| ------------------- | ------------------------------------------------------------- |
| number or ErrorCode | Returns a status code indicating the result of the operation. |
# fee_base
> Fetch the fee base of the current ledger
### Concepts
[Section titled “Concepts”](#concepts)
[Hook Fees](/docs/hooks/concepts/hook-fees)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* Return the fee base from the current ledger
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t fee_base();
```
* JavaScript
```javascript
function fee_base(): number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t fee =
fee_base();
```
* JavaScript
```javascript
const fee = fee_base()
```
### Parameters
[Section titled “Parameters”](#parameters)
This API takes no parameters.
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ---------------------------------- |
| int64\_t | The fee base of the current ledger |
* JavaScript
| Type | Description |
| ------ | ---------------------------------- |
| number | The fee base of the current ledger |
# ledger_keylet
> Search for a keylet within a specified range on the current ledger
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Read a 34 byte Keylet from the `lread_ptr`
* Read a 32 byte Keylet from the `hread_ptr`
* Search the ledger for the first (lowest) Keylet of this type in this range.
* If any matching Keylet is found, write it to `write_ptr`.
* JavaScript
* This function searches the ledger for the first (`lowest`) Keylet of this type in the given range.
* Returns the number of bytes written (34 bytes) on success, or an error code if an error occurs.
### Definition
[Section titled “Definition”](#definition)
C
* C
```c
int64_t ledger_keylet (
uint32_t write_ptr,
uint32_t write_len,
uint32_t lread_ptr,
uint32_t lread_len,
uint32_t hread_ptr,
uint32_t hread_len
);
```
* JavaScript
```javascript
function ledger_keylet(
low: ByteArray | HexString,
high: ByteArray | HexString
): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
C
* C
```c
//TODO
```
* JavaScript
```javascript
ledger_keylet(low, high)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | ---------------------------------------------------------------------------------------------------------- |
| write\_ptr | uint32\_t | Pointer to a buffer to store the output serialised Keylet. . |
| write\_len | uint32\_t | Length of the output buffer. Must be 34 bytes |
| lread\_ptr | uint32\_t | Pointer to the 34 byte serialised Keylet that represents the lower boundary of the Keylet range to search. |
| lread\_len | uint32\_t | Always 34 bytes |
| hread\_ptr | uint32\_t | Pointer to the 34 byte serialised Keylet that represents the upper boundary of the Keylet range to search. |
| hread\_len | uint32\_t | Always 34 bytes |
* JavaScript
| Name | Type | Description |
| ---- | ---------------------- | ---------------------------------------------------------------------------------------------------------- |
| low | ByteArray \| HexString | Pointer to the 34-byte serialized Keylet that represents the lower boundary of the Keylet range to search. |
| high | ByteArray \| HexString | Pointer to the 34-byte serialized Keylet that represents the upper boundary of the Keylet range to search. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The number of bytes written (34 bytes) on success. If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `TOO_SMALL` / `TOO_BIG` - `write_len`, `lread_len` or `hread_len` was not 34 bytes `INVALID_ARGUMENT` - One or more of the provided Keylets was not a valid serialised Keylet `DOES_NOT_MATCH` - The two provided Keylets were not of the same Keylet Type. `DOESNT_EXIST` - No matching Keylet was found in the specified range. |
* JavaScript
| Type | Description |
| ---------------------- | ----------------------------------------------------------------------------------------------- |
| ErrorCode \| ByteArray | Returns the number of bytes written (34 bytes) on success, or an error code if an error occurs. |
# ledger_last_hash
> Retreive the 32 byte namespace biased SHA512H of the last closed ledger
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Write the 32 byte Hash to the write\_ptr
* JavaScript
* Retrieves the hash of the last ledger.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t ledger_last_hash (
uint32_t write_ptr,
uint32_t write_len
);
```
* JavaScript
```javascript
function ledger_last_hash(): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
* C
```c
uint8_t hash[32];
int64_t bytes_written =
ledger_last_hash(hash, 32);
```
* JavaScript
```javascript
const hash = ledger_last_hash()
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | ---------------------------------------------------------------------------------------- |
| write\_ptr | uint32\_t | Pointer to a buffer of a suitable size to store the output. Should be at least 32 bytes. |
| write\_len | uint32\_t | Length of the output buffer. |
* JavaScript
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ----------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The number of bytes written If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. |
* JavaScript
| Type | Description |
| ------ | ----------------------------------------------------------------------------------------------- |
| number | Returns an error code if an error occurs, or an array representing the hash of the last ledger. |
# ledger_last_time
> Fetch the last closed ledger's timestamp
### Behaviour
[Section titled “Behaviour”](#behaviour)
* Return the Xahau Timestamp from the last closed ledger.
Tip
Xahau timestamps are identical to a unix timestamps except that they are offset by `-946684800`.
The equivalent unix timestamp is: `ledger_last_time() + 946684800;`
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t ledger_last_time();
```
* JavaScript
```javascript
function ledger_last_time(): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t ts =
ledger_last_time();
```
* JavaScript
```javascript
const ts = ledger_last_time()
```
### Parameters
[Section titled “Parameters”](#parameters)
This API takes no parameters.
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | -------------------------------------------- |
| int64\_t | The XRPL timestamp of the last closed ledger |
* JavaScript
| Type | Description |
| ------ | ---------------------------------------------------------------------------------------------------- |
| number | Returns an error code if an error occurs, or a number representing the timestamp of the last ledger. |
# ledger_nonce
> Generate a 32 byte nonce for use in an emitted transaction
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Write a 32 byte random value to the write\_ptr
* JavaScript
* Retrieves the nonce of the current ledger.
### Definition
[Section titled “Definition”](#definition)
C
* C
```c
int64_t ledger_nonce (
uint32_t write_ptr,
uint32_t write_len
);
```
* JavaScript
```javascript
function ledger_nonce(): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
* C
```c
uint8_t n[32];
int64_t bytes_written =
ledger_nonce(n, 32);
```
* JavaScript
```javascript
const nonce = ledger_nonce()
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | ---------------------------------------------------------------------------------------- |
| write\_ptr | uint32\_t | Pointer to a buffer of a suitable size to store the output. Should be at least 32 bytes. |
| write\_len | uint32\_t | Length of the output buffer. |
* JavaScript
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| ErrorCode \| ByteArray | Returns an error code if an error occurs, or an array representing the nonce of the current ledger. specified outside of hook memory. |
* JavaScript
| Type | Description |
| -------- | ----------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The number of bytes written If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. |
# ledger_seq
> Fetch the current ledger sequence number
### Behaviour
[Section titled “Behaviour”](#behaviour)
* Return the sequence number from the current ledger
### Definition
[Section titled “Definition”](#definition)
C
* C
```c
int64_t ledger_seq();
```
* JavaScript
```javascript
function ledger_seq(): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t seq =
ledger_seq();
```
* JavaScript
```javascript
const seq = ledger_seq()
```
### Parameters
[Section titled “Parameters”](#parameters)
This API takes no parameters.
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ----------------------------------------- |
| int64\_t | The sequence number of the current ledger |
* JavaScript
| Type | Description |
| ------ | ----------------------------------------- |
| number | The sequence number of the current ledger |
# meta_slot
> Load the metadata of the originating transaction into a slot
### Behaviour
[Section titled “Behaviour”](#behaviour)
* If the Hook is being [Weakly Executed](/docs/hooks/concepts/weak-and-strong) then emplace the metadata of the originating transaction into the slot specified or into a new slot if no slot is specified
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t meta_slot (
uint32_t slot_no
);
```
* JavaScript
```javascript
function meta_slot(slotno: number): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t meta_slot_no =
meta_slot(0);
```
* JavaScript
```javascript
const meta_slot_no = meta_slot(0)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| -------- | --------- | ----------------------------------------------------------------------------- |
| slot\_no | uint32\_t | The slot number to emplace into, or 0 if you wish to pick the next available. |
* JavaScript
| Name | Type | Description |
| ------ | ------ | ----------------------------------------- |
| slotno | number | The slot number to retrieve metadata for. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| int64\_t | The slot the otxn was placed in `INVALID_ARGUMENT` - specified slot number exceeds the largest possible slot number `NO_FREE_SLOTS` - the request could not granted because no free slot was avaialble to place the originating transaction into. `PREREQUISITE_NOT_MET` - The hook is being [Strongly Executed](/docs/hooks/concepts/weak-and-strong) and therefore no transactional metadata is available. |
* JavaScript
| Type | Description |
| ------------------- | --------------------------------------------- |
| ErrorCode \| number | Returns an error code or the slot’s metadata. |
# otxn_burden
> Get the burden of the originating transaction
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Return the burden of the originating transaction or `1` if no burden field is present.
* JavaScript
* Retrieve the burden of the originating transaction.
* Returns the burden as a number, or an ErrorCode if the retrieval fails.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t otxn_burden (
void
);
```
* JavaScript
```javascript
function otxn_burden(): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t burden =
otxn_burden();
```
* JavaScript
```javascript
const burden = otxn_burden()
```
### Parameters
[Section titled “Parameters”](#parameters)
None
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ---------------------------------------------------------------------------------------------------------- |
| int64\_t | The burden of the originating transaction, or `1` if no burden was present on the originating transaction. |
* JavaScript
| Type | Description |
| ------------------- | ----------------------------------------------------------------------- |
| number or ErrorCode | Returns the burden as a number, or an ErrorCode if the retrieval fails. |
# otxn_field
> Serialize and output a field from the originating transaction
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Find the specified `sf` field in the originating transaction
* Write the serialized version of the field to the output buffer
* JavaScript
* Retrieve the value of a specific field in the originating transaction.
* Returns the value of the specified field as an array of numbers, or an ErrorCode if the lookup fails.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t otxn_field (
uint32_t write_ptr,
uint32_t write_len,
uint32_t field_id
);
```
* JavaScript
```javascript
function otxn_field(field_id: number): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t account_field_len =
otxn_field(account_field, 20, sfAccount);
```
* JavaScript
```javascript
const account_field = otxn_field(sfAccount)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| write\_ptr | uint32\_t | Pointer to a buffer of a suitable size to store the output. |
| write\_len | uint32\_t | Length of the output buffer. |
| field\_id | uint32\_t | The `sf` code of the field you are searching for. To compute this manually take the serialized `type` and shift it into the 16 highest bits of uint32\_t, then take the `field` and place it in the 16 lowest bits. For example: `sfEmitNonce` has `type` 5 and `field` 11 thus its value is `0x050BU` |
Important
The field code is *not* written to the output buffer, only the *payload* of the field is.
At time of writing for Hooks Public Testnet, `STI_ACCOUNT` fields like `sfAccount` are returned *without* the leading variable length byte.
* JavaScript
| Name | Type | Description |
| --------- | ------ | ------------------------------------------------------------------------------------- |
| field\_id | number | Returns the value of the specified field as an array of numbers, if the lookup fails. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| int64\_t | The number of bytes written If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `TOO_SMALL` - output buffer was not large enough to hold the serialized field `INVALID_FIELD` - the `sf` field\_id was invalid `DOESNT_EXIST` - the field was not found in the originating transaction |
* JavaScript
| Type | Description |
| ---------------------- | ----------------------------------------------------------------------------------------------------- |
| ByteArray or ErrorCode | Returns the value of the specified field as an array of numbers, or an ErrorCode if the lookup fails. |
# otxn_generation
> Get the generation of the originating transaction
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Return the generation of the originating transaction or `1` if no generation field is present.
* JavaScript
* Retrieve the generation number of the originating transaction.
* Returns the generation number as a number.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t otxn_generation (
void
);
```
* JavaScript
```javascript
function otxn_generation(): number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t generation =
otxn_generation();
```
* JavaScript
```javascript
const generation = otxn_generation()
```
### Parameters
[Section titled “Parameters”](#parameters)
None
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| ------ | ------------------------------------------ |
| number | Returns the generation number as a number. |
* JavaScript
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------ |
| int64\_t | The generation of the originating transaction, or `1` if no generation was present on the originating transaction. |
# otxn_id
> Output the canonical hash of the originating transaction
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Write the canonical hash of the originating transaction to the output buffer.
* If flags = 1 and the transaction is an EMIT\_FAILURE transaction then write the canonical hash of the originating transaction that caused the emission.
* JavaScript
* Output the canonical hash of the originating transaction.
* Returns the transaction hash as an array of numbers, or an ErrorCode if the retrieval fails.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t otxn_id (
uint32_t write_ptr,
uint32_t write_len,
uint32_t flags
);
```
* JavaScript
```javascript
function otxn_id(flag: number): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
* C
```c
uint8_t txn_id[32];
int64_t bytes_written =
otxn_id(txn_id, 32, 0);
```
* JavaScript
```javascript
const tx_id = otxn_id(0)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| write\_ptr | uint32\_t | Pointer to a buffer of to store the hash. |
| write\_len | uint32\_t | Length of the output buffer. Should be at least 32 bytes. |
| flags | uint32\_t | If `0`: Write the canonical hash of the originating transaction. If `1` AND the originating transaction is an EMIT\_FAILURE: Write the canonical hash of the emitting transaction. |
* JavaScript
| Name | Type | Description |
| ----- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| flags | number | If `0`: Write the canonical hash of the originating transaction. If `1` AND the originating transaction is an EMIT\_FAILURE: Write the canonical hash of the emitting transaction. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| int64\_t | The number of bytes written If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `TOO_SMALL` - output buffer was not large enough to hold the serialized object |
* JavaScript
| Type | Description |
| ---------------------- | -------------------------------------------------------------------------------------------- |
| ErrorCode \| ByteArray | Returns the transaction hash as an array of numbers, or an ErrorCode if the retrieval fails. |
# otxn_json
> Output the originating transaction in JSON format.
### Behaviour
[Section titled “Behaviour”](#behaviour)
* JavaScript
* Output the originating transaction in JSON format.
* Returns the originating transaction as a JSON object or Transaction, or an ErrorCode if the retrieval fails.
### Definition
[Section titled “Definition”](#definition)
* JavaScript
```javascript
function otxn_json(): ErrorCode | Record | Transaction
```
### Example
[Section titled “Example”](#example)
* JavaScript
```javascript
const tx_json = otxn_json()
```
### Parameters
[Section titled “Parameters”](#parameters)
No parameters
### Return Code
[Section titled “Return Code”](#return-code)
* JavaScript
| Type | Description |
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------ |
| ErrorCode \| Record\ \| Transaction | Returns the originating transaction as a JSON object or Transaction, or an ErrorCode if the retrieval fails. |
# otxn_param
> Retrieve the parameter value for a named Invoke transaction parameter
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Look up the value for a named parameter specified in `read_ptr` on the originating transaction.
* Write the parameter’s value to `write_ptr`
* JavaScript
* Look up the value for a named parameter specified on the originating transaction.
* Returns the value of the specified parameter, or an ErrorCode if the lookup fails.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t otxn_param (
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len
);
```
* JavaScript
```javascript
function otxn_param(name: ByteArray | HexString): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
* C
```c
uint8_t pname[] = {0xCAU, 0xFEU};
uint8_t pvalue[32];
int64_t value_len =
otxn_param(pvalue, 32, pname, 2);
```
* JavaScript
```javascript
const pname = [0xCA, 0xFE]
const pvalue = otxn_param(pname)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | ---------------------------------------------------------------------------------------- |
| write\_ptr | uint32\_t | Pointer to a buffer of a suitable size to store the output. Should be at least 32 bytes. |
| write\_len | uint32\_t | Length of the output buffer. |
| read\_ptr | uint32\_t | Pointer to a buffer containing the parameter’s name |
| read\_len | uint32\_t | Length of the parameter’s name |
* JavaScript
| Name | Type | Description |
| ---- | ---------------------- | ------------------------------------------------------------------------- |
| name | ByteArray \| HexString | The name of the parameter to look up, specified as a ByteArray or string. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| int64\_t | The number of bytes written If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `DOESNT_EXIST` - The specified paramater doesn’t exist or is null `TOO_SMALL` - The parameter name can’t be null `TOO_BIG` - The parameter name is greater than 32 bytes |
* JavaScript
| Type | Description |
| ---------------------- | ---------------------------------------------------------------------------------- |
| ErrorCode \| ByteArray | Returns the value of the specified parameter, or an ErrorCode if the lookup fails. |
# otxn_slot
> Load the originating transaction into a slot
### Behaviour
[Section titled “Behaviour”](#behaviour)
* Emplace the originating transaction into the slot specified or into a new slot if no slot is specified
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t otxn_slot (
uint32_t slot_no
);
```
* JavaScript
```javascript
function otxn_slot(slotno: number): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t otxn_slot_no =
otxn_slot(0);
```
* JavaScript
```javascript
const otxn_slot_no = otxn_slot(0)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| -------- | --------- | ----------------------------------------------------------------------------- |
| slot\_no | uint32\_t | The slot number to emplace into, or 0 if you wish to pick the next available. |
* JavaScript
| Name | Type | Description |
| ------ | ------ | --------------------------- |
| slotno | number | The slot number to look up. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The slot the otxn was placed in `INVALID_ARGUMENT` - specified slot number exceeds the largest possible slot number `NO_FREE_SLOTS` - the request could not granted because no free slot was avaialble to place the originating transaction into. |
* JavaScript
| Type | Description |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| ErrorCode \| ByteArray | Returns the value associated with the specified slot number as an array of numbers, or an ErrorCode if the lookup fails. |
# otxn_type
> Get the Transaction Type of the originating transaction
### Behaviour
[Section titled “Behaviour”](#behaviour)
* Return the Transaction Type of the originating transaction
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t otxn_type (
void
);
```
* JavaScript
```javascript
function otxn_type(): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t tt =
otxn_type();
```
* JavaScript
```javascript
const tt = txn_type()
```
### Parameters
[Section titled “Parameters”](#parameters)
None
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The Transaction Type of the originating transaction. Check the table below for a list of known Transaction Types at time of writing |
* JavaScript
| Type | Description |
| ------------------- | --------------------------------------------------------------------------------- |
| ErrorCode \| number | Returns the Transaction Type as a number, or an ErrorCode if the retrieval fails. |
### Known Transaction Types
[Section titled “Known Transaction Types”](#known-transaction-types)
| Name | Value |
| ------------------------------- | ----- |
| ttPAYMENT | 0 |
| ttESCROW\_CREATE | 1 |
| ttESCROW\_FINISH | 2 |
| ttACCOUNT\_SET | 3 |
| ttESCROW\_CANCEL | 4 |
| ttREGULAR\_KEY\_SET | 5 |
| ttOFFER\_CREATE | 7 |
| ttOFFER\_CANCEL | 8 |
| ttTICKET\_CREATE | 10 |
| ttTICKET\_CANCEL | 11 |
| ttSIGNER\_LIST\_SET | 12 |
| ttPAYCHAN\_CREATE | 13 |
| ttPAYCHAN\_FUND | 14 |
| ttPAYCHAN\_CLAIM | 15 |
| ttCHECK\_CREATE | 16 |
| ttCHECK\_CASH | 17 |
| ttCHECK\_CANCEL | 18 |
| ttDEPOSIT\_PREAUTH | 19 |
| ttTRUST\_SET | 20 |
| ttACCOUNT\_DELETE | 21 |
| ttHOOK\_SET | 22 |
| ttURITOKEN\_MINT | 45 |
| ttURITOKEN\_BURN | 46 |
| ttURITOKEN\_BUY | 47 |
| ttURITOKEN\_CREATE\_SELL\_OFFER | 48 |
| ttURITOKEN\_CANCEL\_SELL\_OFFER | 49 |
| ttGENESIS\_MINT | 96 |
| ttIMPORT | 97 |
| ttCLAIM\_REWARD | 98 |
| ttINVOKE | 99 |
| ttAMENDMENT | 100 |
| ttFEE | 101 |
| ttUNL\_MODIFY | 102 |
| ttEMIT\_FAILURE | 103 |
| ttUNL\_REPORT | 104 |
# Hook API Conventions
### Naming conventions
[Section titled “Naming conventions”](#naming-conventions)
All Hook APIs follow a standard naming convention:
| | | | |
| --------- | --------------- | ------------ | --------------- |
| namespace | \[ \_ noun #1 ] | \[ \_ verb ] | \[ \_ noun #2 ] |
This may look confusing at first but is actually quite simple:
* If the first noun is missing then it is implicitly the same as the namespace
* If the verb is missing then it is implicitly `get`
Thus:
* `state()` means: fetch a hook state.
* `state_set()` means: set a hook.
* `state_foreign()` means: fetch a foreign hook state.
### Memory model
[Section titled “Memory model”](#memory-model)
Each Hook executes as a singular stack frame. All working memory must exist within this stackframe. There is no heap and no dynamic memory.
When Hooks communicate with `xahaud` they can only pass *integer* values. Typically these integers are pointers within the Hook’s memory. Since the Hook runs within xahaud, these points can then be resolved by xahaud and written to or read from as needed to perform the Hook API function.
### Allowed functions
[Section titled “Allowed functions”](#allowed-functions)
Only two functions are allowed within a Hook: `hook()` and `cbak()`. Read about this [here](/docs/hooks/concepts/compiling-hooks)
### Parameters
[Section titled “Parameters”](#parameters)
* C
All parameters passed to a Hook API must be one of: `uint32_t, int32_t, uint64_t, int64_t`. Typically these are pointers and lengths of buffers within the Hook’s stack frame. Sometimes they are [Integer Encoded Floating Point Numbers (XFL)](/docs/hooks/concepts/floating-point-numbers-xfl) or other data.
The parameters to a Hook API are always in the following order:
1. Writing pointer *if any*
2. Writing length *if any*
3. Reading pointer *if any*
4. Reading length *if any*
5. Specifics / other fields *if any*
Some Hook APIs may only write or may only read from memory, and some might not do either and return a value only by return code.
* JavaScript
All parameters passed to a Hook API must be one of: `string, number[], bigint(xfl), object(json)`. Typically these are pointers and lengths of buffers within the Hook’s stack frame. Sometimes they are [Integer Encoded Floating Point Numbers (XFL)](/docs/hooks/concepts/floating-point-numbers-xfl) or other data.
The parameters to a Hook API are always in the following order:
1. Writing variable *if any*
2. Reading variable *if any*
3. Specifics / other fields *if any*
Some Hook APIs may only write or may only read from memory, and some might not do either and return a value only by return code.
### Return codes
[Section titled “Return codes”](#return-codes)
All Hook APIs return a *signed integer*. Read about return codes here: [Return codes](/docs/hooks/functions/overview/return-codes)
# Return Codes
### Return code design
[Section titled “Return code design”](#return-code-design)
Web assembly allows for exceptions (traps) however this language feature is not used for Hooks. Instead there is only one way to return from any Hook API (you may think of every Hook API as being `noexcept`).
To provide for efficient error handling:
1. All Hook API functions return a *signed* integer.
2. All negative return codes are an error.
3. All return codes `0` or greater are a function specific output, usually but not always the number of bytes read or written.
### Error codes
[Section titled “Error codes”](#error-codes)
Error codes are global across all Hook APIs and may be found in the table below.
| Name | Value | Description |
| ---------------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SUCCESS | >= 0 | Non-negative return codes refer always to success and usually indicate the number of bytes written or events performed, depending on the specific API. |
| OUT\_OF\_BOUNDS | -1 | A pointer or buffer length provided as a parameter described memory outside of the Hook’s allowed memory region. |
| INTERNAL\_ERROR | -2 | Reserved for internal invariant trips, generally unrelated to inputs. These should be reported with an issue. |
| TOO\_BIG | -3 | Attempted to set a parameter or value larger than the allowed space. |
| TOO\_SMALL | -4 | The API was unable to produce output to the write\_ptr because the specified write\_len was too small. |
| DOESNT\_EXIST | -5 | The requested object or item wasn’t found. |
| NO\_FREE\_SLOTS | -6 | The Hook attempted to allocate an item into a slot, but there were no slots free. To avoid ensure re-use of existing slots. The maximum number of slots is 255. |
| INVALID\_ARGUMENT | -7 | One or more of the parameters to the API were invalid according to the individual API’s specification. |
| ALREADY\_SET | -8 | Some APIs allow for a once-per-execution parameter to be set. A second attempt to set a once-per-execution parameter results in this error. |
| PREREQUISITE\_NOT\_MET | -9 | An API required the Hook to do something before the API is allowed to be called. Check the API’s documentation. |
| FEE\_TOO\_LARGE | -10 | During fee calculation if an absurdly large fee is calculated this error is returned. |
| EMISSION\_FAILURE | -11 | An attempt to `emit()` a TXN was unsccessful for any of a number of reasons. Check the `trace` log of the rippled to which you are submitting the originating TXN. |
| TOO\_MANY\_NONCES | -12 | A Hook may only use up to 256 calls to `nonce()` per execution. Further calls result in this error code. |
| TOO\_MANY\_EMITTED\_TXN | -13 | A Hook must declare ahead of time how many TXN it intends to `emit()`. If it emits fewer than this many, this is allowed. If it emits more than this many this error is returned. |
| NOT\_IMPLEMENTED | -14 | While Hooks is/was in development an API may return this if some or all of that API is planned but not yet implemented. |
| INVALID\_ACCOUNT | -15 | An API which accepts a 20 byte Account ID may return this if, in its opinion, the Account ID was not valid for any reason. |
| GUARD\_VIOLATION | -16 | All loops inside a Hook must declare at the top of the loop, as the first non trivial instruction, before any branch instruction, the promised maximum number of iterations of the loop. If this promise is violated the hook terminates immediately with this error code. |
| INVALID\_FIELD | -17 | The requested serialized field could not be found in the specified object. |
| PARSE\_ERROR | -18 | While parsing serialized content an error was encountered (typically indicating an invalidly serialized object). |
| RC\_ROLLBACK | -19 | Used internally to communicate a rollback event. |
| RC\_ACCEPT | -20 | Used internally to communicate an accept event. |
| NO\_SUCH\_KEYLET | -21 | Specified keylet could not be found, or keylet is invalid |
| NOT\_AN\_ARRAY | -22 | API was asked to assume object under analysis is an STArray but it was not. |
| NOT\_AN\_OBJECT | -23 | API was asked to assume object under analysis is an STObject but it was not. |
| INVALID\_FLOAT | -10024 | A floating point operation resulted in Not-A-Number or API call attempted to specify an XFL floating point number outside of the expressible range of XFL. |
| DIVISION\_BY\_ZERO | -25 | API call would result in a division by zero, so API ended early. |
| MANITSSA\_OVERSIZED | -26 | When attempting to create an XFL the mantissa must be 16 decimal digits. |
| MANTISSA\_UNDERSIZED | -27 | When attempting to create an XFL the mantissa must be 16 decimal digits. |
| EXPONENT\_OVERSIZED | -28 | When attempting to create an XFL the exponent must not exceed 80. |
| EXPONENT\_UNDERSIZED | -29 | When attempting to create an XFL the exponent must not be less than -96. |
| OVERFLOW | -30 | A floating point operation done on an XFL resulted in a value larger than XFL format is able to represent. |
| NOT\_IOU\_AMOUNT | -31 | An API assumed an STAmount was an IOU when in fact it was XRP. |
| NOT\_AN\_AMOUNT | -32 | An API assumed an STObject was an STAmount when in fact it was not. |
| CANT\_RETURN\_NEGATIVE | -33 | An API would have returned a negative integer except that negative integers are reserved for error codes (i.e. what you are reading.) |
| NOT\_AUTHORIZED | -34 | Hook attempted to set foreign state but was not authorized to do so (grant was missing or invalid.) |
| PREVIOUS\_FAILURE\_PREVENTS\_RETRY | -35 | Hook previously received a `NOT_AUTHORIZED` return code and is not allowed to retry. |
| TOO\_MANY\_PARAMS | -36 | Attempted to set a hook parameter for a later hook in the chain, but there are now too many parameters. |
| INVALID\_TXN | -37 | Serialized transaction was not a valid transaction (usually because of a missing required field or data corruption / truncation.) |
| RESERVE\_INSUFFICIENT | -38 | Setting an additional state object on this account would cause the reserve requirements to exceed the account’s balance. |
| COMPLEX\_NOT\_SUPPORTED | -39 | Hook API would be forced to return a complex number, which it cannot do. |
| DOES\_NOT\_MATCH | -40 | Two arguments were required to be of the same type but are not. |
| INVALID\_KEY | -41 | The provided public key was not valid. |
| NOT\_A\_STRING | -42 | The buffer did not contain a nul terminated string. |
| MEM\_OVERLAP | -43 | The writing pointer points to a buffer that overlaps with the reading pointer. |
| TOO\_MANY\_STATE\_MODIFICATIONS | -44 | More than 5000 modified state entries in the combined hook chains |
| TOO\_MANY\_NAMESPACES | -45 | More than 256 namespaces on this account |
# sto_emplace
> Emplace a field into an existing STObject at its canonical placement
### Concepts
[Section titled “Concepts”](#concepts)
[Serialized Objects](/docs/hooks/concepts/serialized-objects)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Parse an STObject `S` (source object) pointed to by `sread_ptr`
* Parse an STObject `F` (to inject/emplace) pointed to by `fread_ptr`
* Write a new STObject to `write_ptr` which places `F` into `S` at the canonical position `field_id`
Field ID encoding
The `sto_` apis accept a `field_id` parameter encoded as follows: `(type << 16U) + field`\
Thus type 1 field 2 would be `0x10002U`.
* JavaScript
* Ask for the STO object by the param `sto`
* Ask for the bytes representing the field to be added by the param `field_bytes`
* Ask for the ID of the field to be added by the param `field_id`
* Return the updated STO object in binary encoded ledger data format, or an error code if the operation fails.
### Definition
[Section titled “Definition”](#definition)
C
* C
```c
int64_t sto_emplace (
uint32_t write_ptr,
uint32_t write_len,
uint32_t sread_ptr,
uint32_t sread_len,
uint32_t fread_ptr,
uint32_t fread_len,
uint32_t field_id
);
```
* JavaScript
```javascript
function sto_emplace(
sto: ByteArray | HexString,
field_bytes: ByteArray | HexString,
field_id: number
): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
* C
```c
uint8_t tx_out[1024];
int64_t tx_len =
sto_emplace(tx_out, sizeof(tx_out),
tx_in, tx_len,
sequence_field, 5, sfSequence);
if (tx_len <= 0)
rollback("Emplacing failed.", 17, 1);
```
* JavaScript
```javascript
const tx_out = sto_emplace(tx_in, sequence_field, sfSequence)
if (typeof tx_out === 'number')
rollback("Emplacing failed.", 1)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| write\_ptr | uint32\_t | The buffer to write the modified STObject to |
| write\_len | uint32\_t | The length of the output buffer |
| sread\_ptr | uint32\_t | The buffer to read the source STObject from |
| sread\_len | uint32\_t | The Length of the source object |
| fread\_ptr | uint32\_t | The buffer to read the field to be emplaced/injected from |
| fread\_len | uint32\_t | The length of the field to be emplaced/injected |
| field\_id | uint32\_t | The `sf` code (location) to form the emplacement. If this already exists in the source object then the existing field is overriden. If it doesn’t exist it is inserted. |
* JavaScript
| Name | Type | Description |
| ------------ | ---------------------- | ----------------------------------------------------------------------------- |
| sto | ByteArray \| HexString | The STO object (binary encoded ledger data) to which the field will be added. |
| field\_bytes | ByteArray \| HexString | The bytes representing the field to be added. |
| field\_id | number | The ID of the field to be added. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The number of bytes written to `write_ptr` If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `TOO_SMALL` - Output buffer must be at least as large as the source object + the injected field, even if the field is only being overriden. `TOO_BIG` - Field you are attempting to emplace is too large `PARSE_ERROR` - The supplied STObject is malformed or not an STObject. |
* JavaScript
| Type | Description |
| ---------------------- | ----------------------------------------------------------------------------------------------------- |
| ErrorCode \| ByteArray | The updated STO object in binary encoded ledger data format, or an error code if the operation fails. |
# sto_erase
> Remove a field from an STObject
### Concepts
[Section titled “Concepts”](#concepts)
[Serialized Objects](/docs/hooks/concepts/serialized-objects)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Parse an STObject pointed to by `read_ptr`
* Write a new STObject to `write_ptr` but without `field_id` if it was present in the original object.
* JavaScript
* It will look for the STO object (binary encoded ledger data) from which the field will be removed.
* It will look for the ID of the field to be erased.
* Returns the updated STO object in binary encoded ledger data format, or an error code if the operation fails.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t sto_erase (
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len,
uint32_t field_id
);
```
Field ID encoding
The `sto_` apis accept a `field_id` parameter encoded as follows: `(type << 16U) + field` Thus type 1 field 2 would be `0x10002U`.
* JavaScript
```javascript
function sto_erase(
sto: ByteArray | HexString,
field_id: number
): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t result =
sto_erase(tx_out, sizeof(tx_out),
tx_in, tx_len, sfSigners);
if (tx_len <= 0)
rollback("Erasing failed.", 15, 1);
```
Emplace equivalence
`sto_erase` is the same as `sto_emplace` with `0,0` for `field_ptr, field_len` parameters.
* JavaScript
```javascript
const tx_out = sto_erase(tx_in, sfSigners)
if (typeof tx_out === 'number')
rollback("Erasing failed.", 1)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | -------------------------------------------- |
| write\_ptr | uint32\_t | The buffer to write the modified STObject to |
| write\_len | uint32\_t | The length of the output buffer |
| read\_ptr | uint32\_t | The buffer to read the source STObject from |
| read\_len | uint32\_t | The Length of the source object |
| field\_id | uint32\_t | The `sf` code (location) to erase |
* JavaScript
| Name | Type | Description |
| --------- | ---------------------- | --------------------------------------------------------------------------------- |
| sto | ByteArray \| HexString | The STO object (binary encoded ledger data) from which the field will be removed. |
| field\_id | number | The ID of the field to be erased. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The number of bytes written to `write_ptr` If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `TOO_SMALL` - Output buffer must be at least as large as the source object. `TOO_BIG` - Field you are attempting to erase from is too large `PARSE_ERROR` - The supplied STObject is malformed or not an STObject. `DOESNT_EXIST` - The specified `field_id` isn’t present in the STObject. |
* JavaScript
| Type | Description |
| ---------------------- | ----------------------------------------------------------------------------------------------------- |
| ErrorCode \| ByteArray | The updated STO object in binary encoded ledger data format, or an error code if the operation fails. |
# sto_from_json
> Format JSON as an STO object (binary encoded ledger data).
### Concepts
[Section titled “Concepts”](#concepts)
[Serialized Objects](/docs/hooks/concepts/serialized-objects)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* JavaScript
* Takes a JSON object and converts it into a binary encoded ledger data format.
* Returns STO Object in binary encoded ledger data format, or an error code if the conversion fails.
### Definition
[Section titled “Definition”](#definition)
* JavaScript
```javascript
function sto_from_json(
jsonobj: Record | Transaction
): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
* JavaScript
```javascript
const stoBlob = sto_from_json(stoJson)
```
### Parameters
[Section titled “Parameters”](#parameters)
* JavaScript
| Name | Type | Description |
| ------- | ----------------------------------- | ----------------------------------------------- |
| jsonobj | Record\ \| Transaction | JSON object to be converted into an STO object. |
### Return Code
[Section titled “Return Code”](#return-code)
* JavaScript
| Type | Description |
| ---------------------- | ------------------------------------------------------------------------------------------ |
| ErrorCode \| ByteArray | STO Object in binary encoded ledger data format, or an error code if the conversion fails. |
# sto_subarray
> Index into a xahaud serialized array and return the location and length of an index
### Concepts
[Section titled “Concepts”](#concepts)
[Serialized Objects](/docs/hooks/concepts/serialized-objects)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Parse a STArray pointed to by `read_ptr`
* Find the array index specified by `array_id`
* Return the byte offset and length of the serialized field within the STObject, if it is found
Field ID encoding
The `sto_` apis accept a `field_id` parameter encoded as follows: `(type << 16U) + field` Thus type 1 field 2 would be `0x10002U`.
In the case of this array field ID is `array_id`.
* JavaScript
* Ask for the STO object (binary encoded ledger data) from which to extract the subarray.
* Find the array index specified by `array_id`
* Return a subarray from an STO object.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t sto_subarray (
uint32_t read_ptr,
uint32_t read_len,
uint32_t array_id
);
```
* JavaScript
```javascript
function sto_subarray(
sto: ByteArray | HexString,
array_id: number
): bigint | number
```
### Example
[Section titled “Example”](#example)
* C
```c
#define SUB_OFFSET(x) ((int32_t)(x >> 32))
#define SUB_LENGTH(x) ((int32_t)(x & 0xFFFFFFFFULL))
int64_t memo_lookup =
sto_subarray(memos, memos_len, 0);
if (memo_lookup < 0)
{
// sfMemo was not found in the STObject pointed at by memo_ptr
}
else
{
// 0th index of the STArray was found and its location is as follows:
uint8_t* memo_ptr = SUB_OFFSET(memo_lookup) + memos;
uint32_t memo_len = SUB_LENGTH(memo_lookup);
}
```
Tip
hookmacro.h already contains the `SUB_OFFSET` and `SUB_LENGTH` macros.
* JavaScript
```javascript
const SUB_OFFSET = (x) => Number(x >> 32n)
const SUB_LENGTH = (x) => Number(x & 0xFFFFFFFFn)
const memo_lookup = sto_subarray(memos, 0)
if (typeof memo_lookup === 'number')
{
// sfMemo was not found in the STObject pointed at
}
else
{
// 0th index of the STArray was found and its location is as follows:
const memo_start = SUB_OFFSET(memo_lookup)
const memo_len = SUB_LENGTH(memo_lookup)
const memo = memos.slice(memo_start, memo_len)
}
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| --------- | --------- | ------------------------------------------------------------------------- |
| read\_ptr | uint32\_t | Pointer to the buffer containing the STArray |
| read\_len | uint32\_t | Length of STArray |
| array\_id | uint32\_t | The index of the entry within the STArray you are seeking. Starts from 0. |
* JavaScript
| Name | Type | Description |
| --------- | ---------------------- | ------------------------------------------------------------------------------- |
| sto | ByteArray \| HexString | The STO object (binary encoded ledger data) from which to extract the subarray. |
| array\_id | number | The ID of the array to be extracted. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The location of the field within the specified buffer: - The high 32 bits are the offset location. - The low 32 bits are the length. If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `TOO_SMALL` - Input buffer isn’t large enough to possibly contain a valid STArray. `DOESNT_EXIST` - The searched for index isn’t present in the supplied STArray. `PARSE_ERROR` - The supplied STArray is malformed or not an STArray. |
* JavaScript
| Type | Description |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| bigint / ErrorCode | The location of the field within the specified buffer: - The high 32 bits are the offset location. - The low 32 bits are the length. or an error code if the extraction fails. |
# sto_subfield
> Index into a xahaud serialized object and return the location and length of a subfield
### Concepts
[Section titled “Concepts”](#concepts)
[Serialized Objects](/docs/hooks/concepts/serialized-objects)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Parse a STObject pointed to by `read_ptr`
* Find the field specified by `field_id`
* If the field is found, and:
* 1. It is an array, then return the start and length of the array including the leadin/leadout bytes, or
* 2. It is **not** an array, then return the start and length of the PAYLOAD of the field (excluding the leadin bytes).
Field ID encoding
The `sto_` apis accept a `field_id` parameter encoded as follows: `(type << 16U) + field` Thus type 1 field 2 would be `0x10002U`.
* JavaScript
* Parse a STObject into `sto` variable
* Find the field specified by `field_id`
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t sto_subfield (
uint32_t read_ptr,
uint32_t read_len,
uint32_t field_id
);
```
* JavaScript
```javascript
function sto_subfield(
sto: ByteArray | HexString,
field_id: number
): ErrorCode | bigint
```
### Example
[Section titled “Example”](#example)
* C
```c
#define SUB_OFFSET(x) ((int32_t)(x >> 32))
#define SUB_LENGTH(x) ((int32_t)(x & 0xFFFFFFFFULL))
int64_t memos_lookup =
sto_subfield(txn_ptr, txn_len, sfMemos);
if (memos_lookup < 0)
{
// sfMemos was not found in the STObject pointed at by memo_ptr
}
else
{
// sfMemos was found and its location is as follows:
uint8_t* memos_ptr = SUB_OFFSET(memos_lookup) + memos_ptr;
int64_t memos_len = SUB_LENGTH(memos_lookup);
}
```
Tip
hookmacro.h already contains the `SUB_OFFSET` and `SUB_LENGTH` macros.
* JavaScript
```javascript
const SUB_OFFSET = (x) => Number(x >> 32n)
const SUB_LENGTH = (x) => Number(x & 0xFFFFFFFFn)
const memos_lookup = sto_subfield(txn, sfMemos);
if (typeof memos_lookup === 'number')
{
// sfMemos was not found in the STObject pointed at by memo_ptr
}
else
{
// sfMemos was found and its location is as follows:
const memo_start = SUB_OFFSET(memos_lookup)
const memo_len = SUB_LENGTH(memos_lookup)
const memo = txn.slice(memo_start, memo_len)
}
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| --------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| read\_ptr | uint32\_t | Pointer to the buffer containing the STObject |
| read\_len | uint32\_t | Length of STObject |
| field\_id | uint32\_t | The `sf` code of the field you are searching for. To compute this manually take the serialized `type` and shift it into the 16 highest bits of uint32\_t, then take the `field` and place it in the 16 lowest bits. For example: `sfEmitNonce` has `type` 5 and `field` 11 thus its value is `0x050BU` |
* JavaScript
| Name | Type | Description |
| --------- | ---------------------- | ------------------------------------------------------------------------------- |
| sto | ByteArray or HexString | The STO object (binary encoded ledger data) from which to extract the subfield. |
| field\_id | number | The ID of the field to be extracted. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The location of the field within the specified buffer: - The high 32 bits are the offset location. - The low 32 bits are the length. If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `TOO_SMALL` - Input buffer isn’t large enough to possibly contain a valid STObject. `DOESNT_EXIST` - The searched for field isn’t present in the supplied STObject. `PARSE_ERROR` - The supplied STObject is malformed or not an STObject. |
* JavaScript
| Type | Description |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| bigint / ErrorCode | The location of the field within the specified buffer: - The high 32 bits are the offset location. - The low 32 bits are the length.or an error code if the extraction fails. |
# sto_to_json
> Format an STO object (binary encoded ledger data) as JSON format.
### Concepts
[Section titled “Concepts”](#concepts)
[Serialized Objects](/docs/hooks/concepts/serialized-objects)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* JavaScript
* Format an STO object (binary encoded ledger data) as JSON format.
This function takes a serialized transaction `blob` and converts it into a human-readable JSON format.
* Returns Decoded JSON representation of the STO object, or an error code if the conversion fails.
### Definition
[Section titled “Definition”](#definition)
* JavaScript
```javascript
function sto_to_json(
blob: ByteArray | HexString
): ErrorCode | Record | Transaction
```
### Example
[Section titled “Example”](#example)
* JavaScript
```javascript
const jsonSto = sto_to_json(stoBlob)
```
### Parameters
[Section titled “Parameters”](#parameters)
* JavaScript
| Name | Type | Description |
| ---- | ---------------------- | ------------------------------------------------------- |
| blob | ByteArray \| HexString | The blob (e.g. serialized transaction) to be converted. |
### Return Code
[Section titled “Return Code”](#return-code)
* JavaScript
| Type | Description |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------- |
| ErrorCode \| Record\ \| Transaction | Decoded JSON representation of the STO object, or an error code if the conversion fails. |
# sto_validate
> Validate an STObject
### Concepts
[Section titled “Concepts”](#concepts)
[Serialized Objects](/docs/hooks/concepts/serialized-objects)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Parse an STObject pointed to by `read_ptr`
* Return 1 if the serialization is valid, 0 otherwise.
* JavaScript
* The `blob` (e.g. serialized transaction) is provided to be validated.
* Returns number 1 if the STObject is valid, 0 if it isn’t, or an error code if validation fails.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t sto_validate (
uint32_t read_ptr,
uint32_t read_len
);
```
* JavaScript
```javascript
function sto_validate(blob: ByteArray | HexString): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t result =
sto_validate(tx_out, sizeof(tx_out));
if (tx_len <= 0)
rollback("Invalid STO.", 12, 1);
```
* JavaScript
```javascript
const result = sto_validate(tx_out)
if (result <= 0)
rollback("Invalid STO.", 1)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| --------- | --------- | ------------------------------------------- |
| read\_ptr | uint32\_t | The buffer to read the source STObject from |
| read\_len | uint32\_t | The Length of the source object |
* JavaScript
| Name | Type | Description |
| ---- | ---------------------- | ------------------------------------------------------- |
| blob | ByteArray \| HexString | The blob (e.g. serialized transaction) to be validated. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| int64\_t | `1` if the STObject pointed to by `read_ptr` is a valid STObject. `0` if it isn’t. If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. |
* JavaScript
| Type | Description |
| ------------------- | ----------------------------------------------------------------------------------------------- |
| ErrorCode \| number | Returns number 1 if the STObject is valid, 0 if it isn’t, or an error code if validation fails. |
# slot
> Serialize and output a slotted object
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Serialize the object currently occupying the specified slot
* Write the serialized version of the object to the output buffer
Alternative use
For small objects you may avoid using a buffer. Specify `0, 0` for `write_ptr, write_len` to attempt to return the slotted object as big endian packed data in the `int64_t` return code. Up to 63 bits of data may be returned this way.
* JavaScript
* Retrieves the JSON Retrieves the data associated with the specified slot. of the specified slot.
* Returns an error code or the slot’s data.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t slot (
uint32_t write_ptr,
uint32_t write_len,
uint32_t slot_no
);
```
* JavaScript
```javascript
function slot(slotno: number): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
* C
```c
uint8_t txn[512];
int64_t bytes_written =
slot(txn, 512, 1); // assumes a transaction is slotted into slot=1
```
* JavaScript
```javascript
const txn = slot(1) // assumes a transaction is slotted into slot=1
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | ----------------------------------------------------------- |
| write\_ptr | uint32\_t | Pointer to a buffer of a suitable size to store the output. |
| write\_len | uint32\_t | Length of the output buffer. |
| slot\_no | uint32\_t | The slot number |
* JavaScript
| Name | Type | Description |
| ------ | ------ | --------------- |
| slotno | number | The slot number |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| int64\_t | The number of bytes written If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `TOO_SMALL` - output buffer was not large enough to hold the serialized object |
* JavaScript
| Type | Description |
| ---------------------- | ----------------------------------------- |
| ErrorCode \| ByteArray | Returns an error code or the slot’s data. |
# slot_clear
> Free up a currently occupied slot
### Behaviour
[Section titled “Behaviour”](#behaviour)
* Free the specified slot, releasing any object that was slotted there
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t slot_clear (
uint32_t slot_no
);
```
* JavaScript
```javascript
function slot_clear(slotno: number): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
slot_clear(1); // assumes a transaction is slotted into slot=1
```
* JavaScript
```javascript
slot_clear(1) // assumes a transaction is slotted into slot=1
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| -------- | --------- | --------------- |
| slot\_no | uint32\_t | The slot number |
* JavaScript
| Name | Type | Description |
| ------ | ------ | --------------- |
| slotno | number | The slot number |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | `1` or an error If negative, an error: `DOESNT_EXIST` - the specified slot does not contain any object or it is an invalid slot |
* JavaScript
| Type | Description |
| ------------------- | ----------------------------------------------------------- |
| ErrorCode \| number | Returns an error code or the result of the clear operation. |
# slot_count
> Count the elements of an array object in a slot
### Behaviour
[Section titled “Behaviour”](#behaviour)
* Count the elements of an array in the specified slot
* Return the count
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t slot_count (
uint32_t slot_no
);
```
* JavaScript
```javascript
function slot_count(slotno: number): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
slot_count(1); // assumes an array is slotted into slot=1
```
* JavaScript
```javascript
slot_count(1) // assumes an array is slotted into slot=1
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| -------- | --------- | --------------- |
| slot\_no | uint32\_t | The slot number |
* JavaScript
| Name | Type | Description |
| ------ | ------ | --------------- |
| slotno | number | The slot number |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| int64\_t | The number of elements inside the slotted array If negative, an error: `DOESNT_EXIST` - the specified slot does not contain any object or it is an invalid slot `NOT_AN_ARRAY` - the specified slot does not contain an array object |
* JavaScript
| Type | Description |
| ------------------- | ---------------------------------------------- |
| ErrorCode or number | Returns an error code or the count of entries. |
# slot_float
> Parse the STI_AMOUNT in the specified slot and return it as an XFL enclosed number
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Parse the STI\_AMOUNT in the specified slot and return it as an XFL enclosed number
* JavaScript
* Retrieves the bigint value associated with the specified slot.
* Returns an error code or the bigint value.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t slot_float (
uint32_t slot_no
);
```
* JavaScript
```javascript
function slot_float(slotno: number): ErrorCode | bigint
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t xfl =
slot_float(amt_slot);
```
* JavaScript
```javascript
const xfl = slot_float(amt_slot)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| -------- | --------- | --------------- |
| slot\_no | uint32\_t | The slot number |
* JavaScript
| Name | Type | Description |
| ------ | ------ | -------------------------------------------------- |
| slotno | number | The slot number to retrieve the bigint value from. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The XFL enclosing number If negative, an error: `DOESNT_EXIST` - the specified slot does not contain any object or it is an invalid slot `NOT_AN_AMOUNT` - the specified slot does not contain an `STI_AMOUNT` object |
* JavaScript
| Type | Description |
| ------------------- | ------------------------------------------ |
| bigint or ErrorCode | Returns an error code or the bigint value. |
# slot_set
> Locate an object based on its keylet and place it into a slot
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Locate an object given the Keylet provided in `read_ptr`
* Emplace the located object into the slot specified or into a new slot if no slot (zero) is specified
* JavaScript
* Sets the data for the specified slot.
* Returns an error code or the result of the set operation.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t slot_set (
uint32_t read_ptr,
uint32_t read_len,
uint32_t slot_no
);
```
* JavaScript
```javascript
function slot_set(
kl: ByteArray | HexString,
slotno: number
): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t slot_no =
slot_set(keylet, 34, 0);
```
* JavaScript
```javascript
const slot_no = slot_set(keylet, 0)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| --------- | --------- | ----------------------------------------------------------------------------------------------- |
| read\_ptr | uint32\_t | Pointer to a buffer containing the keylet of the object to locate. This can also be a txn hash. |
| read\_len | uint32\_t | Length of the read buffer. Should always be 32 or 34. |
| slot\_no | uint32\_t | The slot number to emplace into, or 0 if you wish to pick the next available. |
* JavaScript
| Name | Type | Description |
| ------ | ---------------------- | --------------------------------------------------------- |
| kl | ByteArray \| HexString | The data to set in the slot, can be an array or a string. |
| slotno | number | The slot number to set data for. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The slot number the object was inserted into If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `INVALID_ARGUMENT` - `read_len` must be either 32 or 34 bytes depending on whether a txn hash or a keylet is being used in `read_ptr` - the hash or keylet was invalid `DOESNT_EXIST` - the requested object was not found |
* JavaScript
| Type | Description |
| ------------------- | --------------------------------------------------------- |
| ErrorCode or number | Returns an error code or the result of the set operation. |
# slot_size
> Compute the serialized size of an object in a slot
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Return the number of bytes the object in the specified slot occupies when serialized
* JavaScript
* Retrieves the size of the specified slot.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t slot_size (
uint32_t slot_no
);
```
* JavaScript
```javascript
function slot_size(slotno: number): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t bytes_needed = slot_size(1); // get size of slot 1
```
* JavaScript
```javascript
const bytes_needed = slot_size(1); // get size of slot 1
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| -------- | --------- | --------------- |
| slot\_no | uint32\_t | The slot number |
* JavaScript
| Name | Type | Description |
| ------ | ------ | ------------------------------------- |
| slotno | number | The slot number to check the size of. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The number of bytes the object occupies when serialized If negative, an error: `DOESNT_EXIST` - the specified slot does not contain any object or it is an invalid slot |
* JavaScript
| Type | Description |
| ------------------- | ---------------------------------------------- |
| ErrorCode \| number | Returns an error code or the size of the slot. |
# slot_subarray
> Index into a slotted array and assign a sub-object to another slot
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Look up the array in slot `parent_slot`
* Retrieve the sub-object at the index specified in `array_id`
* Place sub-object into the slot `new_slot` or the next available slot if `new_slot` is 0.
* Return the new slot number.
* JavaScript
* Creates a subarray in the specified parent slot.
* Returns an error code or the result of the subarray creation.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t slot_subarray (
uint32_t parent_slot,
uint32_t array_id,
uint32_t new_slot
);
```
* JavaScript
```javascript
function slot_subarray(
parent_slotno: number,
array_id: number,
new_slotno: number
): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t subslot = 0;
subslot =
slot_subarray(slot_no, i, (uint32_t)subslot);
```
* JavaScript
```javascript
let subslot = 0
subslot = slot_subarray(slot_no, i, subslot)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| parent\_slot | uint32\_t | Slot the parent array is in |
| array\_id | uint32\_t | The `sf` code of the field you are searching for. To compute this manually take the serialized `type` and shift it into the 16 highest bits of uint32\_t, then take the `field` and place it in the 16 lowest bits. For example: `sfEmitNonce` has `type` 5 and `field` 11 thus its value is `0x050BU` |
| new\_slot | uint32\_t | New slot number to place the object from the selected array index into. If null, choose the next available slot. *May be null.* |
* JavaScript
| Name | Type | Description |
| -------------- | ------ | --------------------------------------------- |
| parent\_slotno | number | The parent slot number. |
| array\_id | number | The ID of the array to create a subarray for. |
| new\_slotno | number | The new slot number for the subarray. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The slot number of the newly allocated object If negative, an error: `DOESNT_EXIST` - The specified `array_id` doesn’t exist in the array pointed to by `parent_slot` `NO_FREE_SLOTS` - The API would require a new slot to be allocated but the Hook is already at the maximum number of slots. `NOT_AN_ARRAY` - The specified `parent_slot` does not contain an STArray. |
* JavaScript
| Type | Description |
| ------ | ------------------------------------------------------------- |
| number | Returns an error code or the result of the subarray creation. |
# slot_subfield
> Index into a slotted object and assign a sub-object to another slot
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Look up the object in slot `parent_slot`
* Retrieve the sub-object at `field_id`
* Place sub-object into the slot `new_slot` or the next available slot if `new_slot` is 0.
* Return the new slot number.
* JavaScript
* Creates a subfield in the specified parent slot.
* Returns an error code or the result of the subfield creation.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t slot_subfield (
uint32_t parent_slot,
uint32_t field_id,
uint32_t new_slot
);
```
* JavaScript
```javascript
function slot_subfield(
parent_slotno: number,
field_id: number,
new_slotno: number
): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t amt_slot =
slot_subfield(oslot, sfAmount, 0);
```
* JavaScript
```javascript
const amt_slot = slot_subfield(oslot, sfAmount, 0)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| parent\_slot | uint32\_t | Slot the parent object is in |
| field\_id | uint32\_t | The `sf` code of the field you are searching for. To compute this manually take the serialized `type` and shift it into the 16 highest bits of uint32\_t, then take the `field` and place it in the 16 lowest bits. For example: `sfEmitNonce` has `type` 5 and `field` 11 thus its value is `0x050BU` |
| new\_slot | uint32\_t | New slot number to place the object from the selected field into. If null, choose the next available slot. *May be null.* |
* JavaScript
| Name | Type | Description |
| -------------- | ------ | --------------------------------------------- |
| parent\_slotno | number | The parent slot number. |
| field\_id | number | The ID of the field to create a subfield for. |
| new\_slotno | number | The new slot number for the subfield. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The slot number of the newly allocated object If negative, an error: `DOESNT_EXIST` - The searched for field isn’t present in the parent slot or the parent slot is unfilled. `NO_FREE_SLOTS` - The API would require a new slot to be allocated but the Hook is already at the maximum number of slots. `INVALID_FIELD` - The specified field is not a valid `sf` field. `NOT_AN_OBJECT` - The slotted object is not a valid STObject. |
* JavaScript
| Type | Description |
| ------------------- | ------------------------------------------------------------- |
| number or ErrorCode | Returns an error code or the result of the subfield creation. |
# slot_type
> Retrieve the field code of an object in a slot and, optionally, some other information
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Locate the object pointed to by the specified `slot_no`
* Determine its `sf` field code and return this, or some other information (see below) if `flags` are used
* JavaScript
* Retrieves the type of the specified slot.
* Returns an error code or the type of the slot.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t slot_type (
uint32_t slot_no,
uint32_t flags
);
```
* JavaScript
```javascript
function slot_type(slotno: number, flags: number): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t fidle_code =
slot_type(1, 0);
```
* JavaScript
```javascript
const field_code = slot_type(1, 0)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| -------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| slot\_no | uint32\_t | The slot number |
| flags | uin32\_t | For normal operation this should be `0`. To determine whether or not an `STI_AMOUNT` type contains a native (XAH) amount or a floating point (IOU) amount set to `1`. |
* JavaScript
| Name | Type | Description |
| ------ | ------ | ------------------------------------- |
| slotno | number | The slot number to check the type of. |
| flags | number | Flags to determine the type. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | If `flags` is `0` then: The `sf` field code of the slotted object If `flags` is `1` then: `1` if and only if the slotted object is an `STI_AMOUNT` and the type of the amount is XAH. If negative, an error: `DOESNT_EXIST` - the specified `slot_no` does not contain an object. `NOT_AN_AMOUNT` - `flags` was set to `1` but the slotted object is not an `STI_AMOUNT` object |
* JavaScript
| Type | Description |
| ------------------- | ---------------------------------------------- |
| ErrorCode or number | Returns an error code or the type of the slot. |
# xpop_slot
> Serialize and output the xpop transaction blob and metadata
### Behaviour
[Section titled “Behaviour”](#behaviour)
* Locate the xpop blob on the `Import` transaction
* Emplace the located tx and meta objects into the slots specified
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t xpop_slot (
uint32_t slot_no_tx,
uint32_t slot_no_meta
);
```
* JavaScript
```javascript
function xpop_slot(slotno_tx: number, slotno_meta: number): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
int64_t bytes_written =
xpop_slot(1, 2); // assumes a txn is slotted into slot=1 meta is slotted into slot=2
```
* JavaScript
```javascript
const bytes_written = xpop_slot(1, 2)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| -------------- | --------- | ---------------------------------------------- |
| slot\_no\_tx | uint32\_t | The slot number to emplace the tx blob into. |
| slot\_no\_meta | uin32\_t | The slot number to emplace the meta blob into. |
* JavaScript
| Name | Type | Description |
| ------------ | ------ | ----------------------------------- |
| slotno\_tx | number | The transaction slot number to pop. |
| slotno\_meta | number | The metadata slot number to pop. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | `PREREQUISITE_NOT_MET` - The originating tx type was not `Import`. `NO_FREE_SLOTS` - The API would require a new slot to be allocated but the Hook is already at the maximum number of slots. |
* JavaScript
| Type | Description |
| ------------------- | --------------------------------------------------------- |
| number or ErrorCode | Returns an error code or the result of the pop operation. |
# state
> Retrieve the data pointed to by a Hook State key and write it to an output buffer
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Read a 32 byte Hook State key from the `kread_ptr`
* Write the data (value) at that key to the buffer pointed to by `write_ptr`
* JavaScript
* Retrieves the Hook State value associated with the specified key.
* Returns an error code or the Hook State value for the key.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t state (
uint32_t write_ptr,
uint32_t write_len,
uint32_t kread_ptr,
uint32_t kread_len
);
```
* JavaScript
```javascript
function state(key: ByteArray | HexString): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
* C
```c
#define SBUF(str) (uint32_t)(str), sizeof(str)
if (state(SBUF(vault), SBUF(vault_key)) != 16)
rollback(SBUF("Error: could not read state!"), 1);
```
* JavaScript
```javascript
const value = state(SBUF(vault), SBUF(vault_key))
if (typeof value === 'number' || value.length != 16)
rollback("Error: could not read state!", 1);
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | ----------------------------------------------------------------- |
| write\_ptr | uint32\_t | A pointer to the buffer to write the data in the Hook State into. |
| write\_len | uint32\_t | The length of the write buffer. |
| kread\_ptr | uint32\_t | Pointer to a buffer containing the Hook State key. |
| kread\_len | uint32\_t | The length of the Hook State key. (Should be 32.) |
Tip
Ensure you check the return value. A state lookup can fail of a range of reasons and the buffer will then contain whatever it did before the call (typically all zeros).
* JavaScript
| Name | Type | Description |
| ---- | ---------------------- | ----------------------------------------------------- |
| key | ByteArray or HexString | The key of the Hook State to retrieve the value from. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The number of bytes written to the write buffer. If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `DOESNT_EXIST` - the specified Hook State key doesn’t have an associated value on the ledger at the time of the call. `TOO_BIG` - the key specified by `read_ptr` and `read_len` was larger than 32 bytes. `TOO_SMALL` - the output buffer was too small to store the Hook State data. |
* JavaScript
| Type | Description |
| ---------------------- | ---------------------------------------------------------- |
| ByteArray or ErrorCode | Returns an error code or the Hook State value for the key. |
# state_foreign
> Retrieve the data pointed to, on another account, by a Hook State key and write it to an output buffer
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Read a 20 byte Account ID from the `aread_ptr`
* Read a 32 byte Hook State key from the `kread_ptr`
* Write the data (value) at that key at that Account ID to the buffer pointed to by `write_ptr`
* JavaScript
* Retrieves the Foreign Hook State value belonging to another account for the specified key.
* Returns an error code or the Hook State value for the key.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t state_foreign (
uint32_t write_ptr,
uint32_t write_len,
uint32_t kread_ptr,
uint32_t kread_len,
uint32_t nread_ptr,
uint32_t nread_len,
uint32_t aread_ptr,
uint32_t aread_len
);
```
* JavaScript
```javascript
function state_foreign(
key: ByteArray | HexString,
namespace: ByteArray | HexString | undefined | null,
accountid: ByteArray | HexString | undefined | null
): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
* C
```c
#define SBUF(str) (uint32_t)(str), sizeof(str)
uint8_t ns[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int64_t lookup =
state_foreign(SBUF(blacklist_status), SBUF(otxn_accid), SBUF(ns), SBUF(blacklist_accid));
if (lookup < 0)
rollback(SBUF("Error: could not find key on foreign state."), 1);
```
* JavaScript
```javascript
const ns = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
const blacklist_status =
state_foreign(otxn_accid, ns, blacklist_accid)
if (typeof blacklist_status === 'number')
rollback("Error: could not find key on foreign state.", 1);
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | ------------------------------------------------------------------------------- |
| write\_ptr | uint32\_t | A pointer to the buffer to write the data in the Hook State into. |
| write\_len | uint32\_t | The length of the write buffer. |
| kread\_ptr | uint32\_t | Pointer to a buffer containing the Hook State key. |
| kread\_len | uint32\_t | The length of the Hook State key. (Should be 32.) |
| nread\_ptr | uint32\_t | A pointer to the buffer containing the 32 byte Namespace to lookup the state on |
| nread\_len | uint32\_t | The length of the namespace buffer (Should be 32). |
| aread\_ptr | uint32\_t | A pointer to a buffer containing the 20 byte Account ID to look up state on. |
| aread\_len | uint32\_t | The length of the Account buffer. (Should always be 20). |
Tip
Ensure you check the return value. A state lookup can fail of a range of reasons and the buffer will then contain whatever it did before the call (typically all zeros).
* JavaScript
| Name | Type | Description |
| --------- | ---------------------- | ----------------------------------------------------- |
| key | ByteArray or HexString | The key of the Hook State to retrieve the value from. |
| namespace | ByteArray or HexString | The Hook namespace to look in. |
| accountid | ByteArray or HexString | The owner of the state. |
| | | |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The number of bytes written to the write buffer. If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `DOESNT_EXIST` - the specified Hook State key doesn’t have an associated value on the ledger at the time of the call. `TOO_BIG` - the key specified by `read_ptr` and `read_len` was larger than 32 bytes. `TOO_SMALL` - the output buffer was too small to store the Hook State data. `INVALID_ACCOUNT` - the account specified at `aread_ptr` is invalid or does not exist. |
* JavaScript
| Type | Description |
| ---------------------- | ---------------------------------------------------------- |
| ErrorCode or ByteArray | Returns an error code or the Hook State value for the key. |
# state_foreign_set
> Set the Hook State on another account for a given key, value and namespace
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Read a 32 byte Hook State key from the `kread_ptr`
* Read an arbitrary amount of data from `read_ptr` (the value)
* Read a 32 byte Namespace from the `nread_ptr`
* Read a 20 byte Account ID from `aread_ptr`
* Update the Hook State key on the specified account within the specified namespace with the value
* But only if a [Grant](https://xrpl-hooks.readme.io/docs/grants) on that account allows this.
* If the Hook Account is specified in `aread_ptr` then the behaviour is that of state\_set but still allows specification of namespace through `nread_ptr`
* JavaScript
* Sets the Foreign Hook State with the specified value, key, namespace, and account ID.
* This operation requires authorization and a Grant to allow this action.
* Returns the number of bytes written to Hook State (the length of the data), negative on error.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t state_foreign_set (
uint32_t read_ptr,
uint32_t read_len,
uint32_t kread_ptr,
uint32_t kread_len,
uint32_t nread_ptr,
uint32_t nread_len,
uint32_t aread_ptr,
uint32_t aread_len
);
```
* JavaScript
```javascript
function state_foreign_set(
value: ByteArray | HexString | undefined | null,
key: ByteArray | HexString,
namespace: ByteArray | HexString | undefined | null,
accountid: ByteArray | HexString | undefined | null
): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
#define SBUF(str) (uint32_t)(str), sizeof(str)
if (state_foreign_set(SBUF(vault), SBUF(vault_key), SBUF(namespace), SBUF(account)) < 0)
rollback(SBUF("Error: could not set foreign state!"), 1);
```
* JavaScript
```javascript
if (state_foreign_set(vault, vault_key, namespace, account) < 0)
rollback("Error: could not set foreign state!", 1);
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | ---------------------------------------------------------------------------------------------------------------------------- |
| read\_ptr | uint32\_t | Pointer to the data (value) to write into Hook State. If this is `0` (null) then delete the data at this key. *May be null.* |
| read\_len | uint32\_t | The length of the data. If this is `0` (null) then delete the data at this key. *May be null.* |
| kread\_ptr | uint32\_t | A pointer to the Hook State key at which to store the value. |
| kread\_len | uint32\_t | The length of the key. (Should always be 32.) |
| nread\_ptr | uint32\_t | A pointer to the namespace which the key belongs to. |
| nread\_len | uint32\_t | The length of the namespace. (Should always be 32.) |
| aread\_ptr | uint32\_t | A pointer to the Account ID whose state we are trying to modify. |
| aread\_len | uint32\_t | The length of the Account ID. (Should always be 20.) |
Caution
Xahau sets internally a maximum hook data size. At time of writing and for public testnet this is hard coded at 128 bytes, however in future it will be a validator-votable number.
* JavaScript
| Name | Type | Description |
| --------- | ---------------------- | ----------------------------------------------- |
| value | ByteArray or HexString | The value of data to persist. |
| key | ByteArray or HexString | The key of the Hook State to set the value for. |
| namespace | ByteArray or HexString | The Hook namespace to look in. |
| accountid | ByteArray or HexString | The owner of the state. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| int64\_t | The number of bytes written to Hook State (the length of the data.) If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `TOO_BIG` - `kread_len` was greater than 32, or - `read_len` was greater than the maximum hook data size. `TOO_SMALL` - `kread_len` was 0. `NOT_AUTHORIZED` - no appropriate HookGrant was present on the foreign account to allow this state mutation. `PREVIOUS_FAILURE_PREVENTS_RETRY` - during this execution a previous `state_foreign_set` failed with NOT\_AUTHORIZED, and consequently no further calls to this API are allowed during this execution. |
* JavaScript
| Type | Description |
| ------------------- | ---------------------------------------------------------------------------------------------- |
| number or ErrorCode | Returns the number of bytes written to Hook State (the length of the data), negative on error. |
# state_set
> Set the Hook State for a given key and value
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Read a 32 byte Hook State key from the `kread_ptr`
* Read an arbitrary amount of data from `read_ptr` (the value)
* Update the Hook State key with the value
* JavaScript
* Sets the Hook State with the specified value and key.
* Returns the number of bytes written to Hook State (the length of the data), negative on error.
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t state_set (
uint32_t read_ptr,
uint32_t read_len,
uint32_t kread_ptr,
uint32_t kread_len
);
```
* JavaScript
```javascript
function state_set(
value: ByteArray | HexString | undefined | null,
key: ByteArray | HexString
): ErrorCode | number
```
### Example
[Section titled “Example”](#example)
* C
```c
#define SBUF(str) (uint32_t)(str), sizeof(str)
if (state_set(SBUF(vault), SBUF(vault_key)) < 0)
rollback(SBUF("Error: could not set state!"), 1);
```
Tip
To delete the state use `state_set(0, 0, SBUF(key);`.
* JavaScript
```javascript
const result = state_set(vault, vault_key)
if (result < 0)
rollback("Error: could not set state!", 1);
```
Tip
To delete the state use `state_set(null, key);`.
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | ---------------------------------------------------------------------------------------------------------------------------- |
| read\_ptr | uint32\_t | Pointer to the data (value) to write into Hook State. If this is `0` (null) then delete the data at this key. *May be null.* |
| read\_len | uint32\_t | The length of the data. If this is `0` (null) then delete the data at this key. *May be null.* |
| kread\_ptr | uint32\_t | A pointer to the Hook State key at which to store the value. |
| kread\_len | uint32\_t | The length of the key. (Should always be 32.) |
Caution
Xahaud sets internally a maximum hook data size. At time of writing and for mainnet this is hard coded at 256 bytes, however in future it will be a validator-votable number.
* JavaScript
| Name | Type | Description |
| ----- | ---------------------- | ----------------------------------------------- |
| value | ByteArray or HexString | The value of data to persist. |
| key | ByteArray or HexString | The key of the Hook State to set the value for. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The number of bytes written to Hook State (the length of the data.) If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `TOO_BIG` - `kread_len` was greater than 32, or - `read_len` was greater than the maximum hook data size. `TOO_SMALL` - `kread_len` was 0. |
* JavaScript
| Type | Description |
| ------------------- | ---------------------------------------------------------------------------------------------- |
| number or ErrorCode | Returns the number of bytes written to Hook State (the length of the data), negative on error. |
# trace
> Write the contents of a buffer to the Xahaud trace log
### Behaviour
[Section titled “Behaviour”](#behaviour)
* Write a buffer from inside the Hook to the trace log along with a message (if any)
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t trace (
uint32_t mread_ptr,
uint32_t mread_len,
uint32_t dread_ptr,
uint32_t dread_len,
uint32_t as_hex
);
```
* JavaScript
```javascript
function trace(
message: string | null,
data: any,
hex: boolean | 0 | 1
): ErrorCode
```
### Example
[Section titled “Example”](#example)
* C
```c
#define SBUF(str) (uint32_t)(str), sizeof(str)
trace(SBUF("Buffer conatained"), SBUF(some_buffer), 1);
```
* JavaScript
```javascript
trace("Buffer conatained", some_buffer, 1);
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | ------------------------------------------------------------------- |
| mread\_ptr | uint32\_t | Pointer to a message to output before the buffer. *May be null.* |
| mread\_len | uint32\_t | Length of the message. *May be null.* |
| dread\_ptr | uint32\_t | Pointer to the buffer to output. |
| dread\_len | uint32\_t | Length of the buffer to output. |
| as\_hex | uint32\_t | If `1` output the buffer as hex. If `0` output the buffer as utf-8. |
* JavaScript
| Name | Type | Description |
| ------- | ------- | -------------------------------------------------------------------- |
| message | string | The ‘logging key’, message to output before the buffer (can be null) |
| data | any | The data to log |
| hex | boolean | Should it log formatted in HEX? 0 - NO 1 - YES |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------- |
| int64\_t | `0` if successful If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. |
* JavaScript
| Type | Description |
| --------- | ------------------------------------------------------------------------ |
| ErrorCode | int64\_t, value is 0 if successfulIf negative, an error: OUT\_OF\_BOUNDS |
# trace_float
> Write a XFL float to the Xahaud trace log
### Behaviour
[Section titled “Behaviour”](#behaviour)
* Write a XFL floating point to the trace log along with a message (if any)
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t trace_float (
uint32_t mread_ptr,
uint32_t mread_len,
int64_t float1
);
```
### Example
[Section titled “Example”](#example)
* C
```c
#define SBUF(str) (uint32_t)(str), sizeof(str)
trace_float(SBUF("This is a float"), float_one());
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | --------------------------------------------------------------------------------------------------------- |
| rmead\_ptr | uint32\_t | Pointer to a message to output before the hex-encoded serialized object found in the slot. *May be null.* |
| mread\_len | uint32\_t | Length of the message. *May be null.* |
| float1 | int64\_t | The enclosing XFL integer. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------- |
| int64\_t | `0` if successful If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. |
# trace_num
> Write an integer to the Xahaud trace log
### Behaviour
[Section titled “Behaviour”](#behaviour)
* Write an integer to the trace log along with a message (if any)
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t trace_num (
uint32_t mread_ptr,
uint32_t mread_len,
int64_t number
);
```
### Example
[Section titled “Example”](#example)
* C
```c
#define SBUF(str) (uint32_t)(str), sizeof(str)
trace_num(SBUF("This is an integer"), 10);
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | --------------------------------------------------------------------------------------------------------- |
| rmead\_ptr | uint32\_t | Pointer to a message to output before the hex-encoded serialized object found in the slot. *May be null.* |
| mread\_len | uint32\_t | Length of the message. *May be null.* |
| number | int64\_t | The number. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------- |
| int64\_t | `0` if successful If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. |
# util_accid
> Convert an r-address into a 20 byte Account ID
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Read an r-address from the `read_ptr`
* Write a 20 byte Account ID to the `write_ptr`
* JavaScript
* Read an r-address from the `raddress`
* Returns a 20 byte Account ID or an ErrorCode
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t util_accid (
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len
);
```
* JavaScript
```javascript
function util_accid(raddress: string): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
* C
```c
uint8_t accid_out[20];
uint8_t raddr_in[] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
int64_t bytes_written =
util_accid(accid_out, 20, raddr_in, sizeof(raddr_in)-1);
// NB: if specified as a c-string as above, account for the nul char
```
* JavaScript
```javascript
const accId = util_accid('rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh')
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | ------------------------------------------------------------------------------------------------- |
| write\_ptr | uint32\_t | Pointer to a buffer of a suitable size to store the output Account ID. Must be at least 20 bytes. |
| write\_len | uint32\_t | Length of the output buffer. |
| read\_ptr | uint32\_t | Pointer to the r-address. |
| read\_len | uint32\_t | The length of the r-address. |
* JavaScript
| Name | Type | Description |
| -------- | ------ | ------------------------------------------ |
| raddress | string | The r-address to format as HEX account ID. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The number of bytes written (the length of the output r-address). If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `INVALID_ARGUMENT` - `read_ptr` pointed at something which wasn’t a valid r-address. `TOO_SMALL` - `write_len` was not large enough to store produced Account ID. (Should be 20 bytes). `TOO_BIG` - `read_len` was longer than an r-address can be. |
* JavaScript
| Type | Description |
| --------------- | ------------------------------------------------------------------------------------------------ |
| string / number | If there is an error in formatting, otherwise returns the HEX Account ID as an array of numbers. |
# util_keylet
> Compute a serialized keylet of a given type
### Concepts
[Section titled “Concepts”](#concepts)
[Slots and Keylets](/docs/hooks/concepts/slots-and-keylets)
Tip
Not every Keylet type is supported by this utility function. If you need another Keylet type you can derive it yourself using [util\_sha512h](https://xrpl-hooks.readme.io/reference/util_sha512h) and by checking the required fields [here](https://github.com/Xahau/xahaud/blob/dev/src/ripple/protocol/impl/Indexes.cpp). A further Keylet tool may [assist you.](https://richardah.github.io/xrpl-keylet-tools/)
### Behaviour
[Section titled “Behaviour”](#behaviour)
* Compute a keylet of the specified `keylet_type` according to the parameters `a` through `f` depending on type.
* Write the serialized 34 byte keylet into `write_ptr`
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t util_keylet (
uint32_t write_ptr,
uint32_t write_len,
uint32_t keylet_type,
uint32_t a,
uint32_t b,
uint32_t c,
uint32_t d,
uint32_t e,
uint32_t f
);
```
* JavaScript
```javascript
function util_keylet(
keylet_type: number,
accountid: ByteArray | HexString,
statekey: ByteArray | HexString,
namespace: ByteArray | HexString
): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
* C
```c
uint8_t keylet[34];
if (util_keylet(keylet, 34, KEYLET_LINE,
hook_accid, 20,
account_field, 20,
currency_code, 20) != 34)
rollback("Keylet Failed.", 14, 1);
```
* JavaScript
```javascript
if (util_keylet(
KEYLET_LINE, hook_accid, account_field, currency_code
).length < 34)
rollback("Keylet Failed.", 1)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ------------ | --------- | ------------------------------------------------------------------------------------- |
| write\_ptr | uint32\_t | Pointer to a buffer the serialized keylet will be written to |
| write\_len | uint32\_t | Length of output buffer, should be at least 34. |
| keylet\_type | uint32\_t | One of the keylet types as defined in `hookapi.h` e.g. `KEYLET_LINE` for a trustline. |
| a | uint32\_t | See keylet table below |
| b | uint32\_t | See keylet table below |
| c | uint32\_t | See keylet table below |
| d | uint32\_t | See keylet table below |
| e | uint32\_t | See keylet table below |
| f | uint32\_t | See keylet table below |
* JavaScript
| Name | Type | Description |
| ------------ | ---- | -------------------------------------------------------------------------------------------------- |
| keylet\_type | | The type of the keylet to create |
| accountid | | (Optional) First piece of data for the keylet, can be an array of numbers, a string, or a number. |
| statekey | | (Optional) Second piece of data for the keylet, can be an array of numbers, a string, or a number. |
| namespace | | (Optional) Third piece of data for the keylet, can be an array of numbers, a string, or a number. |
### Keylet Table
[Section titled “Keylet Table”](#keylet-table)
* C
| Keylet Type | Parameters |
| -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| KEYLET\_HOOK\_STATE | `a` points to an Account ID `b` is the length of the Account ID (should be 20) `c` points to a hook state key `d` is the length of the key (should be 32) `e` points to a hook state namespace `f` is the length of the namespace (should be 32) |
| KEYLET\_AMENDMENTS KEYLET\_FEES KEYLET\_NEGATIVE\_UNL KEYLET\_EMITTED\_DIR | `a`, `b`, `c`, `d`, `e`, `f` must all be zero |
| KEYLET\_SKIP | Either: `a`, `b`, `c`, `d`, `e`, `f` all zero Or: `a` is a `LedgerIndex` `b` is 1 `c`, `d`, `e`, `f` must all be zero |
| KEYLET\_LINE | `a` points to the High Account ID `b` is the length of the above (should be 20) `c` points to the Low Account ID `d` is the length of the above (should be 20) `e` points to the Currency Code `f` is the length of the above (should be 20) |
| KEYLET\_QUALITY | `a` points to a serialized keylet `b` is the length of the above (should be 34) `c` is the high 32 bits of the uint64 to pass `d` is the low 32 bits of the uint64 to pass `e`, `f` must all be zero |
| KEYLET\_DEPOSIT\_PREAUTH | `a` points to an Account ID `b` is the length (should be 20) `c` points to an Account ID `d` is the length (should be 20) `e`, `f` must all be zero |
| KEYLET\_UNCHECKED KEYLET\_CHILD KEYLET\_EMITTED\_TXN | `a` points to a key. `b` is the length of the key (should be 32.) `c`, `d`, `e`, `f` must both be zero |
| KEYLET\_OWNER\_DIR KEYLET\_SIGNERS KEYLET\_ACCOUNT KEYLET\_HOOK | `a` points to an Account ID. `b` is the length (should be 20.) `c`, `d`, `e`, `f` must all be zero. |
| KEYLET\_PAGE | `a` points to a key. `b` is the length of the key (should be 32.) `c` is the high 32 bits of the uint64 to pass `d` is the low 32 bits of the uint64 to pass `e`, `f` must both be zero |
| KEYLET\_OFFER KEYLET\_CHECK KEYLET\_ESCROW KEYLET\_NFT\_OFFER | `a` points to an Account ID. `b` is the length (should be 20.) And Either: `c` is a 32bit unsigned integer (sequence) `d` is 0 Or: `c` points to a 32 byte key `d` is the length of the key (32). In both cases: `e` and `f` must be 0. |
| KEYLET\_PAYCHAN | `a` points to an Account ID `b` is the length (should be 20) `c` points to an Account ID `d` is the length (should be 20) And Either: `e` 32bit unsigned int to pass `f` is zero Or: `e` points to a 32 byte key `f` is the length of the key (32) |
* JavaScript
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The number of bytes written, should always be 34. If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `INVALID_ARGUMENT` - Call didn’t comply with the above table. `TOO_SMALL` - Writing buffer was smaller than 34 bytes. |
* JavaScript
| Type | Description |
| ------ | --------------------------------------------------------------------------------------------------------------------- |
| number | ErrorCode if there is an error in creating the keylet, otherwise returns the generated keylet as an array of numbers. |
# util_raddr
> Convert a 20 byte Account ID to an r-address
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Read a 20 byte Account ID from the `read_ptr`
* Write the equivalent r-address for that Account ID to `write_ptr`
* JavaScript
* Read a 20 byte Account ID from the `accountid`
* Return the equivalent r-address for that Account ID
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t util_raddr (
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len
);
```
* JavaScript
```javascript
function util_raddr(accountid: ByteArray | HexString): ErrorCode | string
```
### Example
[Section titled “Example”](#example)
* C
```c
uint8_t raddr_out[40];
uint8_t acc_id[20] =
{
0x2dU, 0xd8U, 0xaaU, 0xdbU, 0x4eU, 0x15U,
0xebU, 0xeaU, 0xeU, 0xfdU, 0x78U, 0xd1U, 0xb0U,
0x35U, 0x91U, 0x4U, 0x7bU, 0xfaU, 0x1eU, 0xeU
};
int64_t bytes_written =
util_raddr(raddr_out, sizeof(raddr_out), acc_id, 20);
```
* JavaScript
```javascript
const raddr = util_raddr('8D329C03074A98EF0488AB6ABBF5883F68CCFD4E')
// or
const raddr = util_raddr([
0x8D, 0x32, 0x9C, 0x03, 0x07, 0x4A, 0x98, 0xEF, 0x04, 0x88,
0xAB, 0x6A, 0xBB, 0xF5, 0x88, 0x3F, 0x68, 0xCC, 0xFD, 0x4E
])
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | -------------------------------------------------------------------------------------------------- |
| write\_ptr | uint32\_t | Pointer to a buffer of a suitable size to store the output r-address. Recommend at least 35 bytes. |
| write\_len | uint32\_t | Length of the output buffer. |
| read\_ptr | uint32\_t | Pointer to the Account ID. |
| read\_len | uint32\_t | The length of the input. Always 20. |
* JavaScript
| Name | Type | Description |
| --------- | ---------------- | ---------------------------------------------------------------------------------------------- |
| accountid | number\[]/string | The HEX account ID to return as r-address, can be provided as an array of numbers or a string. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The number of bytes written (the length of the output r-address). If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `INVALID_ARGUMENT` - `read_len` was not 20. `TOO_SMALL` - `write_len` was not large enough to store produced r-address in. |
* JavaScript
| Type | Description |
| ------------- | ----------------------------------------------------------------------------------------- |
| string/number | ErrorCode if there is an error in formatting, otherwise returns the r-address as a string |
# util_sha512h
> Compute an sha512-half over some data
### Behaviour
[Section titled “Behaviour”](#behaviour)
* C
* Compute an `SHA512` hash over the data pointed to by `read_ptr`
* Write the first half of the hash to `write_ptr`
* JavaScript
* Compute an `SHA512` hash over the data pointed to by `data`
* Return the first half of the hash
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t util_sha512h (
uint32_t write_ptr,
uint32_t write_len,
uint32_t read_ptr,
uint32_t read_len
);
```
* JavaScript
```javascript
function util_sha512h(data: ByteArray | HexString): ErrorCode | ByteArray
```
### Example
[Section titled “Example”](#example)
C
* C
```c
uint8_t hash_out[32];
if (util_sha512h(hash_out, 32, data_in_ptr, data_in_len) < 0)
rollback("Could not generate Hash", 23, 1);
```
* JavaScript
```javascript
if (util_sha512h(data) < 0)
rollback("Could not generate Hash", 1)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | ----------------------------------------------------------------------- |
| write\_ptr | uint32\_t | Pointer to a buffer the hash will be written to |
| write\_len | uint32\_t | Length of output buffer, should be at least 32. |
| read\_ptr | uint32\_t | Pointer to the buffer data will be read from (to compute the hash over) |
| read\_len | uint32\_t | Length of input data |
* JavaScript
| Name | Type | Description |
| ---- | ---------------------- | -------------------------------------------------------------------------------------- |
| data | ByteArray or HexString | The data to compute the hash over, can be provided as an array of numbers or a string. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | The number of bytes written, should always be 32. If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. `TOO_SMALL` - Output buffer isn’t large enough |
* JavaScript
| Type | Description |
| --------- | -------------------------------------------------------------------------------------------------------------------- |
| ByteArray | ErrorCode if there is an error in computing the hash, otherwise returns the SHA512-half hash as an array of numbers. |
# util_verify
> Verify a cryptographic signature
### Behaviour
[Section titled “Behaviour”](#behaviour)
Verify a cryptographic signature
* If the public key is prefixed with `0xED` then use `ED25519`
* Otherwise assume `SECP256k1`
### Definition
[Section titled “Definition”](#definition)
* C
```c
int64_t util_verify (
uint32_t dread_ptr,
uint32_t dread_len,
uint32_t sread_ptr,
uint32_t sread_len,
uint32_t kread_ptr,
uint32_t kread_len
);
```
* JavaScript
```javascript
function util_verify(
signedData: ByteArray | HexString,
signature: ByteArray | HexString,
pubkey: ByteArray | HexString
): 0 | 1
```
### Example
[Section titled “Example”](#example)
* C
```c
if (!util_verify(payload_ptr, payload_len,
signature_ptr, signature_len,
publickey_ptr, publickey_len))
rollback("Invalid Signature", 17, 60);
```
* JavaScript
```javascript
if (util_verify(signedData,signature,pubkey))
rollback("Invalid Signature", 60)
```
### Parameters
[Section titled “Parameters”](#parameters)
* C
| Name | Type | Description |
| ---------- | --------- | -------------------------- |
| dread\_ptr | uint32\_t | Pointer to the signed data |
| dread\_len | uint32\_t | Length of the signed data |
| sread\_ptr | uint32\_t | Pointer to the signature |
| sread\_len | uint32\_t | Length of the signature |
| kread\_ptr | uint32\_t | Pointer to the public key |
| kread\_len | uint32\_t | Length of the public key |
* JavaScript
| Name | Type | Description |
| ---------- | --------------- | ------------------------------------------------------------------------------------------------- |
| signedData | number / string | The signed data to verify, can be provided as an array of numbers or a string. |
| signature | number / string | The signature to verify, can be provided as an array of numbers or a string. |
| pubkey | number / string | The public key responsible for the signature, can be provided as an array of numbers or a string. |
### Return Code
[Section titled “Return Code”](#return-code)
* C
| Type | Description |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| int64\_t | `0` - validation failed, the signature is invalid. `1` - validation succeeded, the signature is valid. If negative, an error: `OUT_OF_BOUNDS` - pointers/lengths specified outside of hook memory. |
* JavaScript
| Type | Description |
| ------ | ------------------------------------------------------------------------------------------------------ |
| number | `0` - validation failed, the signature is invalid. `1` - validation succeeded, the signature is valid. |
# account_info
### New features
[Section titled “New features”](#new-features)
The `account_info` API will now provide, in addition to its regular behaviour:
* A list of namespaces currently in use by at least one Hook State Object
* A total count of all Hook State Objects the account has
Example query:
JSON
```json
{
"command": "account_info",
"account": "raaFre81618XegCrzTzVotAmarBcqNSAvK"
}
```
E.g.
JSON
```json
{
"result": {
"account_data": {
"Account": "raaFre81618XegCrzTzVotAmarBcqNSAvK",
...,
"HookNamespaces": [
"01EAF09326B4911554384121FF56FA8FECC215FDDE2EC35D9E59F2C53EC665A0"
],
"HookStateCount": 49,
...
},
"ledger_current_index": 5555046,
"validated": false
},
"status": "success",
"type": "response"
}
```
# account_namespace
Use the `account_namespace` websocket API to query the Hook State Objects on a particular account in a particular namespace.
Usage:
JSON
```json
{
"command": "account_namespace",
"account": "",
"namespace_id": ""
}
```
Example query:
JSON
```json
{
"command": "account_namespace",
"account": "raaFre81618XegCrzTzVotAmarBcqNSAvK",
"namespace_id": "01EAF09326B4911554384121FF56FA8FECC215FDDE2EC35D9E59F2C53EC665A0"
}
```
Example result:
JSON
```json
{
"result": {
"account": "raaFre81618XegCrzTzVotAmarBcqNSAvK",
"ledger_current_index": 5554739,
"namespace_entries": [
{
"Flags": 0,
"HookStateData": "CE66D3EBD1A91E9D6F47ADCF8890C92C3EE65A42313174682047656E20496E74656C28522920436F726528544D292069372D31313635473720322E3800080AF0000C3500000009C400000FA0",
"HookStateKey": "4556520237F1F3A48DFAED331FDB8F894522B5CE634C86A0258BA1B300000018",
"LedgerEntryType": "HookState",
"OwnerNode": "0",
"index": "065E103AC0838155A392DECA99D77FAE768EC822BFEC6BC999268ECBD16C8FAF"
},
{
"Flags": 0,
"HookStateData": "00000000044E8000",
"HookStateKey": "4556520100000000000000000000000000000000000000000000000000000004",
"LedgerEntryType": "HookState",
"OwnerNode": "0",
"index": "0890BE9EE8CD129D21728FC3C2423CC0AB99D325A269A8A749C840F712989E5B"
},
...
],
"namespace_id": "01EAF09326B4911554384121FF56FA8FECC215FDDE2EC35D9E59F2C53EC665A0",
"validated": false
},
"status": "success",
"type": "response"
}
```
# Advanced xahaud Configuration
There are numerous configuration options available to xahaud operators. This section will cover some of the more commonly used options, including those required for clustering servers and configuring databases.
For complete documentation on configuration options, please see the example configuration files in the [xahaud GitHub repository](https://github.com/Xahau/xahaud/tree/dev/cfg).
## Running Databases in Memory
[Section titled “Running Databases in Memory”](#running-databases-in-memory)
Users seeking to maximize xahaud performance may choose to run databases in memory, rather than on dedicated storage media. Memory databases are not suited for machines storing history, as the databases are not persistent across xahaud restarts. Likewise, the amount of history stored is contingent on available system memory. Thus, `online_delete` and `advisory_delete` are required in the `xahaud.cfg` to prevent out of memory errors. When using a memory database, it is advisable to disable SWAP, as SWAP writes the contents of memory to disk, thereby potentially defeating the benefits obtained by storing the database in memory.
To enable the memory database, edit the `xahaud.cfg` file:
```plaintext
[relational_db]
type=RWDB
[node_db]
type=RWDB # RWDB is the memory database
online_delete=256 # This value should be low on machines using memory databases. '256' is the minimum value.
advisory_delete=0 # Do not require human intervention to delete history. This is necessary for preventing out of memory errors.
```
## Clustering
[Section titled “Clustering”](#clustering)
Clustering allows xahaud operators to configure multiple xahaud servers so that the servers trust one another, thereby reducing workload. Properly clustered servers can share information about malicious or problematic websocket, rpc, and peer connections, while also automatically propagating submitted transactions throughout the cluster. Thus, if a transaction is submitted on a sever with a higher load than the transaction’s fee allows for, the transaction will still propagate to other servers in the cluster, thereby increasing the probability that the transaction is included in an upcoming ledger.
Administrators operating xahaud validators can benefit from clustering, as the cluster provides connectivity for the highly secure validator, thereby eliminating the need for the validator to connect to unknown or untrusted servers.
Server operators should not cluster their servers with servers outside of their own control. Likewise, clustered servers should have low latency connections, ideally being located in the same data center.
Generating cluster seeds (public/private keys) is done via the `validation_create` [API method](/docs/features/http-websocket-apis/admin-api-methods). While the method name includes the term ‘validation’, this method is not used to [create the keys](/docs/infrastructure/enabling-validation) used to sign validation messages. Instead, it is used to create keys to identify any xahaud server, validating or non-validating.
To create a cluster:
1. On each xahaud instance that will be included in the cluster, generate a public key and seed: `./xahaud validation_create`
2. Open each server’s `xahaud.cfg` file, and add or edit the following sections:
* `[ips_fixed]` - Include the IPv4/6 addresses and peer listening ports (e.g., `10.1.1.2 21337`) for other servers that will be in the cluster. The listening port is defined under the `[port_peer]` stanza in the `xahaud.cfg` file on the server listening for incoming connections. The default listening port for the main Xahau Network is `21337`.
* `[node_seed]` - The output in the `validation_seed` field from the `validation_create` command. This is a private key, and it must be installed on the same server on which it was generated.
* `[cluster_nodes]` - The output from the `validation_public_key` field of the `validation_create` command. This is a public key, and it must be installed on peer servers, not the server on which it was generated.
3. Restart xahaud on each server in the cluster: `systemctl restart xahaud`
4. Backup each server’s `xahaud.cfg`.
5. Verify connectivity among clustered peers via the [peers](/docs/features/http-websocket-apis/admin-api-methods) API method: `./xahaud peers`
The cluster section of a `xahaud.cfg` file might look like this:
```plaintext
[ips_fixed]
10.1.1.2 21337 # Clustered peer 1
10.1.1.3 21337 # Clustered peer 2
10.1.1.4 21337 # Clustered peer 3
[cluster_nodes]
n9LzAHaB7ka318dAJWLQD1WkpGR86NyvaCzrtUAt4PuNtDCTCqxn # validation_public_key from clustered peer 1
n9KWNMsRdQ66jYHLCVgFBAQAzb16DwDioVdXSuV8pTcfEfaHkdvZ # validation_public_key from clustered peer 2
n9JFK8xUcy9S9TBmCcZKKmY28LEVjTurcpzC5XkXnyAAj1Svytee # validation_public_key from clustered peer 3
[node_seed]
sn8QEFTpBM8nydnLD6FjxKN845uRG # Private validation_seed from the local xahaud instance
```
# Build xahaud
> Setting Up the xahaud Build Environment and Compiling xahaud
Building software, such as xahaud, from the openly available source code is a complex process that requires in-depth knowledge and experience. Thus, there are multiple approaches that developers might take, depending on the environment (e.g., Linux, MacOS, Windows). The instructions in the following documentation chapters are meant to simplify and expand on those in the [xahaud GitHub repository](https://github.com/Xahau/xahaud/blob/dev/BUILD.md). Developers might need to deviate from these instructions to accomplish specific tasks or to ensure compatibility with specific operating systems.
The following articles detail the process of setting up a build environment and building xahaud across various operating system environments.
Danger
Building software from source code is a complex task requiring advanced technical knowledge and experience. It is possible to make changes at an operating system level that cannot be easily recovered from. Undertake the build process at your own risk. This documentation is designed to guide, rather than be definitively accurate.
## Building Software from Source
[Section titled “Building Software from Source”](#building-software-from-source)
When developers write software, they do so in programming languages that are designed to be human readable. However, it is not efficient for computers to run this human readable code. Thus, there is a need for software to be “compiled” from human readable code into bytecode that can be quickly read and interpreted by a computer.
Adding complexity to this process, developers often rely on software that was written by other developers, called “dependencies” because one software package depends on (requires) the other. In order for these dependencies to be included in the final product, they must be “linked” to the code before the code is compiled. The linking process can be very intensive, as dependencies for the original software package might have their own dependencies (which in turn can have even more dependencies, adding layers). Developers rely on tools, such as Conan, to simplify the process of locating, configuring, and linking dependencies.
The entire process of ensuring dependencies are met, compiling software into a machine optimized format, and running tests against the final product is called “building”.
Since xahaud is [published as open source software on GitHub](https://github.com/Xahau/xahaud), anyone may view, audit, modify, build, and run the code. Building from the source code enables certainty that the product being run is based off of the publicly viewable source code, which also has a full audit trail. Thus, validator operators who prioritize a maximum level of security should consider building from source.
## Dependencies
[Section titled “Dependencies”](#dependencies)
For compatibility, it is important to attend to specific versions of software used in the build process. xahaud is written in the C++20 language.
Current requirements for building xahaud include:
| Dependency | Version |
| ---------- | ------- |
| Python3 | >= 3.7 |
| GCC / G++ | >= 14.x |
| CMake | >= 3.16 |
| Conan2 | 2.x |
| openssl | 1.1.1 |
| boost | 1.86.0 |
| SQLite3 | 3.42.0 |
| Snappy\* | 1.1.10 |
| SOCI\* | 4.0.3 |
| WasmEdge\* | 0.11.2 |
\* Included in the Xahau/xahaud GitHub repository.
# Linux Build Instructions
These instructions are designed to work for Debian (i.e., Ubuntu 22.04 and 24.04) and Red Hat Enterprise Linux (9 or 10) based distributions. Many instructions overlap, though differences across operating systems are noted throughout. Efforts are made to test builds across operating systems, however, Ubuntu is the most tested and supported environment for building and running xahaud.
For additional instructions, refer to the [BUILD.md](https://github.com/Xahau/xahaud/blob/dev/BUILD.md) file in the Xahau/xahaud GitHub Repository.
Caution
Creating an environment to build xahaud can cause permanent system damage. The [Build Environments](#build-environments-for-beginners) section of this page contains techniques for isolating your build environment from your underlying operating system. Undertake system changes at your own risk.
## Install Dependencies
[Section titled “Install Dependencies”](#install-dependencies)
Debian/Ubuntu users can install required dependencies using these commands:
```plaintext
sudo apt install -y git curl wget python3-pip python3-venv python3-dev ca-certificates gcc g++ build-essential cmake ninja-build libc6-dev libssl-dev libsqlite3-dev
```
Likewise, RHEL 9 or RHEL 10 users can install dependencies:
```plaintext
sudo dnf install epel-release && sudo dnf update -y
sudo dnf config-manager --set-enabled crb -y
sudo dnf groupinstall "Development Tools" -y
sudo dnf install curl wget git ca-certificates cmake glibc-headers glibc-devel ninja-build perl-interpreter perl perl-FindBin sqlite-devel libstdc++ libstdc++-devel libstdc++-static gcc-c++ -y
```
## Clone the Xahau/xahaud GitHub Repository
[Section titled “Clone the Xahau/xahaud GitHub Repository”](#clone-the-xahauxahaud-github-repository)
Before building, acquire a local copy of the GitHub xahaud repository:
`git clone https://github.com/Xahau/xahaud.git`
It is possible to build from other forks of the repository, simply adjust the above URL as needed.
### Select the Repository Branch
[Section titled “Select the Repository Branch”](#select-the-repository-branch)
The primary branch used for xahaud development is `dev`. Users who prefer to build from an alternate branch can do so:
`git checkout [branch name]`
### Prepare the build directory
[Section titled “Prepare the build directory”](#prepare-the-build-directory)
Create a directory inside the xahaud repository to store the files generated during the build process:
`mkdir [/path/to/xahaud_github_repo]/.build`
## Install and Configure Conan2
[Section titled “Install and Configure Conan2”](#install-and-configure-conan2)
1. Ensure you are in the build directory: `cd [/path/to/xahaud_github_repo]/.build`
2. Create a Python3 virtual environment (venv) in the `env` directory: `python3 -m venv env`
3. Activate the virtual environment: `source ./env/bin/activate`
4. Update pip so the latest software versions are available: `pip install --upgrade pip`
5. Install Conan2: `pip install conan`
6. Create a new Conan2 profile (if you haven’t already): `conan profile detect`
7. Install the Conan recipes for the Snappy, SOCI, and WasmEdge dependencies, included in the “xahaud” GitHub repository:
```plaintext
conan export external/snappy --version 1.1.10 --user xahaud --channel stable
conan export external/soci --version 4.0.3 --user xahaud --channel stable
conan export external/wasmedge --version 0.11.2 --user xahaud --channel stable
```
8. Review your Conan2 profile, located in: `/home/[username]/.conan2/profiles/default`. If needed, add:
```plaintext
[settings]
compiler.cppstd=20
compiler.libcxx=libstdc++11
```
9. It might be necessary to include the following lines at the end of your Conan2 profile:
```plaintext
[conf]
tools.build:cxxflags=['-Wno-restrict']
```
## Build xahaud
[Section titled “Build xahaud”](#build-xahaud)
1. Inside the `.build` directory, with the Python3 virtual environment active, adjust “build\_type” to either “Release” or “Debug” and run the below command. It is possible to run the command twice to generate files for each “build\_type”.
```plaintext
conan install .. --output-folder . --build missing --settings build_type=["Release" or "Debug"] -c tools.build:verbosity=verbose -c tools.compilation:verbosity=verbose
```
2. If needed, additional options can be passed to Conan2:
```plaintext
conan install .. --output-folder . --build missing --settings build_type=["Release" or "Debug"] -s compiler=gcc -s compiler.version=12 -s compiler.libcxx=libstdc++11 -s compiler.cppstd=20 -c tools.build:verbosity=verbose -c tools.compilation:verbosity=verbose -g VirtualBuildEnv -g VirtualRunEnv
```
3. After Conan2 is complete, run cmake. Do not specify “DCMAKE\_BUILD\_TYPE” if building from multiple configurations (both “Release” and “Debug”).
```plaintext
cmake -DCMAKE_POLICY_DEFAULT_CMP0091=NEW \
-DCMAKE_BUILD_TYPE=["Release" or "Debug"] \
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
..
```
4. Finally, use cmake to complete the build process: `cmake --build . [add '--config Release' or '--config Debug' if multiple build types were generated]`.
The output file is named `rippled` and is located in the `.build` directory. If multiple build types (both “Release” and “Debug”) were specified, the final product will be located at: `.build/["Release" or "Debug"]/rippled` Rename the file to ‘xahaud’, and move it to it’s final location (being careful not to overwrite the ‘xahaud’ GitHub repository). Mark the final file as executable, and download a configuration file and validators file as needed.
## Test the Build
[Section titled “Test the Build”](#test-the-build)
To run unit tests: `./xahaud --unittest`
## Build Environments for Beginners
[Section titled “Build Environments for Beginners”](#build-environments-for-beginners)
Maintaining different build environments (Python3 venvs, Conan2 profiles, etc.) is a complex task, even more so as underlying operating systems often rely on or expect specific versions of software. Thus, those new to the build process may benefit from using containers or writing bash scripts that are used on virtual machines that reset their state at reboot.
The following subsections address the basics of configuring amnesiac and container based build environments.
### Containers
[Section titled “Containers”](#containers)
It is possible to use [Docker](https://docker.com) or other containerized environments (Podman, Kubernetes, etc.) to contain the build process, thereby keeping the underlying system clean. Using containers has the additional advantage of easily testing builds in multiple environments. For example, containers based on RHEL, Debian, and other distributions can be configured to use diverse compiler versions. Further, features like Multistage Dockerfiles enable users to build then deploy (run) xahaud using a single Dockerfile. Users can also take advantage of Docker’s `buildx` plugin, which allows users to build for multiple platforms concurrently.
#### Install Docker
[Section titled “Install Docker”](#install-docker)
```plaintext
# Debian/Ubuntu:
sudo apt update && sudo apt install docker.io docker-compose-v2 docker-buildx
# RHEL (requires adding the docker.com repository):
sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
```
After installing, it is possible to add your local user account to Docker, so interacting with Docker does not require root/sudo access: `sudo usermod -aG docker $USER`. For changes to take effect, you must logout and back in to your user session.
#### Example Dockerfile
[Section titled “Example Dockerfile”](#example-dockerfile)
For ease and consistency, it is possible to use Dockerfile scripts (e.g., buildx, multistage, docker-compose v2, etc.) to configure the build environment and to complete the build process.
For example, xahaud can be compiled inside an Ubuntu 24.04 Docker container using a Dockerfile to describe the container, download and install dependencies, and build the final product. Note that the following code follows the same steps outlined earlier on this page for the general Linux build process, the steps are simply applied inside an isolated container. It is possible to add additional variables or adjust the following code to customize the build process.
```plaintext
# ~~~~ Arguments used to customize the container and build ~~~~
ARG BASE_IMAGE=ubuntu:24.04 # Operating system for the build container
ARG REPO_URL=https://github.com/Xahau/xahaud # URL for the repository with the code to be compiled
ARG REPO_BRANCH=dev # Repository branch that will be used for the build
ARG RELEASE_TYPE=Release # Set to "Release" or "Debug"
ARG BASE_DIR=/build # Directory to build xahaud in
# ~~~~ Initiate a container ~~~~
FROM --platform=$BUILDPLATFORM ${BASE_IMAGE} AS builder
ARG REPO_URL
ARG REPO_BRANCH
ARG RELEASE_TYPE
ARG BASE_DIR
ARG TARGETPLATFORM
ARG BUILDPLATFORM
ENV DEBIAN_FRONTEND=noninteractive \
CONAN2_DIR=/root/.conan2
# ~~~~ Install build dependencies ~~~~
RUN set -ex; \
if [ -f /etc/os-release ]; then . /etc/os-release; fi; \
case " $ID $ID_LIKE " in \
*debian*|*ubuntu*) \
apt-get update && apt-get install -y -qq \
git curl wget python3-pip python3-venv python3-dev ca-certificates \
gcc g++ build-essential cmake ninja-build \
libc6-dev libssl-dev libsqlite3-dev \
&& rm -rf /var/lib/apt/lists/* \
;; \
*rhel*|*fedora*|*centos*|*rocky*|*alma*) \
dnf install -y config-manager epel-release && dnf update -y && \
dnf config-manager --set-enabled crb -y && \
dnf groupinstall -y "Development Tools" && \
dnf install -y curl wget git ca-certificates cmake glibc-headers glibc-devel \
ninja-build perl-interpreter perl perl-FindBin sqlite-devel \
libstdc++ libstdc++-devel libstdc++-static gcc-c++ python3-pip python3-devel \
&& dnf clean all \
;; \
*) echo "Unsupported OS"; exit 1 ;; \
esac
# ~~~~ Clone the xahaud GitHub repository and create a '.build' directory ~~~~
WORKDIR ${BASE_DIR}
RUN git clone ${REPO_URL} xahaud && \
cd xahaud && \
git checkout ${REPO_BRANCH} && \
mkdir -p .build
# ~~~~ Create a Python3 virtual environment and install Conan2 ~~~~
RUN python3 -m venv ${BASE_DIR}/env && \
. ${BASE_DIR}/env/bin/activate && \
pip install --upgrade pip && \
pip install conan
# ~~~~ Configure Conan2 profile (the following assumes the user wishes to use cppstd version 20) ~~~~
RUN . ${BASE_DIR}/env/bin/activate && \
conan profile detect && \
CONAN2_PROFILE="${CONAN2_DIR}/profiles/default" && \
if grep -q '^compiler\.cppstd=' "$CONAN2_PROFILE"; then \
sed -i 's/^compiler\.cppstd=.*/compiler.cppstd=20/' "$CONAN2_PROFILE"; \
else \
echo 'compiler.cppstd=20' >> "$CONAN2_PROFILE"; \
fi && \
if ! grep -Fqx "[conf]" "$CONAN2_PROFILE"; then \
printf "[conf]\ntools.build:cxxflags=['-Wno-restrict']\n" >> "$CONAN2_PROFILE"; \
fi
# ~~~~ Export Conan recipies for snappy, soci, and wasmedge ~~~~
RUN . ${BASE_DIR}/env/bin/activate && \
cd ${BASE_DIR}/xahaud && \
conan export external/snappy --version 1.1.10 --user xahaud --channel stable && \
conan export external/soci --version 4.0.3 --user xahaud --channel stable && \
conan export external/wasmedge --version 0.11.2 --user xahaud --channel stable
# ~~~~ Build xahaud ~~~~
RUN . ${BASE_DIR}/env/bin/activate && \
cd ${BASE_DIR}/xahaud/.build && \
conan install .. --output-folder . \
--settings build_type=${RELEASE_TYPE} \
--options *:shared=False \
--build missing \
-c tools.build:verbosity=verbose \
-c tools.compilation:verbosity=verbose \
-g VirtualBuildEnv \
-g VirtualRunEnv && \
cmake -DCMAKE_POLICY_DEFAULT_CMP0091=NEW \
-DCMAKE_BUILD_TYPE=${RELEASE_TYPE} \
-DBUILD_SHARED_LIBS=OFF \
-DCMAKE_EXE_LINKER_FLAGS="-static-libgcc -static-libstdc++" \
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
.. && \
cmake --build . --parallel $(nproc)
# ~~~~ Copy the config files to the BASE_DIR ~~~~
RUN cp ${BASE_DIR}/xahaud/cfg/xahaud-example.cfg ${BASE_DIR}/xahaud.cfg && \
cp ${BASE_DIR}/xahaud/cfg/validators-example.txt ${BASE_DIR}/validators-xahau.txt && \
cp ${BASE_DIR}/xahaud/.build/rippled ${BASE_DIR}/rippled
# ~~~~ Copy the xahaud.cfg and validators-xahau.txt files into the host OS ~~~~
FROM scratch AS export
ARG BASE_DIR
COPY --from=builder ${BASE_DIR}/rippled /xahaud
COPY --from=builder ${BASE_DIR}/xahaud.cfg /xahaud.cfg
COPY --from=builder ${BASE_DIR}/validators-xahau.txt /validators-xahau.txt
# ~~~~ Create a Docker image with xahaud and configuration files ~~~~
FROM ${BASE_IMAGE} AS runtime
ARG BASE_DIR
ENV DEBIAN_FRONTEND=noninteractive
# ~~~~ Install runtime dependencies ~~~~
RUN set -ex; \
if [ -f /etc/os-release ]; then . /etc/os-release; fi; \
case " $ID $ID_LIKE " in \
*debian*|*ubuntu*) \
apt-get update && apt-get install -y -qq \
libssl3 libsqlite3-0 ca-certificates \
&& update-ca-certificates \
&& rm -rf /var/lib/apt/lists/* \
;; \
*rhel*|*fedora*|*centos*|*rocky*|*alma*) \
dnf install -y openssl-libs sqlite-libs ca-certificates \
&& dnf clean all && update-ca-trust \
;; \
esac
# ~~~~ Copy built binary and configs from builder ~~~~
RUN mkdir -p /opt/xahaud/etc /opt/xahaud/bin /opt/xahaud/db /var/log/xahaud
COPY --from=builder ${BASE_DIR}/rippled /opt/xahaud/bin/xahaud
COPY --from=builder ${BASE_DIR}/xahaud.cfg /opt/xahaud/etc/xahaud.cfg
COPY --from=builder ${BASE_DIR}/validators-xahau.txt /opt/xahaud/etc/validators-xahau.txt
# ~~~~ Create dicrectories and copy required shared libraries from builder ~~~~
RUN --mount=type=bind,from=builder,source=/root/.conan2,target=/tmp/conan \
find /tmp/conan -name "*.so*" -type f -exec cp {} /usr/local/lib/ \; && \
ldconfig
# ~~~~ Set permissions ~~~~
RUN chmod -R 755 /opt/xahaud /var/log/xahaud
WORKDIR /opt/xahaud
# ~~~~ Expose ports ~~~~
EXPOSE 5009 6009 50051 21337 21338
# ~~~~ Run xahaud ~~~~
ENTRYPOINT ["/opt/xahaud/bin/xahaud"]
CMD ["--conf", "/opt/xahaud/etc/xahaud.cfg"]
```
The above “multistage” Dockerfile can be used to build xahaud by running:
`docker buildx build -t xahaud-builder --target builder --load .`
This creates a Docker image named “xahaud-builder” from the Dockerfile. The `--target builder` flag stops the script at the build process and the `--load` flag imports the resultant image into Docker.
The built image can also be exported to the host operating system (along with configuration files):
`docker buildx build --target export --output type=local,dest=$HOME .`
To run the multistage build file and create a new Docker image with xahaud and the required configuration files:
`docker buildx build --target runtime --load -t xahaud:latest .`
The resultant image can be viewed with: `docker images` and run with:
`docker run --rm -d --name xahaud -p 5009:5009 -p 6009:6009 -p 21337:21337 -v /home/$USER/xahaud/opt:/opt/xahaud -v /home/$USER/xahaud/log:/var/log/xahaud xahaud:latest`
In the above command, you can adjust the `-d` flag to toggle running in detached mode, the `-p xxxx:xxxx` flags which define the port mappings, the `--name xahaud` flag to change the container’s name, and the `-v /path/on/host:/path/in/container` flag to change where persistent data is stored on the underlying operating system. If running in detached mode, logs can be viewed with `docker logs -f xahaud`.
### Amnesiac Operating Systems
[Section titled “Amnesiac Operating Systems”](#amnesiac-operating-systems)
Configuring a Linux system to completely forget all the software that was installed or modified during runtime provides an easy path to recover from build errors. Typically, an amnesiac operating system is run as a virtual machine with a very large amount of memory available, as all changes are written to memory instead of disk. Building xahaud can take over 20 GB of memory, if all software dependencies/requirements are installed in a memory based overlay file system. It is typically possible to install most of the software dependencies (using `apt` or `dnf`) prior to making the system amnesiac, thereby reducing required memory.
#### Configure an amnesic operating system using a Debian based virtual machine
[Section titled “Configure an amnesic operating system using a Debian based virtual machine”](#configure-an-amnesic-operating-system-using-a-debian-based-virtual-machine)
```plaintext
# Install the 'overlayroot' software package
apt update && apt install overlayroot
# Update the configuration file (/etc/overlayroot.conf) to enable an in-memory overlay file system.
sudo sed -i 's/^overlayroot=.*/overlayroot="tmpfs:swap=1,recurse=0"/' /etc/overlayroot.conf
# Rebuild initramfs
update-initramfs -u
# Reboot into the overlay
reboot
# After rebooting, it is possible to remount the overlay filesystem with more memory, as only 50% of available memory is dedicated to the overlayfs by default.
# When resizing memory, ensure some memory remains available for system use. The following will remount with the overlayfs set to use 30G of memory, adjust as needed.
# It is also possible to use a systemd file to enable persistent changes to the overlayfs size.
sudo mount -o remount,size=30G /media/root-rw
```
#### Configure an amnesic operating system using a RHEL based virtual machine
[Section titled “Configure an amnesic operating system using a RHEL based virtual machine”](#configure-an-amnesic-operating-system-using-a-rhel-based-virtual-machine)
```plaintext
# Ensure dracut is installed
dnf install dracut -y
# Configure dracut to support the overlay
printf 'add_drivers+=" overlay "\n' > /etc/dracut.conf.d/overlay.conf # Use this line for RHEL 9
printf 'add_drivers+=" overlay "\nadd_dracutmodules+=" overlayfs "\n' > /etc/dracut.conf.d/overlay.conf # Use this line for RHEL 10
# Rebuild
dracut -f
# Update the boot image to use a systemd volatile overlay
grubby --update-kernel=ALL --args="systemd.volatile=overlay"
```
#### Building xahaud
[Section titled “Building xahaud”](#building-xahaud)
Once an amnesiac virtual machine with sufficient memory has been created, it is possible to build xahaud following the instructions [above on this page](#_top).
#### Disabling amnesia
[Section titled “Disabling amnesia”](#disabling-amnesia)
Installing software updates or performing other tasks that should persist will require users to disable amnesia. This can be done temporarily or permanently. Some software updates require additional configuration after a reboot, so it recommended to disable amnesia a second time when rebooting following a software update.
To disable amnesia on Debian based systems:
1. Press `e` to edit the Ubuntu boot entry.
2. On the line starting with “linux…” edit or add `overlayroot=` option to read `overlayroot=disabled`. This will allow a one-time boot into a system with persistent storage.
3. To permanently disable amnesia, run `sudo sed -i '/^overlayroot=/c\overlayroot="disabled"' /etc/overlayroot.conf` to change `overlayroot="disabled"` in the /etc/overlayroot.conf file. Then update initramfs `sudo update-initramfs -u`.
To disable amnesia on RHEL 9/10 based systems:
1. Press `e` at the boot menu to edit the options.
2. Remove the “systemd.volatile=overlay” option.
3. Press `F10` to boot.
4. To permanently disable amnesia, run `grubby --update-kernel=ALL --remove-args="systemd.volatile=overlay"`
# macOS
Note
While this page is being updated, please refer to the [BUILD.md](https://github.com/Xahau/xahaud/blob/dev/BUILD.md) file in the Xahau/xahaud GitHub Repository.
# Enable Validation in xahaud
Validators are xahaud nodes that are configured with an additional public/private keypair, which is used to sign each proposed ledger. Thus, validators are the primary mechanism used to achieve consensus regarding the order in which transactions are applied on the Xahau Network.
## Background Considerations
[Section titled “Background Considerations”](#background-considerations)
Running a validating xahaud server may seem straight forward, however, there are a number of considerations for production node operators including uptime and security. This following introductory sections provide background on these considerations.
### Security and Availability
[Section titled “Security and Availability”](#security-and-availability)
When running xahaud as a validator, system security and availability are critical. Validator operators are expected to actively monitor their servers and to respond quickly to outages. Some validator operators choose to host standby machines in diverse data centers, so they can quickly recover from outages. While it is possible to host a reliable validator in one’s home, it is unlikely that such a setup could provide sufficient stability and security for the validator to gain broader trust (e.g., inclusion on published UNLs). Similarly, validator operators are strongly discouraged from running software other than xahaud on a machine used as a xahaud validator, since this increases the probability of running out of resources or exposing a security vulnerability. System administrators who require websocket or RPC access to a server are encouraged to run different machines for queries, so resources are not taken away from the critical task of validating ledgers.
The private/public validation keypair should be stored and backed up in a secure, offline environment. Anyone with access to the keys of a trusted validator has potential to harm the network. After installing a validation token into the xahaud.cfg file, it is advised to restrict read access (`chmod 400 xahaud.cfg`) and change ownership of the file to “root” or “xahaud”, depending on the type of install (`chown root:root xahaud.cfg`).
### Identity Attestation
[Section titled “Identity Attestation”](#identity-attestation)
To avoid a [Sybil attack](https://en.wikipedia.org/wiki/Sybil_attack) and build trust, validating xahaud nodes attest to their identity by cryptographically signing a domain name with their validation keys. This signature is then hosted at the same domain, in a [TOML format file](/docs/infrastructure/identity). In addition to verifying the identity of a validator, this TOML file can also be used to verify the identity of individual account holders on the Xahau Network, by providing an attestation signed by the private account key instead of the private validation key. The TOML file should be hosted on a web server with TLS encryption enabled at:\
`https://[your-domain.com]/.well-known/xahau.toml`
### Peering
[Section titled “Peering”](#peering)
To maintain a high level of security, xahaud nodes that are configured as validators should only peer with known, trusted peers. Enabling the `peer_private` setting and explicitly defining `ips_fixed` in the xahaud.cfg file will force a server to only connect to defined peers. Operating system and hardware level protections, such as firewalls, provide additional reassurance that the server is only connecting to defined peers. However, this can be a challenge, as validators with too few peers, typically less than about five, are at risk of falling out of sync with the rest of the network.
### Governance and Trust
[Section titled “Governance and Trust”](#governance-and-trust)
The Xahau Network utilizes the [Governance Game](/docs/features/governance-game) as a democratic method for managing the Network. Additionally, each xahaud instance participating in the Network is required to install a list of trusted validating servers, called a Unique Node List or UNL. Thus, the existing governance participants can vote a new validator into a seat at the governance table. Separately, trusted UNL publishers, such as the [InFTF](https://inftf.org), can choose to include a validator in their recommended list of trusted validators. Running a validator does not guarantee inclusion in either the Governance Game or any UNL. Typically, validating servers that are selected for inclusion in the governance process have:
1. High availability
* Effective 24/7/365 monitoring with rapid responses to outages
2. High agreement with the rest of the network
3. An identified owner/operator and a clear geographic location
4. A proactive approach to updating and voting for [amendments](/docs/features/amendments) and fees
* This requires taking the time to watch what is in development
## Enabling Validation
[Section titled “Enabling Validation”](#enabling-validation)
Switching a stock xahaud server into a validator is a straight forward process. Essentially, users will generate a public/private keypair, which is then used to generate a token using an ephemeral key derived from the master pair. That token is installed into the `xahaud.cfg` file, thereby instructing xahaud to propose validations to the Network.
### Building the Validation Keys Tool
[Section titled “Building the Validation Keys Tool”](#building-the-validation-keys-tool)
At this time, there is not an official binary release of the software used for generating validation keys. Thus, users can either build the tool from scratch or rely on unofficial builds. The instructions for building the tool are the same as the instructions for [building xahaud](../build-xahaud), and they are provided on the [Xahau/validator-keys-tool](https://github.com/Xahau/validator-keys-tool) repository page. There are also some [packaged binaries](https://github.com/jscottbranson/xahau-examples/) available in unofficial repositories. Users seeking to generate keys for production validators should build the tool from scratch on a secure, air-gapped machine.
While xahaud provides the `validation_create` [Admin API method](/docs/features/http-websocket-apis/admin-api-methods), this method is NOT capable of generating the necessary validation token or allowing for domain verification. Thus, despite the name, the `validation_create` method is used to create public/private keys to identify a server broadly, for example when [clustering multiple servers](/docs/infrastructure/advanced-configuration).
### Generating and Installing Validation Keys
[Section titled “Generating and Installing Validation Keys”](#generating-and-installing-validation-keys)
Consider using an offline machine to generate validation keys and a validation token.
1. Navigate to the directory containing the validation keys tool: `cd [/path/to/tool]`
2. Generate a new keypair: `./validator-keys create_keys`
3. The newly generated keypair is stored in `/home/[username]/[.ripple or .xahaud]/validator-keys.json`. The storage path depends on which version of the validator-keys-tool is used.
4. Ideally, validators should provide identity attestation. To do so, set your domain in the validator-keys.json file: `./validator-keys set_domain [example.com]`
* If you do not wish to provide an identifying domain, generate a validation token without a domain: `./validator-keys create_token --keyfile /home/[username]/.xahaud/validator-keys.json`
5. Review the output of the previous command. Note the `[validator_token]`, as this will be installed in xahaud.cfg to enable validation. If a domain was set, note the `attestation=""` line, as it will need to be added into the TOML file served at your domain.
* Anytime the tool is used to generate a new `validator_token`, a field, `token_sequence`, is incremented in the `validator-keys.json` file. The Network will ignore validations from any server that has a token generated with a lower sequence number than the highest observed number. For example, if your validation token has sequence number “3” and you generate a new token with sequence number “2”, validations from any machine using the new token with the lower sequence number will be ignored. This feature enables server operators to generate a new token, rather than generating new master validation keys, in the event of a security compromise or other incident.
6. Open xahaud.cfg and paste in the `[validation_token]`, then restart the xahaud service.
7. Paste the `attestation=""` into your [TOML](/docs/infrastructure/identity) file to prove the identity of your validator.
8. Ensure private validation keys are stored securely, ideally separate from the validator.
# Serve a TOML File for Identity Verification
***Identity verification requires two parts. NEVER TRUST TOML FILES OR ON NETWORK VALIDATOR/ACCOUNT ATTESTATIONS ALONE TO CONFIRM IDENTITY, AS ANYONE CAN SET THEM. A website (URL) must claim ownership of the validator/account, and the on-network data must match.***
Given that trust is foundational to the Xahau Network, it is ideal for entities operating xahaud validators to take credit for their servers. Identity attestation provides users with assurances that one entity isn’t gaining disproportionate control over the trusted (default UNL) validators in the Network. This is is done by publishing two attestations: one from a validating server on the Xahau Network and a second from a web server that serves the identifying domain over TLS. Thus, the validator claims association with the web domain and the web domain claims association with the validator. *Without both of these claims, it is not possible to trust the identity attestation.*
Similarly, individual Xahau account holders might wish to publish a TOML file attesting that specific accounts on the network are under their control. Account ownership attestations are particularly relevant for enterprises, such as exchanges or financial institutions. As with validators, these attestations require two parts: a web server that claims ownership of a Xahau Network address as well as an on-network account address that claims to be owned by the same domain. Account attestations provide users with confidence that they are routing deposits to the correct address.
The contents and structure of this file are similar to those used by [Stellar](https://developers.stellar.org/docs/tokens/publishing-asset-info) and the [XRP Ledger](https://xrpl.org/docs/references/xrp-ledger-toml). Since the file can contain custom fields, it is important to allow flexibility when building tools designed to parse the TOML file.
## Web Server and DNS Configuration
[Section titled “Web Server and DNS Configuration”](#web-server-and-dns-configuration)
1. The file contents must be in the [TOML format](https://github.com/toml-lang/toml).
2. The TOML file must be served from: `https://[optional-subdomain.your-domain.com]/.well-known/xahau.toml`
* The path `/.well-known/xahau.toml` must not be altered. The path must be all lower case.
* [RFC 5785](https://datatracker.ietf.org/doc/html/rfc5785) contains more information on the “/.well-known/” path.
3. A TLS certificate chaining to a trusted certificate authority must be used to encrypt connections serving the TOML file.
4. DNS Sec is recommended for the domain.
5. Subdomains may be used to serve the file, and identical files may be hosted from multiple subdomains.
6. Content type for the file is `application/toml`.
7. The TOML file must be served with a CORS header: `Access-Control-Allow-Origin: *`
8. Additional headers may be served with the TOML file, if needed.
9. Custom or nonstandard fields may be added to the TOML file, as required by individual users.
10. No field is strictly required in the TOML file.
### CORS Configuration
[Section titled “CORS Configuration”](#cors-configuration)
Apache:
```plaintext
Header set Access-Control-Allow-Origin "*"
```
Nginx:
```plaintext
location /.well-known/xahau.toml {
add_header 'Access-Control-Allow-Origin' '*';
}
```
### TOML File Contents
[Section titled “TOML File Contents”](#toml-file-contents)
TOML files are typically subdivided into sections describing the TOML file itself (metadata), principals (responsible parties), and claimed assets including: validators, non-validating xahaud servers, accounts, and issued currencies.
#### Example TOML
[Section titled “Example TOML”](#example-toml)
The below example is intended to illustrate all sections that are commonly included in a Xahau Network TOML file. Individual users may not have all of these sections in their TOML file, and some users may need to include multiple of the same section. For example, if one exchange issues multiple currencies, it would include a `[[CURRENCIES]]` section for each IOU issued on the Network.
```plaintext
[METADATA]
modified = 2025-08-04T14:24:34.123Z
expired = 2025-12-31T14:24:34.123Z
[ORGANIZATION]
name = "A Company B.V."
website = "https://example.com"
email = "contact@example.com"
[[PRINCIPALS]]
name = "A. Person"
email = "a_person@example.com"
social_1 = "https://www.linkedin.com/company/incfintech"
x = "@IncFinTech"
[[VALIDATORS]]
public_key = "nHBixLw8q7XUP5AKceK2aZriN67PPjQW7JJ7hLkJgxvkTTs5go6k"
attestation = "07FA61020CA5E0605BE29D213DCC33F934B631EB6215F52D3E99D8AEA841272E300758B5C03CD2332190307324B4869838B77BAD275B31CF59D13E8FA6A8780B"
owner_country = "US"
server_country = "CA"
network_asn = "398726"
network = "21337"
unl = "https://vl.xahau.org"
[[SERVERS]]
ws = "wss://"
json_rpc = "https://"
peer = "https://"
network = "21337"
[[ACCOUNTS]]
address = "rabc..."
network = "21337"
desc = "This wallet is used for client deposits."
[[CURRENCIES]]
code = "USD"
issuer = "rabc..."
symbol = "$"
network = "21337"
display_decimals = 2
[[CURRENCIES]]
code = "EUR"
issuer = "rabc..."
symbol = "€"
network = "21337"
display_decimals = 2
```
#### Metadata
[Section titled “Metadata”](#metadata)
Dates/times in the TOML file should be specified in UTC and include millisecond precision. For example, `2025-08-04T14:24:34.123Z`. Only one metadata section can be included in a TOML file.
| Field | Data Type | Description |
| ---------- | --------- | -------------------------------------------------------------------------------- |
| `modified` | Date-Time | Date and time when the TOML was most recently modified. |
| `expires` | Date-Time | After this date/time, the TOML file will be considered expired and thus invalid. |
#### Organization
[Section titled “Organization”](#organization)
If an entity rather than an individual is claiming responsibility for the TOML file, that entity should use this section to identify itself. It would be unusual and likely an error for one TOML file to have multiple `[ORGANIZATION]` sections. If multiple sections are needed, ensure an additional set of brackets are added: `[[ORGANIZATION]]`.
| Field | Data Type | Description |
| ------------ | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | String | The name of organization hosting the TOML file. |
| `email` | String | Email address for the organization. |
| `website` | String | Website for the organization (typically this is the same as the URL where the TOML is hosted). |
| `social_[x]` | String | Link to a social media profile. This field is not standardized at this time. Thus, `x = "@IncFinTech` and `social_1 = https://x.com/IncFinTech` are both valid. |
#### Principals
[Section titled “Principals”](#principals)
This section is used to identify individual points of contact for the Xahau Network infrastructure and/or accounts.
| Field | Data Type | Description |
| ------------ | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | String | The name of an individual responsible for overseeing the organizations Xahau Network operations. |
| `email` | String | Email address for the principal. |
| `website` | String | Website for the principal. |
| `social_[x]` | String | Link to a social media profile. This field is not standardized at this time. Thus, `x = "@IncFinTech` and `social_1 = https://x.com/IncFinTech` are both valid. |
#### Validators
[Section titled “Validators”](#validators)
Validator operators are strongly encouraged to publish an attestation as proof of ownership. Providing geographic and ISP information is important, as it enables trusted (dUNL) list publishers to evaluate the geographic diversity of trusted validators on the network. If too many trusted validators are concentrated in one geographic region or on one network ASN, there is a risk to the broader network.
| Field | Data Type | Description |
| ---------------- | --------- | ---------------------------------------------------------------------------------------------------------------------- |
| `public_key` | String | The master public key used to validations. |
| `attestation` | String | Domain attestation generated by the validator-keys tool. |
| `owner_country` | String | [ISO-3166-2](https://en.wikipedia.org/wiki/ISO_3166-2) country code for the entity or person in charge of the server. |
| `server_country` | String | ISO-3166-2 country code for the server’s physical location. |
| `network_asn` | String | The Autonomous System Number (ASN) for the Internet Service Provider(s) providing internet connectivity to the server. |
| `network` | String | Identifies which network (Mainnet, Testnet, etc.) the server participates in. |
| `unl` | String | A URL hosting the list of trusted validators that the validator subscribes to. |
#### Servers
[Section titled “Servers”](#servers)
Network participants who provide public peering or API access via websocket or RPC can publish details for accessing individual servers.
| Field | Data Type | Description |
| ---------- | --------- | ----------------------------------------------------------------------------- |
| `ws` | String | The URL for public websocket access. This begins with “ws\:// or wss\://”. |
| `json_rpc` | String | The URL for public RPC access. This begins with “http\:// or https\://”. |
| `peer` | String | URL other servers can use to peer with the server identified in the TOML. |
| `network` | String | Identifies which network (Mainnet, Testnet, etc.) the server participates in. |
#### Accounts
[Section titled “Accounts”](#accounts)
Entities needing account verification can use this section to claim ownership of a given Xahau Network wallet.
| Field | Data Type | Description |
| --------- | --------- | ------------------------------------------------------------------------------- |
| `address` | String | The encoded public key (beginning with `r`) identifying a Xahau Network wallet. |
| `network` | String | Identifies which network (Mainnet, Testnet, etc.) the wallet is used on. |
| `desc` | String | Human readable description of what the wallet is used for. |
#### Currencies
[Section titled “Currencies”](#currencies)
It is possible for multiple wallets to issue currencies with the same currency code. ***Thus, it is critical that users verify the issuing wallet as well as the currency code.***
| Field | Data Type | Description |
| ------------------ | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `code` | String | The ticker symbol of the token as three digits or 40 hex characters. This field is case sensitive. |
| `issuer` | String | The wallet address (beginning with `r`) that issued the currency. The referenced wallet should be present in the `[[ACCOUNTS]]` section of the TOML file. |
| `symbol` | String | The symbol (e.g., ”$”) used to identify the currency. |
| `network` | String | Identifies which network (Mainnet, Testnet, etc.) the currency is issued on. |
| `display_decimals` | Integer | The number of digits to the right of the decimal point that clients should display when showing quantities of the currency. |
## Validator Domain Verification
[Section titled “Validator Domain Verification”](#validator-domain-verification)
Hosting the `xahau.toml` file enables domain owners to claim ownership of a validator. However, it is critical that the validator also acknowledge this ownership, so third parties can reliably trust network operators. Since validators form the backbone of forward progress on the Xahau Network, it is important that operators appropriately secure their private validation keys.
If you are not familiar with the Validator Keys Tool, see the page on [Enabling Validation in xahaud](/docs/infrastructure/enabling-validation).
Users who have already complete the steps on the Enabling Validation page do not need to repeat them. Simply paste the `attestation = ""` field into the TOML file and ensure the correct `[validator_token]` is installed in the `xahaud.cfg`.
Users who did not configure a domain when they initially generated a validation token may do so by running `./validator-keys set_domain [example.com]`. Prior to attempting to set the domain, ensure that the master validation key JSON file is stored in the correct path: `/home/[username]/[.ripple or .xahaud]/validator-keys.json`.
## Wallet Address Verification
[Section titled “Wallet Address Verification”](#wallet-address-verification)
Consistent with validator domain verification, verifying ownership of a wallet address on the Xahau Network requires two components: A TOML file served over a TLS encrypted connection (with a properly chained certificate) from the domain claiming ownership and a transaction from the wallet address verifying the ownership claim. To claim ownership of a wallet address:
1. Include the address as an `[[accounts]]` section in the TOML file.
2. Submit an [AccountSet transaction](/docs/protocol-reference/transactions/transaction-types/accountset) with the `Domain` field specified.
# Install xahaud
> The software behind Xahau is open source, and anyone can run a node locally. Users can run a Docker container, a local instance, or a binary file.
When running a node, users will have to configure settings based on whether the node will run on the test network or the main network. When transitioning a single node from one network to the other, database files must be wiped, except wallet.db, which contains the server’s identity credentials.
The most common techniques for installing xahaud are either locally using systemd or inside a container, such as Docker.
Tip
The install documentation on this page expands on the install documentation in the [xahaud GitHub repository](https://github.com/xahau/xahaud/blob/dev/docs/build/install.md).
## Linux Install Process
[Section titled “Linux Install Process”](#linux-install-process)
Regardless of how xahaud is installed (Docker or system-wide), the overall process is similar across Linux systems. The following sections, [Docker Container](#docker-container-install-script) and [Local Install](#local-install-script), take advantage of bash scripts, which automate the following steps:
1. Obtain the xahaud binary:
* Downoad a compiled binary image from
* [Build from source](/docs/infrastructure/build-xahaud/)
2. Obtain the configuration files:
* [xahaud.cfg](https://raw.githubusercontent.com/Xahau/xahaud/refs/heads/dev/cfg/xahaud-example.cfg)
* [validators-xahau.txt](https://raw.githubusercontent.com/Xahau/xahaud/refs/heads/dev/cfg/validators-example.txt)
3. If desired, create a xahaud user and group, which can own the binary and other relevant files:
* `sudo groupadd --system xahaud`
* `sudo useradd --system --gid xahaud --no-create-home xahaud`
4. Decide on (and create) a directory structure to store:
* The xahaud binary. The default is typically: `/opt/xahaud/bin/xahaud`
* Two xahaud configuration files, `xahaud.cfg` and `validators-xahau.txt`. The default is: `/etc/xahaud/`, though `/opt/xahaud/etc/` is often used. These two locations can be symbolically linked.
* The xahaud databases. The default is often: `/opt/xahaud/db/`
* A logfile location, such as: `/var/log/xahaud/default.log`
5. Move the xahaud binary and configuration files into their places in the directory structure.
6. Edit `xahaud.cfg` so paths in the configuration match the paths in the directory structure.
7. If needed, change ownership permissions. If running xahaud as a validator, it is important to restrict the `xahaud.cfg` file, as that contains the validation token.
* `chown -R xahaud:xahaud /opt/xahaud /var/log/xahaud`
* `chmod -R 750 /opt/xahaud /var/log/xahaud`
8. Create a systemd service file (such as the example [below](#example-systemd-service-file) to run xahaud as a daemon.
* The file is located at: `/etc/systemd/system/xahaud.service`
* After creating or editing the file, run: `systemctl daemon-reload`
* To run xahaud automatically at system startup: `systemctl enable --now xahaud`
* If preferred, xahaud can be run without systemd: `/path/to/xahaud --conf=/path/to/xahaud.cfg`
9. Create a wrapper to run xahaud commands without having to specify the full path.
* Typically stored at `/usr/local/bin/xahaud`
* Contents might be: `exec ${XAHAUD_DIR}xahaud --conf=${CONF_DIR}xahaud.cfg "$@"`
### Example systemd Service File
[Section titled “Example systemd Service File”](#example-systemd-service-file)
The following service file should be modified based on the user’s selected directory structure and ownership permissions.
```plaintext
[Unit]
Description=Xahaud Daemon
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/path/to/xahaud --silent --conf=/path/to/xahaud.cfg
Restart=on-failure
User=xahaud
Group=xahaud
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
```
### Example Linux Install Script
[Section titled “Example Linux Install Script”](#example-linux-install-script)
A basic bash script used to install xahaud. This script follows the instructions provided earlier this this section.
```plaintext
### VARIABLES ###
#### Directory structure ####
XAHAUD_DIR="/opt/xahaud/bin/" # Path where xahaud binary will be stored
CONF_DIR="/opt/xahaud/etc/" # Path where the xahaud.cfg and validators-xahau.txt will be stored
DB_DIR="/opt/xahaud/db/" # Path where xahaud will store databases
LOG_DIR="/var/log/xahaud/" # Path where logfile(s) will be stored.
#### Ownership ####
XAHAUD_USER="xahaud" # User that owns the xahaud process.
#### Download links ####
BINARY_URL="https://build.xahau.tech/2025.9.8-HEAD%2B2194" # URL to the xahaud binary that will be downloaded.
CFG_URL="https://raw.githubusercontent.com/Xahau/xahaud/refs/heads/dev/cfg/xahaud-example.cfg" # This will be renamed to 'xahaud.cfg'
VAL_URL="https://raw.githubusercontent.com/Xahau/xahaud/refs/heads/dev/cfg/validators-example.txt" # This will be renamed to 'validators-xahau.txt'
########## SCRIPT BEGINS HERE. DO NOT ADJUST VARIABLES BELOW THIS LINE ##########
### CREATE DIRECTORIES ####
echo "Checking directory structure."
sudo mkdir -p ${XAHAUD_DIR} ${CONF_DIR} ${DB_DIR} ${LOG_DIR}
### CREATE xahaud GROUP AND USER ###
echo "Checking for user and group."
if ! getent group ${XAHAUD_USER} > /dev/null; then
sudo groupadd --system ${XAHAUD_USER}
fi
if ! getent passwd ${XAHAUD_USER} > /dev/null; then
sudo useradd --system --gid ${XAHAUD_USER} --no-create-home ${XAHAUD_USER}
fi
### DOWNLOAD CONFIGURATION FILES ###
echo "Downloading files."
if [[ ! -f "${CONF_DIR}xahaud.cfg" ]]; then
curl -fsSL ${CFG_URL} -o ${CONF_DIR}xahaud.cfg
fi
if [[ ! -f "${CONF_DIR}validators-xahau.txt" ]]; then
curl -fsSL ${VAL_URL} -o ${CONF_DIR}validators-xahau.txt
fi
### DOWNLOAD xahaud ###
if [[ ! -f "${XAHAUD_DIR}xahaud" ]]; then
curl -fsSL ${BINARY_URL} -o ${XAHAUD_DIR}xahaud
elif [[ -f "${XAHAUD_DIR}xahaud" ]]; then
echo "Existing xahaud binary found. It will be renamed to 'xahaud.old'."
mv ${XAHAUD_DIR}xahaud ${XAHAUD_DIR}xahaud.old
curl -fsSL ${BINARY_URL} -o ${XAHAUD_DIR}xahaud
fi
### CHANGE OWNERSHIP AND PERMISSIONS ###
echo "Checking ownership and permissions."
sudo chown -R ${XAHAUD_USER}:${XAHAUD_USER} ${XAHAUD_DIR} ${CONF_DIR} ${DB_DIR} ${LOG_DIR}
sudo chmod -R 0750 ${XAHAUD_DIR} ${CONF_DIR} ${DB_DIR} ${LOG_DIR}
### Install systemd SERVICE FILE ###
if [[ ! -f "/etc/systemd/system/xahaud.service" ]]; then
echo "Installing system service file."
sudo cat > /etc/systemd/system/xahaud.service < /usr/local/bin/xahaud < | Same as Mainnet |
| Hooks Smart Contract Documentation | [](https://xahau.network/docs/hooks/) | Same as Mainnet |
| Explorer | [](https://explorer.xahau.network/) | [](https://explorer.xahau-test.net/) |
| Public WebSocket URL | | |
| Network ID and Peer Listening Port | 21337 [IANA assigned port](https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=21337) | 21338 |
| Peering and Bootstrap Servers | bacab.alloy.ee 21337 hubs.xahau.as16089.net 21337 | 79.110.60.122 21338 79.110.60.124 21338 79.110.60.125 21338 79.110.60.121 21338 2a0c:3bc0::1c74 21338 2a0c:3bc0::169d 21338 2a0c:3bc0::1aaf 21338 2a0c:3bc0::1d78 21338 |
| Docker Container | [](https://github.com/Xahau/mainnet-docker) | [](https://github.com/Xahau/Xahau-Testnet-Docker) |
| Local Install Scripts | [](https://raw.githubusercontent.com/Xahau/mainnet-docker/refs/heads/main/xahaud-install-update.sh) | [](https://github.com/Xahau/Xahau-Testnet-Docker/blob/main/xahaud-install-update.sh) |
| Binary Releases | [](https://build.xahau.tech) | Same as Mainnet |
| Sample Configuration File | [](https://github.com/Xahau/xahaud/blob/dev/cfg/xahaud-example.cfg) | [](https://github.com/Xahau/Xahau-Testnet-Docker/blob/main/store/etc/xahaud.cfg) |
| Sample Trusted Validators (UNL) File | [](https://github.com/Xahau/xahaud/blob/dev/cfg/validators-example.txt) | [](https://github.com/Xahau/Xahau-Testnet-Docker/blob/main/store/etc/validators-xahau.txt) |
| Documented Configuration Files | [](https://github.com/Xahau/xahaud/tree/dev/cfg) | Same as Mainnet |
| Github Build Actions (release numbers) | [](https://github.com/Xahau/xahaud/actions?query=branch%3Arelease+is%3Asuccess+build+using+docker) | Same as Mainnet |
# Interact With xahaud Using Websocket and RPC
The xahaud software provides both websocket and RPC interfaces that can be configured for a variety of use cases, such as submitting transactions or querying ledger history. Some users may choose to place proxy software in front of xahaud to provide encryption, load balancing, or other benefits. It is possible to install TLS certificates in the xahaud.cfg file using parameters such as `ssl_key = [/path/to/key]`.
## Configuring Websocket and RPC Ports
[Section titled “Configuring Websocket and RPC Ports”](#configuring-websocket-and-rpc-ports)
To enable listening ports, edit the `xahaud.cfg` file. Enabled ports are listed under the `[server]` stanza in the configuration file. Each port listed under the `[server]` section must be further defined via it’s own stanza. In addition to configuring websocket or RPC ports, administrators can also configure the port used to listen for incoming peer connections (`port_peer`). On validating servers, it is ideal to remove `port_peer` from the configuration file, to avoid incoming connections. A configuration file with the peer protocol, one websocket port, and one RPC port might look like:
```plaintext
[server]
port_peer
port_ws_public
port_rpc_public
[port_peer] # Name of the port.
protocol = peer # Required field.
port = 21337 # Required field.
ip = :: # Address of interface to bind to.
[port_ws_public]
protocol = ws
port = 16006
ip = ::
limit = 150 # Maximum number of clients allowed to connect to a given port. "0" is unlimited.
admin = [ 10.10.10.5, 10.11.11.0/24 ] # IP addresses or subnets allowed to submit [admin](/docs/features/http-websocket-apis/admin-api-methods) requests.
secure_gateway = [ 10.10.10.20, 10.15.15.0/24 ] # Addresses allowed to send X-Forwarded-For and X-User headers.
[port_rpc_public]
protocol = http
port = 16007
ip = ::
```
Additional configuration options for websocket and RPC connections are available in the [Example Configuration File](https://github.com/Xahau/xahaud/blob/dev/cfg/rippled-example.cfg).
## UDP RPC
[Section titled “UDP RPC”](#udp-rpc)
xahaud supports UDP-based RPC for high-performance, low-latency queries. UDP RPC is useful for applications that need to make many rapid queries and can tolerate occasional packet loss.
To enable UDP RPC, add a UDP port definition in your `xahaud.cfg`:
```plaintext
[server]
port_udp_rpc
[port_udp_rpc]
protocol = http
port = 16008
ip = ::
transport = udp
```
UDP RPC requests use the same JSON-RPC format as HTTP RPC, but are sent as UDP datagrams. Responses are also sent via UDP. Since UDP is connectionless, each request must include all necessary context, and clients should handle potential packet loss by implementing retry logic.
**Note:** UDP RPC is best suited for read-only operations. Transaction submission should use WebSocket or HTTP RPC for reliability.
# System Requirements
Hardware requirements for nodes customized for various tasks (e.g., RPC/WS, hubs, validators, etc.) should be consistent with the specs outlined below. Consider tailoring your individual system based on your intended use case.
## Types of Nodes
[Section titled “Types of Nodes”](#types-of-nodes)
It is possible to run xahaud in diverse configurations, based on a users needs. Similarly, one xahaud server can be configured for multiple purposes, such as a full history server that is also used for RPC/WS calls. The server’s purpose dictates necessary system requirements. Some xahaud configurations might include:
1. Stock server - This term is commonly used to refer to any xahaud node that is not configured as a validator. A stock server generally has very few changes from the default configuration.
2. Full history servers - Are useful for querying historic data. In addition to a large amount of storage space, potentially higher disk IOPS and network bandwidth are needed, depending on the number of users querying the server.
3. RPC/Websocket servers - Are tailored for tasks such as submitting transactions or querying current ledger data, like order books or the validation stream. Nginx or other proxy sofware is often placed in front of RPC/WS servers to provide load balancing, encryption, and other benefits.
4. Hub server - Peering between nodes is critical for relaying messages across the Xahau Network, and a single server can be configured to provide peering for hundreds of peers. However, a large amount of bandwidth can be required (10 Gbit+).
5. [Validating servers](/docs/infrastructure/enabling-validation) - Validators differ from other types of nodes, in that they require an additional cryptographic key to be installed, so they can sign off on the sequence of transactions in a proposed ledger. As availability and security are critical, it is not recommended to use a validator for other functions.
## General Notes
[Section titled “General Notes”](#general-notes)
* Builds are typically tested on Ubuntu LTS. However, Docker, portable binaries, custom builds, and other install methods allow for diverse operating system support.
* Typically one IPv4 and/or IPv6 address is needed for each xahaud instance. Running multiple instances behind one IPv4 address is not recommended.
* Machines storing full history must use XFS or similar to avoid limitations with single file size in EXT4 (max. file size of 16TB). If storing less history, EXT4 is sufficient.
* It may be possible to run xahaud on machines that do not meet the below “Minimum” specifications for production servers. However, doing so risks instability.
* These system requirements may grow over time. For example, disk space for full history servers is consistently increasing.
* As of November 1, 2025 **the full history for the Xahau Network is 10TB**.
## Recommended Specs for Production xahaud Servers
[Section titled “Recommended Specs for Production xahaud Servers”](#recommended-specs-for-production-xahaud-servers)
| | Minimum | Preferred | Ideal |
| ---------------------- | ------------- | ------------- | ------------- |
| CPU (2.5+ GHz x86\_64) | 8 cores | 20 cores | 40+ cores |
| Memory | 32GB | 64GB | 128GB+ |
| Disk IO (sustained) | 15k random RW | 20k random RW | 30k random RW |
| Disk Size | 500GB | 1TB | 20TB+ |
| Filesystem | XFS | XFS | XFS |
| Network IO | 500Mbit+ | 1Gbit | 10Gbit |
# Update xahaud
The process for updating xahaud varies depending on the install method used, however, all three methods rely on the releases published at . When updating a validator, hub, or other ‘critical’ infrastructure, please check the network health prior to restarting a server to install an update. It is possible to automate the update process using a crontab entry and an update script, however, administrators are discouraged from doing so, as automatic updates may result in restarts at times when the network is unstable. Similarly, human presence allows operators to ensure updates are successful, thereby minimizing downtime.
## Backup
[Section titled “Backup”](#backup)
Users should always keep backups of:
1. The primary configuration file: `xahaud.cfg`
* Location varies based on install type.
2. The trusted validators file: `validators-xahau.txt`
* Location is specified in ‘xahaud.cfg’.
3. The server’s identity credentials: `wallet.db`
* Located in the database directory defined in ‘xahaud.cfg’.
4. Validators must keep their validation private key backed up in a secure, offline location.
## Updating Docker Containers
[Section titled “Updating Docker Containers”](#updating-docker-containers)
Updating xahaud inside a Docker container involves replacing the currently running binary with the new version, downloaded from . This can be accomplished either by replacing the xahaud binary inside the container or by updating the entire container.
To update the xahaud binary inside a running Docker container:
1. Download the [script](https://gist.githubusercontent.com/WietseWind/2ed35d85dcd056d82645de2958934f86/raw/34be773fd6af42e82cc3a21baf70bfb1e2a6c583/update.sh): `wget https://gist.githubusercontent.com/WietseWind/2ed35d85dcd056d82645de2958934f86/raw/34be773fd6af42e82cc3a21baf70bfb1e2a6c583/update.sh`
2. Edit the script and change the first line to the [release version](https://build.xahau.tech) you would like to install.
3. Run the script: `bash ./update.sh`
4. Verify xahaud is running: `docker exec xahaud-[mainnet/testnet] xahaud server_info`
To replace the current Docker image with a new version, without overwriting databases or configuration files (which are ignored via the .gitignore file):
1. Navigate to the repository: `cd [/path/to/docker-repo]`
2. Update to the latest version `git pull`
3. List running Docker containers and note the name of the xahaud container: `docker ps`
4. Stop the old xahaud instance: `docker stop xahaud-[mainnet/testnet]`
5. Remove the old instance: `docker rm xahaud-[mainnet/testnet]`
6. Start the new instance: `./build && ./up`
## Updating Local Installations
[Section titled “Updating Local Installations”](#updating-local-installations)
To update a locally installed version of xahaud, simply replace the current binary with a new binary:
1. Download the new binary from:
2. Mark the new binary executable: `chmod +x [/path/to/download]`
3. Stop the currently running xahaud instance: `/opt/xahaud/bin/xahaud stop`
4. Replace the old binary with the new: `mv [/path/to/download] /opt/xahaud/bin/xahaud`
5. Start xahaud: `systemctl start xahaud`
6. Verify xahaud is running: `/opt/xahaud/bin/xahaud server_info`
A [script](https://gist.githubusercontent.com/WietseWind/9480a4fc95e904e54524406005c8c963/raw/2b200fdc2e5b471ae4f6625674aff1765d63e744/update.sh) that automates the above steps is available.
## Updating Binary Files
[Section titled “Updating Binary Files”](#updating-binary-files)
Updating the xahaud binary files is essentially the same as the original install instructions:
1. Remove the currently running version: `rm [/path/to/xahaud]`
2. Download the new version:
3. Mark the download as executable: `chmod 500 [/path/to/xahaud]`
4. Start xahaud: `./[path/to/xahud] --net --conf [/path/to/xahaud.cfg]`
# Binary Format
[\[Source\]](https://github.com/Xahau/xahaud/blob/dev/src/ripple/protocol/impl/STObject.cpp#L696-L718)
This page describes the Xahau’s canonical binary format for transactions and other data. This binary format is necessary to create and verify digital signatures of those transactions’ contents, and is also used in other places including in the peer-to-peer communications between servers. The `xahaud` APIs typically use JSON to communicate with client applications. However, JSON is unsuitable as a format for serializing transactions for being digitally signed, because JSON can represent the same data in many different but equivalent ways.
The process of serializing a transaction from JSON or any other representation into their canonical binary format can be summarized with these steps:
1. Make sure all required fields are provided, including any required but “auto-fillable” fields.
The Transaction Formats Reference defines the required and optional fields for Xahau transactions.
**Note:** The `SigningPubKey` must also be provided at this step. When signing, you can derive this key from the secret key that is provided for signing.
2. Convert each field’s data into its “internal” binary format.
3. Sort the fields in canonical order.
4. Prefix each field with a Field ID.
5. Concatenate the fields (including prefixes) in their sorted order.
The result is a single binary blob that can be signed using well-known signature algorithms such as ECDSA (with the secp256k1 elliptic curve) and Ed25519. For purposes of Xahau, you must also \[hash]\[Hash] the data with the appropriate prefix (`0x53545800` if single-signing, or `0x534D5400` if multi-signing). After signing, you must re-serialize the transaction with the `TxnSignature` field included.
**Note:** Xahau uses the same serialization format to represent other types of data, such as ledger objects and processed transactions. However, only certain fields are appropriate for including in a transaction that gets signed. (For example, the `TxnSignature` field, containing the signature itself, should not be present in the binary blob that you sign.) Thus, some fields are designated as “Signing” fields, which are included in objects when those objects are signed, and “non-signing” fields, which are not.
#### Examples
[Section titled “Examples”](#examples)
Both signed and unsigned transactions can be represented in both JSON and binary formats. The following samples show the same signed transaction in its JSON and binary formats:
**JSON:**
```json
```
**Binary (represented as hexadecimal):**
```plaintext
```
### Sample Code
[Section titled “Sample Code”](#sample-code)
The serialization processes described here are implemented in multiple places and programming languages:
* In C++ [in the `rippled` code base](https://github.com/Xahau/xahaud/blob/dev/src/ripple/protocol/impl/STObject.cpp).
* In JavaScript in this repository’s code samples section.
* In Python 3 in this repository’s code samples section.
Additionally, many client libraries provide serialization support under permissive open-source licenses, so you can import, use, or adapt the code for your needs.
### Internal Format
[Section titled “Internal Format”](#internal-format)
Each field has an “internal” binary format used in the `xahaud` source code to represent that field when signing (and in most other cases). The internal formats for all fields are defined in the source code of [`SField.cpp`](https://github.com/Xahau/xahaud/blob/master/src/ripple/protocol/impl/SField.cpp). (This file also includes fields other than transaction fields.) The Transaction Format Reference also lists the internal formats for all transaction fields.
For example, the `Flags` common transaction field becomes a UInt32 (32-bit unsigned integer).
#### Definitions File
[Section titled “Definitions File”](#definitions-file)
The following JSON file defines the important constants you need for serializing Xahau data to its binary format and deserializing it from binary:
[**https://github.com/Xahau/xahau.js/tree/main-xahau/packages/xahau-binary-codec/src/enums/definitions.json**](https://github.com/Xahau/xahau.js/tree/main-xahau/packages/xahau-binary-codec/src/enums/definitions.json)
The following table defines the top-level fields from the definitions file:
| Field | Contents |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `TYPES` | Map of data types to their “type code” for constructing field IDs and sorting fields in canonical order. Codes below 1 should not appear in actual data; codes above 10000 represent special “high-level” object types such as “Transaction” that cannot be serialized inside other objects. See the Type List for details of how to serialize each type. |
| `LEDGER_ENTRY_TYPES` | Map of ledger objects to their data type. These appear in ledger state data, and in the “affected nodes” section of processed transactions’ metadata. |
| `FIELDS` | A sorted array of tuples representing all fields that may appear in transactions, ledger objects, or other data. The first member of each tuple is the string name of the field and the second member is an object with that field’s properties. (See the “Field properties” table below for definitions of those fields.) |
| `TRANSACTION_RESULTS` | Map of transaction result codes to their numeric values. Result types not included in ledgers have negative values; `tesSUCCESS` has numeric value 0; `tec`-class codes represent failures that are included in ledgers. |
| `TRANSACTION_TYPES` | Map of all transaction types to their numeric values. |
For purposes of serializing transactions for signing and submitting, the `FIELDS`, `TYPES`, and `TRANSACTION_TYPES` fields are necessary.
The field definition objects in the `FIELDS` array have the following fields:
| Field | Type | Contents |
| ---------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `nth` | Number | The field code of this field, for use in constructing its Field ID and ordering it with other fields of the same data type. |
| `isVLEncoded` | Boolean | If `true`, this field is length-prefixed. |
| `isSerialized` | Boolean | If `true`, this field should be encoded into serialized binary data. When this field is `false`, the field is typically reconstructed on demand rather than stored. |
| `isSigningField` | Boolean | If `true` this field should be serialized when preparing a transaction for signing. If `false`, this field should be omitted from the data to be signed. (It may not be part of transactions at all.) |
| `type` | String | The internal data type of this field. This maps to a key in the `TYPES` map, which gives the type code for this field. |
#### Field IDs
[Section titled “Field IDs”](#field-ids)
[\[Source - Encoding\]](https://github.com/seelabs/rippled/blob/cecc0ad75849a1d50cc573188ad301ca65519a5b/src/ripple/protocol/impl/Serializer.cpp#L117-L148) [\[Source - Decoding\]](https://github.com/seelabs/rippled/blob/cecc0ad75849a1d50cc573188ad301ca65519a5b/src/ripple/protocol/impl/Serializer.cpp#L484-L509)
When you combine a field’s type code and field code, you get the field’s unique identifier, which is prefixed before the field in the final serialized blob. The size of the Field ID is one to three bytes depending on the type code and field codes it combines. See the following table:
| | Type Code < 16 | Type Code >= 16 |
| -------------------- | -------------- | --------------- |
| **Field Code < 16** | | |
| **Field Code >= 16** | | |
When decoding, you can tell how many bytes the field ID is by which bits **of the first byte** are zeroes. This corresponds to the cases in the above table:
| | High 4 bits are nonzero | High 4 bits are zero |
| -------------------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
| **Low 4 bits are nonzero** | 1 byte: high 4 bits define type; low 4 bits define field. | 2 bytes: low 4 bits of the first byte define field; next byte defines type |
| **Low 4 bits are zero** | 2 bytes: high 4 bits of the first byte define type; low 4 bits of first byte are 0; next byte defines field | 3 bytes: first byte is `0x00`, second byte defines type; third byte defines field |
**Caution:** Even though the Field ID consists of the two elements that are used to sort fields, you should not sort by the serialized Field ID itself, because the byte structure of the Field ID changes the sort order.
#### Length Prefixing
[Section titled “Length Prefixing”](#length-prefixing)
Some types of variable-length fields are prefixed with a length indicator. `Blob` fields (containing arbitrary binary data) are one such type. For a list of which types are length-prefixed, see the Type List table.
**Note:** Some types of fields that vary in length are not length-prefixed. Those types have other ways of indicating the end of their contents.
The length prefix consists of one to three bytes indicating the length of the field immediately after the type prefix and before the contents.
* If the field contains 0 to 192 bytes of data, the first byte defines the length of the contents, then that many bytes of data follow immediately after the length byte.
* If the field contains 193 to 12480 bytes of data, the first two bytes indicate the length of the field with the following formula:
```plaintext
193 + ((byte1 - 193) * 256) + byte2
```
* If the field contains 12481 to 918744 bytes of data, the first three bytes indicate the length of the field with the following formula:
```plaintext
12481 + ((byte1 - 241) * 65536) + (byte2 * 256) + byte3
```
* A length-prefixed field cannot contain more than 918744 bytes of data.
When decoding, you can tell from the value of the first length byte whether there are 0, 1, or 2 additional length bytes:
* If the first length byte has a value of 192 or less, then that’s the only length byte and it contains the exact length of the field contents in bytes.
* If the first length byte has a value of 193 to 240, then there are two length bytes.
* If the first length byte has a value of 241 to 254, then there are three length bytes.
### Canonical Field Order
[Section titled “Canonical Field Order”](#canonical-field-order)
All fields in a transaction are sorted in a specific order based first on the field’s type (specifically, a numeric “type code” assigned to each type), then on the field itself (a “field code”). (Think of it as sorting by family name, then given name, where the family name is the field’s type and the given name is the field itself.)
#### Type Codes
[Section titled “Type Codes”](#type-codes)
Each field type has an arbitrary type code, with lower codes sorting first. These codes are defined in [`SField.h`](https://github.com/Xahau/xahaud/blob/master/src/ripple/protocol/SField.h#L57-L74).
For example, [UInt32 has type code 2](https://github.com/Xahau/xahaud/blob/72e6005f562a8f0818bc94803d222ac9345e1e40/src/ripple/protocol/SField.h#L59), so all UInt32 fields come before all [Amount fields, which have type code 6](https://github.com/Xahau/xahaud/blob/72e6005f562a8f0818bc94803d222ac9345e1e40/src/ripple/protocol/SField.h#L63).
The definitions file lists the type codes for each type in the `TYPES` map.
#### Field Codes
[Section titled “Field Codes”](#field-codes)
Each field has a field code, which is used to sort fields that have the same type as one another, with lower codes sorting first. These fields are defined in [`SField.cpp`](https://github.com/Xahau/xahaud/blob/72e6005f562a8f0818bc94803d222ac9345e1e40/src/ripple/protocol/impl/SField.cpp#L72-L266).
For example, the `Account` field of a [Payment transaction](/docs/protocol-reference/transactions/transaction-types/payment) [has sort code 1](https://github.com/Xahau/xahaud/blob/72e6005f562a8f0818bc94803d222ac9345e1e40/src/ripple/protocol/impl/SField.cpp#L219), so it comes before the `Destination` field which [has sort code 3](https://github.com/Xahau/xahaud/blob/72e6005f562a8f0818bc94803d222ac9345e1e40/src/ripple/protocol/impl/SField.cpp#L221).
Field codes are reused for fields of different field types, but fields of the same type never have the same field code. When you combine the type code with the field code, you get the field’s unique Field ID.
### Type List
[Section titled “Type List”](#type-list)
Transaction instructions may contain fields of any of the following types:
| Type Name | Type Code | Bit Length | Length-prefixed? | Description |
| --------- | --------- | ---------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| AccountID | 8 | 160 | Yes | The unique identifier for an account. |
| Amount | 6 | 64 or 384 | No | An amount of XRP or tokens. The length of the field is 64 bits for XRP or 384 bits (64+160+160) for tokens. |
| Blob | 7 | Variable | Yes | Arbitrary binary data. One important such field is `TxnSignature`, the signature that authorizes a transaction. |
| Hash128 | 4 | 128 | No | A 128-bit arbitrary binary value. The only such field is `EmailHash`, which is intended to store the MD-5 hash of an account owner’s email for purposes of fetching a [Gravatar](https://www.gravatar.com/). |
| Hash160 | 17 | 160 | No | A 160-bit arbitrary binary value. This may define a currency code or issuer. |
| Hash256 | 5 | 256 | No | A 256-bit arbitrary binary value. This usually represents the “SHA-512Half” hash of a transaction, ledger version, or ledger data object. |
| PathSet | 18 | Variable | No | A set of possible payment paths for a cross-currency payment. |
| STArray | 15 | Variable | No | An array containing a variable number of members, which can be different types depending on the field. Two cases of this include memos and lists of signers used in multi-signing. |
| STIssue | 24 | 160 or 320 | No | An asset definition, XRP or a token, with no quantity. |
| STObject | 14 | Variable | No | An object containing one or more nested fields. |
| UInt8 | 16 | 8 | No | An 8-bit unsigned integer. |
| UInt16 | 1 | 16 | No | A 16-bit unsigned integer. The `TransactionType` is a special case of this type, with specific strings mapping to integer values. |
| UInt32 | 2 | 32 | No | A 32-bit unsigned integer. The `Flags` and `Sequence` fields on all transactions are examples of this type. |
In addition to all of the above field types, the following types may appear in other contexts, such as ledger objects and transaction metadata:
| Type Name | Type Code | Length-prefixed? | Description |
| ----------- | --------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Transaction | 10001 | No | A “high-level” type containing an entire transaction. |
| LedgerEntry | 10002 | No | A “high-level” type containing an entire ledger object. |
| Validation | 10003 | No | A “high-level” type used in peer-to-peer communications to represent a validation vote in the consensus process. |
| Metadata | 10004 | No | A “high-level” type containing metadata for one transaction. |
| UInt64 | 3 | No | A 64-bit unsigned integer. This type does not appear in transaction instructions, but several ledger objects use fields of this type. |
| Vector256 | 19 | Yes | This type does not appear in transaction instructions, but the Amendments ledger object’s `Amendments` field uses this to represent which amendments are currently enabled. |
#### AccountID Fields
[Section titled “AccountID Fields”](#accountid-fields)
Fields of this type contain the 160-bit identifier for an XRP Ledger account. In JSON, these fields are represented as \[base58]\[] XRP Ledger “addresses”, with additional checksum data so that typos are unlikely to result in valid addresses. (This encoding, sometimes called “Base58Check”, prevents accidentally sending money to the wrong address.) The binary format for these fields does not contain any checksum data nor does it include the `0x00` “type prefix” used in address base58 encoding. (However, since the binary format is used mostly for signed transactions, a typo or other error in transcribing a signed transaction would invalidate the signature, preventing it from sending money.)
AccountIDs that appear as stand-alone fields (such as `Account` and `Destination`) are length-prefixed despite being a fixed 160 bits in length. As a result, the length indicator for these fields is always the byte `0x14`. AccountIDs that appear as children of special fields (Amount `issuer` and PathSet `account`) are *not* length-prefixed.
#### Amount Fields
[Section titled “Amount Fields”](#amount-fields)
The “Amount” type is a special field type that represents an amount of currency, either XAH or a token. This type consists of two sub-types:
* XAH
XAH is serialized as a 64-bit unsigned integer (big-endian order), except that the most significant bit is always 0 to indicate that it’s XAH, and the second-most-significant bit is `1` to indicate that it is positive. Since the maximum amount of XAH (1017 drops) only requires 57 bits, you can calculate XAH serialized format by taking standard 64-bit unsigned integer and performing a bitwise-OR with `0x4000000000000000`.
* **Tokens**
Tokens consist of three segments in order:
1. 64 bits indicating the amount in the token amount format. The first bit is `1` to indicate that this is not XAH.
2. 160 bits indicating the currency code. The standard API converts 3-character codes such as “USD” into 160-bit codes using the standard currency code format, but custom 160-bit codes are also possible.
3. 160 bits indicating the issuer’s Account ID. (See also: Account Address Encoding)
You can tell which of the two sub-types it is based on the first bit: `0` for XAH; `1` for tokens.
The following diagram shows the serialization formats for both XAH amounts and token amounts:
include\_svg(“img/serialization-amount.svg”, ‘XAH amounts have a “not XAH” bit, a sign bit, and 62 bits of precision. Token amounts consist of a “not XRP” bit, a sign bit, an exponent (8 bits), significant digits (54 bits), currency code (160 bits), and issuer (160 bits).’)
**Token Amount Format**
[\[Source\]](https://github.com/Xahau/xahaud/blob/35fa20a110e3d43ffc1e9e664fc9017b6f2747ae/src/ripple/protocol/impl/STAmount.cpp)
include\_svg(“img/currency-number-format.svg”, “Token Amount Format diagram”)
Xahau uses 64 bits to serialize the numeric amount of a (fungible) token. (In JSON format, the numeric amount is the `value` field of a currency amount object.) In binary format, the numeric amount consists of a “not XAH” bit, a sign bit, significant digits, and an exponent, in order:
1. The first (most significant) bit for a token amount is `1` to indicate that it is not an XAH amount. (XAH amounts always have the most significant bit set to `0` to distinguish them from this format.)
2. The sign bit indicates whether the amount is positive or negative. Unlike standard [two’s complement](https://en.wikipedia.org/wiki/Two's_complement) integers, `1` indicates **positive** in Xahau format, and `0` indicates negative.
3. The next 8 bits represent the exponent as an unsigned integer. The exponent indicates the scale (what power of 10 the significant digits should be multiplied by) in the range -96 to +80 (inclusive). However, when serializing, we add 97 to the exponent to make it possible to serialize as an unsigned integer. Thus, a serialized value of `1` indicates an exponent of `-96`, a serialized value of `177` indicates an exponent of 80, and so on.
4. The remaining 54 bits represent the significant digits (sometimes called a *mantissa*) as an unsigned integer. When serializing, this value is normalized to the range 1015 (`1000000000000000`) to 1016-1 (`9999999999999999`) inclusive, except for the special case of the value 0. In the special case for 0, the sign bit, exponent, and significant digits are all zeroes, so the 64-bit value is serialized as `0x8000000000000000000000000000000000000000`.
The numeric amount is serialized alongside the currency code and issuer to form a full token amount.
**Currency Codes**
At a protocol level, currency codes in Xahau are arbitrary 160-bit values, except the following values have special meaning:
* The currency code `0x0000000000000000000000005852500000000000` is **always disallowed**. (This is the code “XAH” in the “standard format”.)
* The currency code `0x0000000000000000000000000000000000000000` (all zeroes) is **generally disallowed**. Usually, XAH amounts are not specified with currency codes. However, this code is used to indicate XAH in rare cases where a field must specify a currency code for XAH.
The `xahaud` APIs support a **standard format** for translating three-character ASCII codes to 160-bit hex values as follows:
include\_svg(“img/currency-code-format.svg”, “Standard Currency Code Format”)
1. The first 8 bits must be `0x00`.
2. The next 88 bits are reserved, and should be all `0`’s.
3. The next 24 bits represent 3 characters of ASCII. Ripple recommends using [ISO 4217](https://www.xe.com/iso4217.php) codes, or popular pseudo-ISO 4217 codes such as “BTC”. However, any combination of the following characters is permitted: all uppercase and lowercase letters, digits, as well as the symbols `?`, `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `<`, `>`, `(`, `)`, `{`, `}`, `[`, `]`, and `|`. The currency code XAH (all-uppercase) is reserved for XAH and cannot be used by tokens.
4. The next 40 bits are reserved and should be all `0`’s.
The **nonstandard format** is any 160 bits of data as long as the first 8 bits are not `0x00`.
#### Array Fields
[Section titled “Array Fields”](#array-fields)
Some transaction fields, such as `SignerEntries` (in [SignerListSet transactions](/docs/protocol-reference/transactions/transaction-types/signerlistset)) and `Memos`, are arrays of objects (called the “STArray” type).
Arrays contain several object fields in their native binary format in a specific order. In JSON, each array member is a JSON “wrapper” object with a single field, which is the name of the member object field. The value of that field is the (“inner”) object itself.
In the binary format, each member of the array has a Field ID prefix (based on the single key of the wrapper object) and contents (comprising the inner object, serialized as an object). To mark the end of an array, append an item with a “Field ID” of `0xf1` (the type code for array with field code of 1) and no contents.
The following example shows the serialization format for an array (the `SignerEntries` field):
include\_svg(“img/serialization-array.svg”, ‘Array field ID, followed by the Field ID and contents of each array element, followed by the “Array end” field ID’)
#### Blob Fields
[Section titled “Blob Fields”](#blob-fields)
The Blob type is a length-prefixed field with arbitrary data. Two common fields that use this type are `SigningPubKey` and `TxnSignature`, which contain (respectively) the public key and signature that authorize a transaction to be executed.
Blob fields have no further structure to their contents, so they consist of exactly the amount of bytes indicated in the variable-length encoding, after the Field ID and length prefixes.
#### Hash Fields
[Section titled “Hash Fields”](#hash-fields)
Xahau has several “hash” types: Hash128, Hash160, and Hash256. These fields contain arbitrary binary data of the given number of bits, which may or may not represent the result of a hash operation.
All such fields are serialized as the specific number of bits, with no length indicator, in big-endian byte order.
#### Issue Fields
[Section titled “Issue Fields”](#issue-fields)
Some fields specify a *type* of asset, which could be XAH or a fungible token, without an amount. These fields have consist of one or two 160-bit segments in order:
1. The first 160 bits are the currency code of the asset. For XAH, this is all 0’s.
2. If the first 160 bits are all 0’s (the asset is XAH), the field ends there. Otherwise, the asset is a token and the next 160 bits are the AccountID of the token issuer.
#### Object Fields
[Section titled “Object Fields”](#object-fields)
Some fields, such as `SignerEntry` (in [SignerListSet transactions](/docs/protocol-reference/transactions/transaction-types/signerlistset)), and `Memo` (in `Memos` arrays) are objects (called the “STObject” type). The serialization of objects is very similar to that of arrays, with one difference: **object members must be placed in canonical order** within the object field, where array fields have an explicit order already.
The canonical field order of object fields is the same as the canonical field order for all top-level fields, but the members of the object must be sorted within the object. After the last member, there is an “Object end” Field ID of `0xe1` with no contents.
The following example shows the serialization format for an object (a single `Memo` object in the `Memos` array).
include\_svg(“img/serialization-object.svg”, ‘Object field ID, followed by the Object ID and contents of each object member in canonical order, followed by the “Object end” field ID’)
#### PathSet Fields
[Section titled “PathSet Fields”](#pathset-fields)
The `Paths` field of a cross-currency [Payment transaction](/docs/protocol-reference/transactions/transaction-types/payment) is a “PathSet”, represented in JSON as an array of arrays. For more information on what paths are used for, see Paths.
A PathSet is serialized as **1 to 6** individual paths in sequence[\[Source\]](https://github.com/Xahau/xahaud/blob/4cff94f7a4a05302bdf1a248515379da99c5bcd4/src/ripple/app/tx/impl/Payment.h#L35-L36). Each complete path is followed by a byte that indicates what comes next:
* `0xff` indicates another path follows
* `0x00` indicates the end of the PathSet
Each path consists of **1 to 8** path steps in order[\[Source\]](https://github.com/Xahau/xahaud/blob/4cff94f7a4a05302bdf1a248515379da99c5bcd4/src/ripple/app/tx/impl/Payment.h#L38-L39). Each step starts with a **type** byte, followed by one or more fields describing the path step. The type indicates which fields are present in that path step through bitwise flags. (For example, the value `0x30` indicates changing both currency and issuer.) If more than one field is present, the fields are always placed in a specific order.
The following table describes the possible fields and the bitwise flags to set in the type byte to indicate them:
| Type Flag | Field Present | Field Type | Bit Size | Order |
| --------- | ------------- | ------------- | -------- | ----- |
| `0x01` | `account` | AccountID | 160 bits | 1st |
| `0x10` | `currency` | Currency Code | 160 bits | 2nd |
| `0x20` | `issuer` | AccountID | 160 bits | 3rd |
Some combinations are invalid; see Path Specifications for details.
The AccountIDs in the `account` and `issuer` fields are presented *without* a length prefix. When the `currency` is XRP, the currency code is represented as 160 bits of zeroes.
Each step is followed directly by the next step of the path. As described above, the last step of a path is followed by either `0xff` (if another path follows) or `0x00` (if this ends the last path).
The following example shows the serialization format for a PathSet:
include\_svg(“img/serialization-pathset.svg”, “PathSet is several paths each followed by a continue or end byte; each path is several path steps consisting of a type byte and one or more 160-bit fields based on the type byte”)
#### UInt Fields
[Section titled “UInt Fields”](#uint-fields)
Xahau has several unsigned integer types: UInt8, UInt16, UInt32, and UInt64. All of these are standard big-endian binary unsigned integers with the specified number of bits.
When representing these fields in JSON objects, most are represented as JSON numbers by default. One exception is UInt64, which is represented as a string because some JSON decoders may try to represent these integers as 64-bit “double precision” floating point numbers, which cannot represent all distinct UInt64 values with full precision.
Another special case is the `TransactionType` field. In JSON, this field is conventionally represented as a string with the name of the transaction type, but in binary, this field is a UInt16. The `TRANSACTION_TYPES` object in the definitions file maps these strings to specific numeric values.
# Data Types
Different types of objects are uniquely identified in different ways:
Accounts are identified by their Address, for example `"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59"`. Addresses always start with “r”. Many `rippled` methods also accept a hexadecimal representation.
Transactions are identified by a Hash of the transaction’s binary format. You can also identify a transaction by its sending account and Sequence Number.
Each closed Ledger has a Ledger Index and a Hash value. When \[Specifying Ledgers]\[] you can use either one.
### Addresses
[Section titled “Addresses”](#addresses)
### Hashes
[Section titled “Hashes”](#hashes)
#### Hash Prefixes
[Section titled “Hash Prefixes”](#hash-prefixes)
[\[Source\]](https://github.com/Xahau/xahaud/blob/master/src/ripple/protocol/HashPrefix.h)
In many cases, Xahau prefixes an object’s binary data with a 4-byte code before calculating its hash, so that objects of different types have different hashes even if their binary formats are the same. The existing 4-byte codes are structured as three alphabetic characters, encoded as ASCII, followed by a zero byte.
Some types of hash appear in API requests and responses. Others are only calculated as the first step of signing a certain type of data, or calculating a higher-level hash. The following table shows all 4-byte hash prefixes Xahau uses:
| Object Type | API Fields | Hash Prefix (Hex) | Hash Prefix (Text) |
| ------------------------------------- | -------------------------------- | ----------------- | ------------------ |
| Consensus proposal | N/A | `0x50525000` | `PRP\0` |
| Ledger Version | `ledger_hash` | `0x4C575200` | `LWR\0` |
| Ledger state data | `account_state` in ledger header | `0x4D4C4E00` | `MLN\0` |
| Ledger data inner node | N/A | `0x4D494E00` | `MIN\0` |
| Ledger data inner node (SHAMapv2) | N/A | `0x494E5200` | `INR\0` |
| Payment Channel Claim | N/A | `0x434C4D00` | `CLM\0` |
| Signed Transaction | `hash` of transactions | `0x54584E00` | `TXN\0` |
| Transaction with metadata | N/A | `0x534E4400` | `SND\0` |
| Unsigned Transaction (Single-signing) | N/A | `0x53545800` | `STX\0` |
| Unsigned Transaction (Multi-signing) | N/A | `0x534D5400` | `SMT\0` |
| Validation vote | N/A | `0x56414C00` | `VAL\0` |
| Validator manifest | N/A | `0x4D414E00` | `MAN\0` |
Ledger objects IDs are calculated in a similar way, but they use a 2-byte prefix called a “space key” instead of a prefix in the form described here.
### Account Sequence
[Section titled “Account Sequence”](#account-sequence)
### Ledger Index
[Section titled “Ledger Index”](#ledger-index)
#### Specifying Ledgers
[Section titled “Specifying Ledgers”](#specifying-ledgers)
Many API methods require you to specify an instance of the ledger, with the data retrieved being considered up-to-date as of that particular version of the shared ledger. The commands that accept a ledger version all work the same way. There are three ways you can specify which ledger you want to use:
1. Specify a ledger by its Ledger Index in the `ledger_index` parameter. Each closed ledger has a ledger index that is 1 higher than the previous ledger. (The very first ledger had ledger index 1.)
```plaintext
"ledger_index": 61546724
```
2. Specify a ledger by its Hash value in the `ledger_hash` parameter.
```plaintext
"ledger_hash": "8BB204CE37CFA7A021A16B5F6143400831C4D1779E6FE538D9AC561ABBF4A929"
```
3. Specify a ledger by one of the following shortcuts, in the `ledger_index` parameter:
* `validated` for the most recent ledger that has been validated by consensus
```plaintext
"ledger_index": "validated"
```
* `closed` for the most recent ledger that has been closed for modifications and proposed for validation
* `current` for the server’s current working version of the ledger.
There is also a deprecated `ledger` parameter which accepts any of the above three formats. *Do not* use this parameter; it may be removed without further notice.
If you do not specify a ledger, the server decides which ledger to use to serve the request. By default, the server chooses the `current` (in-progress) ledger. In Reporting Mode, the server uses the most recent validated ledger instead. Do not provide more than one field specifying ledgers.
**Note:** Do not rely on the default behavior for specifying a ledger; it is subject to change. Always specify a ledger version in the request if you can.
Reporting Mode does not record ledger data until it has been validated. If you make a request to a Reporting Mode server for the `current` or `closed` ledger, the server forwards the request to a P2P Mode server. If you request a ledger index or hash that is not validated, a Reporting Mode server responds with a `lgrNotFound` error.
### Specifying Currency Amounts
[Section titled “Specifying Currency Amounts”](#specifying-currency-amounts)
There are two kinds of currencies in Xahau: XAH and tokens. These two types of currencies are specified in different formats, with different precision and rounding behavior.
Some fields, such as the destination `Amount` of a [Payment transaction](/docs/protocol-reference/transactions/transaction-types/payment), can be either type. Some fields only accept XAH specifically, such as the `Fee` field (transaction cost).
XAH is specified as a string containing an integer number of “drops” of XAH, where 1 million drops equals 1 XAH. Tokens are instead specified as an object with fields for the decimal amount, currency code, and issuer. For example:
* **XAH** - To specify an `Amount` field with a value of 13.1 XAH:
```plaintext
"Amount": "13100000"
```
* **Token** - To specify an `Amount` field with a value of 13.1 FOO issued by or to `rf1B...`:
```plaintext
"Amount": {
"value": "13.1",
"currency": "FOO",
"issuer": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"
}
```
For more information, see Currency Formats.
### Specifying Time
[Section titled “Specifying Time”](#specifying-time)
The `xahaud` server and its APIs represent time as an unsigned integer. This number measures the number of seconds since the “Ripple Epoch” of January 1, 2000 (00:00 UTC). This is like the way the [Unix epoch](http://en.wikipedia.org/wiki/Unix_time) works, except the Ripple Epoch is 946684800 seconds after the Unix Epoch.
Don’t convert Ripple Epoch times to UNIX Epoch times in 32-bit variables: this could lead to integer overflows.
# Base 58 Encodings
Xahau APIs often use a “base58” encoding with a checksum (sometimes called “Base58Check”) to represent account addresses and other types of values related to cryptographic keys. This encoding is the same as [the one used for Bitcoin addresses](https://en.bitcoin.it/wiki/Base58Check_encoding), except that Xahau uses the following dictionary: `rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz`.
Xahau prefixes different types of values with a specific 8-bit number before encoding them to distinguish between different data types. With the arrangement of characters in Xahau’s base58 dictionary, the result is that the base58 representations for different types of encoded values start with specific letters by type.
The following table lists all the encodings Xahau uses:
| Data Type | Starts With | Type Prefix | Content size¹ | Maximum characters |
| ---------------------------------------- | ----------- | ----------- | ------------- | ------------------ |
| Account address | r | `0x00` | 20 bytes | 35 |
| Account public key | a | `0x23` | 33 bytes | 53 |
| Seed value (for secret keys) | s | `0x21` | 16 bytes | 29 |
| Validation public key or node public key | n | `0x1C` | 33 bytes | 53 |
¹ Content size excludes the 1-byte type prefix.
### See Also
[Section titled “See Also”](#see-also)
* Address Encoding - detailed information on address encoding
* Cryptographic Keys - types of cryptographic keys in Xahau and how they’re used
* \[wallet\_propose Reference]\[wallet\_propose method] - API method for generating account keys
* \[validation\_create Reference]\[validation\_create method] - API method for generating validator keys
# Currency Formats
Xahau has two kinds of digital asset: XAH and tokens. Both types have high precision, although their formats are different.
### Comparison
[Section titled “Comparison”](#comparison)
The following table summarizes some of the differences between XAH and tokens in Xahau:
| XAH | Tokens |
| ------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- |
| Has no issuer. | Always issued by a Xahau account. |
| Specified as a string. | Specified as an object. |
| Tracked in accounts. | Tracked in trust lines. |
| Can never be created; can only be destroyed. | Can be issued or redeemed freely. |
| Minimum value: `0`. (Cannot be negative.) | Minimum value: `-9999999999999999e80`. Minimum nonzero absolute value: `1000000000000000e-96`. |
| Maximum value `100000000000` (1011) XAH. That’s `100000000000000000` (1017) “drops”. | Maximum value `9999999999999999e80`. |
| Precise to the nearest “drop” (0.000001 XAH) | 15 decimal digits of precision. |
| Can’t be frozen. | The issuer can freeze balances. |
| No transfer fees; XAH-to-XAH payments are always direct. | Can take indirect paths with each issuer charging a percentage transfer fee. |
| Can be used in Payment Channels and Escrow. | Can be used with Payment Channels or Escrow. |
For more information, see What is XAH? and Tokens.
### Specifying Currency Amounts
[Section titled “Specifying Currency Amounts”](#specifying-currency-amounts)
Use the appropriate format for the type of currency you want to specify:
* XAH Amounts
* Token Amounts
#### XAH Amounts
[Section titled “XAH Amounts”](#xah-amounts)
To specify an amount of XAH, use a String Number indicating *drops* of XAH, where each drop is equal to 0.000001 XAH. For example, to specify 13.1 XAH:
```plaintext
"13100000"
```
**Do not specify XAH as an object.**
XAH amounts cannot be negative.
#### Token Amounts
[Section titled “Token Amounts”](#token-amounts)
To specify an amount of a (fungible) token, use an Amount object. This is a JSON object with three fields:
| `Field` | Type | Description |
| ---------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `currency` | String - Currency Code | Arbitrary currency code for the token. Cannot be XAH. |
| `value` | String Number | Quoted decimal representation of the amount of the token. This can include scientific notation, such as `1.23e11` meaning 123,000,000,000. Both `e` and `E` may be used. This can be negative when displaying balances, but negative values are disallowed in other contexts such as specifying how much to send. |
| `issuer` | String | Generally, the account that issues this token. In special cases, this can refer to the account that holds the token instead (for example, in a Clawback transaction). |
**Caution:** These field names are case-sensitive.
For example, to represent $153.75 US dollars issued by account `r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59`, you would specify:
```json
{
"currency": "USD",
"value": "153.75",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59"
}
```
#### Specifying Without Amounts
[Section titled “Specifying Without Amounts”](#specifying-without-amounts)
In some cases, you need to define an asset (which could be XAH or a token) without a specific amount, such as when defining an order book in the decentralized exchange.
To describe a token without an amount, specify it as a currency object, but omit the `value` field. For example:
```json
{
"currency": "TST",
"issuer": "rP9jPyP5kyvFRb6ZiRghAGw5u8SGAmU4bd"
}
```
To describe XAH without an amount, specify it as a JSON object with *only* a `currency` field. Never include an `issuer` field for XAH. For example:
```json
{
"currency": "XAH"
}
```
### String Numbers
[Section titled “String Numbers”](#string-numbers)
### XAH Precision
[Section titled “XAH Precision”](#xah-precision)
XAH has the same precision as a 64-bit unsigned integer where each unit is equivalent to 0.000001 XAH. It uses integer math, so that any amount less than a full drop is rounded down.
### Token Precision
[Section titled “Token Precision”](#token-precision)
Tokens can represent a wide variety of assets, including those typically measured in very small or very large denominations. This format uses significant digits and a power-of-ten exponent in a similar way to scientific notation. The format supports positive and negative significant digits and exponents within the specified range. Unlike typical floating-point representations of non-whole numbers, this format uses integer math for all calculations, so it always maintains 15 decimal digits of precision. Multiplication and division have adjustments to compensate for over-rounding in the least significant digits.
When sending token amounts in Xahau’s peer-to-peer network, servers serialize the amount to a 64-bit binary value.
**Tip:** For tokens that should not be divisible at all, see Non-Fungible Tokens (NFTs).
### Currency Codes
[Section titled “Currency Codes”](#currency-codes)
#### Standard Currency Codes
[Section titled “Standard Currency Codes”](#standard-currency-codes)
The standard format for currency codes is a three-character string such as `USD`. This is intended for use with [ISO 4217 Currency Codes](https://www.xe.com/iso4217.php). The following rules apply:
* Currency codes must be exactly 3 ASCII characters in length. The following characters are permitted: all uppercase and lowercase letters, digits, as well as the symbols `?`, `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `<`, `>`, `(`, `)`, `{`, `}`, `[`, `]`, and `|`.
* Currency codes are case-sensitive.
* The currency code XAH (all-uppercase) is disallowed. Real XAH typically does not use a currency code in Xahau’s protocol.
At the protocol level, this format is serialized into a 160-bit binary value starting with `0x00`.
#### Nonstandard Currency Codes
[Section titled “Nonstandard Currency Codes”](#nonstandard-currency-codes)
You can also use a 160-bit (40-character) hexadecimal string such as `015841551A748AD2C1F76FF6ECB0CCCD00000000` as the currency code. To prevent this from being treated as a “standard” currency code, the first 8 bits MUST NOT be `0x00`.
**Deprecated:** Some previous versions of [ripple-lib](https://github.com/XRPLF/xrpl.js) supported an “interest-bearing” or “demurraging” currency code type. These codes have the first 8 bits `0x01`. Demurraging / interest-bearing currencies are no longer supported, but you may find them in ledger data. For more information, see Demurrage.
# Ledger Data
Each ledger version in the XRP Ledger is made up of three parts:
* **Ledger Header**: Metadata about this ledger version itself.
* **Transaction Set**: All the transactions that were executed to create this ledger version.
* **State Data**: The complete record of objects representing accounts, settings, and balances as of this ledger version. (This is also called the “account state”.)
### State Data
[Section titled “State Data”](#state-data)
Each ledger version’s state data is a set of **ledger objects**, sometimes called *ledger entries*, which collectively represent all settings, balances, and relationships at a given point in time. To store or retrieve an object in the state data, the protocol uses that object’s unique [**Ledger Object ID**](/docs/protocol-reference/ledger-data/ledger-object-ids).
In the peer protocol, ledger objects have a [canonical binary format](/docs/protocol-reference/binary-format). In `xahaud` APIs, ledger objects are represented as JSON objects.
A ledger object’s data fields depend on the type of object; the Xahau Network supports the following types:
* [Ledger Header](/docs/protocol-reference/ledger-data/ledger-header)
* [Ledger Entry Common Fields](/docs/protocol-reference/ledger-data/ledger-object-ids)
* [Ledger Entry Types](/docs/protocol-reference/ledger-data/ledger-objects-types/)
### Expanded Ledgers
[Section titled “Expanded Ledgers”](#expanded-ledgers)
Xahau supports expanded ledgers, which allow for larger ledger sizes beyond the traditional limits. Expanded ledgers enable the network to handle increased transaction volumes and more complex state data while maintaining performance and consensus stability.
When expanded ledgers are enabled, the ledger can accommodate:
* More transactions per ledger
* Larger state data sets
* Increased complexity in Hook executions
Expanded ledgers are automatically used when the network determines they are necessary based on transaction volume and state size. No special configuration is required for nodes to participate in expanded ledgers.
# Ledger Header
[\[Source\]](https://github.com/ripple/rippled/blob/master/src/ripple/ledger/ReadView.h#L71)
Every ledger version has a unique header that describes the contents. You can look up a ledger’s header information with the \[ledger method]\[]. The contents of the ledger header are as follows:
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ----------------------- | --------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `ledger_index` | String | UInt32 | The \[ledger index]\[Ledger Index] of the ledger. Some API methods display this as a quoted integer; some display it as a native JSON number. |
| `ledger_hash` | String | Hash256 | The [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of this ledger version. This serves as a unique identifier for this ledger and all its contents. |
| `account_hash` | String | Hash256 | The [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of this ledger’s state tree information. |
| `close_time` | Number | UInt32 | The approximate time this ledger version closed, as the number of seconds since the Ripple Epoch of 2000-01-01 00:00:00. This value is rounded based on the `close_time_resolution`. |
| `closed` | Boolean | Boolean | If `true`, this ledger version is no longer accepting new transactions. (However, unless this ledger version is validated, it might be replaced by a different ledger version with a different set of transactions.) |
| `parent_hash` | String | Hash256 | The `ledger_hash` value of the previous ledger version that is the direct predecessor of this one. If there are different versions of the previous ledger index, this indicates from which one the ledger was derived. |
| `total_coins` | String | UInt64 | The total number of [drops of XAH](/docs/protocol-reference/data-types/#specifying-currency-amounts) owned by accounts in the ledger. This omits XAH that has been destroyed by transaction fees. The actual amount of XAH in circulation is lower because some accounts are “black holes” whose keys are not known by anyone. |
| `transaction_hash` | String | Hash256 | The [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of the transactions included in this ledger. |
| `close_time_resolution` | Number | Uint8 | An integer in the range \[2,120] indicating the maximum number of seconds by which the `close_time` could be rounded. |
| `closeFlags` | (Omitted) | UInt8 | A bit-map of flags relating to the closing of this ledger. |
### Ledger Index
[Section titled “Ledger Index”](#ledger-index)
### Close Flags
[Section titled “Close Flags”](#close-flags)
The ledger has only one flag defined for `closeFlags`: **`sLCF_NoConsensusTime`** (value `1`). If this flag is enabled, it means that validators had different close times for the ledger, but built otherwise the same ledger, so they declared consensus while “agreeing to disagree” on the close time. In this case, official `close_time` value of the ledger is 1 second after that of the parent ledger.
The `closeFlags` field is not included in any JSON representations of a ledger, but is included in the binary representation of a ledger, and is one of the fields that determine the ledger’s hash.
### See Also
[Section titled “See Also”](#see-also)
For ledger basics, see Ledgers.
# Ledger Object IDs
[\[Source\]](https://github.com/ripple/rippled/blob/master/src/ripple/protocol/impl/Indexes.cpp)
Each object in a ledger’s state data has a unique ID. The ID is derived by hashing important contents of the object, along with a [namespace identifier](https://github.com/ripple/rippled/blob/master/src/ripple/protocol/LedgerFormats.h#L99). The ledger object type determines which namespace identifier to use and which contents to include in the hash. This ensures every ID is unique. To calculate the hash, `xahaud` uses SHA-512 and then truncates the result to the first 256 bits. This algorithm, informally called **SHA-512Half**, provides an output that has comparable security to SHA-256, but runs faster on 64-bit processors.
Generally, a ledger object’s ID is returned as the `index` field in JSON, at the same level as the object’s contents. In transaction metadata, the ledger object’s ID in JSON is `LedgerIndex`.
**Tip:** The `index` or `LedgerIndex` field of an object in the ledger is the ledger object ID. This is not the same as a [ledger index](/docs/protocol-reference/data-types/#ledger-index).
include\_svg(“img/ledger-object-ids.svg”, “Diagram: xahaud uses SHA-512Half to generate IDs for ledger objects. The space key prevents IDs for different object types from colliding.”)
### Flags[](#flags)
[Section titled “Flags ”](#flags)
Flags are on/off settings, which are represented as binary values that are combined into a single number using bitwise-OR operations. The bit values for the flags in ledger entries are different than the values used to enable or disable those flags in a transaction. Ledger state flags have names that begin with **`lsf`**.
The possible values for the flags field vary based on the ledger entry type. Some ledger entry types have no flags defined. In these cases, the `Flags` field always has the value `0`.
### See Also
[Section titled “See Also”](#see-also)
* For more information how Xahau creates and uses hashes, see Hashes.
* For ledger basics, see Ledgers.
# Ledger Objects Types
## Ledger Entry Common Fields[](#ledger-entry-common-fields)
[Section titled “Ledger Entry Common Fields ”](#ledger-entry-common-fields)
[\[Source\]](https://github.com/Xahau/xahaud/blob/master/src/ripple/protocol/impl/LedgerFormats.cpp)
Every entry in a ledger’s state data has the same set of common fields, plus additional fields based on the ledger entry type. Field names are case-sensitive. The common fields for all ledger entries are:
| Field | JSON Type | Internal Type | Required? | Description |
| ------------------------ | --------- | ------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `index` or `LedgerIndex` | String | Hash256 | No | The unique ID for this ledger entry. In JSON, this field is represented with different names depending on the context and API method. (Note, even though this is specified as “optional” in the code, every ledger entry should have one unless it’s legacy data from very early in the XRP Ledger’s history.) |
| `LedgerEntryType` | String | UInt16 | Yes | The type of ledger entry. Valid ledger entry types include `AccountRoot`, `Offer`, `RippleState`, and others. |
| `Flags` | Number | UInt32 | Yes | Set of bit-flags for this ledger entry. |
| `Remarks` | Array | STArray | No | Array of remark objects to set, update, or delete (see Remarks Format) |
Caution
CautionIn JSON, the ledger entry ID is in the `index` or `LedgerIndex` field. This is not the same as a ledger index in the `ledger_index` field.
# AccountRoot
[\[Source\]](https://github.com/Xahau/xahaud/blob/264280edd79b7f764536e02459f33f66a59c0531/src/ripple/protocol/impl/LedgerFormats.cpp#L36-L60)
An `AccountRoot` ledger entry type describes a single account, its settings, and XAH balance.
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"AccountTxnID": "0D5FB50FA65C9FE1538FD7E398FFFE9D1908DFA4576D8D7A020040686F93C77D",
"AccountIndex": "59",
"Balance": "148446663",
"Domain": "6D64756F31332E636F6D",
"HookStateScale": 10,
"EmailHash": "98B4375E1D753E5B91627516F6D70977",
"Flags": 8388608,
"LedgerEntryType": "AccountRoot",
"MessageKey": "0000000000000000000000070000000300",
"OwnerCount": 3,
"PreviousTxnID": "0D5FB50FA65C9FE1538FD7E398FFFE9D1908DFA4576D8D7A020040686F93C77D",
"PreviousTxnLgrSeq": 14091160,
"Sequence": 336,
"TransferRate": 1004999999,
"index": "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8"
}
```
### Fields
[Section titled “Fields”](#fields)
An `AccountRoot` object has the following fields:
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ---------------------- | --------- | ------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Account` | String | AccountID | Yes | The identifying (classic) address of this account. |
| `Sequence` | Number | UInt32 | Yes | The sequence number of the next valid transaction for this account. |
| `Balance` | String | Amount | No | The account’s current \[XAH balance in drops]\[drops of XAH], represented as a string. |
| `OwnerCount` | Number | UInt32 | Yes | The number of objects this account owns in the ledger, which contributes to its owner reserve. |
| `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. |
| `AccountTxnID` | String | Hash256 | No | The identifying hash of the transaction most recently sent by this account. This field must be enabled to use the `AccountTxnID` transaction field. To enable it, send an AccountSet transaction with the `asfAccountTxnID` flag enabled. |
| `RegularKey` | String | AccountID | No | The address of a key pair that can be used to sign transactions for this account instead of the master key. Use a [SetRegularKey transaction](/docs/protocol-reference/transactions/transaction-types/setregularkey) to change this value. |
| `EmailHash` | String | Hash128 | No | The md5 hash of an email address. Clients can use this to look up an avatar through services such as [Gravatar](https://en.gravatar.com/). |
| `WalletLocator` | String | Hash256 | No | An arbitrary 256-bit value that users can set. |
| `WalletSize` | Number | UInt32 | No | Unused. (The code supports this field but there is no way to set it.) |
| `MessageKey` | String | Blob | No | A public key that may be used to send encrypted messages to this account. In JSON, uses hexadecimal. Must be exactly 33 bytes, with the first byte indicating the key type: `0x02` or `0x03` for secp256k1 keys, `0xED` for Ed25519 keys. |
| `TransferRate` | Number | UInt32 | No | A transfer fee to charge other users for sending currency issued by this account to each other. |
| `Domain` | String | Blob | No | A domain associated with this account. In JSON, this is the hexadecimal for the ASCII representation of the domain. [Cannot be more than 256 bytes in length.](https://github.com/Xahau/xahaud/blob/55dc7a252e08a0b02cd5aa39e9b4777af3eafe77/src/ripple/app/tx/impl/SetAccount.h#L34) |
| `TickSize` | Number | UInt8 | No | How many significant digits to use for exchange rates of Offers involving currencies issued by this address. Valid values are `3` to `15`, inclusive. *(Added by the \[TickSize amendment]\[].)* |
| `TicketCount` | Number | UInt32 | No | How many Tickets this account owns in the ledger. This is updated automatically to ensure that the account stays within the hard limit of 250 Tickets at a time. This field is omitted if the account has zero Tickets. *(Added by the \[TicketBatch amendment]\[].)* |
| `NFTokenMinter` | String | AccountID | No | Another account that can mint non-fungible tokens on behalf of this account. *(Added by the \[NonFungibleTokensV1\_1 amendment]\[])* |
| `MintedNFTokens` | Number | UInt32 | No | How many total non-fungible tokens have been minted by and on behalf of this account. *(Added by the \[NonFungibleTokensV1\_1 amendment]\[])* |
| `BurnedNFTokens` | Number | UInt32 | No | How many total of this account’s issued non-fungible tokens have been burned. This number is always equal or less than `MintedNFTokens`. |
| `HookStateCount` | Number | UInt32 | No | The number of states on the Hook. |
| `HookNamespaces` | Array | Vector256 | No | A unique value to prevent state conflicts between multiple Hooks installed on the same XAHL account. |
| `RewardLgrFirst` | Number | UInt32 | No | The ledger number of the last ClaimReward transaction. |
| `RewardLgrLast` | Number | UInt32 | No | The ledger sequence number of the last transaction in or out of your account. |
| `RewardTime` | Number | UInt32 | No | The ledger time the last reward was claimed. |
| `RewardAccumulator` | String | UInt64 | No | The area under of the balance-time graph for your account since last ClaimReward transaction. |
| `FirstNFTokenSequence` | Number | UInt32 | No | The account’s [Sequence Number](/docs/protocol-reference/data-types/#account-sequence) at the time it minted its first non-fungible-token. *(Added by the \[fixNFTokenRemint amendment]\[] :not\_enabled:)* |
| `ImportSequence` | Number | UInt32 | No | The current sequence number from the importing account on the XAHL Ledger. |
| `GovernanceFlags` | String | Hash256 | No | |
| `GovernanceMarks` | String | Hash256 | No | |
| `AccountIndex` | String | UInt64 | No | The account’s created index number. *(Added by the \[xahauGenesis amendment]\[] :enabled:)* |
| `TouchCount` | String | UInt64 | No | An incrementing counter for every time the ledger entry is “touched”. |
| `HookStateScale` | Number | UInt16 | No | Scale factor for determining when Hook state entries become stale. Valid values are `1` to `16` inclusive. *(Added by the [ExtendedHookState amendment](/docs/features/amendments/#extendedhookstate).)* |
### AccountRoot Flags
[Section titled “AccountRoot Flags”](#accountroot-flags)
There are several options which can be either enabled or disabled for an account. These options can be changed with an [AccountSet transaction](/docs/protocol-reference/transactions/transaction-types/accountset). In the ledger, flags are represented as binary values that can be combined with bitwise-or operations. The bit values for the flags in the ledger are different than the values used to enable or disable those flags in a transaction. Ledger flags have names that begin with **`lsf`**.
AccountRoot objects can have the following flag values:
| Flag Name | Hex Value | Decimal Value | Corresponding AccountSet Flag | Description |
| --------------------------------- | ------------ | ------------- | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `lsfDefaultRipple` | `0x00800000` | 8388608 | `asfDefaultRipple` | Enable rippling on this addresses’s trust lines by default. Required for issuing addresses; discouraged for others. |
| `lsfDepositAuth` | `0x01000000` | 16777216 | `asfDepositAuth` | This account has DepositAuth enabled, meaning it can only receive funds from transactions it sends, and from preauthorized accounts. *(Added by the [DepositAuth amendment](/docs/features/amendments/#depositauth))* |
| `lsfDisableMaster` | `0x00100000` | 1048576 | `asfDisableMaster` | Disallows use of the master key to sign transactions for this account. |
| `lsfDisallowIncomingCheck` | `0x08000000` | 134217728 | `asfDisallowIncomingCheck` | This account blocks incoming Checks. |
| `lsfDisallowIncomingNFTokenOffer` | `0x04000000` | 67108864 | `asfDisallowIncomingNFTokenOffer` | This account blocks incoming NFTokenOffers. |
| `lsfDisallowIncomingPayChan` | `0x10000000` | 268435456 | `asfDisallowIncomingPayChan` | This account blocks incoming Payment Channels. |
| `lsfDisallowIncomingTrustline` | `0x20000000` | 536870912 | `asfDisallowIncomingTrustline` | This account blocks incoming trust lines. |
| `lsfDisallowIncomingRemit` | `0x80000000` | 2147483648 | `asfDisallowIncomingRemit` | This account blocks incoming remit transactions. |
| `lsfDisallowXRP` | `0x00080000` | 524288 | `asfDisallowXRP` | Client applications should not send XAH to this account. (Advisory; not enforced by the protocol.) |
| `lsfGlobalFreeze` | `0x00400000` | 4194304 | `asfGlobalFreeze` | All assets issued by this account are frozen. |
| `lsfNoFreeze` | `0x00200000` | 2097152 | `asfNoFreeze` | This account cannot freeze trust lines connected to it. Once enabled, cannot be disabled. |
| `lsfPasswordSpent` | `0x00010000` | 65536 | (None) | This account has used its free SetRegularKey transaction. |
| `lsfRequireAuth` | `0x00040000` | 262144 | `asfRequireAuth` | This account must individually approve other users for those users to hold this account’s tokens. |
| `lsfRequireDestTag` | `0x00020000` | 131072 | `asfRequireDest` | Requires incoming payments to specify a Destination Tag. |
| `lsfTshCollect` | `0x02000000` | 33554432 | `asfTshCollect` | The TSH pays for the execution of their own Hook Chain. |
| `lsfURITokenIssuer` | `0x04000000` | 67108864 | `asfURITokenIssuer` | This account cannot be deleted after it has issued a URIToken. |
### AccountRoot ID Format
[Section titled “AccountRoot ID Format”](#accountroot-id-format)
The ID of an AccountRoot object is the [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of the following values, concatenated in order:
* The Account space key (`0x0061`)
* The AccountID of the account
# Amendments
[\[Source\]](https://github.com/ripple/rippled/blob/master/src/ripple/protocol/impl/LedgerFormats.cpp#L138-L144)
The `Amendments` object type contains a list of Amendments that are currently active. Each ledger version contains **at most one** `Amendments` object.
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"Majorities": [
{
"Majority": {
"Amendment": "1562511F573A19AE9BD103B5D6B9E01B3B46805AEC5D3C4805C902B514399146",
"CloseTime": 535589001
}
}
],
"Amendments": [
"42426C4D4F1009EE67080A9B7965B44656D7714D104A72F9B4369F97ABF044EE",
"4C97EBA926031A7CF7D7B36FDE3ED66DDA5421192D63DE53FFB46E43B9DC8373",
"6781F8368C4771B83E8B821D88F580202BCB4228075297B19E4FDC5233F1EFDC",
"740352F2412A9909880C23A559FCECEDA3BE2126FED62FC7660D628A06927F11"
],
"Flags": 0,
"LedgerEntryType": "Amendments",
"index": "7DB0788C020F02780A673DC74757F23823FA3014C1866E72CC4CD8B226CD6EF4"
}
```
### Fields
[Section titled “Fields”](#fields)
| Name | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ----------------- | --------- | ------------------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Amendments` | Array | Vector256 | No | Array of 256-bit amendment IDs for all currently enabled amendments. If omitted, there are no enabled amendments. |
| `Flags` | Number | UInt32 | Yes | A bit-map of boolean flags enabled for this object. Currently, the protocol defines no flags for `Amendments` objects. The value is always `0`. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0066`, mapped to the string `Amendments`, indicates that this object describes the status of amendments to Xahau. |
| `Majorities` | Array | STArray | No | Array of objects describing the status of amendments that have majority support but are not yet enabled. If omitted, there are no pending amendments with majority support. |
Each member of the `Majorities` field, if it is present, is an object with one field, `Majority`, whose contents are a nested object with the following fields:
| Name | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ----------- | --------- | ------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| `Amendment` | String | Hash256 | The Amendment ID of the pending amendment. |
| `CloseTime` | Number | UInt32 | The `close_time` field of the ledger version where this amendment most recently gained a majority. |
In the amendment process, a consensus of validators adds a new amendment to the `Majorities` field using an [EnableAmendment](/docs/protocol-reference/transactions/pseudo-transaction-types/enableamendment) pseudo-transaction with the `tfGotMajority` flag when 80% or more of validators support it. If support for a pending amendment goes below 80%, an [EnableAmendment](/docs/protocol-reference/transactions/pseudo-transaction-types/enableamendment) pseudo-transaction with the `tfLostMajority` flag removes the amendment from the `Majorities` array. If an amendment remains in the `Majorities` field for at least 2 weeks, an [EnableAmendment](/docs/protocol-reference/transactions/pseudo-transaction-types/enableamendment) pseudo-transaction with no flags removes it from `Majorities` and permanently adds it to the `Amendments` field.
**Note:** Technically, all transactions in a ledger are processed based on which amendments are enabled in the ledger version immediately before it. While applying transactions to a ledger version where an amendment becomes enabled, the rules don’t change mid-ledger. After the ledger is closed, the next ledger uses the new rules as defined by any new amendments that apply.
### Amendments ID Format
[Section titled “Amendments ID Format”](#amendments-id-format)
The `Amendments` object ID is the hash of the `Amendments` space key (`0x0066`) only. This means that the ID of the `Amendments` object in a ledger is always:
```plaintext
7DB0788C020F02780A673DC74757F23823FA3014C1866E72CC4CD8B226CD6EF4
```
(Don’t mix up the ID of the `Amendments` ledger object type with the Amendment ID of an individual amendment.)
# Check
[\[Source\]](https://github.com/ripple/rippled/blob/master/src/ripple/protocol/impl/LedgerFormats.cpp#L157-L170)
*(Added by the \[Checks amendment]\[].)*
A `Check` object describes a check, similar to a paper personal check, which can be cashed by its destination to get money from its sender. (The potential payment has already been approved by its sender, but no money moves until it is cashed. Unlike an Escrow, the money for a Check is not set aside, so cashing the Check could fail due to lack of funds.)
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"Account": "rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo",
"Destination": "rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy",
"DestinationNode": "0000000000000000",
"DestinationTag": 1,
"Expiration": 570113521,
"Flags": 0,
"InvoiceID": "46060241FABCF692D4D934BA2A6C4427CD4279083E38C77CBE642243E43BE291",
"LedgerEntryType": "Check",
"OwnerNode": "0000000000000000",
"PreviousTxnID": "5463C6E08862A1FAE5EDAC12D70ADB16546A1F674930521295BC082494B62924",
"PreviousTxnLgrSeq": 6,
"SendMax": "100000000",
"Sequence": 2,
"index": "49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0"
}
```
### Fields
[Section titled “Fields”](#fields)
A `Check` object has the following fields:
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ------------------- | ---------------- | ------------------------------------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Account` | String | Account | Yes | The sender of the Check. Cashing the Check debits this address’s balance. |
| `Destination` | String | Account | Yes | The intended recipient of the Check. Only this address can cash the Check, using a [CheckCash transaction](/docs/protocol-reference/transactions/transaction-types/checkcash). |
| `DestinationNode` | String | UInt64 | No | A hint indicating which page of the destination’s owner directory links to this object, in case the directory consists of multiple pages. |
| `DestinationTag` | Number | UInt32 | No | An arbitrary tag to further specify the destination for this Check, such as a hosted recipient at the destination address. |
| `Expiration` | Number | UInt32 | No | Indicates the time after which this Check is considered expired. See [Specifying Time](/docs/protocol-reference/data-types/#specifying-time) for details. |
| `Flags` | Number | UInt32 | Yes | A bit-map of boolean flags enabled for this object. Currently, the protocol defines no flags for `Check` objects. The value is always `0`. |
| `InvoiceID` | String | Hash256 | No | Arbitrary 256-bit hash provided by the sender as a specific reason or identifier for this Check. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0043`, mapped to the string `Check`, indicates that this object is a Check object. |
| `OwnerNode` | String | UInt64 | Yes | A hint indicating which page of the sender’s owner directory links to this object, in case the directory consists of multiple pages. **Note:** The object does not contain a direct link to the owner directory containing it, since that value can be derived from the `Account`. |
| `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. |
| `SendMax` | String or Object | Amount | Yes | The maximum amount of currency this Check can debit the sender. If the Check is successfully cashed, the destination is credited in the same currency for up to this amount. |
| `Sequence` | Number | UInt32 | Yes | The sequence number of the [CheckCreate transaction](/docs/protocol-reference/transactions/transaction-types/checkcreate) that created this check. |
| `SourceTag` | Number | UInt32 | No | An arbitrary tag to further specify the source for this Check, such as a hosted recipient at the sender’s address. |
### Check ID Format
[Section titled “Check ID Format”](#check-id-format)
The ID of a `Check` object is the [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of the following values, concatenated in order:
* The Check space key (`0x0043`)
* The AccountID of the sender of the [CheckCreate transaction](/docs/protocol-reference/transactions/transaction-types/checkcreate) that created the `Check` object
* The `Sequence` number of the [CheckCreate transaction](/docs/protocol-reference/transactions/transaction-types/checkcreate) that created the `Check` object. If the CheckCreate transaction used a Ticket, use the `TicketSequence` value instead.
# Cron
[\[Source\]](https://github.com/Xahau/xahaud/blob/dev/src/ripple/protocol/impl/LedgerFormats.cpp)
*(Added by the [Cron amendment](/docs/features/amendments/#cron).)*
A `Cron` object represents a scheduled Hook execution created by a [CronSet transaction](/docs/protocol-reference/transactions/transaction-types/cronset). The Cron engine automatically inserts pseudo-transactions of type `Cron` into the ledger when scheduled executions are due.
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"Owner": "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm",
"OwnerNode": "0000000000000000",
"StartTime": 816348759,
"RepeatCount": 3,
"DelaySeconds": 120,
"PreviousTxnID": "5463C6E08862A1FAE5EDAC12D70ADB16546A1F674930521295BC082494B62924",
"PreviousTxnLgrSeq": 6,
"LedgerEntryType": "Cron",
"index": "49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0"
}
```
### Fields
[Section titled “Fields”](#fields)
A `Cron` object has the following fields:
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ------------------- | --------- | ------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Owner` | String | AccountID | Yes | The account that owns the scheduled Hook execution. This is the account that will be invoked when the cron executes. |
| `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. **Note:** The object does not contain a direct link to the owner directory containing it, since that value can be derived from the `Owner`. |
| `StartTime` | Number | UInt32 | Yes | Ripple Epoch timestamp when the first execution should occur. Use `0` for immediate execution. See [Specifying Time](/docs/protocol-reference/data-types/#specifying-time) for details. |
| `RepeatCount` | Number | UInt32 | Yes | Number of times the cron should execute. Can be extended via subsequent [CronSet transactions](/docs/protocol-reference/transactions/transaction-types/cronset). Maximum 256 per transaction, but can be extended beyond this limit. |
| `DelaySeconds` | Number | UInt32 | Yes | Time interval in seconds between each execution. Maximum of 31,536,000 seconds (365 days). |
| `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. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0061`, mapped to the string `Cron`, indicates that this object is a Cron object. |
### Cron ID Format
[Section titled “Cron ID Format”](#cron-id-format)
The ID of a `Cron` object is the [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of the following values, concatenated in order:
* The Cron space key (`0x0076`)
* The timestamp of the `StartTime` field
* The randomized AccountID of the `Owner` field
### Execution Behavior
[Section titled “Execution Behavior”](#execution-behavior)
When a cron is ready to execute, the Cron engine inserts a pseudo-transaction of type `Cron` into the ledger. This pseudo-transaction contains an `Owner` field referencing the originating Hook account. The scheduled Hook will be invoked automatically at the specified intervals without requiring external triggers.
Hook developers must enable collect calls (`hsfCOLLECT` flag) on their Hooks, as the `Owner` constitutes a weak transactional stakeholder (TSH) when the Cron pseudo-transaction executes.
### Related Transactions
[Section titled “Related Transactions”](#related-transactions)
* [CronSet transaction](/docs/protocol-reference/transactions/transaction-types/cronset): Creates, updates, or deletes a Cron object
# Deposit Pre Auth
[\[Source\]](https://github.com/ripple/rippled/blob/master/src/ripple/protocol/impl/LedgerFormats.cpp#L172-L178)
A `DepositPreauth` object tracks a preauthorization from one account to another. [DepositPreauth transactions](/docs/protocol-reference/transactions/transaction-types/depositpreauth) create these objects.
This has no effect on the processing of transactions unless the account that provided the preauthorization requires Deposit Authorization. In that case, the account that was preauthorized can send payments and other transactions directly to the account that provided the preauthorization. Preauthorizations are one-directional and have no effect on payments going the opposite direction.
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"LedgerEntryType": "DepositPreauth",
"Account": "rsUiUMpnrgxQp24dJYZDhmV4bE3aBtQyt8",
"Authorize": "rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de",
"Flags": 0,
"OwnerNode": "0000000000000000",
"PreviousTxnID": "3E8964D5A86B3CD6B9ECB33310D4E073D64C865A5B866200AD2B7E29F8326702",
"PreviousTxnLgrSeq": 7,
"index": "4A255038CC3ADCC1A9C91509279B59908251728D0DAADB248FFE297D0F7E068C"
}
```
### Fields
[Section titled “Fields”](#fields)
A `DepositPreauth` object has the following fields:
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ------------------- | --------- | ------------------------------------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Account` | String | Account | Yes | The account that granted the preauthorization. (The destination of the preauthorized payments.) |
| `Authorize` | String | Account | Yes | The account that received the preauthorization. (The sender of the preauthorized payments.) |
| `Flags` | Number | UInt32 | Yes | A bit-map of boolean flags enabled for this object. Currently, the protocol defines no flags for `DepositPreauth` objects. The value is always `0`. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0070`, mapped to the string `DepositPreauth`, indicates that this is a DepositPreauth object. |
| `OwnerNode` | String | UInt64 | Yes | A hint indicating which page of the sender’s owner directory links to this object, in case the directory consists of multiple pages. **Note:** The object does not contain a direct link to the owner directory containing it, since that value can be derived from the `Account`. |
| `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. |
### DepositPreauth ID Format
[Section titled “DepositPreauth ID Format”](#depositpreauth-id-format)
The ID of a `DepositPreauth` object is the [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of the following values, concatenated in order:
* The DepositPreauth space key (`0x0070`)
* The AccountID of the owner of this object (the sender of the [DepositPreauth transaction](/docs/protocol-reference/transactions/transaction-types/depositpreauth) that created this object; in other words, the one that granted the preauthorization)
* The AccountID of the preauthorized account (the `Authorized` field of the [DepositPreauth transaction](/docs/protocol-reference/transactions/transaction-types/depositpreauth) that created this object; in other words, the one that received the preauthorization)
# Directory Node
[\[Source\]](https://github.com/ripple/rippled/blob/5d2d88209f1732a0f8d592012094e345cbe3e675/src/ripple/protocol/impl/LedgerFormats.cpp#L44)
The `DirectoryNode` object type provides a list of links to other objects in the ledger’s state tree. A single conceptual *Directory* takes the form of a doubly linked list, with one or more DirectoryNode objects each containing up to 32 IDs of other objects. The first object is called the root of the directory, and all objects other than the root object can be added or deleted as necessary.
There are two kinds of Directories:
* **Owner directories** list other objects owned by an account, such as `RippleState` (trust line) or `Offer` objects.
* **Offer directories** list the offers available in the decentralized exchange. A single Offer directory contains all the offers that have the same exchange rate for the same token (currency code and issuer).
### Example JSON
[Section titled “Example JSON”](#example-json)
*Offer Directory*
```json
{
"ExchangeRate": "4F069BA8FF484000",
"Flags": 0,
"Indexes": [
"AD7EAE148287EF12D213A251015F86E6D4BD34B3C4A0A1ED9A17198373F908AD"
],
"LedgerEntryType": "DirectoryNode",
"RootIndex": "1BBEF97EDE88D40CEE2ADE6FEF121166AFE80D99EBADB01A4F069BA8FF484000",
"TakerGetsCurrency": "0000000000000000000000000000000000000000",
"TakerGetsIssuer": "0000000000000000000000000000000000000000",
"TakerPaysCurrency": "0000000000000000000000004A50590000000000",
"TakerPaysIssuer": "5BBC0F22F61D9224A110650CFE21CC0C4BE13098",
"index": "1BBEF97EDE88D40CEE2ADE6FEF121166AFE80D99EBADB01A4F069BA8FF484000"
}
```
*Owner Directory*
```json
{
"Flags": 0,
"Indexes": [
"AD7EAE148287EF12D213A251015F86E6D4BD34B3C4A0A1ED9A17198373F908AD",
"E83BBB58949A8303DF07172B16FB8EFBA66B9191F3836EC27A4568ED5997BAC5"
],
"ReferenceCount": "1",
"LedgerEntryType": "DirectoryNode",
"Owner": "rpR95n1iFkTqpoy1e878f4Z1pVHVtWKMNQ",
"RootIndex": "193C591BF62482468422313F9D3274B5927CA80B4DD3707E42015DD609E39C94",
"index": "193C591BF62482468422313F9D3274B5927CA80B4DD3707E42015DD609E39C94"
}
```
### Fields
[Section titled “Fields”](#fields)
| Name | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ------------------- | --------- | ------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Owner` | String | AccountID | No | (Owner Directories only) The address of the account that owns the objects in this directory. |
| `TakerGetsCurrency` | String | Hash160 | No | (Offer Directories only) The currency code of the `TakerGets` amount from the offers in this directory. |
| `TakerGetsIssuer` | String | Hash160 | No | (Offer Directories only) The issuer of the `TakerGets` amount from the offers in this directory. |
| `TakerPaysCurrency` | String | Hash160 | No | (Offer Directories only) The currency code of the `TakerPays` amount from the offers in this directory. |
| `TakerPaysIssuer` | String | Hash160 | No | (Offer Directories only) The issuer of the `TakerPays` amount from the offers in this directory. |
| `ExchangeRate` | String | UInt64 | No | (Offer Directories only) **DEPRECATED**. Do not use. |
| `ReferenceCount` | String | UInt64 | No | Reference counting in the ledger reduces storage burden and fees by allowing multiple installations of the same Hook to point to the same object on the ledger, only removing it when no accounts have the Hook installed. |
| `Indexes` | Array | Vector256 | Yes | The contents of this Directory: an array of IDs of other objects. |
| `IndexNext` | Number | UInt64 | No | If this Directory consists of multiple pages, this ID links to the next object in the chain, wrapping around at the end. |
| `IndexPrevious` | Number | UInt64 | No | If this Directory consists of multiple pages, this ID links to the previous object in the chain, wrapping around at the beginning. |
| `NFTokenID` | String | Hash256 | No | Unused |
### Directory ID Formats
[Section titled “Directory ID Formats”](#directory-id-formats)
There are three different formulas for creating the ID of a DirectoryNode, depending on which of the following the DirectoryNode represents:
* The first page (also called the root) of an Owner Directory
* The first page of an Offer Directory
* Later pages of either type
**The first page of an Owner Directory** has an ID that is the [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of the following values, concatenated in order:
* The Owner Directory space key (`0x004F`)
* The AccountID from the `Owner` field.
**The first page of an Offer Directory** has a special ID: the higher 192 bits define the order book, and the remaining 64 bits define the exchange rate of the offers in that directory. (The ID is big-endian, so the book is in the more significant bits, which come first, and the quality is in the less significant bits which come last.)
This provides a way to iterate through an order book from best offers to worst. Specifically: the first 192 bits are the first 192 bits of the [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of the following values, concatenated in order:
* The Book Directory space key (`0x0042`)
* The 160-bit currency code from the `TakerPaysCurrency`
* The 160-bit currency code from the `TakerGetsCurrency`
* The AccountID from the `TakerPaysIssuer`
* The AccountID from the `TakerGetsIssuer`
The lower 64 bits of an Offer Directory’s ID represent the `TakerPays` amount divided by `TakerGets` amount from the offer(s) in that directory as a 64-bit number in Xahau’s internal amount format.
**If the DirectoryNode is not the first page in the Directory** (regardless of whether it is an Owner Directory or an Offer Directory), then it has an ID that is the [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of the following values, concatenated in order:
* The DirectoryNode space key (`0x0064`)
* The ID of the root DirectoryNode
* The page number of this object. (Since 0 is the root DirectoryNode, this value is an integer 1 or higher.)
# Emitted Txn
*(Added by the [Hooks amendment](/docs/features/amendments/#hooks).)*
An `EmittedTxn` object describes a transaction that has been emitted by a hook. The object contains all the fields of the original transaction, along with additional details about the emission.
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"Account": "rMPwD1b8dJUaqZHaBgEvFx4ENhtpPVvDsv",
"Amount": "999999",
"Destination": "rfCarbonVNTuXckX6x2qTMFmFSnm6dEWGX",
"DestinationTag": 0,
"EmitDetails": {
"EmitBurden": "1",
"EmitCallback": "rMPwD1b8dJUaqZHaBgEvFx4ENhtpPVvDsv",
"EmitGeneration": 1,
"EmitHookHash": "A9B5411F4A4368008B4736EEE47A34B0EFCBE74016B9B94CC6208FBC0BF5C0C2",
"EmitNonce": "6B2A27D6864903A479614581A79D18E8C8ADCE01E3440C6E993BE07298ADC2A4",
"EmitParentTxnID": "9763EB6B74AEF0F55F642243AD51F48490594434439002A6142E545E47318D56"
},
"Fee": "31",
"FirstLedgerSequence": 7186113,
"Flags": 2147483648,
"LastLedgerSequence": 7186117,
"Sequence": 0,
"SigningPubKey": "000000000000000000000000000000000000000000000000000000000000000000",
"SourceTag": 0,
"TransactionType": "Payment"
}
```
### Fields
[Section titled “Fields”](#fields)
An `EmittedTxn` object has the following fields:
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ----------------- | --------- | ------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `EmitDetails` | Object | Object | Yes | Contains details about the emission. This includes the generation of the emission, the burden of the emission, the callback address, the hash of the hook that emitted the transaction, the nonce of the emission, and the ID of the parent transaction. |
| `TransactionType` | String | UInt16 | Yes | The type of the transaction that was emitted. |
| `Account` | String | Account | Yes | The account that emitted the transaction. |
| `Fee` | String | Amount | Yes | The fee paid for the transaction. |
| `Sequence` | Number | UInt32 | Yes | The sequence number of the transaction. |
| `SigningPubKey` | String | Blob | Yes | The public key that signs the transaction. |
The `EmittedTxn` object also contains all the fields of the original transaction.
### EmitDetails Fields
[Section titled “EmitDetails Fields”](#emitdetails-fields)
An `EmitDetails` object has the following fields:
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ----------------- | --------- | ------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `EmitGeneration` | Number | UInt32 | Yes | This field keeps track of a chain of emitted transactions that in turn cause other transactions to be emitted. |
| `EmitBurden` | String | UInt64 | Yes | This field is a heuristic for detecting forkbombs. Fees are based on burden and will increase exponentially when a chain reaction is started to prevent the network becoming overun by self-reinforcing emitted transactions. |
| `EmitParentTxnID` | String | Hash256 | Yes | The Hook Execution that emitted the transaction is connected to the Originating Transaction. Therefore this field is always required for the efficient tracing of behaviour. |
| `EmitNonce` | String | Hash256 | Yes | Emitted Transactions would be identical with the same fields and therefore have identical transaction hashes if a nonce were not used. However every node on the network needs to agree on the nonce, so a special Hook API to produce a deterministic nonce is made available. |
| `EmitCallback` | String | AccountID | No | This field is used by xahld when it needs to intitate a callback, such that it knows which Hook and account to initate the callback on. Callbacks happen when an emitted transaction is accepted into a ledger. |
| `EmitHookHash` | String | Hash256 | Yes | The SHA512H of the Hook at the time it was executed. |
# Escrow
[\[Source\]](https://github.com/ripple/rippled/blob/c6b6d82a754fe449cc533e18659df483c10a5c98/src/ripple/protocol/impl/LedgerFormats.cpp#L90-L101)
*(Added by the \[Escrow amendment]\[].)*
The `Escrow` object type represents a held payment of XAH or IOU waiting to be executed or canceled. An [EscrowCreate transaction](/docs/protocol-reference/transactions/transaction-types/escrowcreate) creates an `Escrow` object in the ledger. A successful [EscrowFinish](/docs/protocol-reference/transactions/transaction-types/escrowfinish) or [EscrowCancel](/docs/protocol-reference/transactions/transaction-types/escrowcancel) transaction deletes the object.
If the `Escrow` object has a [*crypto-condition*](https://tools.ietf.org/html/draft-thomas-crypto-conditions-02), the payment can only succeed if an EscrowFinish transaction provides the corresponding *fulfillment* that satisfies the condition. (The only supported crypto-condition type is [PREIMAGE-SHA-256](https://tools.ietf.org/html/draft-thomas-crypto-conditions-02#section-8.1).) If the `Escrow` object has a `FinishAfter` time, the held payment can only execute after that time.
An `Escrow` object is associated with two addresses:
* The owner, who provides the XAH or IOU when creating the `Escrow` object. If the held payment is canceled, the XAH or IOU returns to the owner.
* The destination, where the XAH or IOU is paid when the held payment succeeds. The destination can be the same as the owner.
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Amount": "10000",
"CancelAfter": 545440232,
"Condition": "A0258020A82A88B2DF843A54F58772E4A3861866ECDB4157645DD9AE528C1D3AEEDABAB6810120",
"Destination": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"DestinationTag": 23480,
"FinishAfter": 545354132,
"Flags": 0,
"LedgerEntryType": "Escrow",
"OwnerNode": "0000000000000000",
"DestinationNode": "0000000000000000",
"PreviousTxnID": "C44F2EB84196B9AD820313DBEBA6316A15C9A2D35787579ED172B87A30131DA7",
"PreviousTxnLgrSeq": 28991004,
"SourceTag": 11747,
"index": "DC5F3851D8A1AB622F957761E5963BC5BD439D5C24AC6AD7AC4523F0640244AC"
}
```
### Fields
[Section titled “Fields”](#fields)
An `Escrow` object has the following fields:
| Name | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ------------------- | ---------------- | ------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Account` | String | AccountID | Yes | The address of the owner (sender) of this held payment. This is the account that provided the amount, and gets it back if the held payment is canceled. |
| `Amount` | String or Object | Amount | Yes | The amount to be delivered by the held payment. |
| `CancelAfter` | Number | UInt32 | No | The held payment can be canceled if and only if this field is present *and* the time it specifies has passed. Specifically, this is specified as [seconds since the Ripple Epoch](/docs/protocol-reference/data-types/#specifying-time) and it “has passed” if it’s earlier than the close time of the previous validated ledger. |
| `Condition` | String | Blob | No | A [PREIMAGE-SHA-256 crypto-condition](https://tools.ietf.org/html/draft-thomas-crypto-conditions-02#section-8.1), as hexadecimal. If present, the [EscrowFinish transaction](/docs/protocol-reference/transactions/transaction-types/escrowfinish) must contain a fulfillment that satisfies this condition. |
| `Destination` | String | AccountID | Yes | The destination address where the amount is paid if the held payment is successful. |
| `DestinationNode` | String | UInt64 | No | A hint indicating which page of the destination’s owner directory links to this object, in case the directory consists of multiple pages. Omitted on escrows created before enabling the \[fix1523 amendment]\[]. |
| `DestinationTag` | Number | UInt32 | No | An arbitrary tag to further specify the destination for this held payment, such as a hosted recipient at the destination address. |
| `FinishAfter` | Number | UInt32 | No | The time, in [seconds since the Ripple Epoch](/docs/protocol-reference/data-types/#specifying-time), after which this held payment can be finished. Any [EscrowFinish transaction](/docs/protocol-reference/transactions/transaction-types/escrowfinish) before this time fails. (Specifically, this is compared with the close time of the previous validated ledger.) |
| `Flags` | Number | UInt32 | Yes | A bit-map of boolean flags enabled for this object. Currently, the protocol defines no flags for `Escrow` objects. The value is always `0`. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0075`, mapped to the string `Escrow`, indicates that this object is an `Escrow` object. |
| `OwnerNode` | String | UInt64 | Yes | A hint indicating which page of the owner directory links to this object, in case the directory consists of multiple pages. **Note:** The object does not contain a direct link to the owner directory containing it, since that value can be derived from the `Account`. |
| `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. |
| `SourceTag` | Number | UInt32 | No | An arbitrary tag to further specify the source for this held payment, such as a hosted recipient at the owner’s address. |
| `TransferRate` | Number | UInt32 | No | |
### Escrow ID Format
[Section titled “Escrow ID Format”](#escrow-id-format)
The ID of an `Escrow` object is the [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of the following values, concatenated in order:
* The Escrow space key (`0x0075`)
* The AccountID of the sender of the [EscrowCreate transaction](/docs/protocol-reference/transactions/transaction-types/escrowcreate) that created the `Escrow` object
* The Sequence number of the [EscrowCreate transaction](/docs/protocol-reference/transactions/transaction-types/escrowcreate) that created the `Escrow` object If the EscrowCreate transaction used a Ticket, use the `TicketSequence` value instead.
# Fee Settings
[\[Source\]](https://github.com/ripple/rippled/blob/master/src/ripple/protocol/impl/LedgerFormats.cpp#L115-L120)
The `FeeSettings` object type contains the current base transaction cost and reserve amounts as determined by fee voting. Each ledger version contains **at most one** `FeeSettings` object.
### Example JSON
[Section titled “Example JSON”](#example-json)
Example `FeeSettings` object:
```json
{
"BaseFee": "000000000000000A",
"Flags": 0,
"LedgerEntryType": "FeeSettings",
"ReferenceFeeUnits": 10,
"ReserveBase": 20000000,
"ReserveIncrement": 5000000,
"XahauActivationLgrSeq": 0,
"NetworkID": 21337,
"AccountCount": 0,
"index": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A651"
}
```
### Fields
[Section titled “Fields”](#fields)
The `FeeSettings` object has the following fields:
| Name | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ----------------------- | --------- | ------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `BaseFee` | String | UInt64 | Yes | The transaction cost of the “reference transaction” in drops of XAH as hexadecimal. |
| `Flags` | Number | UInt32 | Yes | A bit-map of boolean flags enabled for this object. Currently, the protocol defines no flags for `FeeSettings` objects. The value is always `0`. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0073`, mapped to the string `FeeSettings`, indicates that this object contains the ledger’s fee settings. |
| `ReferenceFeeUnits` | Number | UInt32 | Yes | The `BaseFee` translated into “fee units”. |
| `ReserveBase` | Number | UInt32 | Yes | The base reserve for an account in Xahau, as drops of XAH. |
| `ReserveIncrement` | Number | UInt32 | Yes | The incremental owner reserve for owning objects, as drops of XAH. |
| `XahauActivationLgrSeq` | Number | UInt32 | No | The ledger index where Xahau genesis was activated. |
| `AccountCount` | Number | UInt32 | No | The number of accounts created on the Xahau network. |
| `NetworkID` | Number | UInt32 | No | The ID of the network |
**Warning:** The JSON format for this ledger object type is unusual. The `BaseFee`, `ReserveBase`, and `ReserveIncrement` indicate drops of XAH but ***not*** in the usual format for \[specifying XAH]\[Currency Amount].
If the *\[XAHFees amendment]\[]* is enabled, the `FeeSettings` object has these fields instead:
| Name | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ----------------------- | --------- | ------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `BaseFeeDrops` | String | Amount | Yes | The transaction cost of the “reference transaction” in drops of XAH. |
| `Flags` | Number | UInt32 | Yes | A bitmap of boolean flags enabled for this object. Currently, the protocol defines no flags for `FeeSettings` objects. The value is always `0`. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0073`, mapped to the string `FeeSettings`, indicates that this object contains the ledger’s fee settings. |
| `ReserveBaseDrops` | String | Amount | Yes | The base reserve for an account in the XAH Ledger, as drops of XAH. |
| `ReserveIncrementDrops` | String | Amount | Yes | The incremental owner reserve for owning objects, as drops of XAH. |
| `XahauActivationLgrSeq` | Number | UInt32 | No | The ledger index where Xahau genesis was activated. |
| `AccountCount` | Number | UInt32 | No | The number of accounts created on the Xahau network. |
| `NetworkID` | Number | UInt32 | No | |
### FeeSettings ID Format
[Section titled “FeeSettings ID Format”](#feesettings-id-format)
The `FeeSettings` object ID is the hash of the `FeeSettings` space key (`0x0065`) only. This means that the ID of the `FeeSettings` object in a ledger is always:
```plaintext
4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A651
```
# Hook
[\[Source\]](https://github.com/ripple/rippled/blob/master/src/ripple/protocol/impl/LedgerFormats.cpp#L157-L170)
*(Added by the [Hooks amendment](/docs/features/amendments/#hooks).)*
A `Hook` object describes a smart contract, which can be triggered by a transaction to perform predefined operations. The operations are defined by the `Hook` creator and can interact with the ledger and transactions.
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"Account": "rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo",
"OwnerNode": "0000000000000000",
"PreviousTxnID": "5463C6E08862A1FAE5EDAC12D70ADB16546A1F674930521295BC082494B62924",
"PreviousTxnLgrSeq": 6,
"Hooks": [
{
"HookHash": "46060241FABCF692D4D934BA2A6C4427CD4279083E38C77CBE642243E43BE291",
"HookParameters": []
}
],
"LedgerEntryType": "Hook",
"index": "49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0"
}
```
### Fields
[Section titled “Fields”](#fields)
A `Hook` object has the following fields:
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ------------------- | --------- | ------------------------------------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Account` | String | Account | Yes | The account that created the Hook. |
| `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](/docs/protocol-reference/data-types/#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`, `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
[Section titled “Hook Fields”](#hook-fields)
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. |
| `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. |
| `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
[Section titled “Hook ID Format”](#hook-id-format)
The ID of a `Hook` object is the [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of the following values, concatenated in order:
* The Hook space key (`0x0048`)
* The AccountID of the sender of the [SetHook transaction](/docs/protocol-reference/transactions/transaction-types/sethook) that created the `Hook` object
# Hook Definition
[\[Source\]](https://github.com/ripple/rippled/blob/master/src/ripple/protocol/impl/LedgerFormats.cpp#L157-L170)
*(Added by the [Hooks amendment](/docs/features/amendments/#hooks).)*
A `HookDefinition` object describes a hook, which is a piece of code that is executed in response to certain transactions. The hook can modify the transaction, emit new transactions, or perform other actions.
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"HookHash": "49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0",
"HookOn": "0000000000000000000000000000000000000000000000000000000000000000",
"HookCanEmit": "0000000000000000000000000000000000000000000000000000000000000000",
"HookNamespace": "0000000000000000000000000000000000000000000000000000000000000000",
"HookParameters": {
"HookParameter": {
"HookParameterName": "DEADBEEF",
"HookParameterValue": "DEADBEEF"
}
},
"HookApiVersion": 1,
"CreateCode": "5463C6E08862A1FAE5EDAC12D70ADB16546A1F674930521295BC082494B62924",
"HookSetTxnID": "0000000000000000",
"ReferenceCount": "6",
"Fee": "100000000",
"HookCallbackFee": "200000000",
"LedgerEntryType": "HookDefinition",
"index": "49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0"
}
```
### Fields
[Section titled “Fields”](#fields)
A `HookDefinition` object has the following fields:
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ----------------- | --------- | ------------------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `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. |
| `HookSetTxnID` | String | Hash256 | Yes | The ID of the transaction that set the hook. |
| `ReferenceCount` | String | UInt64 | Yes | The number of references to the hook. |
| `Fee` | String | Amount | Yes | The fee for executing the hook. |
| `HookCallbackFee` | String | Amount | No | The fee for executing the hook’s callback function. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0043`, mapped to the string `HookDefinition`, indicates that this object is a HookDefinition object. |
#### Hook Definition ID Format
[Section titled “Hook Definition ID Format”](#hook-definition-id-format)
The ID of a `HookDefinition` object is the [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of the following values, concatenated in order:
* The HookDefinition space key (`0x0044`)
* The `HookHash` of the hook
# Hook State
[\[Source\]](https://github.com/ripple/rippled/blob/master/src/ripple/protocol/impl/LedgerFormats.cpp#L157-L170)
*(Added by the [Hooks amendment](/docs/features/amendments/#hooks).)*
A `HookState` object describes the state of a hook, which is a piece of code running on Xahau that can interact with transactions. The `HookState` object stores the state of the hook, which can be modified by the hook’s code.
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"OwnerNode": "0000000000000000",
"HookStateKey": "49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0",
"HookStateData": "46060241FABCF692D4D934BA2A6C4427CD4279083E38C77CBE642243E43BE291",
"LedgerEntryType": "HookState",
"index": "5463C6E08862A1FAE5EDAC12D70ADB16546A1F674930521295BC082494B62924"
}
```
### Fields
[Section titled “Fields”](#fields)
A `HookState` object has the following fields:
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ----------------- | --------- | ------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `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. |
| `HookStateKey` | String | Hash256 | Yes | The key that uniquely identifies this hook state. |
| `HookStateData` | String | VL | Yes | The data stored by the hook. This can be any data that the hook’s code decides to store. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0043`, mapped to the string `HookState`, indicates that this object is a HookState object. |
#### HookState ID Format
[Section titled “HookState ID Format”](#hookstate-id-format)
[\[Source\]](https://github.com/ripple/rippled/blob/master/src/ripple/protocol/impl/Indexes.cpp#L193-L200)
The ID of a `HookState` object is the [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of the following values, concatenated in order:
* The HookState space key (`0x0076`)
* The AccountID of the account that owns the hook
* The `HookStateKey` of the `HookState` object
* The `HookNamespace` of the hook.
# Import VL Sequence
*(Added by the \[Import amendment]\[].)*
The `ImportVLSequence` helps track and validate the order of operations during the import process. It is used to ensure that the correct sequence of events occurs and to handle any discrepancies or updates to the dUNL on the “burning” ledger.
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"LedgerEntryType": "ImportVLSequence",
"Flags": 0,
"ImportSequence": 2023102101,
"PublicKey": "n9LigbVAi4pQc6pU2KJvQZV5wqJ8C3sVvZvBZUopchH8vqa6PEKy",
"index": "49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0"
}
```
### Fields
[Section titled “Fields”](#fields)
A `ImportVLSequence` object has the following fields:
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ----------------- | --------- | ------------------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------- |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0049`, mapped to the string `ImportVLSequence`, indicates that this object is a ImportVLSequence object. |
| `Flags` | Number | UInt32 | Yes | A bit-map of boolean flags. No flags are defined for the `ImportVLSequence` object type, so this value is always `0`. |
| `ImportSequence` | Number | UInt32 | Yes | The current sequence number of the dUNL list on the “burning” ledger. |
| `PublicKey` | String | Blob | Yes | The `PublicKey` of the dUNL list from the “burning” ledger. |
#### Import VL Sequence ID Format
[Section titled “Import VL Sequence ID Format”](#import-vl-sequence-id-format)
The ID of a `ImportVLSequence` object is the [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of the following values, concatenated in order:
* The Import VL Sequence space key (`0x0049`)
* The Public Key of the Import Validator List
# Ledger Hashes
[\[Source\]](https://github.com/ripple/rippled/blob/master/src/ripple/protocol/impl/LedgerFormats.cpp#L104-L108)
(Not to be confused with the \[“ledger hash” string data type]\[Hash], which uniquely identifies a ledger version. This section describes the `LedgerHashes` ledger object type.)
The `LedgerHashes` object type contains a history of prior ledgers that led up to this ledger version, in the form of their hashes. Objects of this ledger type are modified automatically when closing a ledger. (This is one of the only times a ledger’s state data is modified without a transaction or pseudo-transaction.) The `LedgerHashes` objects exist to make it possible to look up a previous ledger’s hash with only the current ledger version and at most one lookup of a previous ledger version.
There are two kinds of `LedgerHashes` object. Both types have the same fields. Each ledger version contains:
* Exactly one “recent history” `LedgerHashes` object
* A number of “previous history” `LedgerHashes` objects based on the current ledger index (that is, the length of the ledger history). Specifically, Xahau adds a new “previous history” object every 65536 ledger versions.
**Note:** As an exception, a new genesis ledger has no `LedgerHashes` objects at all, because it has no ledger history.
Example `LedgerHashes` object (trimmed for length):
```json
{
"LedgerEntryType": "LedgerHashes",
"Flags": 0,
"FirstLedgerSequence": 2,
"LastLedgerSequence": 33872029,
"Hashes": [
"D638208ADBD04CBB10DE7B645D3AB4BA31489379411A3A347151702B6401AA78",
"254D690864E418DDD9BCAC93F41B1F53B1AE693FC5FE667CE40205C322D1BE3B",
"A2B31D28905E2DEF926362822BC412B12ABF6942B73B72A32D46ED2ABB7ACCFA",
"AB4014846DF818A4B43D6B1686D0DE0644FE711577C5AB6F0B2A21CCEE280140",
"3383784E82A8BA45F4DD5EF4EE90A1B2D3B4571317DBAC37B859836ADDE644C1",
... (up to 256 ledger hashes) ...
],
"index": "B4979A36CDC7F3D3D5C31A4EAE2AC7D7209DDA877588B9AFC66799692AB0D66B"
}
```
A `LedgerHashes` object has the following fields:
| Name | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| --------------------- | ---------------- | ------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `FirstLedgerSequence` | Number | UInt32 | Yes | **DEPRECATED** Do not use. (The “recent hashes” object of the production Xahau has the value `2` in this field as a result of a previous `rippled` software. That value gets carried forward as the “recent hashes” object is updated. New “previous history” objects do not have this field, nor do “recent hashes” objects in parallel networks started with more recent versions of `rippled`.) |
| `Flags` | Number | UInt32 | Yes | A bit-map of boolean flags enabled for this object. Currently, the protocol defines no flags for `LedgerHashes` objects. The value is always `0`. |
| `Hashes` | Array of Strings | Vector256 | Yes | An array of up to 256 ledger hashes. The contents depend on which sub-type of `LedgerHashes` object this is. |
| `LastLedgerSequence` | Number | UInt32 | Yes | The [Ledger Index](/docs/protocol-reference/data-types/#ledger-index) of the last entry in this object’s `Hashes` array. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0068`, mapped to the string `LedgerHashes`, indicates that this object is a list of ledger hashes. |
### Recent History LedgerHashes
[Section titled “Recent History LedgerHashes”](#recent-history-ledgerhashes)
There is exactly one `LedgerHashes` object of the “recent history” sub-type in every ledger after the genesis ledger. This object contains the identifying hashes of the most recent 256 ledger versions (or fewer, if the ledger history has less than 256 ledgers total) in the `Hashes` array. Whenever a new ledger is closed, part of the process of closing it involves updating the “recent history” object with the hash of the previous ledger version this ledger version is derived from (also known as this ledger version’s *parent ledger*). When there are more than 256 hashes, the oldest one is removed.
Using the “recent history” `LedgerHashes` object of a given ledger, you can get the hash of any ledger index within the 256 ledger versions before the given ledger version.
### Previous History LedgerHashes
[Section titled “Previous History LedgerHashes”](#previous-history-ledgerhashes)
The “previous history” `LedgerHashes` entries collectively contain the hash of every 256th ledger version (also called “flag ledgers”) in the full history of the ledger. When the child of a flag ledger closes, the flag ledger’s hash is added to the `Hashes` array of the newest “previous history” `LedgerHashes` object. Every 65536 ledgers, `rippled` creates a new `LedgerHashes` object, so that each “previous history” object has the hashes of 256 flag ledgers.
**Note:** The oldest “previous history” `LedgerHashes` object contains only 255 entries because the genesis ledger has a ledger index of 1, not 0.
The “previous history” `LedgerHashes` objects act as a [skip list](https://en.wikipedia.org/wiki/Skip_list) so you can get the hash of any historical flag ledger from its index. From there, you can use that flag ledger’s “recent history” object to get the hash of any other ledger.
### LedgerHashes ID Formats
[Section titled “LedgerHashes ID Formats”](#ledgerhashes-id-formats)
There are two formats for `LedgerHashes` object IDs, depending on whether the object is a “recent history” sub-type or a “previous history” sub-type.
The **“recent history”** `LedgerHashes` object has an ID that is the [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of the `LedgerHashes` space key (`0x0073`). In other words, the “recent history” always has the ID `B4979A36CDC7F3D3D5C31A4EAE2AC7D7209DDA877588B9AFC66799692AB0D66B`.
The **“previous history”** `LedgerHashes` objects have an ID that is the [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of the following values, concatenated in order:
* The `LedgerHashes` space key (`0x0073`)
* The 32-bit [Ledger Index](/docs/protocol-reference/data-types/#ledger-index) of a flag ledger in the object’s `Hashes` array, divided by 65536.
**Tip:** Dividing by 65536 keeps the most significant 16 bits, which are the same for all the flag ledgers listed in a “previous history” object, and only those ledgers. You can use this fact to look up the `LedgerHashes` object that contains the hash of any flag ledger.
# Negative UNL
*(Added by the \[NegativeUNL amendment]\[].)*
The `NegativeUNL` object type contains the current status of the Negative UNL, a list of trusted validators currently believed to be offline.
Each ledger version contains **at most one** `NegativeUNL` object. If no validators are currently disabled or scheduled to be disabled, there is no `NegativeUNL` object in the ledger.
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"DisabledValidators": [
{
"DisabledValidator": {
"FirstLedgerSequence": 1609728,
"PublicKey": "ED6629D456285AE3613B285F65BBFF168D695BA3921F309949AFCD2CA7AFEC16FE"
}
}
],
"Flags": 0,
"LedgerEntryType": "NegativeUNL",
"index": "2E8A59AA9D3B5B186B0B9E0F62E6C02587CA74A4D778938E957B6357D364B244"
}
```
A `NegativeUNL` object has the following fields:
| Name | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| --------------------- | --------- | ------------------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------- |
| `DisabledValidators` | Array | Array | No | A list of `DisabledValidator` objects (see below), each representing a trusted validator that is currently disabled. |
| `Flags` | Number | UInt32 | Yes | A bit-map of boolean flags. No flags are defined for the NegativeUNL object type, so this value is always `0`. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x004E`, mapped to the string `NegativeUNL`, indicates that this object is the Negative UNL. |
| `ValidatorToDisable` | String | Blob | No | The public key of a trusted validator that is scheduled to be disabled in the next flag ledger. |
| `ValidatorToReEnable` | String | Blob | No | The public key of a trusted validator in the Negative UNL that is scheduled to be re-enabled in the next flag ledger. |
### DisabledValidator Objects
[Section titled “DisabledValidator Objects”](#disabledvalidator-objects)
Each `DisabledValidator` object represents one disabled validator. In JSON, a `DisabledValidator` object has one field, `DisabledValidator`, which in turn contains another object with the following fields:
| Name | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| --------------------- | --------- | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `FirstLedgerSequence` | Number | UInt32 | The [ledger index](/docs/protocol-reference/data-types/#ledger-index) when the validator was added to the Negative UNL. |
| `PublicKey` | String | Blob | The master public key of the validator, in hexadecimal. |
### NegativeUNL ID Format
[Section titled “NegativeUNL ID Format”](#negativeunl-id-format)
The `NegativeUNL` object ID is the hash of the `NegativeUNL` space key (`0x004E`) only. This means that the ID of the `NegativeUNL` object in a ledger is always:
```plaintext
2E8A59AA9D3B5B186B0B9E0F62E6C02587CA74A4D778938E957B6357D364B244
```
# Offer
[\[Source\]](https://github.com/ripple/rippled/blob/5d2d88209f1732a0f8d592012094e345cbe3e675/src/ripple/protocol/impl/LedgerFormats.cpp#L57)
The `Offer` ledger entry describes an Offer to exchange currencies in Xahau’s decentralized exchange. (In finance, this is more traditionally known as an *order*.) An [OfferCreate transaction](/docs/protocol-reference/transactions/transaction-types/offercreate) only creates an `Offer` entry in the ledger when the Offer cannot be fully executed immediately by consuming other Offers already in the ledger.
An Offer can become unfunded through other activities in the network while remaining in the ledger. When processing transactions, the network automatically prunes any unfunded Offers that those transactions come across. (Otherwise, unfunded Offers remain because *only* transactions can change the ledger state.)
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"Account": "rBqb89MRQJnMPq8wTwEbtz4kvxrEDfcYvt",
"BookDirectory": "ACC27DE91DBA86FC509069EAF4BC511D73128B780F2E54BF5E07A369E2446000",
"BookNode": "0000000000000000",
"Flags": 131072,
"LedgerEntryType": "Offer",
"OwnerNode": "0000000000000000",
"PreviousTxnID": "F0AB71E777B2DA54B86231E19B82554EF1F8211F92ECA473121C655BFC5329BF",
"PreviousTxnLgrSeq": 14524914,
"Sequence": 866,
"TakerGets": {
"currency": "XAG",
"issuer": "r9Dr5xwkeLegBeXq6ujinjSBLQzQ1zQGjH",
"value": "37"
},
"TakerPays": "79550000000",
"index": "96F76F27D8A327FC48753167EC04A46AA0E382E6F57F32FD12274144D00F1797"
}
```
### Fields
[Section titled “Fields”](#fields)
An `Offer` object has the following fields:
| Name | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ------------------- | ---------------- | ------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Account` | String | AccountID | Yes | The address of the account that owns this Offer. |
| `BookDirectory` | String | Hash256 | Yes | The ID of the Offer Directory that links to this Offer. |
| `BookNode` | String | UInt64 | Yes | A hint indicating which page of the offer directory links to this object, in case the directory consists of multiple pages. |
| `Expiration` | Number | UInt32 | No | Indicates the time after which this Offer is considered unfunded. See [Specifying Time](/docs/protocol-reference/data-types/#specifying-time) for details. |
| `Flags` | Number | UInt32 | Yes | A bit-map of boolean flags enabled for this offer. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x006F`, mapped to the string `Offer`, indicates that this object describes an Offer. |
| `OwnerNode` | String | UInt64 | Yes | A hint indicating which page of the owner directory links to this object, in case the directory consists of multiple pages. **Note:** The offer does not contain a direct link to the owner directory containing it, since that value can be derived from the `Account`. |
| `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. |
| `Sequence` | Number | UInt32 | Yes | The `Sequence` value of the [OfferCreate](/docs/protocol-reference/transactions/transaction-types/offercreate) transaction that created this `Offer` object. Used in combination with the `Account` to identify this Offer. |
| `TakerPays` | String or Object | Amount | Yes | The remaining amount and type of currency requested by the Offer creator. |
| `TakerGets` | String or Object | Amount | Yes | The remaining amount and type of currency being provided by the Offer creator. |
### Offer Flags
[Section titled “Offer Flags”](#offer-flags)
There are several options that can be either enabled or disabled when an [OfferCreate transaction](/docs/protocol-reference/transactions/transaction-types/offercreate) creates an offer object. In the ledger, flags are represented as binary values that can be combined with bitwise-or operations. The bit values for the flags in the ledger are different than the values used to enable or disable those flags in a transaction. Ledger flags have names that begin with **`lsf`**.
`Offer` objects can have the following flag values:
| | | | | |
| ------------ | ------------ | ------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Flag Name | Hex Value | Decimal Value | Corresponding OfferCreate Flag | Description |
| `lsfPassive` | `0x00010000` | 65536 | `tfPassive` | The object was placed as a passive Offer. This has no effect on the object in the ledger. |
| `lsfSell` | `0x00020000` | 131072 | `tfSell` | The object was placed as a sell Offer. This has no effect on the object in the ledger (because `tfSell` only matters if you get a better rate than you asked for, which cannot happen after the object enters the ledger). |
### Offer ID Format
[Section titled “Offer ID Format”](#offer-id-format)
The ID of an `Offer` object is the [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of the following values, concatenated in order:
* The Offer space key (`0x006F`)
* The AccountID of the account placing the Offer
* The Sequence number of the [OfferCreate transaction](/docs/protocol-reference/transactions/transaction-types/offercreate) that created the Offer.
If the OfferCreate transaction used a Ticket, use the `TicketSequence` value instead.
# 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
[Section titled “Example JSON”](#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
[Section titled “Fields”](#fields)
An `Oracle` object has the following fields:
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | 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
[Section titled “PriceData Object”](#pricedata-object)
Each entry in `PriceDataSeries` contains a `PriceData` object:
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | 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
[Section titled “Reserve”](#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
[Section titled “Oracle ID Format”](#oracle-id-format)
The ID of an `Oracle` object is the [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of the following values, concatenated in order:
* The Oracle space key (`0x0152`)
* The AccountID of the `Owner`
* The `OracleDocumentID` as a 32-bit unsigned integer
# Pay Channel
[\[Source\]](https://github.com/ripple/rippled/blob/c0a0b79d2d483b318ce1d82e526bd53df83a4a2c/src/ripple/protocol/impl/LedgerFormats.cpp#L180-L198)
*(Added by the \[PayChan amendment]\[].)*
The `PayChannel` object type represents a payment channel. Payment channels enable small, rapid off-ledger payments of XAH or IOU that can be later reconciled with the consensus ledger. A payment channel holds a balance of XAH or IOU that can only be paid out to a specific destination address until the channel is closed. Any unspent XAH or IOU is returned to the channel’s owner (the source address that created and funded it) when the channel closes.
The [PaymentChannelCreate transaction](/docs/protocol-reference/transactions/transaction-types/paymentchannelcreate) type creates a `PayChannel` object. The [PaymentChannelFund](/docs/protocol-reference/transactions/transaction-types/paymentchannelfund) and [PaymentChannelClaim transaction](/docs/protocol-reference/transactions/transaction-types/paymentchannelclaim) types modify existing `PayChannel` objects.
When a payment channel expires, at first it remains on the ledger, because only new transactions can modify ledger contents. Transaction processing automatically closes a payment channel when any transaction accesses it after the expiration. To close an expired channel and return the unspent XAH or IOU to the owner, some addresses must send a new PaymentChannelClaim or PaymentChannelFund transaction accessing the channel.
For an example of using payment channels, see the Payment Channels Tutorial.
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"Account": "rBqb89MRQJnMPq8wTwEbtz4kvxrEDfcYvt",
"Destination": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Amount": "4325800",
"Balance": "2323423",
"PublicKey": "32D2471DB72B27E3310F355BB33E339BF26F8392D5A93D3BC0FC3B566612DA0F0A",
"SettleDelay": 3600,
"Expiration": 536027313,
"CancelAfter": 536891313,
"SourceTag": 0,
"DestinationTag": 1002341,
"DestinationNode": "0000000000000000",
"Flags": 0,
"LedgerEntryType": "PayChannel",
"OwnerNode": "0000000000000000",
"PreviousTxnID": "F0AB71E777B2DA54B86231E19B82554EF1F8211F92ECA473121C655BFC5329BF",
"PreviousTxnLgrSeq": 14524914,
"index": "96F76F27D8A327FC48753167EC04A46AA0E382E6F57F32FD12274144D00F1797"
}
```
### Fields
[Section titled “Fields”](#fields)
A `PayChannel` object has the following fields:
| Name | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ------------------- | ---------------- | ------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Account` | String | AccountID | Yes | The source address that owns this payment channel. This comes from the sending address of the transaction that created the channel. |
| `Amount` | String or Object | Amount | Yes | Total amount, that has been allocated to this channel. This includes amounts that has been paid to the destination address. This is initially set by the transaction that created the channel and can be increased if the source address sends a PaymentChannelFund transaction. |
| `Balance` | String or Object | Amount | Yes | Total amount already paid out by the channel. The difference between this value and the `Amount` field is how much amount can still be paid to the destination address with PaymentChannelClaim transactions. If the channel closes, the remaining difference is returned to the source address. |
| `CancelAfter` | Number | UInt32 | No | The immutable expiration time for this payment channel, in [seconds since the Ripple Epoch](/docs/protocol-reference/data-types/#specifying-time). This channel is expired if this value is present and smaller than the previous ledger’s `close_time` field. This is optionally set by the transaction that created the channel, and cannot be changed. |
| `Destination` | String | AccountID | Yes | The destination address for this payment channel. While the payment channel is open, this address is the only one that can receive the amount from the channel. This comes from the `Destination` field of the transaction that created the channel. |
| `DestinationTag` | Number | UInt32 | No | An arbitrary tag to further specify the destination for this payment channel, such as a hosted recipient at the destination address. |
| `DestinationNode` | String | UInt64 | No | A hint indicating which page of the destination’s owner directory links to this object, in case the directory consists of multiple pages. Omitted on payment channels created before enabling the \[fixPayChanRecipientOwnerDir amendment]\[]. |
| `Expiration` | Number | UInt32 | No | The mutable expiration time for this payment channel, in [seconds since the Ripple Epoch](/docs/protocol-reference/data-types/#specifying-time). The channel is expired if this value is present and smaller than the previous ledger’s `close_time` field. See Setting Channel Expiration for more details. |
| `Flags` | Number | UInt32 | Yes | A bit-map of boolean flags enabled for this object. Currently, the protocol defines no flags for `PayChannel` objects. The value is always `0`. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0078`, mapped to the string `PayChannel`, indicates that this object is a payment channel object. |
| `OwnerNode` | String | UInt64 | Yes | A hint indicating which page of the source address’s owner directory links to this object, in case the directory consists of multiple pages. |
| `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. |
| `PublicKey` | String | Blob | Yes | Public key, in hexadecimal, of the key pair that can be used to sign claims against this channel. This can be any valid secp256k1 or Ed25519 public key. This is set by the transaction that created the channel and must match the public key used in claims against the channel. The channel source address can also send amounts from this channel to the destination without signed claims. |
| `SettleDelay` | Number | UInt32 | Yes | Number of seconds the source address must wait to close the channel if it still has any amount in it. Smaller values mean that the destination address has less time to redeem any outstanding claims after the source address requests to close the channel. Can be any value that fits in a 32-bit unsigned integer (0 to 2^32-1). This is set by the transaction that creates the channel. |
| `SourceTag` | Number | UInt32 | No | An arbitrary tag to further specify the source for this payment channel, such as a hosted recipient at the owner’s address. |
| `TransferRate` | Number | UInt32 | No | |
### Setting Channel Expiration
[Section titled “Setting Channel Expiration”](#setting-channel-expiration)
The `Expiration` field of a payment channel is the mutable expiration time, in contrast to the immutable expiration time represented by the `CancelAfter` field. The expiration of a channel is always considered relative to the `close_time` field of the previous ledger. The `Expiration` field is omitted when a `PayChannel` object is created. There are several ways the `Expiration` field of a `PayChannel` object can be updated, which can be summarized as follows: a channel’s source address can set the `Expiration` of the channel freely as long as the channel always remains open at least `SettleDelay` seconds after the first attempt to close it.
#### Source Address
[Section titled “Source Address”](#source-address)
The source address can set the `Expiration` directly with the PaymentChannelFund transaction type. The new value must not be earlier than whichever of the following values is earliest:
* The current `Expiration` value (if one is set)
* The previous ledger’s close time plus the `SettleDelay` of the channel
In other words, the source address can always make the `Expiration` later if an expiration is already set. The source can make an `Expiration` value earlier or set an `Expiration` if one isn’t currently set, as long as the new value is at least `SettleDelay` seconds in the future. If the source address attempts to set an invalid `Expiration` date, the transaction fails with the `temBAD_EXPIRATION` error code.
The source address can also set the `Expiration` with the `tfClose` flag of the PaymentChannelClaim transaction type. If the flag is enabled, the ledger automatically sets the `Expiration` to whichever of the following values is earlier:
* The current `Expiration` value (if one is set)
* The previous ledger’s close time plus the `SettleDelay` of the channel
The source address can remove the `Expiration` with the `tfRenew` flag of the PaymentChannelClaim transaction type.
#### Destination Address
[Section titled “Destination Address”](#destination-address)
The destination address cannot set the `Expiration` field. However, the destination address can use the PaymentChannelClaim’s `tfClose` flag to close a channel immediately.
#### Other Addresses
[Section titled “Other Addresses”](#other-addresses)
If any other address attempts to set an `Expiration` field, the transaction fails with the `tecNO_PERMISSION` error code. However, if the channel is already expired, the transaction causes the channel to close and results in `tesSUCCESS` instead.
### PayChannel ID Format
[Section titled “PayChannel ID Format”](#paychannel-id-format)
The ID of a `PayChannel` object is the [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of the following values, concatenated in order:
* The PayChannel space key (`0x0078`)
* The AccountID of the source account
* The AccountID of the destination account
* The Sequence number of the [PaymentChannelCreate transaction](/docs/protocol-reference/transactions/transaction-types/paymentchannelcreate) that created the channel If the PaymentChannelCreate transaction used a Ticket, use the `TicketSequence` value instead.
# Ripple State
[\[Source\]](https://github.com/ripple/rippled/blob/5d2d88209f1732a0f8d592012094e345cbe3e675/src/ripple/protocol/impl/LedgerFormats.cpp#L70)
The `RippleState` object type connects two accounts in a single currency. Conceptually, a `RippleState` object represents two trust lines between the accounts, one from each side. Each account can change the settings for its side of the `RippleState` object, but the balance is a single shared value. A trust line that is entirely in its default state is considered the same as a trust line that does not exist, so `rippled` deletes `RippleState` objects when their properties are entirely default.
### High vs. Low Account
[Section titled “High vs. Low Account”](#high-vs-low-account)
There can only be one `RippleState` object per currency for any given pair of accounts. Since no account is privileged in Xahau, a `RippleState` object sorts account addresses numerically, to ensure a canonical form. Whichever address is numerically lower when decoded is deemed the “low account” and the other is the “high account”. The net balance of the trust line is stored from the low account’s perspective.
The “issuer” for the balance in a trust line depends on whether the balance is positive or negative. If a `RippleState` object shows a positive balance, the high account is the issuer. If the balance is negative, the low account is the issuer. Often, the issuer has its limit set to 0 and the other account has a positive limit, but this is not reliable because limits can change without affecting an existing balance.
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-10"
},
"Flags": 393216,
"HighLimit": {
"currency": "USD",
"issuer": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"value": "110"
},
"HighNode": "0000000000000000",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "USD",
"issuer": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
"value": "0"
},
"LowNode": "0000000000000000",
"PreviousTxnID": "E3FE6EA3D48F0C2B639448020EA4F03D4F4F8FFDB243A852A0F59177921B4879",
"PreviousTxnLgrSeq": 14090896,
"LockCount": 1,
"LockedBalance": {
"currency": "USD",
"issuer": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
"value": "10"
},
"LowReward": {
"RewardLgrFirst": 1000000,
"RewardLgrLast": 1001234,
"RewardTime": 744000000,
"TrustLineRewardAccumulator": {
"currency": "USD",
"issuer": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
"value": "500"
}
},
"index": "9CA88CDEDFF9252B3DE183CE35B038F57282BC9503CDFA1923EF9A95DF0D6F7B"
}
```
### Fields
[Section titled “Fields”](#fields)
A `RippleState` object has the following fields:
| Name | JSON Type | Internal Type | Required? | Description |
| ------------------- | --------- | ------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Balance` | Object | Amount | Yes | The balance of the trust line, from the perspective of the low account. A negative balance indicates that the high account holds tokens issued by the low account. The issuer in this is always set to the neutral value ACCOUNT\_ONE. |
| `Flags` | Number | UInt32 | Yes | A bit-map of boolean options enabled for this object. |
| `HighLimit` | Object | Amount | Yes | The limit that the high account has set on the trust line. The `issuer` is the address of the high account that set this limit. |
| `HighNode` | String | UInt64 | Yes | (Omitted in some historical ledgers) A hint indicating which page of the high account’s owner directory links to this object, in case the directory consists of multiple pages. |
| `HighQualityIn` | Number | UInt32 | No | The inbound quality set by the high account, as an integer in the implied ratio `HighQualityIn`:1,000,000,000. As a special case, the value 0 is equivalent to 1 billion, or face value. |
| `HighQualityOut` | Number | UInt32 | No | The outbound quality set by the high account, as an integer in the implied ratio `HighQualityOut`:1,000,000,000. As a special case, the value 0 is equivalent to 1 billion, or face value. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0072`, mapped to the string `RippleState`, indicates that this object is a RippleState object. |
| `LowLimit` | Object | Amount | Yes | The limit that the low account has set on the trust line. The `issuer` is the address of the low account that set this limit. |
| `LowNode` | String | UInt64 | Yes | (Omitted in some historical ledgers) A hint indicating which page of the low account’s owner directory links to this object, in case the directory consists of multiple pages. |
| `LowQualityIn` | Number | UInt32 | No | The inbound quality set by the low account, as an integer in the implied ratio `LowQualityIn`:1,000,000,000. As a special case, the value 0 is equivalent to 1 billion, or face value. |
| `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. |
| `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
[Section titled “LowReward / HighReward Fields”](#lowreward--highreward-fields)
*(Added by the [IOURewardClaim amendment](/docs/features/amendments/#iourewardclaim).)*
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 |
| ---------------------------- | --------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `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. |
### RippleState Flags
[Section titled “RippleState Flags”](#ripplestate-flags)
There are several options which can be either enabled or disabled for a trust line. These options can be changed with a [TrustSet transaction](/docs/protocol-reference/transactions/transaction-types/trustset). In the ledger, flags are represented as binary values that can be combined with bitwise-or operations. The bit values for the flags in the ledger are different than the values used to enable or disable those flags in a transaction. Ledger flags have names that begin with **`lsf`**.
RippleState objects can have the following flag values:
| Flag Name | Hex Value | Decimal Value | Corresponding TrustSet Flag | Description |
| ------------------- | ------------ | ------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `lsfLowReserve` | `0x00010000` | 65536 | (None) | This RippleState object contributes to the low account’s owner reserve. |
| `lsfHighReserve` | `0x00020000` | 131072 | (None) | This RippleState object contributes to the high account’s owner reserve. |
| `lsfLowAuth` | `0x00040000` | 262144 | `tfSetAuth` | The low account has authorized the high account to hold tokens issued by the low account. |
| `lsfHighAuth` | `0x00080000` | 524288 | `tfSetAuth` | The high account has authorized the low account to hold tokens issued by the high account. |
| `lsfLowNoRipple` | `0x00100000` | 1048576 | `tfSetNoRipple` | The low account has disabled rippling from this trust line. |
| `lsfHighNoRipple` | `0x00200000` | 2097152 | `tfSetNoRipple` | The high account has disabled rippling from this trust line. |
| `lsfLowFreeze` | `0x00400000` | 4194304 | `tfSetFreeze` | The low account has frozen the trust line, preventing the high account from transferring the asset. |
| `lsfHighFreeze` | `0x00800000` | 8388608 | `tfSetFreeze` | The high account has frozen the trust line, preventing the low account from transferring the asset. |
| `lsfLowDeepFreeze` | `0x02000000` | 33554432 | `tfSetDeepFreeze` | The low account has deep-frozen the trust line, preventing the high account from sending and receiving the asset. *(Requires the [DeepFreeze amendment](/docs/features/amendments/#deepfreeze))* |
| `lsfHighDeepFreeze` | `0x04000000` | 67108864 | `tfSetDeepFreeze` | The high account has deep-frozen the trust line, preventing the low account from sending and receiving the asset. *(Requires the [DeepFreeze amendment](/docs/features/amendments/#deepfreeze))* |
### Contributing to the Owner Reserve
[Section titled “Contributing to the Owner Reserve”](#contributing-to-the-owner-reserve)
If an account modifies a trust line to put it in a non-default state, then that trust line counts towards the account’s owner reserve. In a RippleState object, the `lsfLowReserve` and `lsfHighReserve` flags indicate which account(s) are responsible for the owner reserve. The `rippled` server automatically sets these flags when it modifies a trust line.
The values that count towards a trust line’s non-default state are as follows:
| High account responsible if… | Low account responsible if… |
| ------------------------------------------------------- | ------------------------------------------------------ |
| `Balance` is negative (the high account holds currency) | `Balance` is positive (the low account holds currency) |
| `HighLimit` is not `0` | `LowLimit` is not `0` |
| `LowQualityIn` is not `0` and not `1000000000` | `HighQualityIn` is not `0` and not `1000000000` |
| `LowQualityOut` is not `0` and not `1000000000` | `HighQualityOut` is not `0` and not `1000000000` |
| `lsfHighNoRipple` flag is not in its default state | `lsfLowNoRipple` flag is not in its default state |
| `lsfHighFreeze` flag is enabled | `lsfLowFreeze` flag is enabled |
The **`lsfLowAuth`** and **`lsfHighAuth`** flags do not count against the default state, because they cannot be disabled.
The default state of the two No Ripple flags depends on the state of the `lsfDefaultRipple` flag in their corresponding AccountRoot objects. If Default Ripple is disabled (the default), then the default state of the `lsfNoRipple` flag is *enabled* for all of an account’s trust lines. If an account enables Default Ripple, then the `lsfNoRipple` flag is *disabled* (rippling is enabled) for an account’s trust lines by default.
**Note:** Prior to the introduction of the Default Ripple flag in `rippled` version 0.27.3 (March 10, 2015), the default state for all trust lines was with both No Ripple flags disabled (rippling enabled).
Fortunately, `rippled` uses lazy evaluation to calculate the owner reserve. This means that even if an account changes the default state of all its trust lines by changing the Default Ripple flag, that account’s reserve stays the same initially. If an account modifies a trust line, `rippled` re-evaluates whether that individual trust line is in its default state and should contribute to the owner reserve.
### RippleState ID Format
[Section titled “RippleState ID Format”](#ripplestate-id-format)
The ID of a RippleState object is the [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of the following values, concatenated in order:
* The RippleState space key (`0x0072`)
* The AccountID of the low account
* The AccountID of the high account
* The 160-bit currency code of the trust line(s)
# Signers List
[\[Source\]](https://github.com/ripple/rippled/blob/6d2e3da30696bd10e3bb11a5ff6d45d2c4dae90f/src/ripple/protocol/impl/LedgerFormats.cpp#L127)
*(Added by the [MultiSign amendment](/docs/features/amendments/#multisign).)*
The `SignerList` object type represents a list of parties that, as a group, are authorized to sign a transaction in place of an individual account. You can create, replace, or remove a signer list using a [SignerListSet transaction](/docs/protocol-reference/transactions/transaction-types/signerlistset).
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"Flags": 0,
"LedgerEntryType": "SignerList",
"OwnerNode": "0000000000000000",
"PreviousTxnID": "5904C0DC72C58A83AEFED2FFC5386356AA83FCA6A88C89D00646E51E687CDBE4",
"PreviousTxnLgrSeq": 16061435,
"SignerEntries": [
{
"SignerEntry": {
"Account": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
"SignerWeight": 2
}
},
{
"SignerEntry": {
"Account": "raKEEVSGnKSD9Zyvxu4z6Pqpm4ABH8FS6n",
"SignerWeight": 1
}
},
{
"SignerEntry": {
"Account": "rUpy3eEg8rqjqfUoLeBnZkscbKbFsKXC3v",
"SignerWeight": 1
}
}
],
"SignerListID": 0,
"SignerQuorum": 3,
"index": "A9C28A28B85CD533217F5C0A0C7767666B093FA58A0F2D80026FCC4CD932DDC7"
}
```
### Fields
[Section titled “Fields”](#fields)
A `SignerList` object has the following fields:
| Name | JSON Type | Internal Type | Required? | Description |
| ------------------- | --------- | ------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Flags` | Number | UInt32 | Yes | A bit-map of Boolean flags enabled for this signer list. For more information, see SignerList Flags. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0053`, mapped to the string `SignerList`, indicates that this object is a SignerList object. |
| `OwnerNode` | String | UInt64 | Yes | A hint indicating which page of the owner directory links to this object, in case the directory consists of multiple pages. |
| `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. |
| `SignerEntries` | Array | Array | Yes | An array of Signer Entry objects representing the parties who are part of this signer list. |
| `SignerListID` | Number | UInt32 | Yes | An ID for this signer list. Currently always set to `0`. If a future amendment allows multiple signer lists for an account, this may change. |
| `SignerQuorum` | Number | UInt32 | Yes | A target number for signer weights. To produce a valid signature for the owner of this SignerList, the signers must provide valid signatures whose weights sum to this value or more. |
The `SignerEntries` may be any combination of funded and unfunded addresses that use either secp256k1 or ed25519 keys.
#### Signer Entry Object
[Section titled “Signer Entry Object”](#signer-entry-object)
Each member of the `SignerEntries` field is an object that describes that signer in the list. A Signer Entry has the following fields:
| Name | JSON Type | Internal Type | Description |
| --------------- | --------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Account` | String | AccountID | A Xahau address whose signature contributes to the multi-signature. It does not need to be a funded address in the ledger. |
| `SignerWeight` | Number | UInt16 | The weight of a signature from this signer. A multi-signature is only valid if the sum weight of the signatures provided meets or exceeds the signer list’s `SignerQuorum` value. |
| `WalletLocator` | String | Hash256 | *(Optional)* Arbitrary hexadecimal data. This can be used to identify the signer or for other, related purposes. *(Added by the \[ExpandedSignerList amendment]\[].)* |
When processing a multi-signed transaction, the server looks up the `Account` values with respect to the ledger at the time of transaction execution. If the address *does not* correspond to a funded AccountRoot object, then only the master private key associated with that address can be used to produce a valid signature. If the account *does* exist in the ledger, then it depends on the state of that account. If the account has a Regular Key configured, the Regular Key can be used. The account’s master key can only be used if it is not disabled. A multi-signature cannot be used as part of another multi-signature.
### SignerList Flags
[Section titled “SignerList Flags”](#signerlist-flags)
*(Added by the \[MultiSignReserve amendment]\[].)*
SignerList objects can have the following flag value:
| Flag Name | Hex Value | Decimal Value | Description |
| ------------------ | ------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `lsfOneOwnerCount` | `0x00010000` | 65536 | If this flag is enabled, this SignerList counts as one item for purposes of the owner reserve. Otherwise, this list counts as N+2 items, where N is the number of signers it contains. This flag is automatically enabled if you add or update a signer list after the \[MultiSignReserve amendment]\[] is enabled. |
### Signer Lists and Reserves
[Section titled “Signer Lists and Reserves”](#signer-lists-and-reserves)
A signer list contributes to its owner’s reserve requirement.
The \[MultiSignReserve amendment]\[] (enabled 2019-04-17) made it so each signer list counts as one object, regardless of how many members it has. As a result, the owner reserve associated with a new signer list is 2 XAH.
A signer list created before the \[MultiSignReserve amendment]\[] itself counts as two objects, and each member of the list counts as one. As a result, the total owner reserve associated with the signer list is anywhere from 3 times to 10 times the reserve required by a single trust line (RippleState) or Offer object in the ledger. To update a signer list to use the new, reduced reserve, update the signer list by sending a [SignerListSet transaction](/docs/protocol-reference/transactions/transaction-types/signerlistset).
### SignerList ID Format
[Section titled “SignerList ID Format”](#signerlist-id-format)
The ID of a signer list object is the SHA-512Half of the following values, concatenated in order:
* The RippleState space key (`0x0053`)
* The AccountID of the owner of the signer list
* The `SignerListID` (currently always `0`)
# Ticket
[\[Source\]](https://github.com/ripple/rippled/blob/76a6956138c4ecd156c5c408f136ed3d6ab7d0c1/src/ripple/protocol/impl/LedgerFormats.cpp#L155-L164)
*(Added by the \[TicketBatch amendment]\[].)*
The `Ticket` object type represents a Ticket, which tracks an account \[sequence number]\[Sequence Number] that has been set aside for future use. You can create new tickets with a [TicketCreate transaction](/docs/protocol-reference/transactions/transaction-types/ticketcreate). \[New in: rippled 1.7.0]\[]
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"Account": "rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de",
"Flags": 0,
"LedgerEntryType": "Ticket",
"OwnerNode": "0000000000000000",
"PreviousTxnID": "F19AD4577212D3BEACA0F75FE1BA1644F2E854D46E8D62E9C95D18E9708CBFB1",
"PreviousTxnLgrSeq": 4,
"TicketSequence": 3
}
```
### Fields
[Section titled “Fields”](#fields)
A `Ticket` object has the following fields:
| Name | JSON Type | Internal Type | Required? | Description |
| ------------------- | --------- | ------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Account` | String | AccountID | Yes | The account that owns this Ticket. |
| `Flags` | Number | UInt32 | Yes | A bit-map of boolean flags enabled for this object. Currently, the protocol defines no flags for `Ticket` objects. The value is always `0`. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0054`, mapped to the string `Ticket`, indicates that this object is a Ticket object. |
| `OwnerNode` | String | UInt64 | Yes | A hint indicating which page of the owner directory links to this object, in case the directory consists of multiple pages. **Note:** The object does not contain a direct link to the owner directory containing it, since that value can be derived from the `Account`. |
| `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. |
| `TicketSequence` | Number | UInt32 | Yes | The [Sequence Number](/docs/protocol-reference/data-types/#account-sequence) this Ticket sets aside. |
### Ticket ID Format
[Section titled “Ticket ID Format”](#ticket-id-format)
The ID of a Ticket object is the SHA-512Half of the following values, concatenated in order:
* The Ticket space key (`0x0054`)
* The AccountID of the owner of the Ticket
* The `TicketSequence` number of the Ticket
# UNL Report
*(Added by the [Hooks amendment](/docs/features/amendments/#hooks).)*
A `UNLReport` object describes a report of the Unique Node List (UNL) which is a list of validator nodes that are trusted by the network to validate transactions.
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"LedgerEntryType": "UNLReport",
"PreviousTxnID": "5463C6E08862A1FAE5EDAC12D70ADB16546A1F674930521295BC082494B62924",
"PreviousTxnLgrSeq": 6,
"ImportVLKeys": [
{
"PublicKey": "n9LigbVAi4pQc6pU2KJvQZV5wqJ8C3sVvZvBZUopchH8vqa6PEKy",
"Account": "rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo"
}
],
"ActiveValidators": [
{
"PublicKey": "n9LigbVAi4pQc6pU2KJvQZV5wqJ8C3sVvZvBZUopchH8vqa6PEKy",
"Account": "rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo"
}
],
"index": "49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0"
}
```
### Fields
[Section titled “Fields”](#fields)
A `UNLReport` object has the following fields:
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ------------------- | --------- | ------------------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0073`, mapped to the string `UNLReport`, indicates that this object is a UNLReport object. |
| `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 that contains the transaction that most recently modified this object. |
| `ImportVLKeys` | Array | Array | No | An array of objects, each representing a validator key that has been imported. Each object has a `PublicKey` field and an optional `Account` field. |
| `ActiveValidators` | Array | Array | No | An array of objects, each representing an active validator. Each object has a `PublicKey` field and an optional `Account` field. |
### ImportVLKey Fields
[Section titled “ImportVLKey Fields”](#importvlkey-fields)
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ----------- | --------- | ------------------------------------------------------- | --------- | ------------------------------------------------------------------------------- |
| `PublicKey` | String | VL | Yes | The public key of the imported validator. |
| `Account` | String | Account | No | The account associated with the imported validator key. This field is optional. |
### ActiveValidator Fields
[Section titled “ActiveValidator Fields”](#activevalidator-fields)
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ----------- | --------- | ------------------------------------------------------- | --------- | ------------------------------------------------------------------------- |
| `PublicKey` | String | VL | Yes | The public key of the active validator. |
| `Account` | String | Account | No | The account associated with the active validator. This field is optional. |
### UNLReport ID Format
[Section titled “UNLReport ID Format”](#unlreport-id-format)
The `UNLReport` object ID is the hash of the `UNLReport` space key (`0x0052`) only. This means that the ID of the `UNLReport` object in a ledger is always:
```plaintext
61E32E7A24A238F1C619D5F9DDCC41A94B33B66C0163F7EFCC8A19C9FD6F28DC
```
# URIToken
[\[Source\]](https://github.com/ripple/rippled/blob/master/src/ripple/protocol/impl/LedgerFormats.cpp#L157-L170)
*(Added by the \[URI Token amendment]\[].)*
A `URIToken` object describes a URI token, which can be used to represent a unique resource identifier in the ledger.
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"Owner": "rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo",
"OwnerNode": "0000000000000000",
"Issuer": "rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy",
"URI": "DEADBEEF",
"Digest": "46060241FABCF692D4D934BA2A6C4427CD4279083E38C77CBE642243E43BE291",
"Amount": "100000000",
"Destination": "rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo",
"PreviousTxnID": "5463C6E08862A1FAE5EDAC12D70ADB16546A1F674930521295BC082494B62924",
"PreviousTxnLgrSeq": 6,
"LedgerEntryType": "URIToken",
"index": "49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0"
}
```
### Fields
[Section titled “Fields”](#fields)
A `URIToken` object has the following fields:
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ------------------- | ---------------- | ------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `Owner` | String | Account | Yes | The owner of the URI Token. |
| `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. |
| `Issuer` | String | Account | Yes | The issuer of the URI Token. |
| `URI` | String | VL | Yes | The URI represented by this token. |
| `Digest` | String | Hash256 | No | Arbitrary 256-bit hash provided by the owner as a specific identifier for this URI Token. |
| `Amount` | String or Object | Amount | No | The amount of the URI Token. |
| `Destination` | String | Account | No | The intended recipient of the URI Token. |
| `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 that contains the transaction that most recently modified this object. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0073`, mapped to the string `URIToken`, indicates that this object is a URI Token object. |
### URIToken Flags
[Section titled “URIToken Flags”](#uritoken-flags)
`URIToken` objects can have the following flag values:
| Flag Name | Hex Value | Decimal Value | Corresponding URITokenMint Flag | Description |
| ------------- | ------------ | ------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `lsfBurnable` | `0x00000001` | 1 | `tfBurnable` | The issuer (or an entity authorized by the issuer) to destroy the minted `URIToken`. (The `URIToken`’s owner can *always* do so.) |
### URIToken ID Format
[Section titled “URIToken ID Format”](#uritoken-id-format)
The ID of a `URIToken` object is the [SHA-512Half](/docs/protocol-reference/data-types/#hashes) of the following values, concatenated in order:
* The URI Token space key (`0x0055`)
* The AccountID of the issuer of the URI Token
* The URI represented by the URI Token
# Transactions
## Transaction Reference
[Section titled “Transaction Reference”](#transaction-reference)
A *Transaction* is the only way to cause changes in Xahau. Transactions’ outcomes are only final if signed, submitted, and accepted into a validated ledger version following the consensus process. Some ledger rules also generate *pseudo-transactions*, which aren’t signed or submitted, but still must be accepted by consensus. Transactions that fail are also included in ledgers because they modify balances of XAH to pay for the anti-spam \[transaction cost]\[].
# Pseudo Transaction Types
Pseudo-transactions are never submitted by users, nor propagated through the network. Instead, a server may choose to inject pseudo-transactions in a proposed ledger directly according to specific protocol rules. If enough servers propose the exact same pseudo-transaction, the consensus process approves it, and the pseudo-transaction is included in that ledger’s transaction data.
### Special Values for Common Fields
[Section titled “Special Values for Common Fields”](#special-values-for-common-fields)
Some of the required \[common fields]\[] for normal transactions do not make sense for pseudo-transactions. Pseudo-transactions use following special values for these common fields:
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Value |
| --------------- | --------- | ------------------------------------------------------- | ------------------- |
| `Account` | String | AccountID | ACCOUNT\_ZERO |
| `Fee` | String | Amount | `0` |
| `Sequence` | Number | UInt32 | `0` |
| `SigningPubKey` | String | Blob | `""` (Empty string) |
| `TxnSignature` | String | Blob | `""` (Empty string) |
Pseudo-transactions use the following common fields as normal:
* `TransactionType`
* `Flags`
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ----------------- | --------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `TransactionType` | String | UInt16 | *(Required)* The type of transaction. |
| `Flags` | Number | UInt32 | *(Optional)* A set of bit-flags for this transaction. The meaning of specific flags varies based on the transaction type. |
# Cron
> The Cron pseudo-transaction is automatically inserted by the Cron engine when a scheduled Hook execution is due.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/Cron.cpp)]
*(Added by the [Cron amendment](/docs/features/amendments/#cron).)*
The `Cron` pseudo-transaction is automatically inserted into the ledger by the Cron engine when a scheduled Hook execution is due. This pseudo-transaction triggers the execution of the Hook on the account specified in the `Owner` field.
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType": "Cron",
"Account": "rrrrrrrrrrrrrrrrrrrrrhoLvTp",
"Fee": "0",
"LedgerSequence": 21225473,
"Sequence": 0,
"SigningPubKey": "",
"TxnSignature": "",
"Owner": "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm"
}
```
### Fields
[Section titled “Fields”](#fields)
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ---------------- | --------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Owner` | String | AccountID | The account that owns the scheduled Hook execution. This is the account that will be invoked when the cron executes. |
| `LedgerSequence` | Number | UInt32 | The [ledger index](/docs/protocol-reference/data-types/#ledger-index) where this pseudo-transaction appears. This distinguishes the pseudo-transaction from other occurrences of the same change. |
### Common Fields
[Section titled “Common Fields”](#common-fields)
As a pseudo-transaction, `Cron` uses the standard pseudo-transaction values for common fields:
| Field | Value |
| --------------- | ---------------------------------------------- |
| `Account` | `rrrrrrrrrrrrrrrrrrrrrhoLvTp` (`ACCOUNT_ZERO`) |
| `Fee` | `0` |
| `Sequence` | `0` |
| `SigningPubKey` | `""` (empty string) |
| `TxnSignature` | `""` (empty string) |
### Execution Behavior
[Section titled “Execution Behavior”](#execution-behavior)
When a [Cron ledger object](/docs/protocol-reference/ledger-data/ledger-objects-types/cron) is ready to execute (based on its `StartTime`, `DelaySeconds`, and `RepeatCount` fields), the Cron engine automatically inserts a `Cron` pseudo-transaction into the ledger.
The pseudo-transaction contains an `Owner` field that references the account with the scheduled Hook. The Hook on that account will be invoked automatically, and the account is treated as a **weak transactional stakeholder (TSH)** during execution.
**Important:** Hook developers must enable collect calls (`hsfCOLLECT` flag) on their Hooks, as the `Owner` constitutes a weak transactional stakeholder when the Cron pseudo-transaction executes. The account must also have the `asfTshCollect` flag enabled.
### Related Documentation
[Section titled “Related Documentation”](#related-documentation)
* [CronSet transaction](/docs/protocol-reference/transactions/transaction-types/cronset): Creates, updates, or deletes scheduled Hook executions
* [Cron ledger object](/docs/protocol-reference/ledger-data/ledger-objects-types/cron): The ledger object that represents a scheduled Hook execution
* [Weak and Strong](/docs/hooks/concepts/weak-and-strong): Understanding transactional stakeholders
* [Collect Call Hooks](/docs/hooks/concepts/collect-call): How weak TSH Hooks are executed
# EmitFailure
TBD
# EnableAmendment
An `EnableAmendment` pseudo-transaction marks a change in the status of a proposed amendment when it:
* Gains supermajority approval from validators.
* Loses supermajority approval.
* Is enabled on Xahau protocol.
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"Account": "rrrrrrrrrrrrrrrrrrrrrhoLvTp",
"Amendment": "42426C4D4F1009EE67080A9B7965B44656D7714D104A72F9B4369F97ABF044EE",
"Fee": "0",
"LedgerSequence": 21225473,
"Sequence": 0,
"SigningPubKey": "",
"TransactionType": "EnableAmendment"
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ---------------- | --------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Amendment` | String | Hash256 | A unique identifier for the amendment. This is not intended to be a human-readable name. See Amendments for a list of known amendments. |
| `LedgerSequence` | Number | UInt32 | The [ledger index](/docs/protocol-reference/data-types/#ledger-index) where this pseudo-transaction appears. This distinguishes the pseudo-transaction from other occurrences of the same change. |
### EnableAmendment Flags
[Section titled “EnableAmendment Flags”](#enableamendment-flags)
The `Flags` value of the EnableAmendment pseudo-transaction indicates the status of the amendment at the time of the ledger including the pseudo-transaction.
A `Flags` value of `0` (no flags) or an omitted `Flags` field indicates that the amendment has been enabled, and applies to all ledgers afterward. Other `Flags` values are as follows:
| Flag Name | Hex Value | Decimal Value | Description |
| ---------------- | ------------ | ------------- | -------------------------------------------------------------------------------------------------------------- |
| `tfGotMajority` | `0x00010000` | 65536 | Support for this amendment increased to at least 80% of trusted validators starting with this ledger version. |
| `tfLostMajority` | `0x00020000` | 131072 | Support for this amendment decreased to less than 80% of trusted validators starting with this ledger version. |
# SetFee
A `SetFee` pseudo-transaction marks a change in transaction cost or reserve requirements as a result of Fee Voting.
**Note:** You cannot send a pseudo-transaction, but you may find one when processing ledgers.
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"Account": "rrrrrrrrrrrrrrrrrrrrrhoLvTp",
"BaseFee": "000000000000000A",
"Fee": "0",
"ReferenceFeeUnits": 10,
"ReserveBase": 20000000,
"ReserveIncrement": 5000000,
"Sequence": 0,
"SigningPubKey": "",
"TransactionType": "SetFee",
"date": 439578860,
"hash": "1C15FEA3E1D50F96B6598607FC773FF1F6E0125F30160144BE0C5CBC52F5151B",
"ledger_index": 3721729,
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ------------------- | ---------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `BaseFee` | String | UInt64 | The charge, in drops of XAH, for the reference transaction, as hex. (This is the transaction cost before scaling for load.) |
| `ReferenceFeeUnits` | Unsigned Integer | UInt32 | The cost, in fee units, of the reference transaction |
| `ReserveBase` | Unsigned Integer | UInt32 | The base reserve, in drops |
| `ReserveIncrement` | Unsigned Integer | UInt32 | The incremental reserve, in drops |
| `LedgerSequence` | Number | UInt32 | *(Omitted for some historical `SetFee` pseudo-transactions)* The index of the ledger version where this pseudo-transaction appears. This distinguishes the pseudo-transaction from other occurrences of the same change. |
If the *\[XAHFees amendment]\[]* is enabled, `SetFee` pseudo-transactions use these fields instead:
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ----------------------- | --------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `BaseFeeDrops` | String | Amount | The charge, in drops of XAH, for the reference transaction. (This is the transaction cost before scaling for load.) |
| `ReserveBaseDrops` | String | Amount | The base reserve, in drops |
| `ReserveIncrementDrops` | String | Amount | The incremental reserve, in drops |
| `LedgerSequence` | Number | UInt32 | *(Omitted for some historical `SetFee` pseudo-transactions)* The index of the ledger version where this pseudo-transaction appears. This distinguishes the pseudo-transaction from other occurrences of the same change. |
# UNLModify
*(Added by the \[NegativeUNL amendment]\[].)*
A `UNLModify` pseudo-transaction marks a change to the Negative UNL, indicating that a trusted validator has gone offline or come back online.
**Note:** You cannot send a pseudo-transaction, but you may find one when processing ledgers.
### Example JSON
[Section titled “Example JSON”](#example-json)
```json
{
"Account": "",
"Fee": "0",
"LedgerSequence": 1600000,
"Sequence": 0,
"SigningPubKey": "",
"TransactionType": "UNLModify",
"UNLModifyDisabling": 1,
"UNLModifyValidator": "ED6629D456285AE3613B285F65BBFF168D695BA3921F309949AFCD2CA7AFEC16FE",
}
```
| Name | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| -------------------- | --------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `TransactionType` | String | UInt16 | The value `0x0066`, mapped to the string `UNLModify`, indicates that this object is an `UNLModify` pseudo-transaction. |
| `LedgerSequence` | Number | UInt32 | The [ledger index](/docs/protocol-reference/data-types/#ledger-index) where this pseudo-transaction appears. This distinguishes the pseudo-transaction from other occurrences of the same change. |
| `UNLModifyDisabling` | Number | UInt8 | If `1`, this change represents adding a validator to the Negative UNL. If `0`, this change represents removing a validator from the Negative UNL. (No other values are allowed.) |
| `UNLModifyValidator` | String | Blob | The validator to add or remove, as identified by its master public key. |
# UNLReport
TBD
# Transaction Common Fields
Every transaction has the same set of common fields, plus additional fields based on the transaction type. Field names are case-sensitive. The common fields for all transactions are:
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| -------------------- | ---------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Account` | String | AccountID | *(Required)* The unique address of the account that initiated the transaction. |
| `TransactionType` | String | UInt16 | *(Required)* The type of transaction. Valid transaction types include: `Payment`, `OfferCreate`, `TrustSet`, and many others. |
| `Fee` | String | Amount | *(Required; auto-fillable)* Integer amount of XAH, in drops, to be destroyed as a cost for distributing this transaction to the network. Some transaction types have different minimum requirements. See \[Transaction Cost]\[] for details. |
| `Sequence` | Number | UInt32 | *(Required; auto-fillable)* The sequence number of the account sending the transaction. A transaction is only valid if the `Sequence` number is exactly 1 greater than the previous transaction from the same account. The special case `0` means the transaction is using a Ticket instead *(Added by the \[TicketBatch amendment]\[].)*. |
| `AccountTxnID` | String | Hash256 | *(Optional)* Hash value identifying another transaction. If provided, this transaction is only valid if the sending account’s previously-sent transaction matches the provided hash. |
| `Flags` | Number | UInt32 | *(Optional)* Set of bit-flags for this transaction. |
| `LastLedgerSequence` | Number | UInt32 | *(Optional; strongly recommended)* Highest ledger index this transaction can appear in. Specifying this field places a strict upper limit on how long the transaction can wait to be validated or rejected. See Reliable Transaction Submission for more details. |
| `Memos` | Array of Objects | Array | *(Optional)* Additional arbitrary information used to identify this transaction. |
| `NetworkID` | Number | UInt32 | *(Network-specific)* The network ID of the chain this transaction is intended for. **MUST BE OMITTED** for Mainnet and some test networks. **REQUIRED** on chains whose network ID is 1025 or higher. |
| `Signers` | Array | Array | *(Optional)* Array of objects that represent a multi-signature which authorizes this transaction. |
| `SourceTag` | Number | UInt32 | *(Optional)* Arbitrary integer used to identify the reason for this payment, or a sender on whose behalf this transaction is made. Conventionally, a refund should specify the initial payment’s `SourceTag` as the refund payment’s `DestinationTag`. |
| `SigningPubKey` | String | Blob | *(Automatically added when signing)* Hex representation of the public key that corresponds to the private key used to sign this transaction. If an empty string, indicates a multi-signature is present in the `Signers` field instead. |
| `TicketSequence` | Number | UInt32 | *(Optional)* The sequence number of the ticket to use in place of a `Sequence` number. If this is provided, `Sequence` must be `0`. Cannot be used with `AccountTxnID`. |
| `TxnSignature` | String | Blob | *(Automatically added when signing)* The signature that verifies this transaction as originating from the account it says it is from. |
| `EmitDetails` | Object | Object | Contains details about the emission. This includes the generation of the emission, the burden of the emission, the callback address, the hash of the hook that emitted the transaction, the nonce of the emission, and the ID of the parent transaction. |
| `HookParameters` | Array | Array | The hook parameters of the tx. |
\[Removed in: rippled 0.28.0]\[]: The `PreviousTxnID` field of transactions was replaced by the `AccountTxnID` field. This String / Hash256 field is present in some historical transactions. This is unrelated to the field also named `PreviousTxnID` in some ledger objects.
### AccountTxnID
[Section titled “AccountTxnID”](#accounttxnid)
The `AccountTxnID` field lets you chain your transactions together, so that a current transaction is not valid unless the previous transaction sent from the same account has a specific \[transaction hash]\[identifying hash].
Unlike the `PreviousTxnID` field, which tracks the last transaction to *modify* an account (regardless of sender), the `AccountTxnID` tracks the last transaction *sent by* an account. To use `AccountTxnID`, you must first enable the `asfAccountTxnID` flag, so that the ledger keeps track of the ID for the account’s previous transaction. (`PreviousTxnID`, by comparison, is always tracked.)
One situation in which this is useful is if you have a primary system for submitting transactions and a passive backup system. If the passive backup system becomes disconnected from the primary, but the primary is not fully dead, and they both begin operating at the same time, you could potentially have serious problems like some transactions sending twice and others not at all. Chaining your transactions together with `AccountTxnID` ensures that, even if both systems are active, only one of them can submit valid transactions at a time.
The `AccountTxnID` field cannot be used on transactions that use Tickets. Transactions that use `AccountTxnID` cannot be placed in the transaction queue.
### Auto-fillable Fields
[Section titled “Auto-fillable Fields”](#auto-fillable-fields)
Some fields can be automatically filled in before a transaction is signed, either by a `xahaud` server or by a client library. Auto-filling values requires an active connection to Xahau to get the latest state, so it cannot be done offline. The details can vary by library, but auto-filling always provides suitable values for at least the following fields:
* `Fee` - Automatically fill in the \[Transaction Cost]\[] based on the network.
**Note:** When using `xahaud`’s \[sign command]\[], you can limit the maximum possible auto-filled value, using the `fee_mult_max` and `fee_mult_div` parameters.)
* `Sequence` - Automatically use the next sequence number for the account sending the transaction.
For a production system, we recommend *not* leaving these fields to be filled by the server. For example, if transaction costs become high due to a temporary spike in network load, you may want to wait for the cost to decrease before sending some transactions, instead of paying the temporarily-high cost.
The `Paths` field of the [Payment transaction](/docs/protocol-reference/transactions/transaction-types/payment) type can also be automatically filled in.
### Flags Field
[Section titled “Flags Field”](#flags-field)
The `Flags` field can contain various options that affect how a transaction should behave. The options are represented as binary values that can be combined with bitwise-or operations to set multiple flags at once.
To check whether a transaction has a given flag enabled, use the bitwise-and operator on the flag’s value and the `Flags` field. A result of zero indicates the flag is disabled, and a result equal to the flag value indicates the flag is enabled. (If you got any other result, you did something wrong.)
Most flags only have meaning for a specific transaction type. The same bitwise value may be reused for flags on different transaction types, so it is important to pay attention to the `TransactionType` field when setting and reading flags.
Bits that are not defined as flags MUST be 0. (The \[fix1543 amendment]\[] enforces this rule on some transaction types. Most transaction types enforce this rule by default.)
#### Global Flags
[Section titled “Global Flags”](#global-flags)
The only flag that applies globally to all transactions is as follows:
| Flag Name | Hex Value | Decimal Value | Description |
| --------------------- | ------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `tfFullyCanonicalSig` | `0x80000000` | 2147483648 | **DEPRECATED** No effect. (If the \[RequireFullyCanonicalSig amendment]\[] is not enabled, this flag enforces a fully-canonical signature.) |
When using the \[sign method]\[] (or \[submit method]\[] in “sign-and-submit” mode), `xahaud` adds a `Flags` field with `tfFullyCanonicalSig` enabled unless the `Flags` field is already present. The `tfFullyCanonicalSig` flag is not automatically enabled if `Flags` is explicitly specified. The flag is not automatically enabled when using the \[sign\_for method]\[] to add a signature to a multi-signed transaction.
**Note:** The `tfFullyCanonicalSig` flag was used from 2014 until 2020 to protect against transaction malleability while maintaining compatibility with legacy signing software. The \[RequireFullyCanonicalSig amendment]\[] ended compatibility with such legacy software and made the protections the default for all transactions. If you are using a parallel network that does not have RequireFullyCanonicalSig enabled, you should always enable the `tfFullyCanonicalSig` flag to protect against transaction malleability.
#### Flag Ranges
[Section titled “Flag Ranges”](#flag-ranges)
A transaction’s `Flags` field can contain flags that apply at different levels or contexts. Flags for each context are limited to the following ranges:
| Range Name | Bit Mask | Description |
| ---------------- | ------------ | ---------------------------------------------------------------------------------------------- |
| Universal Flags | `0xff000000` | Flags that apply equally to all transaction types. |
| Type-based Flags | `0x00ff0000` | Flags with different meanings depending on the transaction type that uses them. |
| Reserved Flags | `0x0000ffff` | Flags that are not currently defined. A transaction is only valid if these flags are disabled. |
**Note:** The [AccountSet transaction](/docs/protocol-reference/transactions/transaction-types/accountset) type has its own non-bitwise flags, which serve a similar purpose to type-based flags. Ledger objects also have a `Flags` field with different bitwise flag definitions.
### Memos Field
[Section titled “Memos Field”](#memos-field)
The `Memos` field includes arbitrary messaging data with the transaction. It is presented as an array of objects. Each object has only one field, `Memo`, which in turn contains another object with *one or more* of the following fields:
| Field | Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ------------ | ------ | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `MemoData` | String | Blob | Arbitrary hex value, conventionally containing the content of the memo. |
| `MemoFormat` | String | Blob | Hex value representing characters allowed in URLs. Conventionally containing information on how the memo is encoded, for example as a [MIME type](http://www.iana.org/assignments/media-types/media-types.xhtml). |
| `MemoType` | String | Blob | Hex value representing characters allowed in URLs. Conventionally, a unique relation (according to [RFC 5988](http://tools.ietf.org/html/rfc5988#section-4)) that defines the format of this memo. |
The `MemoType` and `MemoFormat` fields should only consist of the following characters: `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;=%`
The `Memos` field is limited to no more than 1 KB in size (when serialized in binary format).
**Transaction Cost:** Transactions with a `Memos` field incur an additional cost based on the size of the memos. The cost increases proportionally with the total size of all memos in the transaction.
Example of a transaction with a Memos field:
```json
{
"TransactionType": "Payment",
"Account": "rMmTCjGFRWPz8S2zAUUoNVSQHxtRQD4eCx",
"Destination": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
"Memos": [
{
"Memo": {
"MemoType": "687474703a2f2f6578616d706c652e636f6d2f6d656d6f2f67656e65726963",
"MemoData": "72656e74"
}
}
],
"Amount": "1"
}
```
### NetworkID Field
[Section titled “NetworkID Field”](#networkid-field)
\[New in: rippled 1.11.0]\[]
The `NetworkID` field is a protection against “cross-chain” transaction replay attacks, preventing the same transaction from being copied over and executing on a parallel network that it wasn’t intended for. For compatibility with existing chains, the `NetworkID` field must be omitted on any network with a Network ID of 1024 or less, but must be included on any network with a Network ID of 1025 or greater. The following table shows the status and values for various known networks:
| Network | ID | `NetworkID` Field |
| ------------------------------- | ----- | ---------------------------------------------------- |
| Mainnet | 0 | Disallowed |
| Testnet | 1 | Disallowed |
| Devnet | 2 | Disallowed |
| AMM Devnet | 25 | Disallowed |
| Sidechains Devnet Locking Chain | 2551 | Disallowed, but will become required after an update |
| Sidechains Devnet Issuing Chain | 2552 | Disallowed, but will become required after an update |
| Xahau Testnet | 21338 | Required |
| Xahau Mainnet | 21337 | Required |
Transaction replay attacks are theoretically possible, but require specific conditions on the second network. All of the following must be true:
* The transaction’s sender is a funded account on the second network.
* The sender’s `Sequence` number on the second network matches the transaction’s `Sequence`, or the transaction uses a Ticket that’s available on the second network.
* Either the transaction does not have a `LastLedgerSequence` field, or it specifies a value that is higher than the current ledger index on the second ledger.
* Mainnet generally has a higher ledger index than test networks or sidechains, so it is easier to replay Mainnet transactions on a sidechain or test network than the other way around, when transactions use `LastLedgerSequence` as intended.
* Either the networks both have IDs of 1024 or less, both networks use the same ID, or the second network does not require the `NetworkID` field.
### Signers Field
[Section titled “Signers Field”](#signers-field)
The `Signers` field contains a multi-signature, which has signatures from up to 8 key pairs, that together should authorize the transaction. The `Signers` list is an array of objects, each with one field, `Signer`. The `Signer` field has the following nested fields:
| Field | Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| --------------- | ------ | ------------------------------------------------------- | ----------------------------------------------------------------------------- |
| `Account` | String | AccountID | The address associated with this signature, as it appears in the signer list. |
| `TxnSignature` | String | Blob | A signature for this transaction, verifiable using the `SigningPubKey`. |
| `SigningPubKey` | String | Blob | The public key used to create this signature. |
The `SigningPubKey` must be a key that is associated with the `Account` address. If the referenced `Account` is a funded account in the ledger, then the `SigningPubKey` can be that account’s current Regular Key if one is set. It could also be that account’s Master Key, unless the `lsfDisableMaster` flag is enabled. If the referenced `Account` address is not a funded account in the ledger, then the `SigningPubKey` must be the master key associated with that address.
Because signature verification is a compute-intensive task, multi-signed transactions cost additional XAH to relay to the network. Each signature included in the multi-signature increases the \[transaction cost]\[] required for the transaction. For example, if the current minimum transaction cost to relay a transaction to the network is `10000` drops, then a multi-signed transaction with 3 entries in the `Signers` array would need a `Fee` value of at least `40000` drops to relay.
### EmitDetails Fields
[Section titled “EmitDetails Fields”](#emitdetails-fields)
An `EmitDetails` object has the following fields:
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ----------------- | --------- | ------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `EmitGeneration` | Number | UInt32 | Yes | This field keeps track of a chain of emitted transactions that in turn cause other transactions to be emitted. |
| `EmitBurden` | String | UInt64 | Yes | This field is a heuristic for detecting forkbombs. Fees are based on burden and will increase exponentially when a chain reaction is started to prevent the network becoming overun by self-reinforcing emitted transactions. |
| `EmitParentTxnID` | String | Hash256 | Yes | The Hook Execution that emitted the transaction is connected to the Originating Transaction. Therefore this field is always required for the efficient tracing of behaviour. |
| `EmitNonce` | String | Hash256 | Yes | Emitted Transactions would be identical with the same fields and therefore have identical transaction hashes if a nonce were not used. However every node on the network needs to agree on the nonce, so a special Hook API to produce a deterministic nonce is made available. |
| `EmitCallback` | String | AccountID | No | This field is used by xahld when it needs to intitate a callback, such that it knows which Hook and account to initate the callback on. Callbacks happen when an emitted transaction is accepted into a ledger. |
| `EmitHookHash` | String | Hash256 | Yes | The SHA512H of the Hook at the time it was executed. |
### Hook Parameters
[Section titled “Hook Parameters”](#hook-parameters)
The `HookParameters` field is an array of objects that specify the parameters of the hook. Each parameter object has the following fields:
| Field | JSON Type | Internal Type | Description |
| ------- | --------- | ------------- | --------------------------- |
| `Name` | String | Blob | The name of the parameter. |
| `Value` | String | Blob | The value of the parameter. |
**Transaction Cost:** Transactions with a `HookParameters` field incur an additional cost based on the size of the hook parameters. The cost increases proportionally with the total size of all parameters in the transaction.
# Transaction Metadata
Transaction metadata is a section of data that gets added to a transaction after it is processed. Any transaction that gets included in a ledger has metadata, regardless of whether it is successful. The transaction metadata describes the outcome of the transaction in detail.
Caution
The changes described in transaction metadata are only final if the transaction is in a validated ledger version.
Example Metadata
The following JSON object shows the metadata for [a complex cross-currency payment](https://xrpcharts.ripple.com/#/transactions/8C55AFC2A2AA42B5CE624AEECDB3ACFDD1E5379D4E5BF74A8460C5E97EF8706B):
```json
{
"AffectedNodes": [
{
"ModifiedNode": {
"FinalFields": {
"Account": "r9ZoLsJHzMMJLpvsViWQ4Jgx17N8cz1997",
"Balance": "77349986",
"Flags": 0,
"OwnerCount": 2,
"Sequence": 9
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "1E7E658C2D3DF91EFAE5A12573284AD6F526B8F64DD12F013C6F889EF45BEA97",
"PreviousFields": {
"OwnerCount": 3
},
"PreviousTxnID": "55C11248ACEFC2EFD59755BF88867783AC18EA078517108F942069C2FBE4CF5C",
"PreviousTxnLgrSeq": 35707468
}
},
{
"ModifiedNode": {
"FinalFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "2298.927882138068"
},
"Flags": 1114112,
"HighLimit": {
"currency": "USD",
"issuer": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
"value": "0"
},
"HighNode": "000000000000006B",
"LowLimit": {
"currency": "USD",
"issuer": "rpvvAvaZ7TXHkNLM8UJwCTU6yBU2jDTJ1P",
"value": "1000000000"
},
"LowNode": "0000000000000007"
},
"LedgerEntryType": "RippleState",
"LedgerIndex": "220DDA7164F3F41F3C5223FA3125D4CD368EBB4FB954B5FBFFB6D1EA6DACDD5E",
"PreviousFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "2297.927882138068"
}
},
"PreviousTxnID": "1DB2F9C67C3F42F7B8AB02BA2264254A78A201EC8A9974A1CACEFD51545B1263",
"PreviousTxnLgrSeq": 43081739
}
},
{
"ModifiedNode": {
"FinalFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "33403.80553244443"
},
"Flags": 1114112,
"HighLimit": {
"currency": "USD",
"issuer": "rhub8VRN55s94qWKDv6jmDy1pUykJzF3wq",
"value": "0"
},
"HighNode": "0000000000001A40",
"LowLimit": {
"currency": "USD",
"issuer": "rd5Sx93pCMgfxwBuofjen2csoFYmY8VrT",
"value": "1000000000"
},
"LowNode": "0000000000000000"
},
"LedgerEntryType": "RippleState",
"LedgerIndex": "38569918AF54B520463CFDDD00EB5ADD8768039BD94E61A5E25C387EA4FDC9A3",
"PreviousFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "33402.80752845242"
}
},
"PreviousTxnID": "38A0E82ADC2DA6C6D59929B73E9812CD1E1384E452FD23D0717EA0037E2FC9E3",
"PreviousTxnLgrSeq": 43251694
}
},
{
"ModifiedNode": {
"FinalFields": {
"Account": "rBndiPPKs9k5rjBb7HsEiqXKrz8AfUnqWq",
"BookDirectory": "4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5B09B13AC59DBA5E",
"BookNode": "0000000000000000",
"Flags": 0,
"OwnerNode": "0000000000000000",
"Sequence": 407556,
"TakerGets": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "75.1379833998197"
},
"TakerPays": "204986996"
},
"LedgerEntryType": "Offer",
"LedgerIndex": "557BDD35E40EAFFE0AC98108A0F4AC4BB812A168CFD5B4E35475F42A60ABD9C8",
"PreviousFields": {
"TakerGets": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "76.1399833998197"
},
"TakerPays": "207720593"
},
"PreviousTxnID": "961C575073788979815F103D065CEE449D2EA6EFE8FC8C33C26EC08586925D90",
"PreviousTxnLgrSeq": 43251680
}
},
{
"ModifiedNode": {
"FinalFields": {
"Account": "r9KG7Du7aFmABzMvDnwuvPaEoMu4Eurwok",
"Balance": "8080207629",
"Flags": 0,
"OwnerCount": 6,
"Sequence": 1578765
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "5A667CB5FBAB4143EDEFBD6EDDD4B6D19C905209C8EE16486D5D7CD6CB083E78",
"PreviousFields": {
"Balance": "8080152531",
"Sequence": 1578764
},
"PreviousTxnID": "E3CDFD288620871455634DC1E56439136AACA1DDBCE987BE12F97486AB477375",
"PreviousTxnLgrSeq": 43251694
}
},
{
"DeletedNode": {
"FinalFields": {
"Account": "r9ZoLsJHzMMJLpvsViWQ4Jgx17N8cz1997",
"BookDirectory": "A6D5D1C1CC92D56FDDFD4434FB10BD31F63EB991DA3C756653071AFD498D0000",
"BookNode": "0000000000000000",
"Flags": 0,
"OwnerNode": "0000000000000000",
"PreviousTxnID": "DB028A461E98B0398CAD65F2871B381A6D0B9A21662CA5B033438D83C518C0F2",
"PreviousTxnLgrSeq": 35686129,
"Sequence": 7,
"TakerGets": {
"currency": "EUR",
"issuer": "rhub8VRN55s94qWKDv6jmDy1pUykJzF3wq",
"value": "2.5"
},
"TakerPays": {
"currency": "ETH",
"issuer": "rcA8X3TVMST1n3CJeAdGk1RdRCHii7N2h",
"value": "0.05"
}
},
"LedgerEntryType": "Offer",
"LedgerIndex": "6AA7E5121FEB456F0A899E3D6F25D62ABB408BB67B91C9270E13714401ED72B5"
}
},
{
"ModifiedNode": {
"FinalFields": {
"Account": "rd5Sx93pCMgfxwBuofjen2csoFYmY8VrT",
"Balance": "8251028196",
"Flags": 0,
"OwnerCount": 4,
"Sequence": 274
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "6F830A1B38F827CD4BEC946A40F1E2DF726FC22AFC3918FD621567AF17F49F3A",
"PreviousFields": {
"Balance": "8253816902"
},
"PreviousTxnID": "38A0E82ADC2DA6C6D59929B73E9812CD1E1384E452FD23D0717EA0037E2FC9E3",
"PreviousTxnLgrSeq": 43251694
}
},
{
"ModifiedNode": {
"FinalFields": {
"Account": "rd5Sx93pCMgfxwBuofjen2csoFYmY8VrT",
"BookDirectory": "79C54A4EBD69AB2EADCE313042F36092BE432423CC6A4F784E0CB6D74F25A336",
"BookNode": "0000000000000000",
"Flags": 0,
"OwnerNode": "0000000000000000",
"Sequence": 273,
"TakerGets": "8246341599",
"TakerPays": {
"currency": "USD",
"issuer": "rhub8VRN55s94qWKDv6jmDy1pUykJzF3wq",
"value": "2951.147613535471"
}
},
"LedgerEntryType": "Offer",
"LedgerIndex": "7FD1EAAE17B7D68AE640FFC56CECC3999B4F938EFFF6EA6887B6CC8BD9DBDC63",
"PreviousFields": {
"TakerGets": "8249130305",
"TakerPays": {
"currency": "USD",
"issuer": "rhub8VRN55s94qWKDv6jmDy1pUykJzF3wq",
"value": "2952.145617527486"
}
},
"PreviousTxnID": "38A0E82ADC2DA6C6D59929B73E9812CD1E1384E452FD23D0717EA0037E2FC9E3",
"PreviousTxnLgrSeq": 43251694
}
},
{
"ModifiedNode": {
"FinalFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-11.68225001668339"
},
"Flags": 131072,
"HighLimit": {
"currency": "USD",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "5000"
},
"HighNode": "0000000000000000",
"LowLimit": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0"
},
"LowNode": "000000000000004A"
},
"LedgerEntryType": "RippleState",
"LedgerIndex": "826CF5BFD28F3934B518D0BDF3231259CBD3FD0946E3C3CA0C97D2C75D2D1A09",
"PreviousFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-10.68225001668339"
}
},
"PreviousTxnID": "28B271F7C27C1A267F32FFCD8B1795C5D3B1DC761AD705E3A480139AA8B61B09",
"PreviousTxnLgrSeq": 43237130
}
},
{
"ModifiedNode": {
"FinalFields": {
"Account": "rBndiPPKs9k5rjBb7HsEiqXKrz8AfUnqWq",
"Balance": "8276201534",
"Flags": 0,
"OwnerCount": 5,
"Sequence": 407558
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "880C6FB7B9C0083211F950E4449AD45895C0EC1114B5112CE1320AC7275E3237",
"PreviousFields": {
"Balance": "8273467937"
},
"PreviousTxnID": "CB4B54942F11510A47D2731C3260429093F24016B366CBF15D8EC4B705372F02",
"PreviousTxnLgrSeq": 43251683
}
},
{
"ModifiedNode": {
"FinalFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-6557.745685633666"
},
"Flags": 2228224,
"HighLimit": {
"currency": "USD",
"issuer": "rBndiPPKs9k5rjBb7HsEiqXKrz8AfUnqWq",
"value": "1000000000"
},
"HighNode": "0000000000000000",
"LowLimit": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0"
},
"LowNode": "0000000000000512"
},
"LedgerEntryType": "RippleState",
"LedgerIndex": "8A9FEE5192E334195314B5C162BC78F7452ADB14E06839D48943BAE05EE1967F",
"PreviousFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-6558.747685633666"
}
},
"PreviousTxnID": "961C575073788979815F103D065CEE449D2EA6EFE8FC8C33C26EC08586925D90",
"PreviousTxnLgrSeq": 43251680
}
},
{
"ModifiedNode": {
"FinalFields": {
"Balance": {
"currency": "GCB",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "9990651675.348776"
},
"Flags": 3211264,
"HighLimit": {
"currency": "GCB",
"issuer": "rHaans8PtgwbacHvXAL3u6TG28gTAtCwr8",
"value": "0"
},
"HighNode": "0000000000000000",
"LowLimit": {
"currency": "GCB",
"issuer": "r9KG7Du7aFmABzMvDnwuvPaEoMu4Eurwok",
"value": "10000000000"
},
"LowNode": "0000000000000000"
},
"LedgerEntryType": "RippleState",
"LedgerIndex": "A2B41EE7818A5756B6A2276BDBB3CE0ED3A3B350787FD6B76E5EA1354A8F20D2",
"PreviousFields": {
"Balance": {
"currency": "GCB",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "9990651678.137482"
}
},
"PreviousTxnID": "961C575073788979815F103D065CEE449D2EA6EFE8FC8C33C26EC08586925D90",
"PreviousTxnLgrSeq": 43251680
}
},
{
"DeletedNode": {
"FinalFields": {
"ExchangeRate": "53071AFD498D0000",
"Flags": 0,
"RootIndex": "A6D5D1C1CC92D56FDDFD4434FB10BD31F63EB991DA3C756653071AFD498D0000",
"TakerGetsCurrency": "0000000000000000000000004555520000000000",
"TakerGetsIssuer": "2ADB0B3959D60A6E6991F729E1918B7163925230",
"TakerPaysCurrency": "0000000000000000000000004554480000000000",
"TakerPaysIssuer": "06CC4A6D023E68AA3499C6DE3E9F2DC52B8BA254"
},
"LedgerEntryType": "DirectoryNode",
"LedgerIndex": "A6D5D1C1CC92D56FDDFD4434FB10BD31F63EB991DA3C756653071AFD498D0000"
}
},
{
"ModifiedNode": {
"FinalFields": {
"Flags": 0,
"Owner": "r9ZoLsJHzMMJLpvsViWQ4Jgx17N8cz1997",
"RootIndex": "A83C1B192A27582EDB320EBD7A3FE58D7042CE04B67A2B3D87FDD63D871E12D7"
},
"LedgerEntryType": "DirectoryNode",
"LedgerIndex": "A83C1B192A27582EDB320EBD7A3FE58D7042CE04B67A2B3D87FDD63D871E12D7"
}
},
{
"ModifiedNode": {
"FinalFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "0"
},
"Flags": 65536,
"HighLimit": {
"currency": "USD",
"issuer": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
"value": "0"
},
"HighNode": "0000000000000002",
"LowLimit": {
"currency": "USD",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "1"
},
"LowNode": "0000000000000000"
},
"LedgerEntryType": "RippleState",
"LedgerIndex": "C493ABA2619D0FC6355BA862BC8312DF8266FBE76AFBA9636E857F7EAC874A99",
"PreviousFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "1"
}
},
"PreviousTxnID": "28B271F7C27C1A267F32FFCD8B1795C5D3B1DC761AD705E3A480139AA8B61B09",
"PreviousTxnLgrSeq": 43237130
}
},
{
"ModifiedNode": {
"FinalFields": {
"Account": "r9KG7Du7aFmABzMvDnwuvPaEoMu4Eurwok",
"BookDirectory": "E6E8A9842EA2ED1FD5D0599343692CE1EBF977AEA751B7DC5B038D7EA4C68000",
"BookNode": "0000000000000000",
"Flags": 65536,
"OwnerNode": "0000000000000000",
"Sequence": 39018,
"TakerGets": {
"currency": "GCB",
"issuer": "rHaans8PtgwbacHvXAL3u6TG28gTAtCwr8",
"value": "9990651675.348776"
},
"TakerPays": "9990651675348776"
},
"LedgerEntryType": "Offer",
"LedgerIndex": "C939B9B2C5803DD6D89B792E72470F79CBE9F9E999691789E0B68C3808BDDD8E",
"PreviousFields": {
"TakerGets": {
"currency": "GCB",
"issuer": "rHaans8PtgwbacHvXAL3u6TG28gTAtCwr8",
"value": "9990651678.137482"
},
"TakerPays": "9990651678137482"
},
"PreviousTxnID": "961C575073788979815F103D065CEE449D2EA6EFE8FC8C33C26EC08586925D90",
"PreviousTxnLgrSeq": 43251680
}
},
{
"ModifiedNode": {
"FinalFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "2963.413395452545"
},
"Flags": 65536,
"HighLimit": {
"currency": "USD",
"issuer": "rhub8VRN55s94qWKDv6jmDy1pUykJzF3wq",
"value": "0"
},
"HighNode": "0000000000001A97",
"LowLimit": {
"currency": "USD",
"issuer": "rpvvAvaZ7TXHkNLM8UJwCTU6yBU2jDTJ1P",
"value": "0"
},
"LowNode": "0000000000000007"
},
"LedgerEntryType": "RippleState",
"LedgerIndex": "E4D1FBD5CB72A1D3EE38C21F3BCB13E454FCB469CD01C1366E0008A031E6A7FC",
"PreviousFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "2964.413395452545"
}
},
"PreviousTxnID": "1DB2F9C67C3F42F7B8AB02BA2264254A78A201EC8A9974A1CACEFD51545B1263",
"PreviousTxnLgrSeq": 43081739
}
}
],
"DeliveredAmount": {
"currency": "GCB",
"issuer": "rHaans8PtgwbacHvXAL3u6TG28gTAtCwr8",
"value": "2.788706"
},
"TransactionIndex": 38,
"TransactionResult": "tesSUCCESS",
"delivered_amount": {
"currency": "GCB",
"issuer": "rHaans8PtgwbacHvXAL3u6TG28gTAtCwr8",
"value": "2.788706"
}
}
```
### AffectedNodes
[Section titled “AffectedNodes”](#affectednodes)
The `AffectedNodes` array contains a complete list of the objects in the ledger that this transaction modified in some way. Each entry in this array is an object with one top-level field indicating what type it is:
* `CreatedNode` indicates that the transaction created a new object in the ledger.
* `DeletedNode` indicates that the transaction removed an object from the ledger.
* `ModifiedNode` indicates that the transaction modified an existing object in the ledger.
The value of each of these fields is a JSON object describing the changes made to the ledger object.
#### CreatedNode Fields
[Section titled “CreatedNode Fields”](#creatednode-fields)
A `CreatedNode` object contains the following fields:
| Field | Value | Description |
| ----------------- | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `LedgerEntryType` | String | The type of ledger object that was created. |
| `LedgerIndex` | String - [Hash](/docs/protocol-reference/data-types/#hashes) | The ID of this ledger object in the ledger’s state tree. **Note:** This is **not the same** as a ledger index, even though the field name is very similar. |
| `NewFields` | Object | The content fields of the newly-created ledger object. Which fields are present depends on what type of ledger object was created. |
#### DeletedNode Fields
[Section titled “DeletedNode Fields”](#deletednode-fields)
A `DeletedNode` object contains the following fields:
| Field | Value | Description |
| ----------------- | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `LedgerEntryType` | String | The type of ledger object that was deleted. |
| `LedgerIndex` | String - [Hash](/docs/protocol-reference/data-types/#hashes) | The ID of this ledger object in the ledger’s state tree. **Note:** This is **not the same** as a ledger index, even though the field name is very similar. |
| `FinalFields` | Object | The content fields of the ledger object immediately before it was deleted. Which fields are present depends on what type of ledger object was created. |
#### ModifiedNode Fields
[Section titled “ModifiedNode Fields”](#modifiednode-fields)
A `ModifiedNode` object contains the following fields:
| Field | Value | Description |
| ------------------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `LedgerEntryType` | String | The type of ledger object that was deleted. |
| `LedgerIndex` | String - [Hash](/docs/protocol-reference/data-types/#hashes) | The ID of this ledger object in the ledger’s state tree. **Note:** This is **not the same** as a ledger index, even though the field name is very similar. |
| `FinalFields` | Object | The content fields of the ledger object after applying any changes from this transaction. Which fields are present depends on what type of ledger object was created. This omits the `PreviousTxnID` and `PreviousTxnLgrSeq` fields, even though most types of ledger objects have them. |
| `PreviousFields` | Object | The previous values for all fields of the object that were changed as a result of this transaction. If the transaction *only added* fields to the object, this field is an empty object. |
| `PreviousTxnID` | String - [Hash](/docs/protocol-reference/data-types/#hashes) | *(May be omitted)* The \[identifying hash]\[] of the previous transaction to modify this ledger object. Omitted for ledger object types that do not have a `PreviousTxnID` field. |
| `PreviousTxnLgrSeq` | Number - [Ledger Index](/docs/protocol-reference/data-types/#ledger-index) | *(May be omitted)* The [Ledger Index](/docs/protocol-reference/data-types/#ledger-index) of the ledger version containing the previous transaction to modify this ledger object. Omitted for ledger object types that do not have a `PreviousTxnLgrSeq` field. |
**Note:** If the modified ledger object has `PreviousTxnID` and `PreviousTxnLgrSeq` fields, the transaction always updates them with the transaction’s own identifying hash and the index of the ledger version that included the transaction, but these fields’ new value is not listed in the `FinalFields` of the `ModifiedNode` object, and their previous values are listed at the top level of the `ModifiedNode` object rather than in the nested `PreviousFields` object.
### delivered\_amount
[Section titled “delivered\_amount”](#delivered_amount)
The `Amount` of a [Payment transaction](/docs/protocol-reference/transactions/transaction-types/payment) indicates the amount to deliver to the `Destination`, so if the transaction was successful, then the destination received that much — **except if the transaction was a partial payment**. (In that case, any positive amount up to `Amount` might have arrived.) Rather than choosing whether or not to trust the `Amount` field, you should use the `delivered_amount` field of the metadata to see how much actually reached its destination.
The `rippled` server provides a `delivered_amount` field in JSON transaction metadata for all successful Payment transactions. This field is formatted like a normal currency amount. However, the delivered amount is not available for transactions that meet both of the following criteria:
* Is a partial payment
If the tx is a partial payment, then `delivered_amount` contains the string value `unavailable` instead of an actual amount. If this happens, you can only figure out the actual delivered amount by reading the `AffectedNodes` in the transaction’s metadata.
**Note:** The `delivered_amount` field is generated on-demand for the request, and is not included in the binary format for transaction metadata, nor is it used when calculating the hash of the transaction metadata.
See also: Partial Payments
# Transaction Results
[\[Source\]](https://github.com/ripple/rippled/blob/master/src/ripple/protocol/TER.h)
The `rippled` server summarizes transaction results with result codes, which appear in fields such as `engine_result` and `meta.TransactionResult`. These codes are grouped into several categories with different prefixes:
| Category | Prefix | Description |
| --------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Claimed cost only | `tec` | The transaction did not achieve its intended purpose, but the transaction cost was destroyed. This result is only final in a validated ledger. |
| Failure | `tef` | The transaction cannot be applied to the server’s current (in-progress) ledger or any later one. It may have already been applied, or the condition of the ledger makes it impossible to apply in the future. |
| Local error | `tel` | The `rippled` server had an error due to local conditions, such as high load. You may get a different response if you resubmit to a different server or at a different time. |
| Malformed transaction | `tem` | The transaction was not valid, due to improper syntax, conflicting options, a bad signature, or something else. |
| Retry | `ter` | The transaction could not be applied, but it could apply successfully in a future ledger. |
| Success | `tes` | (Not an error) The transaction succeeded. This result only final in a validated ledger. |
The `rippled` server automatically retries failed transactions. It is important not to assume that a transaction has completely failed based on a tentative failure result. A transaction may later succeed unless its success or failure is final.
**Warning:** Transactions’ provisional result codes may differ from their final result. Transactions that provisionally succeeded may eventually fail and transactions that provisionally failed may eventually succeed. Transactions that provisionally failed may also eventually fail with a different code. See the finality of results for how to know when a transaction’s result is final.
The distinction between a local error (`tel`) and a malformed transaction (`tem`) is a matter of protocol-level rules. For example, the protocol sets no limit on the maximum number of paths that can be included in a transaction. However, a server may define a finite limit of paths it can process. If two different servers are configured differently, then one of them may return a `tel` error for a transaction with many paths, while the other server could successfully process the transaction. If enough servers are able to process the transaction so that it survives consensus, then it can still be included in a validated ledger.
By contrast, a `tem` error implies that no server anywhere can apply the transaction, regardless of settings. Either the transaction breaks the rules of the protocol, it is unacceptably ambiguous, or it is completely nonsensical. The only way a malformed transaction could become valid is through changes in the protocol; for example, if a new feature is adopted, then transactions using that feature could be considered malformed by servers that are running older software which predates that feature.
### Immediate Response
[Section titled “Immediate Response”](#immediate-response)
The response from the \[submit method]\[] contains a provisional result from the `rippled` server indicating what happened during the local processing of the transaction.
The response from `submit` contains the following fields:
| Field | Value | Description |
| ----------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `engine_result` | String | A code indicating the outcome of the transaction, such as `tecPATH_DRY`. |
| `engine_result_code` | Signed Integer | A number that corresponds to the `engine_result`. The exact values are subject to change without notice. |
| `engine_result_message` | String | A human-readable message explaining what happened. This message is intended for developers to diagnose problems, and is subject to change without notice. |
If nothing went wrong when submitting and applying the transaction locally, the response looks like this:
```js
"engine_result": "tesSUCCESS",
"engine_result_code": 0,
"engine_result_message": "The transaction was applied. Only final in a validated ledger."
```
**Note:** A successful result at this stage does not indicate that the transaction has completely succeeded; only that it was successfully applied to the provisional version of the ledger kept by the local server. Failed results at this stage are also provisional and may change. See Finality of Results for details.
# TEC Codes
These codes indicate that the transaction failed, but it was applied to a ledger to apply the transaction cost. They have numerical values in the range 100 to 199. It is recommended to use the text code, not the numeric value.
Transactions with `tec` codes destroy the XAH paid as a transaction cost and consume a sequence number. For the most part, the transactions take no other action, but there are some exceptions. For example, a transaction that results in `tecOVERSIZE` still cleans up some unfunded offers. Always look at the transaction metadata to see precisely what a transaction did.
**Caution:** A transaction that provisionally failed with a `tec` code may still succeed or fail with a different code after being reapplied. The result is final when it appears in a validated ledger version. For more information, see Finality of Results and Reliable Transaction Submission.
| Code | Value | Explanation |
| ---------------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tecCANT_ACCEPT_OWN_NFTOKEN_OFFER` | 157 | The transaction tried to accept an offer that was placed by the same account to buy or sell a non-fungible token. *(Added by the \[NonFungibleTokensV1\_1 amendment]\[].)* |
| `tecCLAIM` | 100 | Unspecified failure, with transaction cost destroyed. |
| `tecCRYPTOCONDITION_ERROR` | 146 | This [EscrowCreate](/docs/protocol-reference/transactions/transaction-types/escrowcreate) or [EscrowFinish](/docs/protocol-reference/transactions/transaction-types/escrowfinish) transaction contained a malformed or mismatched crypto-condition. |
| `tecDIR_FULL` | 121 | The transaction tried to add an object (such as a trust line, Check, Escrow, or Payment Channel) to an account’s owner directory, but that account cannot own any more objects in the ledger. |
| `tecDUPLICATE` | 149 | The transaction tried to create an object (such as a [DepositPreauth](/docs/protocol-reference/transactions/transaction-types/depositpreauth) authorization) that already exists. |
| `tecDST_TAG_NEEDED` | 143 | The [Payment transaction](/docs/protocol-reference/transactions/transaction-types/payment) omitted a destination tag, but the destination account has the `lsfRequireDestTag` flag enabled. \[New in: rippled 0.28.0]\[] |
| `tecEXPIRED` | 148 | The transaction tried to create an object (such as an Offer or a Check) whose provided Expiration time has already passed. |
| `tecFAILED_PROCESSING` | 105 | An unspecified error occurred when processing the transaction. |
| `tecFROZEN` | 137 | The [OfferCreate transaction](/docs/protocol-reference/transactions/transaction-types/offercreate) failed because one or both of the assets involved are subject to a global freeze. |
| `tecHAS_OBLIGATIONS` | 151 | The [AccountDelete transaction](/docs/protocol-reference/transactions/transaction-types/accountdelete) failed because the account to be deleted owns objects that cannot be deleted. See Deletion of Accounts for details. |
| `tecINSUF_RESERVE_LINE` | 122 | The transaction failed because the sending account does not have enough XAH to create a new trust line. (See: Reserves) This error occurs when the counterparty already has a trust line in a non-default state to the sending account for the same currency. (See `tecNO_LINE_INSUF_RESERVE` for the other case.) |
| `tecINSUF_RESERVE_OFFER` | 123 | The transaction failed because the sending account does not have enough XAH to create a new Offer. (See: Reserves) |
| `tecINSUFF_FEE` | 136 | The transaction failed because the sending account does not have enough XAH to pay the transaction cost that it specified. (In this case, the transaction processing destroys all of the sender’s XAH even though that amount is lower than the specified transaction cost.) This result only occurs if the account’s balance decreases *after* this transaction has been distributed to enough of the network to be included in a consensus set. Otherwise, the transaction fails with `terINSUF_FEE_B` before being distributed. |
| `tecINSUFFICIENT_FUNDS` | 158 | One of the accounts involved does not hold enough of a necessary asset. *(Added by the \[NonFungibleTokensV1\_1 amendment]\[].)* |
| `tecINSUFFICIENT_PAYMENT` | 161 | The amount specified is not enough to pay all fees involved in the transaction. For example, when trading a non-fungible token, the buy amount may not be enough to pay both the broker fee and the sell amount. *(Added by the \[NonFungibleTokensV1\_1 amendment]\[].)* |
| `tecINSUFFICIENT_RESERVE` | 141 | The transaction would increase the reserve requirement higher than the sending account’s balance. [SignerListSet](/docs/protocol-reference/transactions/transaction-types/signerlistset), [PaymentChannelCreate](/docs/protocol-reference/transactions/transaction-types/paymentchannelcreate), [PaymentChannelFund](/docs/protocol-reference/transactions/transaction-types/paymentchannelfund), and [EscrowCreate](/docs/protocol-reference/transactions/transaction-types/escrowcreate) can return this error code. See Signer Lists and Reserves for more information. |
| `tecINTERNAL` | 144 | Unspecified internal error, with transaction cost applied. This error code should not normally be returned. If you can reproduce this error, please [report an issue](https://github.com/ripple/rippled/issues). |
| `tecINVARIANT_FAILED` | 147 | An invariant check failed when trying to execute this transaction. Added by the \[EnforceInvariants amendment]\[]. If you can reproduce this error, please [report an issue](https://github.com/ripple/rippled/issues). |
| `tecKILLED` | 150 | The [OfferCreate transaction](/docs/protocol-reference/transactions/transaction-types/offercreate) specified the `tfFillOrKill` flag and could not be filled, so it was killed. *(Added by the \[fix1578 amendment]\[].)* |
| `tecMAX_SEQUENCE_REACHED` | 153 | A sequence number field is already at its maximum. This includes the `MintedNFTokens` field. *(Added by the \[NonFungibleTokensV1\_1 amendment]\[].)* |
| `tecNEED_MASTER_KEY` | 142 | This transaction tried to cause changes that require the master key, such as disabling the master key or giving up the ability to freeze balances. \[New in: rippled 0.28.0]\[] |
| `tecNFTOKEN_BUY_SELL_MISMATCH` | 155 | The \[NFTokenAcceptOffer transaction]\[] attempted to match incompatible offers to buy and sell a non-fungible token. *(Added by the \[NonFungibleTokensV1\_1 amendment]\[].)* |
| `tecNFTOKEN_OFFER_TYPE_MISMATCH` | 156 | One or more of the offers specified in the transaction was not the right type of offer. (For example, a buy offer was specified in the `NFTokenSellOffer` field.) *(Added by the \[NonFungibleTokensV1\_1 amendment]\[].)* |
| `tecNO_ALTERNATIVE_KEY` | 130 | The transaction tried to remove the only available method of authorizing transactions. This could be a [SetRegularKey transaction](/docs/protocol-reference/transactions/transaction-types/setregularkey) to remove the regular key, a [SignerListSet transaction](/docs/protocol-reference/transactions/transaction-types/signerlistset) to delete a SignerList, or an [AccountSet transaction](/docs/protocol-reference/transactions/transaction-types/accountset) to disable the master key. (Prior to `rippled` 0.30.0, this was called `tecMASTER_DISABLED`.) |
| `tecNO_AUTH` | 134 | The transaction failed because it needs to add a balance on a trust line to an account with the `lsfRequireAuth` flag enabled, and that trust line has not been authorized. If the trust line does not exist at all, `tecNO_LINE` occurs instead. |
| `tecNO_DST` | 124 | The account on the receiving end of the transaction does not exist. This includes Payment and TrustSet transaction types. (It could be created if it received enough XAH.) |
| `tecNO_DST_INSUF_NATIVE` | 125 | The account on the receiving end of the transaction does not exist, and the transaction is not sending enough XAH to create it. |
| `tecNO_ENTRY` | 140 | The transaction tried to modify a ledger object, such as a Check, Payment Channel, or Deposit Preauthorization, but the specified object does not exist. It may have already been deleted by a previous transaction or the transaction may have an incorrect value in an ID field such as `CheckID`, `Channel`, `Unauthorize`. |
| `tecNO_ISSUER` | 133 | The account specified in the `issuer` field of a currency amount does not exist. |
| `tecNO_LINE` | 135 | The `TakerPays` field of the [OfferCreate transaction](/docs/protocol-reference/transactions/transaction-types/offercreate) specifies an asset whose issuer has `lsfRequireAuth` enabled, and the account making the offer does not have a trust line for that asset. (Normally, making an offer implicitly creates a trust line if necessary, but in this case it does not bother because you cannot hold the asset without authorization.) If the trust line exists, but is not authorized, `tecNO_AUTH` occurs instead. |
| `tecNO_LINE_INSUF_RESERVE` | 126 | The transaction failed because the sending account does not have enough XAH to create a new trust line. (See: Reserves) This error occurs when the counterparty does not have a trust line to this account for the same currency. (See `tecINSUF_RESERVE_LINE` for the other case.) |
| `tecNO_LINE_REDUNDANT` | 127 | The transaction failed because it tried to set a trust line to its default state, but the trust line did not exist. |
| `tecNO_PERMISSION` | 139 | The sender does not have permission to do this operation. For example, the [EscrowFinish transaction](/docs/protocol-reference/transactions/transaction-types/escrowfinish) tried to release a held payment before its `FinishAfter` time, someone tried to use [PaymentChannelFund](/docs/protocol-reference/transactions/transaction-types/paymentchannelfund) on a channel the sender does not own, or a [Payment](/docs/protocol-reference/transactions/transaction-types/payment) tried to deliver funds to an account with the “DepositAuth” flag enabled. |
| `tecNO_REGULAR_KEY` | 131 | The [AccountSet transaction](/docs/protocol-reference/transactions/transaction-types/accountset) tried to disable the master key, but the account does not have another way to authorize transactions. If multi-signing is enabled, this code is deprecated and `tecNO_ALTERNATIVE_KEY` is used instead. |
| `tecNO_SUITABLE_NFTOKEN_PAGE` | 154 | The transaction tried to mint or acquire a non-fungible token but the account receiving the `NFToken` does not have a directory page that can hold it. This situation is rare. *(Added by the \[NonFungibleTokensV1\_1 amendment]\[].)* |
| `tecNO_TARGET` | 138 | The transaction referenced an Escrow or PayChannel ledger object that doesn’t exist, either because it never existed or it has already been deleted. (For example, another [EscrowFinish transaction](/docs/protocol-reference/transactions/transaction-types/escrowfinish) has already executed the held payment.) Alternatively, the destination account has `asfDisallowXAH` set so it cannot be the destination of this [PaymentChannelCreate](/docs/protocol-reference/transactions/transaction-types/paymentchannelcreate) or [EscrowCreate](/docs/protocol-reference/transactions/transaction-types/escrowcreate) transaction. |
| `tecOBJECT_NOT_FOUND` | 160 | One of the objects specified by this transaction did not exist in the ledger. *(Added by the \[NonFungibleTokensV1\_1 amendment]\[].)* |
| `tecOVERSIZE` | 145 | This transaction could not be processed, because the server created an excessively large amount of metadata when it tried to apply the transaction. \[New in: rippled 0.29.0-hf1]\[] |
| `tecOWNERS` | 132 | The transaction cannot succeed because the sender already owns objects in the ledger. For example, an account cannot enable the `lsfRequireAuth` flag if it has any trust lines or available offers. |
| `tecPATH_DRY` | 128 | The transaction failed because the provided paths did not have enough liquidity to send anything at all. This could mean that the source and destination accounts are not linked by trust lines. |
| `tecPATH_PARTIAL` | 101 | The transaction failed because the provided paths did not have enough liquidity to send the full amount. |
| `tecTOO_SOON` | 152 | The [AccountDelete transaction](/docs/protocol-reference/transactions/transaction-types/accountdelete) failed because the account to be deleted had a `Sequence` number that is too high. The current ledger index must be at least 256 higher than the account’s sequence number. |
| `tecUNFUNDED` | 129 | The transaction failed because the account does not hold enough XAH to pay the amount in the transaction *and* satisfy the additional reserve necessary to execute this transaction. |
| `tecUNFUNDED_ADD` | 102 | **DEPRECATED.** |
| `tecUNFUNDED_PAYMENT` | 104 | The transaction failed because the sending account is trying to send more XAH than it holds, not counting the reserve. |
| `tecUNFUNDED_OFFER` | 103 | The [OfferCreate transaction](/docs/protocol-reference/transactions/transaction-types/offercreate) failed because the account creating the offer does not have any of the `TakerGets` currency. |
| `tecREQUIRES_FLAG` | 169 | The SetHook transaction]\[] failed because of an incorrect Flag and Field combination. |
| `tecPRECISION_LOSS` | 170 | The transaction failed because the result would end with significant precision loss. |
# TEF Codes
These codes indicate that the transaction failed and was not included in a ledger, but the transaction could have succeeded in some theoretical ledger. Typically this means that the transaction can no longer succeed in any future ledger. They have numerical values in the range of -199 to -100. The exact code for any given error is subject to change, so don’t rely on it.
**Caution:** Transactions with `tef` codes are not applied to ledgers and cannot cause any changes to the Xahau state. However, a transaction that provisionally failed may still succeed or fail with a different code after being reapplied. For more information, see Finality of Results and Reliable Transaction Submission.
| Code | Explanation |
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tefALREADY` | The same exact transaction has already been applied. |
| `tefBAD_ADD_AUTH` | **DEPRECATED.** |
| `tefBAD_AUTH` | The key used to sign this account is not authorized to modify this account. (It could be authorized if the account had the same key set as the Regular Key.) |
| `tefBAD_AUTH_MASTER` | The single signature provided to authorize this transaction does not match the master key, but no regular key is associated with this address. |
| `tefBAD_LEDGER` | While processing the transaction, the ledger was discovered in an unexpected state. If you can reproduce this error, please [report an issue](https://github.com/ripple/rippled/issues) to get it fixed. |
| `tefBAD_QUORUM` | The transaction was multi-signed, but the total weights of all included signatures did not meet the quorum. |
| `tefBAD_SIGNATURE` | The transaction was multi-signed, but contained a signature for an address not part of a SignerList associated with the sending account. |
| `tefCREATED` | **DEPRECATED.** |
| `tefEXCEPTION` | While processing the transaction, the server entered an unexpected state. This may be caused by unexpected inputs, for example if the binary data for the transaction is grossly malformed. If you can reproduce this error, please [report an issue](https://github.com/ripple/rippled/issues) to get it fixed. |
| `tefFAILURE` | Unspecified failure in applying the transaction. |
| `tefINTERNAL` | When trying to apply the transaction, the server entered an unexpected state. If you can reproduce this error, please [report an issue](https://github.com/ripple/rippled/issues) to get it fixed. |
| `tefINVARIANT_FAILED` | An invariant check failed when trying to claim the transaction cost. Added by the \[EnforceInvariants amendment]\[]. If you can reproduce this error, please [report an issue](https://github.com/ripple/rippled/issues). |
| `tefMASTER_DISABLED` | The transaction was signed with the account’s master key, but the account has the `lsfDisableMaster` field set. |
| `tefMAX_LEDGER` | The transaction included a `LastLedgerSequence` parameter, but the current ledger’s sequence number is already higher than the specified value. |
| `tefNFTOKEN_IS_NOT_TRANSFERABLE` | The transaction attempted to send a non-fungible token to another account, but the `NFToken` has the `lsfTransferable` flag disabled and the transfer would not be to or from the issuer. *(Added by the \[NonFungibleTokensV1\_1 amendment]\[].)* |
| `tefNO_AUTH_REQUIRED` | The [TrustSet transaction](/docs/protocol-reference/transactions/transaction-types/trustset) tried to mark a trust line as authorized, but the `lsfRequireAuth` flag is not enabled for the corresponding account, so authorization is not necessary. |
| `tefNO_TICKET` | The transaction attempted to use a Ticket, but the specified `TicketSequence` number does not exist in the ledger, and cannot be created in the future because it is earlier than the sender’s current sequence number. |
| `tefNOT_MULTI_SIGNING` | The transaction was multi-signed, but the sending account has no SignerList defined. |
| `tefPAST_SEQ` | The sequence number of the transaction is lower than the current sequence number of the account sending the transaction. |
| `tefTOO_BIG` | The transaction would affect too many objects in the ledger. For example, this was an [AccountDelete transaction](/docs/protocol-reference/transactions/transaction-types/accountdelete) but the account to be deleted owns over 1000 objects in the ledger. |
| `tefWRONG_PRIOR` | The transaction contained an `AccountTxnID` field (or the deprecated `PreviousTxnID` field), but the transaction specified there does not match the account’s previous transaction. |
| `tefPAST_IMPORT_SEQ` | The transaction failed because the import sequence number has already been used. |
| `tefPAST_IMPORT_VL_SEQ` | The transaction failed because the import validator list sequence number has already been used. |
# TEL Codes
These codes indicate an error in the local server processing the transaction; it is possible that another server with a different configuration or load level could process the transaction successfully. They have numerical values in the range of -399 to -300. The exact code for any given error is subject to change, so don’t rely on it.
**Caution:** Transactions with `tel` codes are not applied to ledgers and cannot cause any changes to the Xahau state. However, these transactions may be automatically cached and retried later. Transactions that provisionally failed may still succeed or fail with a different code after being reapplied. For more information, see Finality of Results and Reliable Transaction Submission.
| Code | Explanation |
| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `telBAD_DOMAIN` | The transaction specified a domain value (for example, the `Domain` field of an [AccountSet transaction](/docs/protocol-reference/transactions/transaction-types/accountset)) that cannot be used, probably because it is too long to store in the ledger. |
| `telBAD_PATH_COUNT` | The transaction contains too many paths for the local server to process. |
| `telBAD_PUBLIC_KEY` | The transaction specified a public key value (for example, as the `MessageKey` field of an [AccountSet transaction](/docs/protocol-reference/transactions/transaction-types/accountset)) that cannot be used, probably because it is not the right length. |
| `telCAN_NOT_QUEUE` | The transaction did not meet the open ledger cost, but this server did not queue this transaction because it did not meet the queuing restrictions. For example, a transaction returns this code when the sender already has 10 other transactions in the queue. You can try again later or sign and submit a replacement transaction with a higher transaction cost in the `Fee` field. |
| `telCAN_NOT_QUEUE_BALANCE` | The transaction did not meet the open ledger cost and also was not added to the transaction queue because the sum of potential XAH costs of already-queued transactions is greater than the expected balance of the account. You can try again later, or try submitting to a different server. \[New in: rippled 0.70.2]\[] |
| `telCAN_NOT_QUEUE_BLOCKS` | The transaction did not meet the open ledger cost and also was not added to the transaction queue. This transaction could not replace an existing transaction in the queue because it would block already-queued transactions from the same sender by changing authorization methods. (This includes all [SetRegularKey](/docs/protocol-reference/transactions/transaction-types/setregularkey) and [SignerListSet](/docs/protocol-reference/transactions/transaction-types/signerlistset) transactions, as well as [AccountSet](/docs/protocol-reference/transactions/transaction-types/accountset) transactions that change the `RequireAuth`/`OptionalAuth`, `DisableMaster`, or `AccountTxnID` flags.) You can try again later, or try submitting to a different server. \[New in: rippled 0.70.2]\[] |
| `telCAN_NOT_QUEUE_BLOCKED` | The transaction did not meet the open ledger cost and also was not added to the transaction queue because a transaction queued ahead of it from the same sender blocks it. (This includes all [SetRegularKey](/docs/protocol-reference/transactions/transaction-types/setregularkey) and [SignerListSet](/docs/protocol-reference/transactions/transaction-types/signerlistset) transactions, as well as [AccountSet](/docs/protocol-reference/transactions/transaction-types/accountset) transactions that change the `RequireAuth`/`OptionalAuth`, `DisableMaster`, or `AccountTxnID` flags.) You can try again later, or try submitting to a different server. \[New in: rippled 0.70.2]\[] |
| `telCAN_NOT_QUEUE_FEE` | The transaction did not meet the open ledger cost and also was not added to the transaction queue. This code occurs when a transaction with the same sender and sequence number already exists in the queue and the new one does not pay a large enough transaction cost to replace the existing transaction. To replace a transaction in the queue, the new transaction must have a `Fee` value that is at least 25% more, as measured in fee levels. You can increase the `Fee` and try again, send this with a higher `Sequence` number so it doesn’t replace an existing transaction, or try sending to another server. \[New in: rippled 0.70.2]\[] |
| `telCAN_NOT_QUEUE_FULL` | The transaction did not meet the open ledger cost and the server did not queue this transaction because this server’s transaction queue is full. You could increase the `Fee` and try again, try again later, or try submitting to a different server. The new transaction must have a higher transaction cost, as measured in fee levels, than the transaction in the queue with the smallest transaction cost. \[New in: rippled 0.70.2]\[] |
| `telFAILED_PROCESSING` | An unspecified error occurred when processing the transaction. |
| `telINSUF_FEE_P` | The `Fee` from the transaction is not high enough to meet the server’s current transaction cost requirement, which is derived from its load level and network-level requirements. If the individual server is too busy to process your transaction right now, it may cache the transaction and automatically retry later. |
| `telLOCAL_ERROR` | Unspecified local error. |
| `telNO_DST`\_`PARTIAL` | The transaction is an XAH payment that would fund a new account, but the `tfPartialPayment` flag was enabled. This is disallowed. |
| `telWRONG_NETWORK` | The transaction specifies the wrong `NetworkID` value for the current network. Either specify the correct the `NetworkID` value for the intended network, or submit the transaction to a server that is connected to the correct network. |
| `telREQUIRES_NETWORK_ID` | The transaction does not specify a `NetworkID` field, but the current network requires one. If the transaction was intended for a network that requires `NetworkID`, add the field and try again. If the transaction was intended for a different network, submit it to a server that is connected to the correct network. |
| `telNETWORK_ID_MAKES_TX_NON_CANONICAL` | The transaction specified a `NetworkID` field, but the current network requires that the `NetworkID` is not submitted. |
| `telNON_LOCAL_EMITTED_TXN` | The emitted transaction cannot be applied because it was not generated locally. |
| `telIMPORT_VL_KEY_NOT_RECOGNISED` | The transaction was signed on a different network or the transaction was submitted to the wrong network. For `Import` transactions the validations must match the vl keys on receiving network. |
| `telCAN_NOT_QUEUE_IMPORT` | `Import` transaction was not able to be directly applied and cannot be queued. |
# TEM Codes
These codes indicate that the transaction was malformed, and cannot succeed according to the Xahau protocol. They have numerical values in the range of -299 to -200. The exact code for any given error is subject to change, so don’t rely on it.
**Tip:** Transactions with `tem` codes are not applied to ledgers, and cannot cause any changes to the Xahau state. A `tem` result is final unless the rules for a valid transaction change. (For example, using functionality from an Amendment before that amendment is enabled results in `temDISABLED`; such a transaction could succeed later if it becomes valid when the amendment is enabled.)
| Code | Explanation |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `temBAD_AMOUNT` | An amount specified by the transaction (for example the destination `Amount` or `SendMax` values of a [Payment](/docs/protocol-reference/transactions/transaction-types/payment)) was invalid, possibly because it was a negative number. |
| `temBAD_AUTH_MASTER` | The key used to sign this transaction does not match the master key for the account sending it, and the account does not have a Regular Key set. |
| `temBAD_CURRENCY` | The transaction improperly specified a currency field. See \[Specifying Currency Amounts]\[Currency Amount] for the correct format. |
| `temBAD_EXPIRATION` | The transaction improperly specified an expiration value, for example as part of an [OfferCreate transaction](/docs/protocol-reference/transactions/transaction-types/offercreate). Alternatively, the transaction did not specify a required expiration value, for example as part of an [EscrowCreate transaction](/docs/protocol-reference/transactions/transaction-types/escrowcreate). |
| `temBAD_FEE` | The transaction improperly specified its `Fee` value, for example by listing a non-XAH currency or some negative amount of XAH. |
| `temBAD_ISSUER` | The transaction improperly specified the `issuer` field of some currency included in the request. |
| `temBAD_LIMIT` | The [TrustSet transaction](/docs/protocol-reference/transactions/transaction-types/trustset) improperly specified the `LimitAmount` value of a trust line. |
| `temBAD_NFTOKEN_TRANSFER_FEE` | The \[NFTokenMint transaction]\[] improperly specified the `TransferFee` field of the transaction. *(Added by the \[NonFungibleTokensV1\_1 amendment]\[].)* |
| `temBAD_OFFER` | The [OfferCreate transaction](/docs/protocol-reference/transactions/transaction-types/offercreate) specifies an invalid offer, such as offering to trade XAH for itself, or offering a negative amount. |
| `temBAD_PATH` | The [Payment transaction](/docs/protocol-reference/transactions/transaction-types/payment) specifies one or more Paths improperly, for example including an issuer for XAH, or specifying an account differently. |
| `temBAD_PATH_LOOP` | One of the Paths in the [Payment transaction](/docs/protocol-reference/transactions/transaction-types/payment) was flagged as a loop, so it cannot be processed in a bounded amount of time. |
| `temBAD_SEND_NATIVE_LIMIT` | The [Payment transaction](/docs/protocol-reference/transactions/transaction-types/payment) used the `tfLimitQuality` flag in a direct XAH-to-XAH payment, even though XAH-to-XAH payments do not involve any conversions. |
| `temBAD_SEND_NATIVE_MAX` | The [Payment transaction](/docs/protocol-reference/transactions/transaction-types/payment) included a `SendMax` field in a direct XAH-to-XAH payment, even though sending XAH should never require `SendMax`. (XAH is only valid in `SendMax` if the destination `Amount` is not XAH.) |
| `temBAD_SEND_NATIVE_NO_DIRECT` | The [Payment transaction](/docs/protocol-reference/transactions/transaction-types/payment) used the `tfNoDirectRipple` flag for a direct XAH-to-XAH payment, even though XAH-to-XAH payments are always direct. |
| `temBAD_SEND_NATIVE_PARTIAL` | The [Payment transaction](/docs/protocol-reference/transactions/transaction-types/payment) used the `tfPartialPayment` flag for a direct XAH-to-XAH payment, even though XAH-to-XAH payments should always deliver the full amount. |
| `temBAD_SEND_NATIVE_PATHS` | The [Payment transaction](/docs/protocol-reference/transactions/transaction-types/payment) included `Paths` while sending XAH, even though XAH-to-XAH payments should always be direct. |
| `temBAD_SEQUENCE` | The transaction is references a sequence number that is higher than its own `Sequence` number, for example trying to cancel an offer that would have to be placed after the transaction that cancels it. |
| `temBAD_SIGNATURE` | The signature to authorize this transaction is either missing, or formed in a way that is not a properly-formed signature. (See `tecNO_PERMISSION` for the case where the signature is properly formed, but not authorized for this account.) |
| `temBAD_SRC_ACCOUNT` | The `Account` on whose behalf this transaction is being sent (the “source account”) is not a properly-formed account address. |
| `temBAD_TRANSFER_RATE` | The `TransferRate` field of an AccountSet transaction is not properly formatted or out of the acceptable range. |
| `temCANNOT_PREAUTH_SELF` | The sender of the [DepositPreauth transaction](/docs/protocol-reference/transactions/transaction-types/depositpreauth) was also specified as the account to preauthorize. You cannot preauthorize yourself. |
| `temDST_IS_SRC` | The transaction improperly specified a destination address as the `Account` sending the transaction. This includes trust lines (where the destination address is the `issuer` field of `LimitAmount`) and payment channels (where the destination address is the `Destination` field). |
| `temDST_NEEDED` | The transaction improperly omitted a destination. This could be the `Destination` field of a [Payment transaction](/docs/protocol-reference/transactions/transaction-types/payment), or the `issuer` sub-field of the `LimitAmount` field fo a `TrustSet` transaction. |
| `temINVALID` | The transaction is otherwise invalid. For example, the transaction ID may not be the right format, the signature may not be formed properly, or something else went wrong in understanding the transaction. |
| `temINVALID_COUNT` | The transaction includes a `TicketCount` field, but the number of Tickets specified is invalid. |
| `temINVALID_FLAG` | The transaction includes a Flag that does not exist, or includes a contradictory combination of flags. |
| `temMALFORMED` | Unspecified problem with the format of the transaction. |
| `temREDUNDANT` | The transaction would do nothing; for example, it is sending a payment directly to the sending account, or creating an offer to buy and sell the same currency from the same issuer. |
| `temREDUNDANT_SEND_MAX` | \[Removed in: rippled 0.28.0]\[] |
| `temRIPPLE_EMPTY` | The [Payment transaction](/docs/protocol-reference/transactions/transaction-types/payment) includes an empty `Paths` field, but paths are necessary to complete this payment. |
| `temBAD_WEIGHT` | The [SignerListSet transaction](/docs/protocol-reference/transactions/transaction-types/signerlistset) includes a `SignerWeight` that is invalid, for example a zero or negative value. |
| `temBAD_SIGNER` | The [SignerListSet transaction](/docs/protocol-reference/transactions/transaction-types/signerlistset) includes a signer who is invalid. For example, there may be duplicate entries, or the owner of the SignerList may also be a member. |
| `temBAD_QUORUM` | The [SignerListSet transaction](/docs/protocol-reference/transactions/transaction-types/signerlistset) has an invalid `SignerQuorum` value. Either the value is not greater than zero, or it is more than the sum of all signers in the list. |
| `temUNCERTAIN` | Used internally only. This code should never be returned. |
| `temUNKNOWN` | Used internally only. This code should never be returned. |
| `temDISABLED` | The transaction requires logic that is disabled. Typically this means you are trying to use an amendment that is not enabled for the current ledger. |
| `temHOOK_DATA_TOO_LARGE` | The transaction `CreateCode` field contains more than 256 bytes. |
# TER Codes
These codes indicate that the transaction failed, but it could apply successfully in the future, usually if some other hypothetical transaction applies first. They have numerical values in the range of -99 to -1. The exact code for any given error is subject to change, so don’t rely on it.
**Caution:** Transactions with `ter` codes are not applied to the current ledger and cannot cause any changes to the Xahau state. However, a transaction that provisionally failed may still succeed or fail with a different code after being automatically reapplied. For more information, see Finality of Results and Reliable Transaction Submission.
| Code | Explanation |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `terFUNDS_SPENT` | **DEPRECATED.** |
| `terINSUF_FEE_B` | The account sending the transaction does not have enough XAH to pay the `Fee` specified in the transaction. |
| `terLAST` | Used internally only. This code should never be returned. |
| `terNO_ACCOUNT` | The address sending the transaction is not funded in the ledger (yet). |
| `terNO_AUTH` | The transaction would involve adding currency issued by an account with `lsfRequireAuth` enabled to a trust line that is not authorized. For example, you placed an offer to buy a currency you aren’t authorized to hold. |
| `terNO_LINE` | Used internally only. This code should never be returned. |
| `terNO_RIPPLE` | Used internally only. This code should never be returned. |
| `terOWNERS` | The transaction requires that account sending it has a nonzero “owners count”, so the transaction cannot succeed. For example, an account cannot enable the `lsfRequireAuth` flag if it has any trust lines or available offers. |
| `terPRE_SEQ` | The `Sequence` number of the current transaction is higher than the current sequence number of the account sending the transaction. |
| `terPRE_TICKET` | The transaction attempted to use a Ticket, but the specified `TicketSequence` number does not exist in the ledger. However, the Ticket could still be created by another transaction. |
| `terRETRY` | Unspecified retriable error. |
| `terQUEUED` | The transaction met the load-scaled transaction cost but did not meet the open ledger requirement, so the transaction has been queued for a future ledger. |
| `terNO_HOOK` | The transaction attempted to use a `HookHash` that doesn’t exist on the ledger. |
# TES Codes
The codes `tesSUCCESS` and `tesPARTIAL` are the only codes that indicates a transaction succeeded. This does not always mean it accomplished what you expected it to do. (For example, an [OfferCancel](/docs/protocol-reference/transactions/transaction-types/offercancel) can “succeed” even if there is no offer for it to cancel.)
The `tesPARTIAL` code indicates that a transaction has partially succeeded. Specifically, it is used in scenarios where an operation, such as deleting hook state records, exceeds a certain limit (e.g., 512 or 1024 records). In such cases, the transaction deletes up to the limit and then requires you to submit additional transactions with new sequence numbers to continue the deletion process until all records are removed. This ensures that large operations are broken down into manageable parts.
| Code | Explanation |
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tesSUCCESS` | The transaction was applied and forwarded to other servers. If this appears in a validated ledger, then the transaction’s success is final. |
| `tesPARTIAL` | The transaction partially succeeded and requires additional transactions to complete large operations, such as deleting more than a set limit of records. |
# Transaction Types
## Transaction Types
[Section titled “Transaction Types”](#transaction-types)
The type of a transaction (`TransactionType` field) is the most fundamental information about a transaction. This indicates what type of operation the transaction is supposed to do.
All transactions have certain fields in common:
* Common Fields
Each transaction type has additional fields relevant to the type of action it causes.
# AccountDelete
> An AccountDelete transaction deletes an account and any objects it owns in Xahau, if possible, sending the account's remaining XAH to a specified destination account.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/DeleteAccount.cpp)]
*Added by the DeletableAccounts amendment*
Not enabled
The *DeletableAccounts* amendment is not enabled at this time.
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType": "AccountDelete",
"Account": "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm",
"Destination": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe",
"DestinationTag": 13,
"Fee": "2000000",
"Sequence": 2470665,
"Flags": 2147483648
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ---------------- | ------------------------------------------------------------------ | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Destination` | String - [Address](/docs/protocol-reference/data-types/#addresses) | AccountID | The address of an account to receive any leftover XAH after deleting the sending account. Must be a funded account in the ledger, and must not be the sending account. |
| `DestinationTag` | Number | UInt32 | *(Optional)* Arbitrary destination tag that identifies a hosted recipient or other information for the recipient of the deleted account’s leftover XAH. |
### Special Transaction Cost
[Section titled “Special Transaction Cost”](#special-transaction-cost)
As an additional deterrent against ledger spam, the AccountDelete transaction requires a much higher than usual transaction cost: instead of the standard minimum of 0.00001 XAH, AccountDelete must destroy at least the owner reserve amount, currently 2 XRP. This discourages excessive creation of new accounts because the reserve requirement cannot be fully recouped by deleting the account.
The transaction cost always applies when a transaction is included in a validated ledger, even if the transaction fails to delete the account. (See Error Cases.) To greatly reduce the chances of paying the high transaction cost if the account cannot be deleted, submit the transaction with `fail_hard` enabled.
### Error Cases
[Section titled “Error Cases”](#error-cases)
Besides errors that can occur for all transactions, AccountDelete transactions can result in the following transaction result codes:
| Error Code | Description |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `temDISABLED` | Occurs if the DeletableAccounts amendment is not enabled. |
| `temDST_IS_SRC` | Occurs if the `Destination` matches the sender of the transaction (`Account` field). |
| `tecDST_TAG_NEEDED` | Occurs if the `Destination` account requires a destination tag, but the `DestinationTag` field was not provided. |
| `tecNO_DST` | Occurs if the `Destination` account is not a funded account in the ledger. |
| `tecNO_PERMISSION` | Occurs if the `Destination` account requires deposit authorization and the sender is not preauthorized. |
| `tecTOO_SOON` | Occurs if the sender’s `Sequence` number is too high. The transaction’s `Sequence` number plus 256 must be less than the current [Ledger Index](/docs/protocol-reference/data-types/#ledger-index). This prevents replay of old transactions if this account is resurrected after it is deleted. |
| `tecHAS_OBLIGATIONS` | Occurs if the account to be deleted is connected to objects that cannot be deleted in the ledger. (This includes objects created by other accounts, such as escrows and for example NFT’s minted, [even if owned by another account](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/DeleteAccount.cpp#L197).) |
| `tefTOO_BIG` | Occurs if the sending account is linked to more than 1000 objects in the ledger. The transaction could succeed on retry if some of those objects were deleted separately first. |
# AccountSet
> An AccountSet transaction modifies the properties of an account in Xahau.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/SetAccount.cpp)]
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType": "AccountSet",
"Account" : "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Fee": "12",
"Sequence": 5,
"Domain": "6578616D706C652E636F6D",
"SetFlag": 5,
"MessageKey": "03AB40A0490F9B7ED8DF29D246BF2D6269820A0EE7742ACDD457BEA7C7D0931EDB",
"HookStateScale": 10
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ---------------- | --------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ClearFlag` | Number | UInt32 | *(Optional)* Unique identifier of a flag to disable for this account. |
| `Domain` | String | Blob | *(Optional)* The domain that owns this account, as a string of hex representing the ASCII for the domain in lowercase. [Cannot be more than 256 bytes in length.](https://github.com/Xahau/xahaud/blob/55dc7a252e08a0b02cd5aa39e9b4777af3eafe77/src/ripple/app/tx/impl/SetAccount.h#L34) |
| `EmailHash` | String | Hash128 | *(Optional)* An arbitrary 128-bit value. Conventionally, clients treat this as the md5 hash of an email address to use for displaying a [Gravatar](http://en.gravatar.com/site/implement/hash/) image. |
| `MessageKey` | String | Blob | *(Optional)* Public key for sending encrypted messages to this account. To set the key, it must be exactly 33 bytes, with the first byte indicating the key type: `0x02` or `0x03` for secp256k1 keys, `0xED` for Ed25519 keys. To remove the key, use an empty value. |
| `NFTokenMinter` | String | Blob | *(Optional)* Another account that can mint NFTokens for you. *(Added by the \[NonFungibleTokensV1\_1 amendment]\[].)* |
| `SetFlag` | Number | UInt32 | *(Optional)* Integer flag to enable for this account. |
| `TransferRate` | Number | UInt32 | *(Optional)* The fee to charge when users transfer this account’s tokens, represented as billionths of a unit. Cannot be more than `2000000000` or less than `1000000000`, except for the special case `0` meaning no fee. |
| `TickSize` | Number | UInt8 | *(Optional)* Tick size to use for offers involving a currency issued by this address. The exchange rates of those offers is rounded to this many significant digits. Valid values are `3` to `15` inclusive, or `0` to disable. *(Added by the \[TickSize amendment]\[])* |
| `WalletLocator` | String | Hash256 | *(Optional)* An arbitrary 256-bit value. If specified, the value is stored as part of the account but has no inherent meaning or requirements. |
| `WalletSize` | Number | UInt32 | *(Optional)* Not used. This field is valid in AccountSet transactions but does nothing. |
| `HookStateScale` | Number | UInt16 | *(Optional)* Scale factor for determining when Hook state entries become stale. Valid values are `1` to `16` inclusive. *(Added by the [ExtendedHookState amendment](/docs/features/amendments/#extendedhookstate).)* |
If none of these options are provided, then the AccountSet transaction has no effect (beyond destroying the transaction cost). See Cancel or Skip a Transaction for more details.
### Domain
[Section titled “Domain”](#domain)
The `Domain` field is represented as the hex string of the lowercase ASCII of the domain. For example, the domain *example.com* would be represented as `"6578616D706C652E636F6D"`.
To remove the `Domain` field from an account, send an AccountSet with the Domain set to an empty string.
You can put any domain in your account’s `Domain` field. To prove that an account and domain belong to the same person or business, you need a “two-way link”:
* Accounts you own should have a domain you own in the `Domain` field.
* At that domain, host a [xahau.toml](/docs/infrastructure/identity) file listing accounts you own, and optionally other information about how you use Xahau.
### AccountSet Flags
[Section titled “AccountSet Flags”](#accountset-flags)
There are several options which can be either enabled or disabled for an account. Account options are represented by different types of flags depending on the situation:
* The `AccountSet` transaction type has several “AccountSet Flags” (prefixed **`asf`**) that can enable an option when passed as the `SetFlag` parameter, or disable an option when passed as the `ClearFlag` parameter. Newer options have only this style of flag. You can enable up to one `asf` flag per transaction, and disable up to one `asf` flag per transaction.
* The `AccountSet` transaction type has several transaction flags (prefixed **`tf`**) that can be used to enable or disable specific account options when passed in the `Flags` parameter. You can enable and disable a combination of settings in one transaction using multiple `tf` flags, but not all settings have `tf` flags.
* The `AccountRoot` ledger object type has several ledger-state-flags (prefixed **`lsf`**) which represent the state of particular account options within a particular ledger. These settings apply until a transaction changes them.
To enable or disable Account Flags, use the `SetFlag` and `ClearFlag` parameters of an AccountSet transaction. AccountSet flags have names that begin with **`asf`**.
All flags are disabled by default.
The available AccountSet flags are:
| Flag Name | Decimal Value | Corresponding Ledger Flag | Description |
| --------------------------------- | ------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `asfAccountTxnID` | 5 | (None) | Track the ID of this account’s most recent transaction. Required for `AccountTxnID` |
| `asfAllowTrustLineClawback` | 17 | `lsfAllowTrustLineClawback` | Enables an account to clawback tokens it has issued. This flag can only be enabled if the account’s owner directory is empty (no trust lines, offers, escrows, payment channels, checks, or signer lists). Once set, it cannot be undone. |
| `asfAuthorizedNFTokenMinter` | 10 | (None) | Enable to allow another account to mint non-fungible tokens (NFTokens) on this account’s behalf. Specify the authorized account in the `NFTokenMinter` field of the AccountRoot object. To remove an authorized minter, enable this flag and omit the `NFTokenMinter` field. *(Added by the \[NonFungibleTokensV1\_1 amendment]\[].)* |
| `asfDefaultRipple` | 8 | `lsfDefaultRipple` | Enable rippling on this account’s trust lines by default. |
| `asfDepositAuth` | 9 | `lsfDepositAuth` | Enable Deposit Authorization on this account. *(Added by the [DepositAuth amendment](/docs/features/amendments/#depositauth).)* |
| `asfDisableMaster` | 4 | `lsfDisableMaster` | Disallow use of the master key pair. Can only be enabled if the account has configured another way to sign transactions, such as a Regular Key or a Signer List. |
| `asfDisallowIncomingCheck` | 13 | `lsfDisallowIncomingCheck` | Block incoming Checks. *Added by the \[DisallowIncoming amendment]\[].* |
| `asfDisallowIncomingNFTokenOffer` | 12 | `lsfDisallowIncomingNFTokenOffer` | Block incoming NFTokenOffers. *Added by the \[DisallowIncoming amendment]\[].* |
| `asfDisallowIncomingPayChan` | 14 | `lsfDisallowIncomingPayChan` | Block incoming Payment Channels. *Added by the \[DisallowIncoming amendment]\[].* |
| `asfDisallowIncomingTrustline` | 15 | `lsfDisallowIncomingTrustline` | Block incoming trust lines.*Added by the \[DisallowIncoming amendment]\[].* |
| `asfDisallowIncomingRemit` | 16 | `lsfDisallowIncomingRemit` | Block incoming Remit txn.*Added by the [Remit amendment](/docs/features/amendments/#remit).* |
| `asfDisallowXRP` | 3 | `lsfDisallowXRP` | XAH should not be sent to this account. (Advisory; not enforced by Xahau protocol.) |
| `asfGlobalFreeze` | 7 | `lsfGlobalFreeze` | Freeze all assets issued by this account. |
| `asfNoFreeze` | 6 | `lsfNoFreeze` | Permanently give up the ability to freeze individual trust lines or disable Global Freeze. This flag can never be disabled after being enabled. |
| `asfRequireAuth` | 2 | `lsfRequireAuth` | Require authorization for users to hold balances issued by this address. Can only be enabled if the address has no trust lines connected to it. |
| `asfRequireDest` | 1 | `lsfRequireDestTag` | Require a destination tag to send transactions to this account. |
| `asfTshCollect` | 11 | `lsfTshCollect` | The TSH pays for the execution of their own Hook Chain. *Added by the [Hooks amendment](/docs/features/amendments/#hooks).* |
To enable the `asfDisableMaster` or `asfNoFreeze` flags, you must authorize the transaction by signing it with the master key pair. You cannot use a regular key pair or a multi-signature. You can disable `asfDisableMaster` (that is, re-enable the master key pair) using a regular key pair or multi-signature.
The following Transaction flags (`tf` flags), specific to the AccountSet transaction type, serve the same purpose. Due to limited space, some settings do not have associated `tf` flags, and new `tf` flags are not being added to the `AccountSet` transaction type. You can use a combination of `tf` and `asf` flags to enable multiple settings with a single transaction.
| Flag Name | Hex Value | Decimal Value | Replaced by AccountSet Flag |
| ------------------- | ------------ | ------------- | ------------------------------ |
| `tfRequireDestTag` | `0x00010000` | 65536 | `asfRequireDest` (`SetFlag`) |
| `tfOptionalDestTag` | `0x00020000` | 131072 | `asfRequireDest` (`ClearFlag`) |
| `tfRequireAuth` | `0x00040000` | 262144 | `asfRequireAuth` (`SetFlag`) |
| `tfOptionalAuth` | `0x00080000` | 524288 | `asfRequireAuth` (`ClearFlag`) |
| `tfDisallowXRP` | `0x00100000` | 1048576 | `asfDisallowXRP` (`SetFlag`) |
| `tfAllowXRP` | `0x00200000` | 2097152 | `asfDisallowXRP` (`ClearFlag`) |
**Caution:** The numeric values of `tf` and `asf` flags in transactions do not match up with the values they set in the accounts “at rest” in the ledger. To read the flags of an account in the ledger, see `AccountRoot` flags.
#### Blocking Incoming Transactions
[Section titled “Blocking Incoming Transactions”](#blocking-incoming-transactions)
Incoming transactions with unclear purposes may be an inconvenience for financial institutions, who would have to recognize when a customer made a mistake, and then potentially refund accounts or adjust balances depending on the mistake. The `asfRequireDest` and `asfDisallowXRP` flags are intended to protect users from accidentally sending funds in a way that is unclear about the reason the funds were sent.
For example, a destination tag is typically used to identify which hosted balance should be credited when a financial institution receives a payment. If the destination tag is omitted, it may be unclear which account should be credited, creating a need for refunds, among other problems. By using the `asfRequireDest` tag, you can ensure that every incoming payment has a destination tag, which makes it harder for others to send you an ambiguous payment by accident.
You can protect against unwanted incoming payments for non-XAH currencies by not creating trust lines in those currencies. Since XAH does not require trust, the `asfDisallowXRP` flag is used to discourage users from sending XAH to an account. However, this flag is not enforced in Xahau protocol because it could potentially cause accounts to become unusable if they run out of XAH. Instead, client applications should disallow or discourage XAH payments to accounts with the `asfDisallowXRP` flag enabled.
If you want to block *all* incoming payments, you can enable Deposit Authorization. This prevents any transaction from sending money to you, even XAH, unless your account is below the reserve requirement.
If the \[DisallowIncoming amendment]\[] :not\_enabled: is enabled, you also have the option to block all incoming Checks, NFTokenOffers, Payment Channels, and trust lines. It is generally harmless to be on the receiving end of these objects, but they can block you from deleting your account and it can be confusing to have objects you didn’t expect mixed in with the list of objects you created. To block incoming objects, use one or more of these account flags:
* `asfDisallowIncomingCheck` - for Check objects
* `asfDisallowIncomingNFTOffer` - for NFTokenOffer objects
* `asfDisallowIncomingPayChan` - for PayChannel objects
* `asfDisallowIncomingTrustline` - for RippleState (trust line) objects
When a transaction would create one of these ledger entries, if the destination account has the corresponding flag enabled, the transaction fails with the result code `tecNO_PERMISSION`. Unlike Deposit Authorization, these settings do not prevent you from receiving payments in general. Also, enabling this setting doesn’t stop you from creating these types of objects yourself (unless the destination of your transaction is also using the setting, of course).
### TransferRate
[Section titled “TransferRate”](#transferrate)
The `TransferRate` field specifies a fee to charge whenever counterparties transfer the currency you issue.
In the HTTP and WebSocket APIs, the transfer fee is represented as an integer, the amount that must be sent for 1 billion units to arrive. For example, a 20% transfer fee is represented as the value `1200000000`. The value cannot be less than 1000000000. (Less than that would indicate giving away money for sending transactions, which is exploitable.) You can specify `0` as a shortcut for `1000000000`, meaning no fee.
See Transfer Fees for more information.
# CheckCancel
> Cancels an unredeemed Check, removing it from the ledger without sending any money. The source or the destination of the check can cancel a Check at any time using this transaction type.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/URIToken.cpp)]
*(Added by the \[Checks amendment]\[].)*
### Example
[Section titled “Example”](#example)
```json
{
"Account": "rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo",
"TransactionType": "CheckCancel",
"CheckID": "49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0",
"Fee": "12"
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| --------- | --------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| `CheckID` | String | Hash256 | The ID of the Check ledger object to cancel, as a 64-character hexadecimal string. |
### Error Cases
[Section titled “Error Cases”](#error-cases)
* If the object identified by the `CheckID` does not exist or is not a Check, the transaction fails with the result `tecNO_ENTRY`.
* If the Check is not expired and the sender of the CheckCancel transaction is not the source or destination of the Check, the transaction fails with the result `tecNO_PERMISSION`.
# CheckCash
> Attempts to redeem a Check object in the ledger to receive up to the amount authorized by the corresponding CheckCreate transaction.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/URIToken.cpp)]
*(Added by the \[Checks amendment]\[].)*
### Example
[Section titled “Example”](#example)
```json
{
"Account": "rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy",
"TransactionType": "CheckCash",
"Amount": "100000000",
"CheckID": "838766BA2B995C00744175F69A1B11E32C3DBC40E64801A4056FCBD657F57334",
"Fee": "12"
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ------------ | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CheckID` | String | Hash256 | The ID of the Check ledger object to cash, as a 64-character hexadecimal string. |
| `Amount` | [Currency Amount](/docs/protocol-reference/data-types/currency-formats/#specifying-currency-amounts) | Amount | *(Optional)* Redeem the Check for exactly this amount, if possible. The currency must match that of the `SendMax` of the corresponding CheckCreate transaction. You must provide either this field or `DeliverMin`. |
| `DeliverMin` | [Currency Amount](/docs/protocol-reference/data-types/#specifying-currency-amounts) | Amount | *(Optional)* Redeem the Check for at least this amount and for as much as possible. The currency must match that of the `SendMax` of the corresponding CheckCreate transaction. You must provide either this field or `Amount`. |
The transaction ***must*** include either `Amount` or `DeliverMin`, but not both.
### Error Cases
[Section titled “Error Cases”](#error-cases)
* If the sender of the CheckCash transaction is not the `Destination` of the check, the transaction fails with the result code `tecNO_PERMISSION`.
* If the Check identified by the `CheckID` field does not exist, the transaction fails with the result `tecNO_ENTRY`.
* If the Check identified by the `CheckID` field has already expired, the transaction fails with the result `tecEXPIRED`.
* If the destination of the Check has the `RequireDest` flag enabled but the Check, as created, does not have a destination tag, the transaction fails with the result code `tecDST_TAG_NEEDED`.
* If the transaction specifies both `Amount` and `DeliverMin`, or omits both, the transaction fails with the result `temMALFORMED`.
* If the `Amount` or `DeliverMin` does not match the currency (and issuer, if not XAH) of the Check, the transaction fails with the result `temBAD_CURRENCY`.
# CheckCreate
> Create a Check object in the ledger, which is a deferred payment that can be cashed by its intended destination. The sender of this transaction is the sender of the Check.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/URIToken.cpp)]
*(Added by the \[Checks amendment]\[].)*
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType": "CheckCreate",
"Account": "rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo",
"Destination": "rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy",
"SendMax": "100000000",
"Expiration": 570113521,
"InvoiceID": "6F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B",
"DestinationTag": 1,
"Fee": "12"
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ---------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Destination` | String | AccountID | The unique address of the account that can cash the Check. |
| `SendMax` | [Currency Amount](/docs/protocol-reference/data-types/currency-formats/#specifying-currency-amounts) | Amount | Maximum amount of source currency the Check is allowed to debit the sender, including transfer fees on non-XAH currencies. The Check can only credit the destination with the same currency (from the same issuer, for non-XAH currencies). For non-XAH amounts, the nested field names MUST be lower-case. |
| `DestinationTag` | Number | UInt32 | *(Optional)* Arbitrary tag that identifies the reason for the Check, or a hosted recipient to pay. |
| `Expiration` | Number | UInt32 | *(Optional)* Time after which the Check is no longer valid, in [seconds since the Ripple Epoch](/docs/protocol-reference/data-types/#specifying-time). |
| `InvoiceID` | String | Hash256 | *(Optional)* Arbitrary 256-bit hash representing a specific reason or identifier for this Check. |
### Error Cases
[Section titled “Error Cases”](#error-cases)
* If the `Destination` account is blocking incoming Checks, the transaction fails with the result code `tecNO_PERMISSION`.
* If the `Destination` is the sender of the transaction, the transaction fails with the result code `temREDUNDANT`.
* If the `Destination` account does not exist in the ledger, the transaction fails with the result code `tecNO_DST`.
* If the `Destination` account has the `RequireDest` flag enabled but the transaction does not include a `DestinationTag` field, the transaction fails with the result code `tecDST_TAG_NEEDED`.
* If `SendMax` specifies a token which is frozen, the transaction fails with the result `tecFROZEN`.
* If the `Expiration` of the transaction is in the past, the transaction fails with the result `tecEXPIRED`.
* If the sender does not have enough XAH to meet the owner reserve after adding the Check, the transaction fails with the result `tecINSUFFICIENT_RESERVE`.
* If either the sender or the destination of the Check cannot own more objects in the ledger, the transaction fails with the result `tecDIR_FULL`.
# ClaimReward
> 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. With the IOURewardClaim amendment, this transaction also supports claiming rewards for IOU currencies 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 (XAH genesis rewards)
[Section titled “Opt-in + Claim (XAH genesis rewards)”](#opt-in--claim-xah-genesis-rewards)
```json
{
"TransactionType": "ClaimReward",
"Account": "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm",
"Issuer": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"
}
```
### Opt-out (XAH genesis rewards)
[Section titled “Opt-out (XAH genesis rewards)”](#opt-out-xah-genesis-rewards)
```json
{
"TransactionType": "ClaimReward",
"Account": "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm",
"Flags": 1
}
```
### IOU Reward Claim
[Section titled “IOU Reward Claim”](#iou-reward-claim)
*(Requires the \[IOURewardClaim amendment]\[].)*
```json
{
"TransactionType": "ClaimReward",
"Account": "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm",
"Issuer": "rIssuerAccountXXXXXXXXXXXXXXXXXXX",
"ClaimCurrency": {
"currency": "USD",
"issuer": "rIssuerAccountXXXXXXXXXXXXXXXXXXX"
}
}
```
### Fields
[Section titled “Fields”](#fields)
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | 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 (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
[Section titled “ClaimReward Flags”](#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 | Opts the account out of rewards by removing reward-related fields from the account’s ledger object. |
### Special Transaction Cost
[Section titled “Special Transaction Cost”](#special-transaction-cost)
The ClaimReward transaction has a standard transaction cost, which is the minimum transaction cost required for all transactions.
### IOU Reward Behaviour
[Section titled “IOU Reward Behaviour”](#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 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.
The IOU reward counters are entirely independent of the genesis XAH reward fields on the AccountRoot object.
### Error Cases
[Section titled “Error Cases”](#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 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 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 a `ClaimReward` transaction. |
| `tecNO_LINE` | Occurs if no trustline exists between `Account` and the issuer for the specified `ClaimCurrency`. |
# Clawback
> Revoke tokens that were previously issued by your account.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/Clawback.cpp)]
*(Added by the [Clawback amendment](/docs/features/amendments/#clawback).)*
Revoke tokens that were previously issued by your account. The **Clawback** feature is disabled by default. To use it, you must first submit an **AccountSet** transaction that enables *Allow Trust Line Clawback*. If your account has already issued tokens, you cannot enable Clawback afterward. You can only activate *Allow Trust Line Clawback* if your owner directory is completely empty — meaning before creating trust lines, offers, escrows, payment channels, checks, or signer lists. Once enabled, Clawback becomes a permanent capability of your account and cannot be undone.
***
## Example
[Section titled “Example”](#example)
```json
{
"TransactionType": "Clawback",
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Amount": {
"currency": "USD",
"issuer": "rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy",
"value": "123.45"
}
}
```
***
### Fields
[Section titled “Fields”](#fields)
A **Clawback** transaction includes:
| Field | JSON Type | Description |
| -------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Amount` | *Currency Amount* | The quantity to be revoked, as well as the counterparty from which it is taken. The `value` must not be zero. If greater than the holder’s balance, the entire balance is revoked. In the `issuer` sub-field, specify the holder’s address (not the issuer’s). |
In Xahau, an IOU/Non-XAH token on a trust line always has an issuer, but trust lines are bidirectional and under certain settings both sides may act as issuers. In this transaction, the issuer’s address goes in the `Account` field, while the holder’s address goes in the `issuer` sub-field of `Amount`.
***
## Error Cases
[Section titled “Error Cases”](#error-cases)
Besides the standard transaction errors, Clawback may fail with:
| Error Code | Description |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `temDISABLED` | The **Clawback** amendment is not enabled on Xahau. |
| `temBAD_AMOUNT` | The holder’s balance is zero. (It is not an error if the specified amount exceeds the holder’s balance — in that case, the full available balance is revoked). Also occurs if the counterparty in `Amount` is the same account submitting the transaction. |
| `tecNO_LINE` | No trust line exists with the specified counterparty, or the trust line has a balance of zero. |
| `tecNO_PERMISSION` | Happens if you try to enable `lsfAllowTrustLineClawback` while `lsfNoFreeze` is already enabled, or vice versa. |
# CronSet
> A CronSet transaction enables Hooks to schedule recurring self-invocations at regular intervals, similar to Linux cronjobs. This facilitates complex governance structures and automated processes within Hook frameworks.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/CronSet.cpp)]
*(Added by the CronSet amendment.)*
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType": "CronSet",
"Account": "rYourAccountAddress",
"StartTime": 816348759,
"RepeatCount": 3,
"DelaySeconds": 120
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| -------------- | --------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Account` | String | AccountID | The Hook account initiating the cron. This is the account that will be invoked when the cron executes. |
| `StartTime` | Number | UInt32 | *(Optional)* Ripple Epoch timestamp when the first execution should occur. Use `0` for immediate execution. If omitted when deleting a cron, the transaction removes the cron. |
| `RepeatCount` | Number | UInt32 | *(Optional)* Number of times the cron should execute (maximum 256 per transaction). Can be extended via subsequent CronSet transactions. Omit when deleting a cron. |
| `DelaySeconds` | Number | UInt32 | *(Optional)* Time interval in seconds between each execution. Omit when deleting a cron. |
### How CronSet Works
[Section titled “How CronSet Works”](#how-cronset-works)
CronSet transactions enable scheduled, automated Hook execution on the Xahau blockchain at regular intervals, eliminating the need for external services or manual triggers.
The workflow involves four key steps:
1. Install a Hook with the `hsfCOLLECT` flag enabled
2. Enable Transaction Signature Hook Collection `asfTshCollect` on your account (SetFlag: 11)
3. Create a CronSet transaction with scheduling parameters
4. Let Xahau handle automatic execution
### Execution Mechanism
[Section titled “Execution Mechanism”](#execution-mechanism)
When a cron is ready to execute, the Cron engine inserts a pseudo-transaction of type `Cron` into the ledger, containing an `Owner` field referencing the originating Hook account. Hook developers must enable collect calls, as the Owner constitutes a weak transactional stakeholder.
The scheduled Hook will be invoked automatically at the specified intervals without requiring external triggers.
### Time Format
[Section titled “Time Format”](#time-format)
Xahau uses Ripple Epoch time (seconds since January 1, 2000), not Unix time. To convert from JavaScript Date:
```javascript
const rippleEpochTime = Math.floor(Date.now() / 1000) - 946684800;
```
### Deleting a Cron
[Section titled “Deleting a Cron”](#deleting-a-cron)
To remove an existing Cron, omit `StartTime`, `RepeatCount`, and `DelaySeconds` while setting `Flags: 1` (tfCronUnset):
```json
{
"TransactionType": "CronSet",
"Account": "rYourAccountAddress",
"Flags": 1
}
```
### Extending Repeat Count
[Section titled “Extending Repeat Count”](#extending-repeat-count)
Upon reaching a minimum threshold, a subsequent CronSet transaction can extend the repeat count beyond the initial 256 execution limit by submitting a new CronSet transaction with an updated `RepeatCount`.
### CronSet Flags
[Section titled “CronSet Flags”](#cronset-flags)
Transactions of the CronSet type support additional values in the `Flags` field, as follows:
| Flag Name | Hex Value | Decimal Value | Description |
| ------------- | ------------ | ------------- | --------------------------------------------------------------------------------- |
| `tfCronUnset` | `0x00000001` | 1 | Removes an existing Cron. All scheduling fields must be omitted when this is set. |
### Limitations and Constraints
[Section titled “Limitations and Constraints”](#limitations-and-constraints)
* CronSet cannot currently be delegated to another account
* Hooks must self-emit CronSet transactions or operate under joint management arrangements
* `RepeatCount`: Must be greater than 0 and cannot exceed 256 per transaction (extendable via subsequent transactions)
* `DelaySeconds`: Maximum of 31,536,000 seconds (365 days)
* `StartTime`: Must be current time or future; cannot exceed 365 days ahead
* Cannot combine `tfCronUnset` flag with `DelaySeconds`, `RepeatCount`, or `StartTime` fields
* When creating a cron, `DelaySeconds` and `RepeatCount` must both exist or both be absent
### Error Cases
[Section titled “Error Cases”](#error-cases)
Besides errors that can occur for all transactions, CronSet transactions can result in the following transaction result codes:
| Error Code | Description |
| ----------------- | --------------------------------------------------------------------------------------------------- |
| `temDISABLED` | Occurs if the Cron feature is not enabled. |
| `temINVALID_FLAG` | Occurs if invalid flags are set in the transaction. |
| `temMALFORMED` | Occurs if the transaction is malformed with invalid field combinations. |
| `tecEXPIRED` | Occurs if `StartTime` is in the past or more than 365 days in the future. |
| `tefINTERNAL` | Occurs if the account ledger entry is missing. |
| `tefBAD_LEDGER` | Occurs if the Cron object is missing, points to a non-cron entry, or owner directory removal fails. |
# DepositPreauth
> A DepositPreauth transaction gives another account pre-approval to deliver payments to the sender of this transaction.
Tip
You can use this transaction to preauthorize certain counterparties before you enable Deposit Authorization. This may be useful to ensure a smooth transition from not requiring deposit authorization to requiring it.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/URIToken.cpp)]
*Added by the \[DepositPreauth amendment]\[].*
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType" : "DepositPreauth",
"Account" : "rsUiUMpnrgxQp24dJYZDhmV4bE3aBtQyt8",
"Authorize" : "rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de",
"Fee" : "10",
"Flags" : 2147483648,
"Sequence" : 2
}
```
### Fields
[Section titled “Fields”](#fields)
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ------------- | --------- | ------------------------------------------------------- | -------------------------------------------------------------------------------- |
| `Authorize` | String | AccountID | *(Optional)* Xahau address of the sender to preauthorize. |
| `Unauthorize` | String | AccountID | *(Optional)* Xahau address of a sender whose preauthorization should be revoked. |
You must provide *either* `Authorize` or `Unauthorize`, but not both.
### Error Cases
[Section titled “Error Cases”](#error-cases)
* An account cannot preauthorize (or unauthorize) its own address. Attempting to do so fails with the result `temCANNOT_PREAUTH_SELF`.
* Attempting to preauthorize an account which is already preauthorized fails with the result `tecDUPLICATE`.
* Attempting to unauthorize an account which is not preauthorized fails with the result `tecNO_ENTRY`.
* Attempting to preauthorize an address that is not funded in the ledger fails with the result `tecNO_TARGET`.
* Adding authorization adds a DepositPreauth object to the ledger, which counts toward the owner reserve requirement. If the sender of the transaction does not have enough XAH to pay for the increased reserve, the transaction fails with the result `tecINSUFFICIENT_RESERVE`. If the sender of the account is already at the maximum number of owned objects, the transaction fails with the result `tecDIR_FULL`.
# EscrowCancel
> Return escrowed XAH or IOU to the sender.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/URIToken.cpp)]
*Added by the \[Escrow amendment]\[].*
### Cancel Using OfferSequence
[Section titled “Cancel Using OfferSequence”](#cancel-using-offersequence)
```json
{
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"TransactionType": "EscrowCancel",
"Owner": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"OfferSequence": 7,
}
```
### Cancel Using EscrowID
[Section titled “Cancel Using EscrowID”](#cancel-using-escrowid)
```json
{
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"TransactionType": "EscrowCancel",
"Owner": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"EscrowID": "49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0",
}
```
### Fields
[Section titled “Fields”](#fields)
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| --------------- | --------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Owner` | String | AccountID | Address of the source account that funded the escrow payment. |
| `OfferSequence` | Number | UInt32 | *(Optional)* Transaction sequence (or Ticket number) of [EscrowCreate transaction](/docs/protocol-reference/transactions/transaction-types/escrowcreate) that created the escrow to cancel. |
| `EscrowID` | String | Hash256 | *(Optional)* The ID of the Escrow ledger object to cancel, as a 64-character hexadecimal string. |
Any account may submit an EscrowCancel transaction.
* If the corresponding [EscrowCreate transaction](/docs/protocol-reference/transactions/transaction-types/escrowcreate) did not specify a `CancelAfter` time, the EscrowCancel transaction fails.
* Otherwise the EscrowCancel transaction fails if the `CancelAfter` time is after the close time of the most recently-closed ledger.
# EscrowCreate
> Sequester XAH or IOU until the escrow process either finishes or is canceled.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/URIToken.cpp)]
*Added by the \[Escrow amendment]\[].*
### Example
[Section titled “Example”](#example)
```json
{
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"TransactionType": "EscrowCreate",
"Amount" : {
"currency" : "USD",
"value" : "1",
"issuer" : "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"
},
"Destination": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
"CancelAfter": 533257958,
"FinishAfter": 533171558,
"Condition": "A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100",
"DestinationTag": 23480,
"SourceTag": 11747
}
```
### Fields
[Section titled “Fields”](#fields)
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ---------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Amount` | [Currency Amount](/docs/protocol-reference/data-types/currency-formats/#specifying-currency-amounts) | Amount | Amount to deduct from the sender’s balance and escrow. Once escrowed, the Amount can either go to the `Destination` address (after the `FinishAfter` time) or returned to the sender (after the `CancelAfter` time). |
| `Destination` | String | AccountID | Address to receive escrowed Amount. |
| `CancelAfter` | Number | UInt32 | *(Optional)* The time, in [seconds since the Ripple Epoch](/docs/protocol-reference/data-types/#specifying-time), when this escrow expires. This value is immutable; the funds can only be returned to the sender after this time. |
| `FinishAfter` | Number | UInt32 | *(Optional)* The time, in [seconds since the Ripple Epoch](/docs/protocol-reference/data-types/#specifying-time), when the escrowed Amount can be released to the recipient. This value is immutable; the funds cannot move until this time is reached. |
| `Condition` | String | Blob | *(Optional)* Hex value representing a [PREIMAGE-SHA-256 crypto-condition](https://tools.ietf.org/html/draft-thomas-crypto-conditions-02#section-8.1). The funds can only be delivered to the recipient if this condition is fulfilled. |
| `DestinationTag` | Number | UInt32 | *(Optional)* Arbitrary tag to further specify the destination for this escrowed payment, such as a hosted recipient at the destination address. |
Either `CancelAfter` or `FinishAfter` must be specified. If both are included, the `FinishAfter` time must be before the `CancelAfter` time.
With the \[fix1571 amendment]\[] enabled, you must supply `FinishAfter`, `Condition`, or both. \[New in: rippled 1.0.0]\[]
# EscrowFinish
> Deliver XAH or IOU from a held payment to the recipient.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/URIToken.cpp)]
*Added by the \[Escrow amendment]\[].*
### Finish with OfferSequence
[Section titled “Finish with OfferSequence”](#finish-with-offersequence)
```json
{
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"TransactionType": "EscrowFinish",
"Owner": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"OfferSequence": 7,
"Condition": "A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100",
"Fulfillment": "A0028000"
}
```
### Finish with EscrowID
[Section titled “Finish with EscrowID”](#finish-with-escrowid)
```json
{
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"TransactionType": "EscrowFinish",
"Owner": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"EscrowID": "49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0",
"Condition": "A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100",
"Fulfillment": "A0028000"
}
```
### Fields
[Section titled “Fields”](#fields)
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| --------------- | --------- | ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Owner` | String | AccountID | Address of the source account that funded the held payment. |
| `OfferSequence` | Number | UInt32 | *(Optional)* Transaction sequence of [EscrowCreate transaction](/docs/protocol-reference/transactions/transaction-types/escrowcreate) that created the held payment to finish. |
| `Condition` | String | Blob | *(Optional)* Hex value matching the previously-supplied [PREIMAGE-SHA-256 crypto-condition](https://tools.ietf.org/html/draft-thomas-crypto-conditions-02#section-8.1) of the held payment. |
| `Fulfillment` | String | Blob | *(Optional)* Hex value of the [PREIMAGE-SHA-256 crypto-condition fulfillment](https://tools.ietf.org/html/draft-thomas-crypto-conditions-02#section-8.1.4) matching the held payment’s `Condition`. |
| `EscrowID` | String | Hash256 | *(Optional)* The ID of the Escrow ledger object to finish, as a 64-character hexadecimal string. |
Any account may submit an EscrowFinish transaction.
* If the held payment has a `FinishAfter` time, you cannot execute it before this time. Specifically, if the corresponding [EscrowCreate transaction](/docs/protocol-reference/transactions/transaction-types/escrowcreate) specified a `FinishAfter` time that is after the close time of the most recently-closed ledger, the EscrowFinish transaction fails.
* If the held payment has a `Condition`, you cannot execute it unless you provide a matching `Fulfillment` for the condition.
* You cannot execute a held payment after it has expired. Specifically, if the corresponding [EscrowCreate transaction](/docs/protocol-reference/transactions/transaction-types/escrowcreate) specified a `CancelAfter` time that is before the close time of the most recently-closed ledger, the EscrowFinish transaction fails.
**Note:** The minimum transaction cost to submit an EscrowFinish transaction increases if it contains a fulfillment. If the transaction has no fulfillment, the transaction cost is the standard 10 drops. If the transaction contains a fulfillment, the transaction cost is 330 [drops of XAH](/docs/protocol-reference/data-types/#specifying-currency-amounts) plus another 10 drops for every 16 bytes in size of the preimage.
In non-production networks, it may be possible to delete the destination account of a pending escrow. In this case, an attempt to finish the escrow fails with the result `tecNO_TARGET`, but the escrow object remains unless it has expired normally. If another payment re-creates the destination account, the escrow can be finished successfully. The destination account of an escrow can only be deleted if the escrow was created before the fix1523 amendment became enabled. No such escrows exist in the production Xahau, so this edge case is not possible on the production Xahau. This edge case is also not possible in test networks that enable both fix1523 and Escrow amendments at the same time, which is the default when you start a new genesis ledger.
# GenesisMint - (Emitted Txn)
> The GenesisMint transaction is used to mint new XAH and distribute it to multiple accounts. This transaction can only be used by the genesis account.
\[[Source](https://github.com/ripple/rippled/blob/develop/src/ripple/app/tx/impl/GenesisMint.cpp)]
*Added by the [XahauGenesis amendment](/docs/features/amendments/#xahaugenesis) and the [Hooks amendment](/docs/features/amendments/#hooks)*
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType": "GenesisMint",
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"GenesisMints": [
{
"GenesisMint": {
"Destination": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe",
"Amount": "1000000000"
},
}
]
}
```
### Fields
[Section titled “Fields”](#fields)
| Field | JSON Type | Internal Type | Description |
| -------------- | --------- | ------------- | -------------------------------------------------------------------------------- |
| `Account` | String | AccountID | The address of the genesis account that will mint and distribute XAH. |
| `GenesisMints` | Array | Array | An array of objects representing the destinations and amounts of the minted XAH. |
### GenesisMint Object
[Section titled “GenesisMint Object”](#genesismint-object)
The GenesisMint transaction includes an array of objects called `GenesisMints`. Each object represents a destination account and the amount of XAH to be minted and distributed to that account.
| Field | JSON Type | Internal Type | Description |
| ----------------- | --------- | ------------- | -------------------------------------------------------------------------- |
| `Destination` | String | AccountID | The address of the account that will receive the minted XAH. |
| `Amount` | String | Amount | The amount of XAH to be minted and distributed to the destination account. |
| `GovernanceFlags` | String | Hash256 | *(Optional)* The governance flags associated with the destination account. |
| `GovernanceMarks` | String | Hash256 | *(Optional)* The governance marks associated with the destination account. |
### Special Transaction Cost
[Section titled “Special Transaction Cost”](#special-transaction-cost)
The GenesisMint transaction has a standard transaction cost, which is the minimum transaction cost required for all transactions.
### Error Cases
[Section titled “Error Cases”](#error-cases)
Besides errors that can occur for all transactions, the GenesisMint transaction can result in the following transaction result codes:
| Error Code | Description |
| -------------- | ------------------------------------------------------------------------------------------ |
| `temDISABLED` | Occurs if the “Hooks” or “XahauGenesis” amendments are not enabled. |
| `temMALFORMED` | Occurs if the transaction is malformed, such as missing required fields or invalid values. |
# Import
> Import is a new transaction which accepts an XPOP from the XRPL Mainnet chain (network_id=0) or Testnet (network_id=1) and provides account synchronisation.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/URIToken.cpp)]
*(Added by the \[Import amendment]\[].)*
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType": "Import",
"Sequence": 0,
"Fee": "0",
"Account": "rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo",
"Blob" : "DEADBEEF"
}
```
### Fields
[Section titled “Fields”](#fields)
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ------------- | --------- | ------------------------------------------------------- | ---------------------------------------------------- |
| `Blob` | String | Blob | Hex value representing an XPOP |
| `Issuer` | String | AccountID | (Optional) Address that can be used inside the Hook. |
| `Destination` | String | AccountID | (Optional) Address that can be used inside the Hook. |
### Error Cases
[Section titled “Error Cases”](#error-cases)
* If the account is Non Activated then the `Sequence` must be 0 and the `Fee` must also be 0
* If the account is Activated then the `Sequence` and the `Fee` are calculated using the standard method.
* If the `Issuer` field is present then the `Fee` must be calculated using the standard method.
### Notes
[Section titled “Notes”](#notes)
*It is recommended that if you use a `SignerList` or `RegularKey` to sign your transactions that you key your accounts **FIRST** before attempting to *B2M* XAH* .
* If the inner (xpop) transaction is `AccountSet` the mainet existing flags will be transfered to the new network.
* If the inner (xpop) transaction is `SetRegularKey` with the `RegularKey` field omitted or empty, and a signers list does not exist for the account then the `lsfDisableMaster` flag will be set on the account.
* If the inner (xpop) transaction is `SetRegularKey` then the `lsfPasswordSpent` flag will be set on the account.
* TicketSequence is not available on `Import`
### Importing for the Issuer
[Section titled “Importing for the Issuer”](#importing-for-the-issuer)
For issuers, there are additional steps to follow before their asset holders can import transactions.
Firstly, issuers need to install a hook. There are two options for this: `B2MNFToken` or `B2MPayment`.
#### B2MNFToken
[Section titled “B2MNFToken”](#b2mnftoken)
A `NFTokenBurn` transaction on mainnet will result in a `URITokenMint` transaction on the network.
> c hook:
#### B2MPayment
[Section titled “B2MPayment”](#b2mpayment)
A `Payment` transaction on mainnet to the Issuer will result in a `Payment` transaction from the Issuer on the network.
> c hook:
*Please note that the process of importing for the issuer involves specific transaction types and requires careful configuration. Always ensure that the hooks are correctly set up and that the transactions are valid for the intended operations.*
# Invoke
> An Invoke transaction is used to call a hook, which is a piece of code that is executed in response to certain ledger operations.
\[[Source](https://github.com/ripple/rippled/blob/develop/src/ripple/app/tx/impl/Invoke.cpp)]
*(Added by the [Hooks amendment](/docs/features/amendments/#hooks).)*
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType": "Invoke",
"Account": "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm",
"Blob": "697066733A2F2F4445414442454546",
"Destination": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe"
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Required? | Description |
| ------------- | --------- | ------------------------------------------------------- | --------- | ---------------------------------------------------------- |
| `Account` | String | AccountID | Yes | The address of the account that is invoking the hook. |
| `Blob` | String | Blob | No | A blob of data that is passed to the hook. (128k byte max) |
| `Destination` | String | AccountID | No | The address of the account that is the target of the hook. |
### Special Transaction Cost
[Section titled “Special Transaction Cost”](#special-transaction-cost)
The Invoke transaction has a standard transaction cost, plus an additional cost based on the size of the Blob field.
### Error Cases
[Section titled “Error Cases”](#error-cases)
Besides errors that can occur for all transactions, Invoke transactions can result in the following transaction result codes:
| Error Code | Description |
| --------------- | ------------------------------------------------------------------------ |
| `temDISABLED` | Occurs if the Hooks amendment is not enabled. |
| `temMALFORMED` | Occurs if the Blob field is larger than 128k bytes. |
| `terNO_ACCOUNT` | Occurs if the sending account or the destination account does not exist. |
# OfferCancel
> An OfferCancel transaction removes an Offer object from Xahau.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/URIToken.cpp)]
### Cancel with OfferSequence
[Section titled “Cancel with OfferSequence”](#cancel-with-offersequence)
```json
{
"TransactionType": "OfferCancel",
"Account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"Fee": "12",
"Flags": 0,
"LastLedgerSequence": 7108629,
"OfferSequence": 6,
"Sequence": 7
}
```
### Cancel with OfferID
[Section titled “Cancel with OfferID”](#cancel-with-offerid)
```json
{
"TransactionType": "OfferCancel",
"Account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"Fee": "12",
"Flags": 0,
"LastLedgerSequence": 7108629,
"OfferID": "49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0",
"Sequence": 7
}
```
### Fields
[Section titled “Fields”](#fields)
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| --------------- | --------- | ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `OfferSequence` | Number | UInt32 | *(Optional)* The sequence number (or Ticket number) of a previous OfferCreate transaction. If specified, cancel any offer object in the ledger that was created by that transaction. It is not considered an error if the offer specified does not exist. |
| `OfferID` | String | Hash256 | *(Optional)* The ID of the Offer ledger object to cancel, as a 64-character hexadecimal string. |
*Tip:* To remove an old offer and replace it with a new one, you can use an [OfferCreate transaction](/docs/protocol-reference/transactions/transaction-types/offercreate) with an `OfferSequence` parameter, instead of using OfferCancel and another OfferCreate.
The OfferCancel method returns `tesSUCCESS` even if it did not find an offer with the matching sequence number.
# OfferCreate
> An OfferCreate transaction places an Offer in the decentralized exchange.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/URIToken.cpp)]
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType": "OfferCreate",
"Account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"Fee": "12",
"Flags": 0,
"LastLedgerSequence": 7108682,
"Sequence": 8,
"TakerGets": "6000000",
"TakerPays": {
"currency": "GKO",
"issuer": "ruazs5h1qEsqpke88pcqnaseXdm6od2xc",
"value": "2"
}
}
```
### Fields
[Section titled “Fields”](#fields)
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| --------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Expiration` | Number | UInt32 | *(Optional)* Time after which the Offer is no longer active, in [seconds since the Ripple Epoch](/docs/protocol-reference/data-types/#specifying-time). |
| `OfferSequence` | Number | UInt32 | *(Optional)* An Offer to delete first, specified in the same way as [OfferCancel](/docs/protocol-reference/transactions/transaction-types/offercancel). |
| `OfferID` | String | Hash256 | *(Optional)* The ID of the Offer ledger object to cancel, as a 64-character hexadecimal string. |
| `TakerGets` | [Currency Amount](/docs/protocol-reference/data-types/currency-formats/#specifying-currency-amounts) | Amount | The amount and type of currency being sold. |
| `TakerPays` | [Currency Amount](/docs/protocol-reference/data-types/currency-formats/#specifying-currency-amounts) | Amount | The amount and type of currency being bought. |
### OfferCreate Flags
[Section titled “OfferCreate Flags”](#offercreate-flags)
Transactions of the OfferCreate type support additional values in the `Flags` field, as follows:
| Flag Name | Hex Value | Decimal Value | Description |
| --------------------- | ------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tfPassive` | `0x00010000` | 65536 | If enabled, the Offer does not consume Offers that exactly match it, and instead becomes an Offer object in the ledger. It still consumes Offers that cross it. |
| `tfImmediateOrCancel` | `0x00020000` | 131072 | Treat the Offer as an [Immediate or Cancel order](http://en.wikipedia.org/wiki/Immediate_or_cancel). The Offer never creates an \[Offer object]\[] in the ledger: it only trades as much as it can by consuming existing Offers at the time the transaction is processed. If no Offers match, it executes “successfully” without trading anything. In this case, the transaction still uses the result code `tesSUCCESS`. |
| `tfFillOrKill` | `0x00040000` | 262144 | Treat the offer as a [Fill or Kill order](http://en.wikipedia.org/wiki/Fill_or_kill). The Offer never creates an \[Offer object]\[] in the ledger, and is canceled if it cannot be fully filled at the time of execution. By default, this means that the owner must receive the full `TakerPays` amount; if the `tfSell` flag is enabled, the owner must be able to spend the entire `TakerGets` amount instead. |
| `tfSell` | `0x00080000` | 524288 | Exchange the entire `TakerGets` amount, even if it means obtaining more than the `TakerPays` amount in exchange. |
### Error Cases
[Section titled “Error Cases”](#error-cases)
| Error Code | Description |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `temINVALID_FLAG` | Occurs if the transaction specifies both `tfImmediateOrCancel` and `tfFillOrKill`. |
| `tecEXPIRED` | Occurs if the transaction specifies an `Expiration` time that has already passed. |
| `tecKILLED` | Occurs if the transaction specifies `tfFillOrKill`, and the full amount cannot be filled. If the *\[ImmediateOfferKilled amendment]\[]* is enabled, this result code also occurs when the transaction specifies `tfImmediateOrCancel` and executes without moving funds (previously, this would return `tesSUCCESS`). |
| `temBAD_EXPIRATION` | Occurs if the transaction contains an `Expiration` field that is not validly formatted. |
| `temBAD_SEQUENCE` | Occurs if the transaction contains an `OfferSequence` that is not validly formatted, or is higher than the transaction’s own `Sequence` number. |
| `temBAD_OFFER` | Occurs if the Offer tries to trade XAH for XAH, or tries to trade an invalid or negative amount of a token. |
| `temREDUNDANT` | Occurs if the transaction specifies a token for the same token (same issuer and currency code). |
| `temBAD_CURRENCY` | Occurs if the transaction specifies a token with the currency code “XAH”. |
| `temBAD_ISSUER` | Occurs if the transaction specifies a token with an invalid `issuer` value. |
| `tecNO_ISSUER` | Occurs if the transaction specifies a token whose `issuer` value is not a funded account in the ledger. |
| `tecFROZEN` | Occurs if the transaction involves a token on a frozen trust line (including local and global freezes). |
| `tecUNFUNDED_OFFER` | Occurs if the owner does not hold a positive amount of the `TakerGets` currency. (Exception: if `TakerGets` specifies a token that the owner issues, the transaction can succeed.) |
| `tecNO_LINE` | Occurs if the transaction involves a token whose issuer uses Authorized Trust Lines and the necessary trust line does not exist. |
| `tecNO_AUTH` | Occurs if the transaction involves a token whose issuer uses Authorized Trust Lines and the the trust line that would receive the tokens exists but has not been authorized. |
| `tecINSUF_RESERVE_OFFER` | Occurs if the owner does not have enough XAH to meet the reserve requirement of adding a new Offer object to the ledger, and the transaction did not convert any currency. (If the transaction successfully traded any amount, the transaction succeeds with the result code `tesSUCCESS`, but does not create an Offer object in the ledger for the rest.) |
| `tecDIR_FULL` | Occurs if the owner owns too many items in the ledger, or the order book contains too many Offers at the same exchange rate already. |
# OracleDelete
> 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
[Section titled “Example”](#example)
```json
{
"TransactionType": "OracleDelete",
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"OracleDocumentID": 1
}
```
### Fields
[Section titled “Fields”](#fields)
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | 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
[Section titled “Special Transaction Cost”](#special-transaction-cost)
OracleDelete transactions have the standard transaction cost.
### Error Cases
[Section titled “Error Cases”](#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`. |
# OracleSet
> 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
[Section titled “Create”](#create)
```json
{
"TransactionType": "OracleSet",
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"OracleDocumentID": 1,
"Provider": "70726F7669646572",
"AssetClass": "63757272656E6379",
"LastUpdateTime": 1763033559,
"PriceDataSeries": [
{
"PriceData": {
"BaseAsset": "XAH",
"QuoteAsset": "USD",
"AssetPrice": 74560,
"Scale": 4
}
}
]
}
```
### Update
[Section titled “Update”](#update)
```json
{
"TransactionType": "OracleSet",
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
"OracleDocumentID": 1,
"LastUpdateTime": 1763033700,
"PriceDataSeries": [
{
"PriceData": {
"BaseAsset": "XAH",
"QuoteAsset": "USD",
"AssetPrice": 74800,
"Scale": 4
}
}
]
}
```
### Fields
[Section titled “Fields”](#fields)
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | 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 | 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
[Section titled “PriceData Object”](#pricedata-object)
Each entry in `PriceDataSeries` is a `PriceData` object:
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | 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
[Section titled “Reserve”](#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
[Section titled “Special Transaction Cost”](#special-transaction-cost)
OracleSet transactions have the standard transaction cost.
### Error Cases
[Section titled “Error Cases”](#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 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. |
| `tecINSUFFICIENT_RESERVE` | The account does not have enough XAH to meet the reserve requirement for creating the Oracle object. |
# Payment
> A Payment transaction represents a transfer of value from one account to another. (Depending on the path taken, this can involve additional exchanges of value, which occur atomically.) This transactio
[\[Source\]](https://github.com/ripple/rippled/blob/5425a90f160711e46b2c1f1c93d68e5941e4bfb6/src/ripple/app/transactors/Payment.cpp)
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType" : "Payment",
"Account" : "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Destination" : "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"Amount" : {
"currency" : "USD",
"value" : "1",
"issuer" : "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"
},
"Fee": "12",
"Flags": 2147483648,
"Sequence": 2,
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ---------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Amount` | [Currency Amount](/docs/protocol-reference/data-types/currency-formats/#specifying-currency-amounts) | Amount | The amount of currency to deliver. For non-XAH amounts, the nested field names MUST be lower-case. If the `tfPartialPayment` flag is set, deliver *up to* this amount instead. |
| `Destination` | String | AccountID | The unique address of the account receiving the payment. |
| `DestinationTag` | Number | UInt32 | *(Optional)* Arbitrary tag that identifies the reason for the payment to the destination, or a hosted recipient to pay. |
| `InvoiceID` | String | Hash256 | *(Optional)* Arbitrary 256-bit hash representing a specific reason or identifier for this payment. |
| `Paths` | Array of path arrays | PathSet | (Optional, auto-fillable) Array of payment paths to be used for this transaction. Must be omitted for XAH-to-XAH transactions. |
| `SendMax` | [Currency Amount](/docs/protocol-reference/data-types/currency-formats/#specifying-currency-amounts) | Amount | *(Optional)* Highest amount of source currency this transaction is allowed to cost, including transfer fees, exchange rates, and [slippage](http://en.wikipedia.org/wiki/Slippage_\(finance\)). Does not include the XAH destroyed as a cost for submitting the transaction. For non-XAH amounts, the nested field names MUST be lower-case. Must be supplied for cross-currency/cross-issue payments. Must be omitted for XAH-to-XAH payments. |
| `DeliverMin` | [Currency Amount](/docs/protocol-reference/data-types/#specifying-currency-amounts) | Amount | *(Optional)* Minimum amount of destination currency this transaction should deliver. Only valid if this is a partial payment. For non-XAH amounts, the nested field names are lower-case. |
### Types of Payments
[Section titled “Types of Payments”](#types-of-payments)
The Payment transaction type is a general-purpose tool that can represent several different types of abstract actions. You can identify the transaction type based on the transaction’s fields, as described in the table below:
| Payment type | `Amount` | `SendMax` | `Paths` | `Address` = `Destination`? | Description |
| ---------------------------- | ------------------------------- | ------------------------------- | ---------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Direct XAH-to-XAH Payment | String (XAH) | Omitted | Omitted | No | Transfers XAH directly from one account to another. Always delivers the exact amount. No fee applies other than the basic transaction cost. |
| Creating or redeeming tokens | Object | Object (optional) | Optional | No | Increases or decreases the amount of a non-XAH currency or asset tracked in Xahau. Transfer fees and freezes do not apply when sending and redeeming directly. |
| Cross-currency Payment | Object (non-XAH) / String (XAH) | Object (non-XAH) / String (XAH) | Usually required | No | Send tokens from one holder to another. The `Amount` or `SendMax` can be XAH or tokens, but they cannot both be XAH. These payments ripple through the issuer and can take longer paths through several intermediaries if the transaction specifies a path set. Transfer fees set by the issuer(s) apply to this type of transaction. These transactions consume offers in the decentralized exchange to connect between different currencies, or possibly even between currencies with the same currency code and different issuers. |
| Partial payment | Object (non-XAH) / String (XAH) | Object (non-XAH) / String (XAH) | Usually required | No | Sends *up to* a specific amount of any currency. Uses the `tfPartialPayment` flag. May include a `DeliverMin` amount specifying the minimum that the transaction must deliver to be successful; if the transaction does not specify `DeliverMin`, it can succeed by delivering *any positive amount*. |
| Currency conversion | Object (non-XAH) / String (XAH) | Object (non-XAH) / String (XAH) | Required | Yes | Consumes offers in the decentralized exchange to convert one currency to another, possibly taking [arbitrage](https://en.wikipedia.org/wiki/Arbitrage) opportunities. The `Amount` and `SendMax` cannot both be XAH. Also called a *circular payment* because it delivers money to the sender. The Data API tracks this type of transaction as an “exchange” and not a “payment”. |
### Special issuer Values for SendMax and Amount
[Section titled “Special issuer Values for SendMax and Amount”](#special-issuer-values-for-sendmax-and-amount)
Most of the time, the `issuer` field of a non-XAH [Currency Amount](/docs/protocol-reference/data-types/#specifying-currency-amounts) indicates the issuer of a token. However, when describing payments, there are special rules for the `issuer` field in the `Amount` and `SendMax` fields of a payment.
* There is only ever one balance between two addresses for the same currency code. This means that, sometimes, the `issuer` field of an amount actually refers to a counterparty, instead of the address that issued the token.
* When the `issuer` field of the destination `Amount` field matches the `Destination` address, it is treated as a special case meaning “any issuer that the destination accepts.” This includes all addresses to which the destination has trust lines with a positive limit, as well as tokens with the same currency code issued by the destination.
* When the `issuer` field of the `SendMax` field matches the source account’s address, it is treated as a special case meaning “any issuer that the source can use.” This includes creating new tokens on trust lines that other accounts have extended to the source account, and sending tokens the source account holds from other issuers.
### Creating Accounts
[Section titled “Creating Accounts”](#creating-accounts)
The Payment transaction type can create new accounts in Xahau by sending enough XAH to an unfunded address. Other transactions to unfunded addresses always fail.
For more information, see Accounts.
### Paths
[Section titled “Paths”](#paths)
If present, the `Paths` field must contain a *path set* - an array of path arrays. Each individual path represents one way value can flow from the sender to receiver through various intermediary accounts and order books. A single transaction can potentially use multiple paths, for example if the transaction exchanges currency using several different order books to achieve the best rate.
You must omit the `Paths` field for direct payments, including:
* An XAH-to-XAH transfer.
* A direct transfer on a trust line that connects the sender and receiver.
If the `Paths` field is provided, the server decides at transaction processing time which paths to use, from the provided set plus a *default path* (the most direct way possible to connect the specified accounts). This decision is deterministic and attempts to minimize costs, but it is not guaranteed to be perfect.
The `Paths` field must not be an empty array, nor an array whose members are all empty arrays.
For more information, see Paths.
### Payment Flags
[Section titled “Payment Flags”](#payment-flags)
Transactions of the Payment type support additional values in the `Flags` field, as follows:
| Flag Name | Hex Value | Decimal Value | Description |
| ------------------ | ------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `tfNoDirectRipple` | `0x00010000` | 65536 | Do not use the default path; only use paths included in the `Paths` field. This is intended to force the transaction to take arbitrage opportunities. Most clients do not need this. |
| `tfPartialPayment` | `0x00020000` | 131072 | If the specified `Amount` cannot be sent without spending more than `SendMax`, reduce the received amount instead of failing outright. See Partial Payments for more details. |
| `tfLimitQuality` | `0x00040000` | 262144 | Only take paths where all the conversions have an input:output ratio that is equal or better than the ratio of `Amount`:`SendMax`. See Limit Quality for details. |
### Partial Payments
[Section titled “Partial Payments”](#partial-payments)
A partial payment allows a payment to succeed by reducing the amount received. Partial payments are useful for returning payments without incurring additional costs to oneself. However, partial payments can also be used to exploit integrations that naively assume the `Amount` field of a successful transaction always describes the exact amount delivered.
A partial payment is any [Payment transaction](/docs/protocol-reference/transactions/transaction-types/payment) with the `tfPartialPayment` flag enabled. A partial payment can be successful if it delivers any positive amount greater than or equal to its `DeliverMin` field (or any positive amount at all if `DeliverMin` is not specified) without sending more than the `SendMax` value.
The `delivered_amount` field of a payment’s metadata indicates the amount of currency actually received by the destination account.
For more information, see the full article on Partial Payments.
### Limit Quality
[Section titled “Limit Quality”](#limit-quality)
Xahau defines the “quality” of a currency exchange as the ratio of the numeric amount in to the numeric amount out. For example, if you spend $2 USD to receive £1 GBP, then the “quality” of that exchange is `0.5`.
The `tfLimitQuality` flag allows you to set a minimum quality of conversions that you are willing to take. This limit quality is defined as the destination `Amount` divided by the `SendMax` amount (the numeric amounts only, regardless of currency). When set, the payment processing engine avoids using any paths whose quality (conversion rate) is worse (numerically lower) than the limit quality.
By itself, the `tfLimitQuality` flag reduces the number of situations in which a transaction can succeed. Specifically, it rejects payments where some part of the payment uses an unfavorable conversion, even if the overall *average* quality of conversions in the payment is equal or better than the limit quality. If a payment is rejected in this way, the transaction result is `tecPATH_DRY`.
Consider the following example. If I am trying to send you 100 Chinese Yuan (`Amount` = 100 CNY) for 20 United States dollars (`SendMax` = 20 USD) or less, then the limit quality is `5`. Imagine one trader is offering ¥95 for $15 (a ratio of about `6.3` CNY per USD), but the next best offer in the market is ¥5 for $2 (a ratio of `2.5` CNY per USD). If I were to take both offers to send you 100 CNY, then it would cost me 17 USD, for an average quality of about `5.9`.
Without the `tfLimitQuality` flag set, this transaction would succeed, because the $17 it costs me is within my specified `SendMax`. However, with the `tfLimitQuality` flag enabled, the transaction would fail instead, because the path to take the second offer has a quality of `2.5`, which is worse than the limit quality of `5`.
The `tfLimitQuality` flag is most useful when combined with partial payments. When both `tfPartialPayment` and `tfLimitQuality` are set on a transaction, then the transaction delivers as much of the destination `Amount` as it can, without using any conversions that are worse than the limit quality.
In the above example with a ¥95/$15 offer and a ¥5/$2 offer, the situation is different if my transaction has both `tfPartialPayment` and `tfLimitQuality` enabled. If we keep my `SendMax` of 20 USD and a destination `Amount` of 100 CNY, then the limit quality is still `5`. However, because I am doing a partial payment, the transaction sends as much as it can instead of failing if the full destination amount cannot be sent. This means that my transaction consumes the ¥95/$15 offer, whose quality is about `6.3`, but it rejects the ¥5/$2 offer because that offer’s quality of `2.5` is worse than the quality limit of `5`. In the end, my transaction only delivers ¥95 instead of the full ¥100, but it avoids wasting money on poor exchange rates.
# PaymentChannelClaim
> Claim Amount from a payment channel, adjust the payment channel's expiration, or both. This transaction can be used differently depending on the transaction sender's role in the specified channel:
[\[Source\]](https://github.com/ripple/rippled/blob/master/src/ripple/app/tx/impl/PayChan.cpp)
*Added by the \[PayChan amendment]\[].*
The **source address** of a channel can:
* Send Amount from the channel to the destination with *or without* a signed Claim.
* Set the channel to expire as soon as the channel’s `SettleDelay` has passed.
* Clear a pending `Expiration` time.
* Close a channel immediately, with or without processing a claim first. The source address cannot close the channel immediately if the channel has Amount remaining.
The **destination address** of a channel can:
* Receive Amount from the channel using a signed Claim.
* Close the channel immediately after processing a Claim, refunding any unclaimed Amount to the channel’s source.
**Any address** sending this transaction can:
* Cause a channel to be closed if its `Expiration` or `CancelAfter` time is older than the previous ledger’s close time. Any validly-formed PaymentChannelClaim transaction has this effect regardless of the contents of the transaction.
### Example
[Section titled “Example”](#example)
```json
{
"Channel": "C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B9E5992CA6198",
"Amount" : {
"currency" : "USD",
"value" : "1",
"issuer" : "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"
},
"Signature": "30440220718D264EF05CAED7C781FF6DE298DCAC68D002562C9BF3A07C1E721B420C0DAB02203A5A4779EF4D2CCC7BC3EF886676D803A9981B928D3B8ACA483B80ECA3CD7B9B",
"PublicKey": "32D2471DB72B27E3310F355BB33E339BF26F8392D5A93D3BC0FC3B566612DA0F0A"
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ----------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Channel` | String | Hash256 | The unique ID of the channel, as a 64-character hexadecimal string. |
| `Balance` | [Currency Amount](/docs/protocol-reference/data-types/currency-formats/#specifying-currency-amounts) | Amount | *(Optional)* Total amount delivered by this channel after processing this claim. Required to deliver Amount. Must be more than the total amount delivered by the channel so far, but not greater than the `Amount` of the signed claim. Must be provided except when closing the channel. |
| `Amount` | [Currency Amount](/docs/protocol-reference/data-types/currency-formats/#specifying-currency-amounts) | Amount | *(Optional)* The amount authorized by the `Signature`. This must match the amount in the signed message. This is the cumulative amount of Amount that can be dispensed by the channel, including XAH previously redeemed. |
| `Signature` | String | Blob | *(Optional)* The signature of this claim, as hexadecimal. The signed message contains the channel ID and the amount of the claim. Required unless the sender of the transaction is the source address of the channel. |
| `PublicKey` | String | Blob | *(Optional)* The public key used for the signature, as hexadecimal. This must match the `PublicKey` stored in the ledger for the channel. Required unless the sender of the transaction is the source address of the channel and the `Signature` field is omitted. (The transaction includes the public key so that `rippled` can check the validity of the signature before trying to apply the transaction to the ledger.) |
If the payment channel was created before the fixPayChanRecipientOwnerDir amendment became enabled (on 2020-05-01), it is possible that the destination of the payment channel has been deleted and does not currently exist in the ledger. If the destination has been deleted, the source account cannot send XAH from the channel to the destination; instead, the transaction fails with `tecNO_DST`. (And, of course, the deleted account cannot send any transactions at all.) Other uses of this transaction type are unaffected when the destination account has been deleted, including adjusting the channel expiration, closing a channel with no Amount, or removing a channel that has passed its expiration time.
### PaymentChannelClaim Flags
[Section titled “PaymentChannelClaim Flags”](#paymentchannelclaim-flags)
Transactions of the PaymentChannelClaim type support additional values in the `Flags` field, as follows:
| Flag Name | Hex Value | Decimal Value | Description |
| --------- | ------------ | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tfRenew` | `0x00010000` | 65536 | Clear the channel’s `Expiration` time. (`Expiration` is different from the channel’s immutable `CancelAfter` time.) Only the source address of the payment channel can use this flag. |
| `tfClose` | `0x00020000` | 131072 | Request to close the channel. Only the channel source and destination addresses can use this flag. This flag closes the channel immediately if it has no more Amount allocated to it after processing the current claim, or if the destination address uses it. If the source address uses this flag when the channel still holds an Amount, this schedules the channel to close after `SettleDelay` seconds have passed. (Specifically, this sets the `Expiration` of the channel to the close time of the previous ledger plus the channel’s `SettleDelay` time, unless the channel already has an earlier `Expiration` time.) If the destination address uses this flag when the channel still holds an Amount, any Amount that remains after processing the claim is returned to the source address. |
# PaymentChannelCreate
> Create a payment channel and fund it with an Amount. The address sending this transaction becomes the "source address" of the payment channel.
[\[Source\]](https://github.com/Xahau/xahaud/blob/master/src/ripple/app/tx/impl/PayChan.cpp)
*Added by the \[PayChan amendment]\[].*
### Example
[Section titled “Example”](#example)
```json
{
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"TransactionType": "PaymentChannelCreate",
"Amount" : {
"currency" : "USD",
"value" : "1",
"issuer" : "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"
},
"Destination": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
"SettleDelay": 86400,
"PublicKey": "32D2471DB72B27E3310F355BB33E339BF26F8392D5A93D3BC0FC3B566612DA0F0A",
"CancelAfter": 533171558,
"DestinationTag": 23480,
"SourceTag": 11747
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ---------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Amount` | [Currency Amount](/docs/protocol-reference/data-types/currency-formats/#specifying-currency-amounts) | Amount | Amount to deduct from the sender’s balance and set aside in this channel. While the channel is open, the Amount can only go to the `Destination` address. When the channel closes, any unclaimed Amount is returned to the source address’s balance. |
| `Destination` | String | AccountID | Address to receive claims against this channel. This is also known as the “destination address” for the channel. Cannot be the same as the sender (`Account`). |
| `SettleDelay` | Number | UInt32 | Amount of time the source address must wait before closing the channel if it has unclaimed Amount. |
| `PublicKey` | String | Blob | The 33-byte public key of the key pair the source will use to sign claims against this channel, in hexadecimal. This can be any secp256k1 or Ed25519 public key. For more information on key pairs, see Key Derivation |
| `CancelAfter` | Number | UInt32 | *(Optional)* The time, in [seconds since the Ripple Epoch](/docs/protocol-reference/data-types/#specifying-time), when this channel expires. Any transaction that would modify the channel after this time closes the channel without otherwise affecting it. This value is immutable; the channel can be closed earlier than this time but cannot remain open after this time. |
| `DestinationTag` | Number | UInt32 | *(Optional)* Arbitrary tag to further specify the destination for this payment channel, such as a hosted recipient at the destination address. |
If the `Destination` account is blocking incoming payment channels, the transaction fails with result code `tecNO_PERMISSION`. *(Requires the \[DisallowIncoming amendment]\[] :not\_enabled:)*
# PaymentChannelFund
> Add additional Amount to an open payment channel, and optionally update the expiration time of the channel. Only the source address of the channel can use this transaction.
[\[Source\]](https://github.com/ripple/rippled/blob/master/src/ripple/app/tx/impl/PayChan.cpp)
*Added by the \[PayChan amendment]\[].*
### Example
[Section titled “Example”](#example)
```json
{
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"TransactionType": "PaymentChannelFund",
"Channel": "C1AE6DDDEEC05CF2978C0BAD6FE302948E9533691DC749DCDD3B9E5992CA6198",
"Amount" : {
"currency" : "USD",
"value" : "1",
"issuer" : "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"
},
"Expiration": 543171558
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ------------ | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Channel` | String | Hash256 | The unique ID of the channel to fund, as a 64-character hexadecimal string. |
| `Amount` | [Currency Amount](/docs/protocol-reference/data-types/currency-formats/#specifying-currency-amounts) | Amount | Amount to add to the channel. Must be a positive amount. |
| `Expiration` | Number | UInt32 | *(Optional)* New `Expiration` time to set for the channel, in [seconds since the Ripple Epoch](/docs/protocol-reference/data-types/#specifying-time). This must be later than either the current time plus the `SettleDelay` of the channel, or the existing `Expiration` of the channel. After the `Expiration` time, any transaction that would access the channel closes the channel without taking its normal action. Any unspent Amount is returned to the source address when the channel closes. (`Expiration` is separate from the channel’s immutable `CancelAfter` time.) For more information, see the PayChannel ledger object type. |
### Error Cases
[Section titled “Error Cases”](#error-cases)
Besides errors that can occur for all transactions, PaymentChannelFund transactions can result in the following transaction result codes:
| Error Code | Description |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tecINSUFFICIENT_RESERVE` | The sending account has less XAH than the reserve requirement. |
| `tecNO_DST` | The destination account of the channel has been deleted. This is only possible if the payment channel was created before the fixPayChanRecipientOwnerDir amendment became enabled (on 2020-05-01). |
| `tecNO_ENTRY` | The Payment Channel identified by the `Channel` field does not exist. |
| `tecNO_PERMISSION` | The sender of the transaction is not the source address for the channel. |
| `tecUNFUNDED` | The sending account does not have enough Amount to fund the channel with the requested amount and still meet the reserve requirement. |
| `temBAD_AMOUNT` | The `Amount` field of the transaction is invalid. The amount cannot be zero or negative. |
| `temBAD_EXPIRATION` | The `Expiration` field is invalid. |
# Remit
> The Remit transaction allows the user to send multiple payment types, mint a URIToken, transfer a list of URITokens and activate an account.
Caution
The Remit transaction pays all fees for *Account Activation, Trustlines and URIToken Reserves.*
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/Remit.cpp)]
*(Added by the [Remit amendment](/docs/features/amendments/#remit).)*
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType": "Remit",
"Account": "rGvbdrdCxG2tk9ZU2673XmsjRdHCDQEpt7",
"Amounts": [
{
"AmountEntry": {
"Amount": "1000000"
}
}, {
"AmountEntry": {
"Amount": {
"currency": "USD",
"issuer": "rExKpRKXNz25UAjbckCRtQsJFcSfjL9Er3",
"value": "1"
}
}
}
],
"Destination": "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
"URITokenIDs": [
"714F206C865D334721B2F3388BEAF33AA91BC1D78C71941D10A2A653C873EDD3"
],
"MintURIToken": {
"Digest": "6F11A4DF4EE794E2800BB361173D454BFBECB3D7506C4F4CB0EC5AE98BE43747",
"Flags": 1,
"URI": "697066733A2F2F"
}
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ---------------- | --------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `Account` | String | AccountID | The address of the account that will activate the account, send the payment and/or mint/transfer the URIToken/s. |
| `Destination` | String | AccountID | The unique address of the account receiving the payment and/or URIToken/s. |
| `DestinationTag` | Number | UInt32 | *(Optional)* A DestinationTag for deposits to a shared custody account. |
| `MintURIToken` | Object | STObject | *(Optional)* A `MintURIToken` STObject containing the URIToken details you want to mint on the `Destination`. |
| `URITokenIDs` | Array | STArray | *(Optional)* An array of URITokenIDs (256-bit hash) to to be transferred to the `Destination`. *Limit 32.* |
| `Amounts` | Array | STArray | *(Optional)* An array of `AmountEntry` STObjects the account wants to send to the `Destination`. *Limit 32.* |
| `Inform` | String | AccountID | *(Optional)* A unique address of an account that can have a hook installed and be informed when a remit occurs. |
| `Blob` | String | Blob | *(Optional)* Arbitrary hex value that can be added to the tx for use in Hooks. |
| `InvoiceID` | String | Hash256 | *(Optional)* Arbitrary 256-bit hash representing a specific reason or identifier for this remit. |
### AmountEntry Fields
[Section titled “AmountEntry Fields”](#amountentry-fields)
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| -------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------- |
| `Amount` | [Currency Amount](/docs/protocol-reference/data-types/currency-formats/#specifying-currency-amounts) | Amount | The amount of currency the account wants to send to the `Destination`. |
### MintURIToken Fields
[Section titled “MintURIToken Fields”](#minturitoken-fields)
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| -------- | --------- | ------------------------------------------------------- | ----------------------------------------------------------- |
| `URI` | String | String | The URI associated with the minted URIToken. (256 byte max) |
| `Digest` | String | Hash256 | *(Optional)* The digest of the URIToken. |
| `Flags` | Number | UInt32 | *(Optional)* Flags on the mint transaction |
### MintURIToken Flags
[Section titled “MintURIToken Flags”](#minturitoken-flags)
The `MintURIToken` STObject supports the values in the `Flags` field, as follows:
| Flag Name | Hex Value | Decimal Value | Description |
| ------------ | ------------ | ------------- | ----------------------------------------------------------------------------------------------- |
| `tfBurnable` | `0x00000001` | 1 | Allow the issuer to destroy the minted `URIToken`. (The `URIToken`’s owner can *always* do so.) |
### Special Transaction Cost
[Section titled “Special Transaction Cost”](#special-transaction-cost)
The Remit transaction has a standard transaction cost, which is the minimum fee required for any transaction in Xahau.
In addition to the minimum fee required the Remit transaction will also deduct the fees for the following:
| Action | Fee |
| -------------------- | ---------------------------- |
| `Account Activation` | Standard Reserve Requirement |
| `Create Trustline` | Standard Reserve Requirement |
| `URIToken Mint` | Standard Reserve Requirement |
| `URIToken Transfer` | Standard Reserve Requirement |
### Error Cases
[Section titled “Error Cases”](#error-cases)
Besides errors that can occur for all transactions, Remit transactions can result in the following transaction result codes:
| Error Code | Description |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `temINVALID_FLAG` | Occurs if any flag is specific `tfFullyCanonicalSig` |
| `temREDUNDANT` | Occurs if the Account is the same as the Destination |
| `temMALFORMED (Inform & Blob)` | Occurs when; sfInform is same as ” “source or destination. Blob was more than 128kib. |
| `temMALFORMED (AmountEntry)` | Occurs when; AmountEntry count exceeds `32.` Expected AmountEntry. Native Currency appears more than once. Issued Currency appears more than once. |
| `temMALFORMED (MintURIToken)` | Occurs when; sfMintURIToken contains invalid field. URI was not provided. URI was too long/short. Invalid UTF8 inside MintURIToken. |
| `temMALFORMED (URITokenIDs)` | Occurs when; URITokenIDs too short/long. Duplicate URITokenID. |
| `temBAD_AMOUNT` | Occurs when an Amount in the AmountEntry is invalid. |
| `terNO_ACCOUNT` | Occurs when the source account does not exist. |
| `tecNO_TARGET` | Occurs when the `sfInform` field is present but the account does not exist. |
| `tecNO_PERMISSION` | Occurs when `disallowIncomingRemit` is enabled on the `Destination` |
| `tecNO_PERMISSION` | Occurs when the `Destination` has `DepositAuthorization` enabled. |
| `tecDST_TAG_NEEDED` | Occurs if the destination account requires a destination tag, but the transaction does not include one. |
| `tecDUPLICATE` | Occurs when the `MintURIToken` URI from that issuer already exists. |
| `tecDIR_FULL` | Occurs when the source or destination accouts directory is full. |
| `tecNO_ENTRY` | Occurs when the URIToken does not exist. |
| `tecNO_PERMISSION` | Occurs when the URIToken is not owned by the source account. |
| `tecUNFUNDED_PAYMENT` | Occurs when the source account does not have the required funds to execute the transaction. (XAH or Issued Currencies) |
# SetHook
> The SetHook transaction allows users to install, update, delete, or perform other operations on hooks in Xahau.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/SetHook.cpp)]
*(Added by the [Hooks amendment](/docs/features/amendments/#hooks).)*
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType": "SetHook",
"Account": "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm",
"Flags": 0,
"Hooks": [
{
"Hook": {
"HookHash": "610F33B8EBF7EC795F822A454FB852156AEFE50BE0CB8326338A81CD74801864",
"CreateCode": "697066733A2F2F4445414442454546697066733A2F2F44454144424545467878",
"HookGrants": [],
"HookNamespace": "0000000000000000000000000000000000000000000000000000000000000000",
"HookParameters": [],
"HookOn": "0000000000000000000000000000000000000000000000000000000000000000",
"HookApiVersion": 0,
"Flags": 0
}
}
]
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| --------- | --------- | ------------------------------------------------------- | -------------------------------------------------- |
| `Account` | String | AccountID | The address of the account that will own the hook. |
| `Hooks` | Array | Array | The array of hooks to be set. |
### Special Transaction Cost
[Section titled “Special Transaction Cost”](#special-transaction-cost)
The SetHook transaction has a standard transaction cost, which is the minimum transaction cost required for all transactions.
### Error Cases
[Section titled “Error Cases”](#error-cases)
Besides errors that can occur for all transactions, SetHook transactions can result in the following transaction result codes:
| Error Code | Description |
| --------------- | ---------------------------------------------------------------------------- |
| `tecDUPLICATE` | Occurs if a hook with the same hash already exists. |
| `tecDIR_FULL` | Occurs if the owner’s directory is full and cannot accommodate the new hook. |
| `terNO_ACCOUNT` | Occurs if the sending account does not exist. |
| `terNO_HOOK` | Occurs if no hook exists with the specified hash. |
| `temDISABLED` | Occurs if the Hooks Amendment is not enabled. |
| `temMALFORMED` | Occurs if the transaction is malformed. |
### SetHook Operations
[Section titled “SetHook Operations”](#sethook-operations)
There are six possible operations: No Operation, Create, Update, Delete, Install and Namespace Delete
Each operation is specified by the inclusion or omission of certain HookSet Object fields. This might seem confusing at first but by working through a few examples the reader should find it intuitive; Essentially HookSet operations are a type of **diff** between a specific Hook’s *defaults*, *existing* and newly specified fields.
Achieving each type of operation is explained in a subsection below.
### No Operation
[Section titled “No Operation”](#no-operation)
**Occurs when**:
* The HookSet Object is empty
**Behaviour**:
* No change of any kind is made.
**Example**:
JSON
```json
{
Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
TransactionType: "SetHook",
Fee: "2000000",
Hooks:
[
{
Hook: {}
}
]
}
```
### Create Operation
[Section titled “Create Operation”](#create-operation)
**Occurs when**:
*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 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 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`.
* The `Hook` object contains no fields except `HookHash` which points at the created `HookDefinition`.
* If `hsfNSDELETE` flag is specified then any HookState entires in the destination namespace are deleted if they currently exist.
**Example**:
JSON
```json
{
Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
TransactionType: "SetHook",
Fee: "2000000",
Hooks:
[
{
Hook: {
CreateCode: fs.readFileSync('accept.wasm').toString('hex').toUpperCase(),
HookOn: '0000000000000000',
HookNamespace: addr.codec.sha256('accept').toString('hex').toUpperCase(),
HookApiVersion: 0
}
}
]
}
```
### Install Operation
[Section titled “Install Operation”](#install-operation)
**Occurs when**:
*All* of the following conditions are met:
* The Corresponding Hook does not exist *or*`FLAG_OVERRIDE` is specified.
* `HookHash` field is specified and is not blank and contains the hash of a Hook that already exists as a `HookDefinition` on the ledger *or* `CreateCode` field is specified and is not blank and contains the valid web assembly bytecode for a valid hook that already exists on the ledger as a `HookDefinition`.
**Behaviour**:
* The reference count of the `HookDefinition` object is incremented.
* 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`.
* The `Hook` object contains all the fields in the HookSet Object, except and unless:
* A field or key-pair within a field is identical to the Hook Defaults set on the `HookDefinition`, in which case it is omitted due to defaults.
* If `hsfNSDELETE` flag is specified then any HookState entires in the destination namespace are deleted if they currently exist.
**Example**:
JSON
```json
{
Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
TransactionType: "SetHook",
Fee: "2000000",
Hooks:
[
{
Hook: {
HookHash: "A5663784D04ED1B4408C6B97193464D27C9C3334AAF8BBB4FA5EB8E557FC4A2C",
HookOn: '0000000000000000',
HookNamespace: addr.codec.sha256('accept').toString('hex').toUpperCase(),
}
}
]
}
```
### Update Operation
[Section titled “Update Operation”](#update-operation)
**Occurs when**:
*All* of the following conditions are met:
* The Corresponding Hook exists.
* `HookHash` is absent.
* `CreateCode` is absent.
* One or more of `HookNamespace`, `HookParameters` or `HookGrants` is present.
**General Behaviour**:
* The Corresponding Hook is updated in such a way that the desired changes are reflected in the Corresponding Hook.
**Specific Behaviour**:
If `HookNamespace` is specified and differs from the Corresponding Hook’s Namespace:
* the Corresponding Hook’s `HookNamespace` is updated, and
* if the `hsfNSDELETE` flag is specified all HookState entires in the old namespace are deleted.
If `HookParameters` is specified, then for each entry:
* If `HookParameterName` exists but `HookParameterValue` is absent and the Corresponding Hook’s Parameters (either specifically or via defaults) contains this `HookParameterName` then the parameter is marked as deleted on the Corresponding Hook.
* If `HookParameterName` exists and `HookParameterValue` exists then the Corresponding Hook’s Parameters are modified to include the new or updated parameter.
If `HookGrants` is specified then:
* The Corresponding Hook’s `HookGrants` array is replaced with the array.
**Example**:
JSON
```json
{
Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
TransactionType: "SetHook",
Fee: "2000000",
Hooks:
[
{
Hook: {
HookNamespace: addr.codec.sha256('new_accept').toString('hex').toUpperCase(),
}
}
]
}
```
### Delete Operation
[Section titled “Delete Operation”](#delete-operation)
**Occurs when**:
*All* of the following conditions are met:
* The Corresponding Hook exists.
* `hsfOVERRIDE` is specified.
* optionally `hsfNSDELETE` is also specified.
* `HookHash` is absent.
* `CreateCode` is present but empty.
**Behaviour**:
* The reference count of the `HookDefinition` object is decremented.
* If the reference count is now zero the `HookDefintion` is removed from the ledger.
* The `Hook` object in the Corresponding Hook position is deleted, leaving an empty position.
* If `hsfNSDELETE` is specified the namespace and all HookState entries are also deleted.
**Example**:
JSON
```json
{
Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
TransactionType: "SetHook",
Fee: "2000000",
Hooks:
[
{
Hook: {
CreateCode: "",
Flags: 1,
}
}
]
}
```
### Namespace Reset
[Section titled “Namespace Reset”](#namespace-reset)
**Occurs when**:
*All* of the following conditions are met:
* `flags` is present and `hsfNSDELETE` is set. `hsfOVERRIDE` can optionally also be specified if the Hook at this position is to be deleted.
* `HookNamespace` is specified.
* `CreateCode` is absent.
* `HookHash` is absent.
* `HookGrants`, `HookParameters`, `HookOn`, `HookOnIncoming`, `HookOnOutgoing` and `HookApiVersion` are absent.
**Behaviour**:
* If the Corresponding Hook exists, it remains, nothing happens to it.
* A subset of HookState objects and the HookState directory for the specified namespace are removed from the ledger, up to the defined limit (512). Further transactions are needed to continue the deletion process until all relevant records are removed. See [`tesPARTIAL`](/docs/protocol-reference/transactions/transaction-results/tes-codes).
**Example**:
JSON
```json
{
Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
TransactionType: "SetHook",
Fee: "2000000",
Hooks:
[
{
Hook: {
HookNamespace: addr.codec.sha256('accept').toString('hex').toUpperCase(),
Flags: 3,
}
}
]
}
```
### Hook Fields
[Section titled “Hook Fields”](#hook-fields)
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 | *(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. |
| `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. |
### Flags
[Section titled “Flags”](#flags)
The `Flags` field in the hook object specifies additional flags for the hook. The following flags are supported:
| Flag Name | Description |
| ------------- | ------------------------------------------------------------------------ |
| `hsfOVERRIDE` | Allows the hook to be deleted even if it is referenced by other objects. |
| `hsfNSDELETE` | Deletes an entire namespace of hooks. |
| `hsfCOLLECT` | Collects the hook’s associated objects. |
### Hook Grants
[Section titled “Hook Grants”](#hook-grants)
The `HookGrants` field is an array of objects that specify the grants associated with the hook. Each grant object has the following fields:
| Field | JSON Type | Internal Type | Description |
| ----------- | --------- | ------------- | -------------------------------------------------- |
| `HookHash` | String | Hash256 | The hook to apply the grant to. |
| `Authorize` | String | AccountID | The address of the account that is granted access. |
| `Flags` | Number | Uint32 | Flags |
### Hook Parameters
[Section titled “Hook Parameters”](#hook-parameters)
The `HookParameters` field is an array of objects that specify the parameters of the hook. Each parameter object has the following fields:
| Field | JSON Type | Internal Type | Description |
| -------------------- | --------- | ------------- | --------------------------- |
| `HookParameterName` | String | Blob | The name of the parameter. |
| `HookParameterValue` | String | Blob | The value of the parameter. |
### Hook Executions
[Section titled “Hook Executions”](#hook-executions)
When Hooks execute they leave behind information about the status of that execution. This appears in the Originating Transaction metadata as an `sfHookExecutions` block. This block contains the following fields:
| Field | JSON Type | Internal Type | Description |
| ---------------------- | --------- | ------------- | ---------------------------------------------------------------------------------------------------------- |
| `HookAccount` | String | AccountID | The account the Hook ran on. |
| `HookEmitCount` | Number | UInt16 | The total number of Emitted Transactions produced by the Hook. |
| `HookExecutionIndex` | Number | UInt16 | The SHA512H of the Hook at the time it was executed. |
| `HookHash` | String | Hash256 | The value of the parameter. |
| `HookInstructionCount` | String | UInt64 | The total number of webassembly instructions that were executed when the Hook ran. |
| `HookResult` | Number | UInt8 | Hooks can end in three ways: `accept`, `rollback` and `error`. This is *not* the same as sfHookReturnCode! |
| `HookReturnCode` | String | UInt64 | The integer returned as the third parameter of `accept` or `rollback`. |
| `HookReturnString` | String | Blob | The string returned in the first two parameters of `accept` or `rollback`, if any. |
| `HookStateChangeCount` | Number | UInt16 | The number of Hook State changes the Hook made during execution. |
# SetRegularKey
> A SetRegularKey transaction assigns, changes, or removes the regular key pair associated with an account.
[\[Source\]](https://github.com/ripple/rippled/blob/4239880acb5e559446d2067f00dabb31cf102a23/src/ripple/app/transactors/SetRegularKey.cpp)
You can protect your account by assigning a regular key pair to it and using it instead of the master key pair to sign transactions whenever possible. If your regular key pair is compromised, but your master key pair is not, you can use a `SetRegularKey` transaction to regain control of your account.
### Example SetRegularKey JSON
[Section titled “Example SetRegularKey JSON”](#example-setregularkey-json)
```json
{
"Flags": 0,
"TransactionType": "SetRegularKey",
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Fee": "12",
"RegularKey": "rAR8rR8sUkBoCZFawhkWzY4Y5YoyuznwD"
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ------------ | --------- | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `RegularKey` | String | AccountID | *(Optional)* A base-58-encoded [Address](/docs/protocol-reference/data-types/#addresses) that indicates the regular key pair to be assigned to the account. If omitted, removes any existing regular key pair from the account. Must not match the master key pair for the address. |
### See Also
[Section titled “See Also”](#see-also)
For more information about regular and master key pairs, see Cryptographic Keys.
For a tutorial on assigning a regular key pair to an account, see Working with a Regular Key Pair.
For even greater security, you can use multi-signing, but multi-signing requires additional XAH for the \[transaction cost]\[] and reserve.
# SetRemarks
> The SetRemarks transaction enables accounts to attach, update, or remove arbitrary remarks (key-value pairs) on supported ledger objects.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/SetRemarks.cpp)]
*(Added by the \[*Remarks *amendment]\[].)*
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType": "SetRemarks",
"Account": "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm",
"Flags": 0,
"ObjectID": "AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00112233445566778899",
"Remarks": [
{
"Remark": {
"RemarkName": "CAFE",
"RemarkValue": "DEADBEEF",
"Flags": 0
}
}
]
}
```
| Field | JSON Type | Internal Type | Description |
| ---------- | --------- | ------------- | ---------------------------------------------------------------------------------------------- |
| `Account` | String | AccountID | The address of the account submitting the transaction (must be the owner/issuer of the object) |
| `ObjectID` | String | Hash256 | The ledger object ID to which the remarks are attached (see Supported Objects) |
| `Remarks` | Array | Array | Array of remark objects to set, update, or delete (see Remarks Format) |
### SetRemarks Flags
[Section titled “SetRemarks Flags”](#setremarks-flags)
| Flag Name | Hex Value | Decimal Value | Description |
| ------------- | ------------ | ------------- | ------------------------------------------------------- |
| `tfImmutable` | `0x00000001` | 1 | Marks the remark as immutable (cannot change or delete) |
### Remarks Format
[Section titled “Remarks Format”](#remarks-format)
Each entry in the `Remarks` array is an object with a single `Remark` field, which itself is an object with the following fields:
| Field | JSON Type | Internal Type | Required | Description |
| ------------- | --------- | ------------- | -------- | ------------------------------------------------------------------------ |
| `RemarkName` | String | Blob | Yes | The name/key of the remark (1–256 bytes, must be unique per object) |
| `RemarkValue` | String | Blob | No | The value of the remark (1–256 bytes). Omit to delete the remark. |
| `Flags` | Number | UInt32 | No | Set to `1` (`tfImmutable`) to make the remark immutable. Default is `0`. |
### Supported Objects and Permissions
[Section titled “Supported Objects and Permissions”](#supported-objects-and-permissions)
Remarks can be attached to the following ledger object types. **Only the specified party (owner or issuer) may create, update, or delete remarks on each object:**
| Ledger Object Type | Who Can Set Remarks? | Notes |
| --------------------------- | -------------------- | ---------------------------------------------------------------------------------------- |
| **AccountRoot** | Owner | The account itself (the address in the object) |
| **Offer** | Owner | The account that created the offer |
| **Escrow** | Owner | The account that created the escrow |
| **Ticket** | Owner | The account that created the ticket |
| **PayChannel** | Owner | The account that created the payment channel |
| **Check** | Owner | The account that created the check |
| **DepositPreauth** | Owner | The account that created the deposit preauthorization |
| **URI Token** | Issuer | The account that issued the URI token (field `sfIssuer`) |
| **Trustline (RippleState)** | Issuer | Only the issuer side of the trustline (the account that issued the IOU) can set remarks. |
### Limits
[Section titled “Limits”](#limits)
* **Maximum 32 remarks** per object.
* Each `RemarkName` and `RemarkValue` must be 1–256 bytes.
* Each `RemarkName` must be unique per object.
* Once a remark is marked as immutable (`Flags: 1`), it cannot be changed or deleted.
### Special Transaction Cost
[Section titled “Special Transaction Cost”](#special-transaction-cost)
The base transaction cost is increased by **1 drop per byte** of all `RemarkName` and `RemarkValue` fields in the transaction.
### Error Cases
[Section titled “Error Cases”](#error-cases)
| Error Code | Description |
| --------------------- | -------------------------------------------------------------------------------------------- |
| `temDISABLED` | The Remarks amendment is not enabled. |
| `temINVALID_FLAG` | Invalid flags set on the transaction. |
| `temMALFORMED` | The transaction is malformed (e.g., too many remarks, duplicate names, invalid field sizes). |
| `terNO_ACCOUNT` | The sending account does not exist. |
| `tecNO_TARGET` | The target object does not exist. |
| `tecNO_PERMISSION` | The sender is not the owner/issuer of the object. |
| `tecIMMUTABLE` | Attempted to modify or delete an immutable remark. |
| `tecTOO_MANY_REMARKS` | The number of remarks on the object would exceed the limit of 32. |
# SignerListSet
> The SignerListSet transaction creates, replaces, or removes a list of signers that can be used to multi-sign a transaction. This transaction type was introduced by the [MultiSign amendment][].
[\[Source\]](https://github.com/Xahau/xahaud/blob/master/src/ripple/app/tx/impl/SetSignerList.cpp)
### Example
[Section titled “Example”](#example)
```json
{
"Flags": 0,
"TransactionType": "SignerListSet",
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Fee": "12",
"SignerQuorum": 3,
"SignerEntries": [
{
"SignerEntry": {
"Account": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
"SignerWeight": 2
}
},
{
"SignerEntry": {
"Account": "rUpy3eEg8rqjqfUoLeBnZkscbKbFsKXC3v",
"SignerWeight": 1
}
},
{
"SignerEntry": {
"Account": "raKEEVSGnKSD9Zyvxu4z6Pqpm4ABH8FS6n",
"SignerWeight": 1
}
}
]
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| --------------- | --------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `SignerQuorum` | Number | UInt32 | A target number for the signer weights. A multi-signature from this list is valid only if the sum weights of the signatures provided is greater than or equal to this value. To delete a signer list, use the value `0`. |
| `SignerEntries` | Array | Array | *(Omitted when deleting)* Array of `SignerEntry` objects, indicating the addresses and weights of signers in this list. This signer list must have at least 1 member and no more than 32 members. No address may appear more than once in the list, nor may the `Account` submitting the transaction appear in the list. *(Updated by the \[ExpandedSignerList amendment]\[].)* |
A successful SignerListSet transaction replaces the account’s `SignerList` object in the ledger, or adds one if it did not exist before. An account may not have more than one signer list. To delete a signer list, you must set `SignerQuorum` to `0` *and* omit the `SignerEntries` field. Otherwise, the transaction fails with the error `temMALFORMED`. A transaction to delete a signer list is considered successful even if there was no signer list to delete.
You cannot create a signer list such that the `SignerQuorum` could never be met. The `SignerQuorum` must be greater than 0 but less than or equal to the sum of the `SignerWeight` values in the list. Otherwise, the transaction fails with the error `temMALFORMED`.
You can create, update, or remove a signer list using the master key, regular key, or the current signer list, if those methods of signing transactions are available.
You cannot remove the last method of signing transactions from an account. If an account’s master key is disabled (the account has the `lsfDisableMaster` flag enabled) and the account does not have a Regular Key configured, then you cannot delete the signer list from the account. Instead, the transaction fails with the error `tecNO_ALTERNATIVE_KEY`.
Creating or replacing a signer list enables the `lsfOneOwnerCount` flag on the SignerList object. Lists that were created before the \[MultiSignReserve amendment]\[] became enabled do not have this flag and have a higher owner reserve. You can decrease the owner reserve for these lists by replacing the list with the same list. For more information, see SignerList Flags.
# TicketCreate
> A TicketCreate transaction sets aside one or more [sequence numbers][Sequence Number] as Tickets.
[\[Source\]](https://github.com/ripple/rippled/blob/develop/src/ripple/app/tx/impl/CreateTicket.cpp)
*(Added by the \[TicketBatch amendment]\[].)*
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType": "TicketCreate",
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Fee": "10",
"Sequence": 381,
"TicketCount": 10
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ------------- | --------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `TicketCount` | Number | UInt32 | How many Tickets to create. This must be a positive number and cannot cause the account to own more than 250 Tickets after executing this transaction. |
If the transaction cannot create *all* of the requested Tickets (either due to the 250-Ticket limit or the owner reserve), it fails and creates no Tickets. To look up how many Tickets an account currently owns, use the \[account\_info method]\[] and check the `account_data.TicketCount` field.
**Tip:** This transaction increases the sending account’s \[sequence number]\[Sequence Number] by 1 *plus* the number of tickets created (`TicketCount`). This is the only transaction that increases an account’s sequence number by more than 1.
### Error Cases
[Section titled “Error Cases”](#error-cases)
Besides errors that can occur for all transactions, TicketCreate transactions can result in the following transaction result codes:
| Error Code | Description |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `temINVALID_COUNT` | The `TicketCount` field is invalid. It must be an integer from 1 to 250. |
| `tecDIR_FULL` | This transaction would cause the account to own more than the limit of 250 Tickets at a time, or more than the maximum number of ledger objects in general. |
| `tecINSUFFICIENT_RESERVE` | The sending account does not have enough XAH to meet the owner reserve of all the requested Tickets. |
# TrustSet
> Create or modify a trust line linking two accounts.
[\[Source\]](https://github.com/Xahau/xahaud/blob/master/src/ripple/app/tx/impl/SetTrust.cpp)
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType": "TrustSet",
"Account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"Fee": "12",
"Flags": 262144,
"LastLedgerSequence": 8007750,
"LimitAmount": {
"currency": "USD",
"issuer": "rsP3mgGb2tcYUrxiLFiHJiQXhsziegtwBc",
"value": "100"
},
"Sequence": 12
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ------------------------ | --------- | ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `LimitAmount` | Object | Amount | Object defining the trust line to create or modify, in the format of a [Currency Amount](/docs/protocol-reference/data-types/#specifying-currency-amounts). |
| `LimitAmount`.`currency` | String | (Amount.currency) | The currency to this trust line applies to, as a three-letter [ISO 4217 Currency Code](https://www.xe.com/iso4217.php) or a 160-bit hex value according to currency format. “XAH” is invalid. |
| `LimitAmount`.`value` | String | (Amount.value) | Quoted decimal representation of the limit to set on this trust line. |
| `LimitAmount`.`issuer` | String | (Amount.issuer) | The address of the account to extend trust to. |
| `QualityIn` | Number | UInt32 | *(Optional)* Value incoming balances on this trust line at the ratio of this number per 1,000,000,000 units. A value of `0` is shorthand for treating balances at face value. |
| `QualityOut` | Number | UInt32 | *(Optional)* Value outgoing balances on this trust line at the ratio of this number per 1,000,000,000 units. A value of `0` is shorthand for treating balances at face value. |
If the account specified in `LimitAmount.issuer` is blocking incoming trust lines, the transaction fails with the result code `tecNO_PERMISSION`. *(Requires the \[DisallowIncoming amendment]\[] :not\_enabled:)*
### TrustSet Flags
[Section titled “TrustSet Flags”](#trustset-flags)
Transactions of the TrustSet type support additional values in the `Flags` field, as follows:
| Flag Name | Hex Value | Decimal Value | Description |
| ------------------- | ------------ | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tfSetfAuth` | `0x00010000` | 65536 | Authorize the other party to hold currency issued by this account. (No effect unless using the `asfRequireAuth` AccountSet flag.) Cannot be unset. |
| `tfSetNoRipple` | `0x00020000` | 131072 | Enable the No Ripple flag, which blocks rippling between two trust lines of the same currency if this flag is enabled on both. |
| `tfClearNoRipple` | `0x00040000` | 262144 | Disable the No Ripple flag, allowing rippling on this trust line. |
| `tfSetFreeze` | `0x00100000` | 1048576 | Freeze the trust line. |
| `tfClearFreeze` | `0x00200000` | 2097152 | Unfreeze the trust line. |
| `tfSetDeepFreeze` | `0x00400000` | 4194304 | Deep freeze the trust line. *(Requires the [DeepFreeze amendment](/docs/features/amendments/#deepfreeze))* |
| `tfClearDeepFreeze` | `0x00800000` | 8388608 | Clear a deep-freeze on the trust line. *(Requires the [DeepFreeze amendment](/docs/features/amendments/#deepfreeze))* |
If a transaction tries to enable No Ripple but cannot, it fails with the result code `tecNO_PERMISSION`. Before the \[fix1578 amendment]\[] became enabled, such a transaction would result in `tesSUCCESS` (making any other changes it could) instead.
The Auth flag of a trust line does not determine whether the trust line counts towards its owner’s XAH reserve requirement. However, an enabled Auth flag prevents the trust line from being in its default state. An authorized trust line can never be deleted. An issuer can pre-authorize a trust line with the `tfSetfAuth` flag only, even if the limit and balance of the trust line are 0.
### Deep Freeze Rules
[Section titled “Deep Freeze Rules”](#deep-freeze-rules)
With the [DeepFreeze amendment](/docs/features/amendments/#deepfreeze) enabled, the following rules apply to deep freeze operations:
A TrustSet transaction trying to set `tfSetDeepFreeze` succeeds if and only if one of the following is true:
* The holder is already frozen, indicated by `lsfLowFreeze`/`lsfHighFreeze` on the trust line.
* `tfSetFreeze` is also set in the same TrustSet transaction.
If the trust line is deep-frozen by the issuer (indicated by `lsfLowDeepFreeze`/`lsfHighDeepFreeze`), the TrustSet transaction fails if the issuer sets the `tfClearFreeze` flag without also setting the `tfClearDeepFreeze` flag. In other words, the issuer cannot clear the regular freeze on a trust line without also clearing the deep freeze.
See [High vs. Low Account](/docs/protocol-reference/ledger-data/ledger-objects-types/ripple-state#high-vs-low-account) for information about how the low and high accounts are determined.
# URITokenBurn
> The URITokenBurn transaction is used to burn a URIToken in Xahau. Burning a URIToken permanently removes it from circulation.
[\[Source\]](https://github.com/ripple/rippled/blob/develop/src/ripple/app/tx/impl/URIToken.cpp)
*(Added by the \[URIToken amendment]\[].)*
The URITokenBurn transaction is used to burn a URIToken in Xahau. Burning a URIToken permanently removes it from circulation.
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType": "URITokenBurn",
"Account": "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm",
"URITokenID": "C1AE6DDDEEC05CF2978C0BAD6FE27362498DGS691DC749DCDD3B95992978C0BA",
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ------------ | --------- | ------------------------------------------------------- | --------------------------------------------------------------- |
| `Account` | String | AccountID | The address of the account that owns the URIToken to be burned. |
| `URITokenID` | String | Hash256 | The ID of the URIToken to burn. |
### Special Transaction Cost
[Section titled “Special Transaction Cost”](#special-transaction-cost)
The URITokenBurn transaction does not have any special transaction cost requirements.
### Error Cases
[Section titled “Error Cases”](#error-cases)
Besides errors that can occur for all transactions, URITokenBurn transactions can result in the following transaction result codes:
| Error Code | Description |
| ------------------ | ----------------------------------------------------------------- |
| `tecNO_PERMISSION` | Occurs if the account does not have permission to burn the token. |
# URITokenBuy
> The URITokenBuy transaction allows a user to buy a URIToken from the issuer. This transaction is used to transfer ownership of a URIToken from the issuer to the buyer.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/URIToken.cpp)]
*(Added by the \[URIToken amendment]\[].)*
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType": "URITokenBuy",
"Account": "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm",
"URITokenID": "C1AE6DDDEEC05CF2978C0BAD6FE27362498DGS691DC749DCDD3B95992978C0BA",
"Amount": {
"issuer": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"currency": "USD",
"value": "100",
},
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ------------ | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | --------------------------------------------------- |
| `Account` | String | AccountID | The address of the buyer’s account. |
| `URITokenID` | String | Hash256 | The unique identifier of the URIToken to be bought. |
| `Amount` | [Currency Amount](/docs/protocol-reference/data-types/currency-formats/#specifying-currency-amounts) | Amount | The amount of currency to pay for the URIToken. |
### Special Transaction Cost
[Section titled “Special Transaction Cost”](#special-transaction-cost)
The URITokenBuy transaction has a standard transaction cost, which is the minimum fee required for any transaction in Xahau.
### Error Cases
[Section titled “Error Cases”](#error-cases)
Besides errors that can occur for all transactions, URITokenBuy transactions can result in the following transaction result codes:
| Error Code | Description |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `tecCANT_ACCEPT_OWN_NFTOKEN_OFFER` | Occurs if the owner of the token is the one claiming the offer. |
| `tecDST_TAG_NEEDED` | Occurs if the destination account requires a destination tag, but the transaction does not include one. |
| `tecNO_PERMISSION` | Occurs if the seller does not have the token listed for sale or the token `Destination` is not the account buying the token. |
| `temBAD_CURRENCY` | Occurs when the buying currency does not match the offer currency. |
| `tecINSUFFICIENT_PAYMENT` | Occurs when the buy amount is less than the offer amount. |
| `tecINSUFFICIENT_FUNDS` | Occurs when the buyer doesn’t have sufficient funds including the `Fee` to purchase the token. |
# URITokenCancelSellOffer
> An URITokenCancelSellOffer transaction cancels a sell offer for a URIToken in Xahau.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/URIToken.cpp)]
*(Added by the \[URIToken amendment]\[].)*
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType": "URITokenCancelSellOffer",
"Account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"URITokenID": "C1AE6DDDEEC05CF2978C0BAD6FE27362498DGS691DC749DCDD3B95992978C0BA",
}
```
### Fields
[Section titled “Fields”](#fields)
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ------------ | --------- | ------------------------------------------------------- | -------------------------------------------------------------- |
| `Account` | String | AccountID | The address of the account that owns the sell offer to cancel. |
| `URITokenID` | String | Hash256 | The ID of the URIToken to cancel the sell offer. |
### Error Cases
[Section titled “Error Cases”](#error-cases)
Besides errors that can occur for all transactions, URITokenCancelSellOffer transactions can result in the following transaction result codes:
| Error Code | Description |
| ------------------ | ----------------------------------------------------------------------- |
| `tecNO_PERMISSION` | Occurs when the account executing the tx is not the owner of the token. |
# URITokenCreateSellOffer
> An URITokenCreateSellOffer transaction allows a user to create a sell offer for a URIToken on Xahau's decentralized exchange.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/URIToken.cpp)]
*(Added by the \[URIToken amendment]\[].)*
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType": "URITokenCreateSellOffer",
"Account": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe",
"URITokenID": "C1AE6DDDEEC05CF2978C0BAD6FE27362498DGS691DC749DCDD3B95992978C0BA",
"Destination": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe",
"Amount": {
"issuer": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"currency": "USD",
"value": "100",
},
}
```
### Fields
[Section titled “Fields”](#fields)
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | --------------------------------------------------------------------------------- |
| `Account` | String | AccountID | The address of the account creating the sell offer. |
| `URITokenID` | String | Hash256 | The ID of the URIToken being sold. |
| `Destination` | String | AccountID | *(Optional)* The address of the account to receive the sell offer. |
| `Amount` | [Currency Amount](/docs/protocol-reference/data-types/currency-formats/#specifying-currency-amounts) | Amount | The amount of currency the account wants to receive in exchange for the URIToken. |
### Error Cases
[Section titled “Error Cases”](#error-cases)
Besides errors that can occur for all transactions, URITokenCreateSellOffer transactions can result in the following transaction result codes:
| Error Code | Description |
| ------------------------ | -------------------------------------------------------------------------------- |
| `tecNO_TARGET` | Occurs if the target account does not exist. |
| `tecNO_PERMISSION` | Occurs if the account does not have permission to create a sell offer. |
| `tecINSUF_RESERVE_LINE` | Occurs if the account does not have a sufficient reserve to create a sell offer. |
| `tecINSUF_RESERVE_OFFER` | Occurs if the account does not have a sufficient reserve to create a sell offer. |
| `tecUNFUNDED_OFFER` | Occurs if the account does not have a sufficient balance to create a sell offer. |
| `tecOFFER_INVALID` | Occurs if the sell offer is invalid. |
# URITokenMint
> An URIToken Mint transaction mints a new URIToken and assigns ownership to the specified account. The URIToken represents a unique digital asset that can be used in various applications.
\[[Source](https://github.com/Xahau/xahaud/blob/dev/src/ripple/app/tx/impl/URIToken.cpp)]
*(Added by the \[URIToken amendment]\[].)*
### Example
[Section titled “Example”](#example)
```json
{
"TransactionType": "URITokenMint",
"Account": "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm",
"Flags": 1,
"URI": "697066733A2F2F4445414442454546",
"Digest": "697066733A2F2F4445414442454546697066733A2F2F44454144424545467878",
"Destination": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe",
"Amount": {
"issuer": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"currency": "USD",
"value": "100",
},
}
```
| Field | JSON Type | [Internal Type](/docs/protocol-reference/binary-format) | Description |
| ------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `Account` | String | AccountID | The address of the account that will own the minted URIToken. |
| `URI` | String | String | The URI associated with the minted URIToken. (256 byte max) |
| `Digest` | String | Hash256 | *(Optional)* The digest of the URIToken. |
| `Destination` | String | AccountID | *(Optional)* The address of the account that can buy the minted URIToken. |
| `Amount` | [Currency Amount](/docs/protocol-reference/data-types/currency-formats/#specifying-currency-amounts) | Amount | *(Optional)* The amount of currency the account wants to receive in exchange for the URIToken. |
### URITokenMint Flags
[Section titled “URITokenMint Flags”](#uritokenmint-flags)
Transactions of the URITokenMint type support additional values in the `Flags` field, as follows:
| Flag Name | Hex Value | Decimal Value | Description |
| ------------ | ------------ | ------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `tfBurnable` | `0x00000001` | 1 | Allow the issuer (or an entity authorized by the issuer) to destroy the minted `URIToken`. (The `URIToken`’s owner can *always* do so.) |
### Error Cases
[Section titled “Error Cases”](#error-cases)
### Special Transaction Cost
[Section titled “Special Transaction Cost”](#special-transaction-cost)
The URIToken Mint transaction has a standard transaction cost, which is the minimum transaction cost required for all transactions.
### Error Cases
[Section titled “Error Cases”](#error-cases-1)
Besides errors that can occur for all transactions, URIToken Mint transactions can result in the following transaction result codes:
| Error Code | Description |
| ----------------- | -------------------------------------------------------------------------------- |
| `tecDUPLICATE` | Occurs if a URIToken with the same URI from the same issuer already exists. |
| `tecDIR_FULL` | Occurs if the owner’s directory is full and cannot accommodate the new URIToken. |
| `temINVALID_FLAG` | Occurs when the user specified an incorrect `Flag`. |
| `terNO_ACCOUNT` | Occurs if the sending account does not exist. |
# Media Kit
Logos and branding guidelines are available on
# Whitepaper
Disclaimer
This whitepaper is based on [the whitepaper](https://github.com/Xahau/Whitepaper) by the Xahau Launch Alliance, but is continuously updated to reflect changes made by the decentralised governance since launch.
Last update: **July 1, 2025**
Disclaimer
This crypto-asset white paper has not been approved by any competent authority in any Member State of the European Union. The offeror of the crypto-asset is solely responsible for the content of this crypto-asset white paper.
## 1. Summary
[Section titled “1. Summary”](#1-summary)
1. The Xahau Ledger (Xahau) is the smart contract sidechain for the XRPL ecosystem. It is a fork of the XRP Ledger’s (XRPL’s) open-source rippled codebase that embodies all the useful and innovative features of the XRPL, including its environmental sustainability, but tweaks and upgrades the codebase to support smart contracts.
2. Xahau’s core features are:
* **XRPL Core:** Xahau retains the key features that have made the XRPL one of the most enduring and popular networks, including the **XRP Ledger Consensus Protocol** (Previously: Ripple Protocol Consensus Algorithm), the **DEX**, and the logic of protecting the ledger against spam and bloat by charging and burning fees in the native token, but it substitutes the recent **XLS-20 NFTs** for the cleaner, simpler **URITokens**.
* **Hooks for Smart Contracts:** The big new feature of Xahau is Hooks, the smart contract implementation for rippled. Hooks are small pieces of code installed on an account that impose rules on the transactions the account sends or receives before those transactions can be finalized.
* **Native Token & Better Tokenomics:** Xahau will be secured by its native token, XAH (currency code: XAH), and powered by better tokenomics designed to reward validators and support smart contracts.
* **Genesis Hook Governance Game:** Xahau’s Genesis account is powered by a Hook that regulates, amongst other things, the emission of new XAH and this Hook is governed by a two-tiered governance game with up to 20 independently owned validators as participants.
3. In concert, these features create a new network within the XRPL ecosystem that implements the Hooks amendment to deliver fast, cheap, secure smart contracts for the XRPL ecosystem supported by a properly incentivised community of validators and developers.
4. The development of the Xahau Ledger has been driven by the Xahau Launch Alliance, five experienced and committed entities within the XRPL community that have carried the cost and risk of establishing the new network without an ICO.
5. Xahau will launch fully functional and decentralised with over 10 independently owned validators run by a representative mixture of the XRPL ecosystem, including developers, exchanges, and long-term community members.
## 2. Xahau – Built from the XRPL’s DNA
[Section titled “2. Xahau – Built from the XRPL’s DNA”](#2-xahau--built-from-the-xrpls-dna)
1. Xahaud - the software that runs Xahau - is a fork of rippled, the open-source codebase of the XRPL. It retains the key features that have made the XRPL one of the most popular and enduring networks since it was launched in 2012.
### XRP Ledger Consensus Protocol
[Section titled “XRP Ledger Consensus Protocol”](#xrp-ledger-consensus-protocol)
2. Xahau uses the XRP Ledger Consensus Protocol (Previously: Ripple Protocol Consensus Algorithm) – sometimes called Proof of Association (PoA). It is designed to overcome the limitations of traditional consensus mechanisms like Proof of Work (PoW) or Proof of Stake (PoS), particularly the high energy consumption associated with PoW.
3. The XRP Ledger Consensus Protocol (Previously: Ripple Protocol Consensus Algorithm) works as follows
* **Validator Proposal:** Each validator proposes a new set of transactions, called a “candidate set,” which they believe should be included in the next ledger. This candidate set includes both new transactions and any transactions that were not previously included in a validated ledger.
* **Agreement Phase:** Validators communicate with each other to exchange and evaluate candidate sets. They independently verify the validity and order of transactions proposed by other validators. Through a series of iterative rounds, validators attempt to converge on a single candidate set that the majority agrees upon.
* **Finalization:** Once a supermajority of validators (at least 80%) agrees on a specific candidate set, that set is considered “finalized.” Finalized candidate sets become the basis for the next ledger.
* **Ledger Closing:** The ledger is closed, and a new ledger is created based on the transactions in the finalized candidate set. This process occurs roughly every 3-5 seconds in the XRPL, allowing for fast transaction settlement times.
4. Under the XRP Ledger Consensus Protocol (Previously: Ripple Protocol Consensus Algorithm), each validator specifies a UNL (Unique Node List) being a list of other validators it trusts. The canonical ledger is found through the overlap between the UNLs of all the validators.
5. To facilitate social consensus on the appropriate UNL, several entities, including the XRPL Foundation, publish recommended Validator Lists (or VLs) of the validators they deem suitably trustworthy. Following a generally accepted dUNL helps ensure you stay on the main ledger and do not unintentionally end up following an irrelevant fork. Xahau will follow a similar, social-consensus approach to defining a dUNL, with organisations like the XRPL Foundation publishing its recommended VL.
6. The XRP Ledger Consensus Protocol (Previously: Ripple Protocol Consensus Algorithm) Protocol provides several advantages, including high scalability, low energy consumption, and resistance to censorship and network forks. By utilizing a set of trusted validators and this unique consensus algorithm, Xahau achieves fast and secure transaction processing while maintaining decentralization and reliability.
### The DEX
[Section titled “The DEX”](#the-dex)
7. Xahau retains a version of the XRPL’s limit order book decentralized exchange (DEX) that allows users to trade and exchange assets directly on the ledger. The DEX leverages Xahau’s decentralized and trustless architecture to enable peer-to-peer asset trading without the need for intermediaries.
8. In summary, the decentralized exchange works as follows:
* **Order Creation:** Users can create buy or sell orders on the DEX by specifying the asset they want to trade, the desired quantity, and the price they are willing to accept or pay.
* **Order Matching:** The DEX’s order book maintains a record of all open buy and sell orders. When a new order is placed, the DEX automatically matches it against existing orders based on price and quantity.
* **Cross-Currency Trading:** The DEX supports cross-currency trading, enabling users to trade between different assets. To facilitate this, the DEX uses the ledger’s native currency as a bridge currency, allowing users to convert one asset to the native currency and then to another asset.
* **Pathfinding Function:** The pathfinding function is a key component of the DEX. It helps users find the most efficient trading path when converting one asset to another. For example, if a user wants to trade Asset A for Asset D, but there is no direct market available, the pathfinding function will search for the best sequence of trades (e.g., A to B, B to C, and C to D) to achieve the desired conversion with minimal slippage and fees.
* **Automatic Order Execution:** Once a trade is matched, the DEX automatically executes the transaction. The ledger’s consensus mechanism ensures that the transaction is validated and added to the ledger, providing a high level of security and immutability.
* **Trustless and Decentralized:** The DEX operates in a trustless and decentralized manner. It does not rely on a centralized exchange or require users to deposit their funds into a third-party wallet. Instead, users maintain control over their assets throughout the trading process, reducing counterparty risk.
* **Low Fees and Fast Settlement:** Trading on the DEX incurs minimal fees compared to traditional centralized exchanges. Xahau’s consensus protocol allows for fast settlement times, enabling near-instantaneous transaction processing.
9. With these features, the DEX provides users with a convenient and secure platform for peer-to-peer token trading. By leveraging the trustless and decentralized nature of Xahau, the DEX offers efficient cross-token trading and seamless order matching while maintaining user control and privacy.
### Burned Transaction Fees
[Section titled “Burned Transaction Fees”](#burned-transaction-fees)
10. To protect itself against spam and bloat, the XRPL charges transaction fees and account reserves in its native currency and burns all transaction fees, rather than redistribute them to validators. Xahau follows this “fees charged and burned” model to likewise protect itself.
11. While this is a proven mechanism for protecting the ledger, it has implications for Xahau’s Tokenomics, as discussed later. The fees burned by Xahau’s smart contracts, while still small, will be much higher and more variable than standard transaction fees on the XRPL.
### URIToken NFTs instead of XLS-20 NFTs
[Section titled “URIToken NFTs instead of XLS-20 NFTs”](#uritoken-nfts-instead-of-xls-20-nfts)
12. Unlike the XLS-20 NFT standard introduced to the XRPL, which relies on compressing NFTs into on-ledger “pages”, Xahau will use URIToken objects.
13. URITokens (short for Uniform Resource Identifier Token) are an innovative way to represent and manage NFTs, their metadata and ownership information within Xahau. Each token is a first-class ledger object with a unique address that does not change when the current owner does.
14. URIToken NFTs have many benefits over the XLS-20 NFT standard, including:
* **Lightweight and Efficient:** URITokens are first-class on-ledger objects that can be created, destroyed, transferred, bought and sold, and which interoperate easily with Hooks. Trading is limited to a single sell offer per token, that can be accepted either by the specified destination account or, if no destination is specified, then the general public. There is no brokered mode.
* **Interoperability and Immutability:** URITokens come with a built-in extensible metadata JSON standard and an optional Digest field (a hash making the content of the NFT immutable). This provides flexibility for developers and creators to choose their preferred storage solutions, such as IPFS or traditional web servers. It also promotes interoperability with existing NFT standards and platforms, facilitating the integration with the broader NFT ecosystem.
* **Improved User Experience:** URITokens can be easily located by their keylet (on ledger address) that does not depend on the current owner of the token. The NFT metadata and ownership information can be easily accessed and updated through standard web protocols. Users can simply click on the URI associated with an NFT to view its details, including images, descriptions, and provenance. This approach simplifies the user experience and reduces the complexity of interacting with NFTs on Xahau.
15. Thus, URITokens provide a lightweight, flexible, and cost-efficient solution for NFTs on Xahau.
## 3. Hooks – Smart Contracts for the XRPL Ecosystem
[Section titled “3. Hooks – Smart Contracts for the XRPL Ecosystem”](#3-hooks--smart-contracts-for-the-xrpl-ecosystem)
1. Hooks is a smart contract solution developed specifically for the XRPL ecosystem. Hooks are small, efficient pieces of code defined on a Xahau account that execute logic on transactions sent to or received by the account before those transactions are finalised in the ledger. Hooks are thus a way for developers to create and deploy smart contracts on Xahau, opening a wide range of possibilities for decentralized applications (dApps) and automated transactions.
2. Xahau implements the Hooks amendment as a sidechain so the XRPL ecosystem can benefit from Hooks now rather than later. It also allows the XRPL community to better evaluate whether and how to implement Hooks on the XRPL mainnet in the future.
### Benefits of Hooks
[Section titled “Benefits of Hooks”](#benefits-of-hooks)
3. Some key benefits of Hooks over other smart contract solutions include:
* **Simplicity and Efficiency:** Hooks are lightweight and efficient compared to conventional smart contract solutions. The underlying architecture of Xahau, which focuses on transaction settlement and fast consensus, ensures quick execution of smart contracts without compromising performance.
* **Native Integration:** Hooks are a layer-one smart contract solution and thus live natively inside the ledger, allowing developers to create contracts that interact directly with on-ledger objects, balances and transactions. In contrast to layer-two smart contract solutions, this tight integration simplifies the development process and ensures seamless interoperability with Xahau’s ecosystem.
* **Low Fees and Scalability:** Hooks leverage Xahau’s low transaction fees and high scalability. Like most chains, Xahau can handle a high volume of transactions per second, making it suitable for applications that require fast and cost-effective smart contract execution.
* **Security and Reliability:** Hooks inherit the robust security and reliability of the XRPL. The XRP Ledger Consensus Protocol (Previously: Ripple Protocol Consensus Algorithm), which powers Xahau, ensures a decentralized network with consensus among trusted validators. This strong security foundation provides confidence for developers and users alike.
* **Ecosystem Compatibility:** Hooks are designed to be compatible with existing XRPL tools and services, making it easier for developers to integrate smart contracts into their applications. This compatibility enables seamless interaction with other features of the XRPL, such as decentralized exchanges and payment channels.
* **Account Decentralisation:** Using Hooks it is possible for a Xahau account to be fully autonomous and to emit and receive transactions according to the logic of its Hook, instead of relying on external private key holders to manually authorise transactions.
### Sample Use-Cases
[Section titled “Sample Use-Cases”](#sample-use-cases)
4. By introducing smart contract capabilities to the XRPL ecosystem, Hooks offer a powerful and efficient solution for developers seeking to build decentralized applications and automate transactions. Examples of the kinds of functions Hooks can achieve include:
* **Whitelists:** A Hook enabled account can protect accounts against fraud or sanctioned transactions by being coded to only accept or send transactions to whitelisted accounts.
* **Blacklists:** A hook enabled account can be coded to refuse to receive or send transactions to any prohibited (blacklisted) account.
* **Sophisticated Escrow:** A Hook enabled account can hold any asset received from nominated account and only forward or return those assets if told to do so by a valid transaction that meets predetermined criteria.
* **Automated Registry:** A Hook enabled account can act as an automated registry and mint and redeem URI NFTs as evidence of registration or registration rights.
* **Self-Sovereign Treasury:** Issued currencies can mimic decentralised, counterparty-free assets by being deposited into a self-owned Account with a Hook that emits the currency according to a disclosed and predetermined emission schedule.
5. The combination of simplicity, low fees, scalability, security, and ecosystem compatibility means Xahau offers early access to an attractive smart contract solution for the XRPL ecosystem. Xahau’s experience with Hooks will help the community determine whether and how to implement Hooks on the XRPL in the future.
## 4. XAH – Native Token & Tokenomics
[Section titled “4. XAH – Native Token & Tokenomics”](#4-xah--native-token--tokenomics)
1. Xahau is secured by its native token, XAH. Its salient details are as follows:
* **Native Token:** XAH
* **Ticker:** XAH
* **Smallest Unit:** 1 drop or 0.000001 XAH
* **Function:** XAH is the currency of the network. It is a utility token to purchase network services. Like the XRPL, transactions on Xahau incur a fee or reserve that is charged in XAH to protect the Ledger against spam and bloat.
* **Initial Liquidity:** 600 million distributed to launch participants.
* **Max Supply:** Uncapped.
* **Emission Mechanisms:** The supply of XAH is determined via the amendments enabled in Xahau’s consensus protocol:
* **Monthly Balance Adjustment:** To put back into circulation some of the XAH burned from transaction fees, each active user can claim an increase in their account balance of \~0.34% of their average monthly balance (equal to 4% pa. compounding). This emission is controlled by the Protocol Governance Game which uses a combination of the Hooks, BalanceRewards and the XahauGenesis amendments.
* **Monthly Seat Rewards:** To put back into circulation some of the XAH burned from the transaction fees, and to incentivise active and appropriate governance, an amount matching the total claimed Monthly Balance Adjustments is also rewarded to Governance Game validators.
### Initial Distribution
[Section titled “Initial Distribution”](#initial-distribution)
2. The Launch parties have invested significant time and resources to launch Xahau. An initial distribution is provided at the protocol level by the XahauGenesis amendment.
3. The protocol will pay a modest 600 million Xahau XAH as follows: 12 million to each of the eight Governance Game validator Seats on launch.
* 16 million additional to GateHub for DEX stablecoin liquidity bootstrapping.
* 160 additional million to XRPL Labs (Xaman) for Intellectual Property - Xaman has carried the main technical and financial burden of developing Hooks and xahaud. This additional distribution is for that effort.
* 328 million to the XRPL Foundation (now INFTF), to help ensure the health of the XRPL Protocol (now Xahau) ecosystem moving forward.
### Monthly Balance Adjustment
[Section titled “Monthly Balance Adjustment”](#monthly-balance-adjustment)
4. One challenge Xahau must manage is the additional expense of smart contracts compared to normal XRPL transactions.
5. On the XRPL, transaction fees cost as little as one drop or 0.000001 XRP. Against a total supply of 100 billion XRP, this is a trivial-but-sufficient cost. Hooks transactions, on the other hand, can cost orders of magnitude more to set and to trigger. Further, while every XRPL transaction is standardised, Hooks can vary enormously in their complexity and cost. To properly protect itself against spam and bloat from its Hooks, the Ledger must charge appropriately (and dynamically) for the size and logic complexity of every Hook transaction.
6. The consequence is that, as a smart contract chain that burns fees, XAH could easily be burned to near-zero, and certainly much more rapidly than equivalent XRP would be burned on the XRPL, potentially leading to perverse incentives to horde Xahau rather than use it to deploy and run Hooks.
7. To guard against these risks, Xahau needs a protocol-level mechanism that puts burned tokens back into circulation, but one that does not simply incentivise high fees. This is the purpose of the monthly balance adjustment.
8. The Monthly Balance Adjustment works as follows:
* Each month, each Xahau account can choose to claim (against the protocol) an adjustment based on their average XAH balance (computed since the last adjustment). The adjusted amount is the equivalent of 4% p.a. compounded (roughly 0.34% per month).
* Users can claim their balance adjustment by sending a RewardClaim transaction to the Genesis account at any time provided 30 days has passed since the last claim. Doing so demonstrates they are an active user.
* Upon receipt of the claim transaction, the protocol, via the BalanceRewards and XahauGenesis amendments, increases the user’s account balance by the balance adjustment.
* Unclaimed balance adjustments are foregone as a penalty for inactivity.
* 4% is the initial rate at launch, but it can be changed via the Governance Game if it proves too small or too large in the future.
9. This mechanism allows active users to claim a monthly adjustment that puts further XAH into circulating supply, mitigating the risk of the token being burned down to zero through smart contract execution fees.
### Monthly Governance Validator Rewards
[Section titled “Monthly Governance Validator Rewards”](#monthly-governance-validator-rewards)
10. The Xahau Genesis Account is enabled with a Hook that controls, among other things, the emission of XAH. This Hook needs a governance arrangement so that it can be monitored, amended, and/or replaced in the face of changing network and real-world conditions.
11. It is well known that XRPL mainnet validators do not receive any kind of reward for the services they provide for underpinning the mainnet Ledger. However, infrastructure costs money to run, and real-world experience shows that this lack of incentive leads to a lack of actively managed validators.
12. The Xahau Genesis Hook needs to know, or be told, which accounts it must trust when deciding whether to update itself. So, those accounts must be known in advance, rather than emerging from the overlapping UNLs.
13. The technical solution to this problem is an incentivised Genesis Hook Governance Game that rewards certain Validators for overseeing the Hook. It works as follows:
* There are 20 “Seats” on the Genesis Hook Governance Game.
* Each Seat is controlled either by a single Xahau Account (Level 1) or a self-managing committee of 3-20 Accounts (Level 2).
* For each occupied Seat, the protocol mints and distributes 1/20th of the total Monthly Balance Adjustments claimed that month.
* If a Seat is held by a committee of Accounts, the rewards for that Seat are split in a manner of that committee’s choosing.
* If no users claim a Balance Adjustment that month no rewards are paid to any validators.
* Each Flag Ledger (256 ledgers) an on-ledger record called a UNLReport is generated. This report contains a list of validators’ public keys that 80% of other validators believe participated adequately in consensus since the previous Flag Ledger. The Genesis Hook will only distribute validator rewards to Seats that correspond to the public keys of validators on the UNLReport.
14. Thus, the Genesis Hook Governance Game includes a reward mechanism designed to ensure that trusted accounts are rewarded for running trustworthy validators, that those rewards are linked to user activity, and that those rewards put new XAH into distribution, mitigating the risk of a token liquidity crunch from high smart contract execution fees.
## 5. Xahau Governance Game
[Section titled “5. Xahau Governance Game”](#5-xahau-governance-game)
1. XRP Ledger Consensus Protocol (Previously: Ripple Protocol Consensus Algorithm) chains rely on a robust overlap in validator UNLs to define the canonical ledger. If a validator does not trust enough of the same machines that everyone else trusts, they risk unknowingly listening to an irrelevant fork of the ledger. Determining the best UNL is a matter of social (off-chain) consensus.
2. To assist that social consensus, various entities publish dUNLs – lists of validators everyone should follow. Xahau will follow the same approach, with the XRPL Foundation and others expected to publish such lists. So, like the XRPL, Xahau will be a public permissionless chain for which anyone can run a validator. And like the XRPL, any update of the protocol will be dependent on more than 80% of UNL validators supporting the changes, in the same manner as the XRPL.
3. While the dUNL helps define the validators responsible for the canonical Ledger, Xahau has a second governance challenge, not present in the XRPL mainnet: the governance of its Genesis Hook. The XRPL mainnet minted all of its XRP on creation. Xahau cannot follow this approach. Its native token needs to be minted in response to the happening of predefined events (i.e. Burn2Mint, Account Adjustments, Validator Rewards.) It uses a Hook on its Genesis Account to achieve this.
4. This means Xahau needs a governance mechanism for its Genesis Hook in case the Hook needs to be adjusted or replaced. This is known as the Governance Game:
* **Purpose:** The Governance Game exists to ensure that the UNL validators remain active and allows those active members to maintain the Hook on the Genesis account that controls the distribution of XAH.
* **Seats:** There are 20 Seats at a table. A Seat is a Xahau Account whose vote counts in the Governance Game.
* **L1 Table:** The Governance Game requires at least the top-level table. This is called the Level 1 table (L1 Table). This table by definition exists only on the Genesis account according to the Governance Game Hook installed there. A seat at the L1 table may be filled by an Account or may be empty. These seats are called L1s.
* **L2 Table:** An L1 seat may itself be filled by an Account which has another, different, Governance Hook installed on it. The seats at this table are called L2s, and the table is an L2 Table. The structure is a self-managing committee of 3-20 Accounts that collectively control the L1 seat and its voting rights. Thus up to 400 Accounts may be involved in the two layer Governance game, depending on the mix of L1 and L2 Seats.
* **Filling Seats:** L1 Seats are filled or vacated by 80% vote of all existing filled L1 Seats. For L2 Seats, the committee of Accounts that collectively holds that L1 Seat invites or disinvites new members (up to a maximum or 20 and down a minimum of 3) by majority vote, or according to whatever other logic or rules they deem fit. No other Seats have any control over the members of an L2 Table.
* **Voting:** Each L1 Seat has 1 vote in the Governance Game. For L2 Seats, the single vote of its L2 table is determined by whatever logic that L2 table decides. The default is more than 50% vote of the L2 Seat members at that L2 table.
* **Hook Changes:** All changes to the Hook are voted on via the Governance Game. A Hook change is only successful if supported by the defined % vote of all Seats. The regular vote is 80%, but for the increase of the rate of balance adjustment it is 100%.
* **Rewards:** To incentivise L1 Seats to run reliable validators, L1 Seats earn monthly Rewards provided they actively participate in consensus.
* **Foundation of dUNL**: The validators run by those participating in the Genesis Hook Governance Game should form the foundation of any dUNL, as any Seat that performs unreliably risks being voted out by the other Seats.
5. The different types of Seats allow for a greater diversity of participating Accounts without undermining security. Level 1 Seats are suitable to Accounts controlled by significant entities the community can trust, while Layer 2 Seats allow a broader pool of participants, but since their collective participation counts as 1 vote, their numbers do not overwhelm the trust placed in Level 1 Seats.
6. Thus, the Governance Game allows up to 400 Accounts to participate and rewards those Accounts for doing so provided they also participate in consensus by running a reliable validator.
## 6. The Xahau Launch Alliance
[Section titled “6. The Xahau Launch Alliance”](#6-the-xahau-launch-alliance)
1. Xahau has been developed by an alliance of 5 independent entities with a track record of building on and supporting the XRPL ecosystem. Those entities are as follows:
* XRPL Labs (Xaman), the software developer behind the XUMM wallet, Hooks, and Xahaud that has carried most of the expertise and cost of developing Xahau.
* GateHub Limited, a multinational technology company, crypto exchange, and crypto service provider, including Stablecoins issued on the XRPL.
* Titanium OU, an IT consulting and infrastructure firm specialising in providing secure hosting and a major provider of the infrastructure for the XRPL (as Alloy Networks).
* Evernode Labs Ltd, the developer of the Evernode smart contract project and responsible for deploying it to Xahau.
* Digital Governing OU, an incorporated entity associated with a globally active firm for accounting, audit, and legal services.
## 7. Launch Fully Functional & Decentralised
[Section titled “7. Launch Fully Functional & Decentralised”](#7-launch-fully-functional--decentralised)
1. Xahau will launch fully functional and decentralised without raising funds. No Centralised Control
2. Xahau will launch with 8 of its 20 Governance Game Seats filled:
* 5 will be Layer 1 Seats, each filled by a member of the Xahau Launch Alliance.
* 3 will be Layer 2 Tables, one of which will be filled by a committee of Exchanges and the other a diverse committee of XRP community projects, developers, and long-term supporters.
* 1 will be FYEO, a company offering code audit and review services on blockchain development, including software such as Hooks.
### No Funds Being Raised
[Section titled “No Funds Being Raised”](#no-funds-being-raised)
3. There is no ICO, and no funds are being raised from the launch.
4. The Xahau Alliance members have each independently funded their own development efforts. There’s no communal funding, nor any pooling of money or resources for the further development of Xahau. Nor is there any roadmap, or “Xahau Foundation”, or other centralised treasury. Any further development is wholly at the discretion of independent actors within the ecosystem.
### No Promises
[Section titled “No Promises”](#no-promises)
5. The Governance Game members are independent entities. There is no agreement, arrangement, or understanding between them about how to cast their vote, deploy their resources, or use their assets, including any XAH. It is only the logic of the Game – be a trustworthy Validator in the eyes of the other members or be voted out of the Game – that drives Validator behaviour. This is an inherent feature of the XRP Ledger Consensus Protocol (Previously: Ripple Protocol Consensus Algorithm) (PoA) mechanism Xahau uses.
### No Further Features Needed
[Section titled “No Further Features Needed”](#no-further-features-needed)
6. While software, by its nature, needs to be maintained, there are no essential functionalities missing from Xahaud or in need of further development for the software to be useful as a smart contract sidechain of the XRPL.
# Help Us
The Xahau documentation is open source and open for contributions [on GitHub](https://github.com/Xahau/xahau-web).
A lot of gaps and uncovered details are expected in the documentation, so we invite **everyone** to collaborate on bringing it up to standard.
Do you see anything that is missing, please [create an issue](https://github.com/Xahau/xahau-web/issues) on the repository or just go ahead and create a pull request to the main branch, with suggested changes or updated documentation.
If you would like to contribute, but don’t know what to do, you can always refer to the [GitHub Project board](https://github.com/orgs/Xahau/projects/2/views/1) where issues are organized. If you are unfamiliar with GitHub, the [Community Discord](https://discord.com/invite/UzU58haAn4) is a great place to get help and get involved.
# XRPL/Xahau: What is Different?
> A list of notable differences between the XRP Ledger and Xahau.
#### IOU Token Escrow & PayChannels
[Section titled “IOU Token Escrow & PayChannels”](#iou-token-escrow--paychannels)
Xahau introduces IOU Token Escrow and PayChannels as unique features, enhancing transaction flexibility and security. They facilitate the temporary holding of IOU tokens under predefined conditions (escrow) and the establishment of payment channels for efficient, off-ledger transactions.
[Payments ](/docs/features/network-features/payments)
#### URITokens NOT NFTokens
[Section titled “URITokens NOT NFTokens”](#uritokens-not-nftokens)
Instead of using NFTokens like XRPL, Xahau employs URITokens. URITokens are a form of non-fungible digital assets with unique identifiers and metadata, offering a novel approach to asset representation on the blockchain.
[URIToken ](/docs/features/network-features/uritoken)
#### Different Repo
[Section titled “Different Repo”](#different-repo)
Xahau and XRPL operate from different repositories, signifying that they are separate protocols with their own development trajectories and documentation. This distinction implies that Xahau may offer unique features and optimizations not found in XRPL.
#### Different Build Process (WASM & LLVM)
[Section titled “Different Build Process (WASM & LLVM)”](#different-build-process-wasm--llvm)
Xahau’s build process incorporates WebAssembly (WASM) and the Low-Level Virtual Machine (LLVM), which is not described in the XRPL build process. Xahau is utilizing these technologies for enhanced smart contract capabilities and to improve the performance and cross-platform compatibility of its codebase.
[Build Xahau ](/docs/infrastructure/build-xahaud)
#### Different Amendment Time (5 days)
[Section titled “Different Amendment Time (5 days)”](#different-amendment-time-5-days)
The amendment process in Xahau has a specified time frame of 5 days, differing from XRPL’s timeline. Amendments are protocol changes, and the 5-day period refers to the duration validators have to reach a consensus and implement these changes.
[Amendments ](/docs/features/amendments)
#### Different Starting Sequence
[Section titled “Different Starting Sequence”](#different-starting-sequence)
Xahau employs a different starting sequence for accounts than XRPL. The initial sequence on the account is the ripple epoch time when the account was create/imported into Xahau.
#### Import / Burn 2 Mint
[Section titled “Import / Burn 2 Mint”](#import--burn-2-mint)
Importing from XRPL to Xahau grants users 2 XAH tokens, indicating an incentive mechanism to encourage asset migration or bridging from XRPL to Xahau, potentially to enhance network adoption and liquidity.
[Burn 2 Mint (B2M) ](/docs/features/burn-2-mint)
#### Balance Rewards (Rewards for using XAH)
[Section titled “Balance Rewards (Rewards for using XAH)”](#balance-rewards-rewards-for-using-xah)
Xahau offers balance rewards for utilizing XAH, a feature absent in XRPL. This is a reward system for holding or using Xahau’s native token, XAH, to promote network engagement and stability.
[Balance Rewards ](/docs/features/network-features/balance-rewards)
#### Hooks
[Section titled “Hooks”](#hooks)
Hooks in Xahau, which are not present in XRPL, are programmable scripts or smart contract-like functions that can be attached to accounts. They add a layer of programmability and automation to the network’s operations.
[Hooks ](/docs/hooks/)
#### Governance Structure
[Section titled “Governance Structure”](#governance-structure)
Xahau’s governance structure differs from XRPL’s. Xahau has its own approach to decision-making, proposal systems, or validator roles, which could influence the network’s evolution.
[Governance Game ](/docs/features/governance-game)
#### Node Requirements
[Section titled “Node Requirements”](#node-requirements)
Running a Xahau node has different requirements compared to an XRPL node. These differences relate to the technical specifications needed to support Xahau’s unique features and network demands.
[System Requirements ](/docs/infrastructure/system-requirements)
#### Native Token
[Section titled “Native Token”](#native-token)
Xahau’s native token is XAH, distinct from XRPL’s XRP. As the primary currency within the Xahau network, XAH likely serves as the main medium of exchange and a store of value, central to the network’s economic framework.
[Currency Formats ](/docs/protocol-reference/data-types/currency-formats)
#### Versioning (Uses Dates)
[Section titled “Versioning (Uses Dates)”](#versioning-uses-dates)
Xahau employs a date-based versioning system, unlike XRPL’s versioning approach. This method may provide a more intuitive means of tracking the network’s updates and historical development.
[Versioning Process ](/docs/features/versioning-process)