Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
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.
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 Ledger. This section is designed to help you understand the functionality and capabilities of Xahau, with practical examples to help illustrate these features in action.
The Infrastructure section provides detailed instructions for setting up the build environment on both Ubuntu 22.04 and macOS 13.5.2.
In the 'Building Xahau' chapter, you will find a step-by-step guide through the process of establishing environmental variables, installing core and Xahaud dependencies, and compiling the software.
This includes the acquisition and setup of essential components like LLVM, Boost, WasmEdge, and Protobuf. The steps explain why certain versions and configurations are needed to ensure compatibility and optimal performance.
This section ends with cloning the Xahau repository and creating the Xahaud target, setting developers on the path to adding to or deploying the Xahau network.
The Technical 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.
We hope this documentation provides you with the information you need to understand, use, and contribute to Xahau. Happy exploring!
A list of notable differences between the XRP Ledger and Xahau.
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.
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.
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.
https://github.com/Xahau/xahaud
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.
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.
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.
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.
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.
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.
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.
Running a Xahau node has different requirements compared to an XRPL node. These differences could be related to the technical specifications needed to support Xahau's unique features and network demands.
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.
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.
Please read the introduction of Hooks in this blog.
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
Welcome to 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:
Block or allow incoming and outgoing transactions on the account,
Modify and maintain internal state and logic specific to the hook on that account, and
Emit new transactions on behalf of the account.
This Hooks documentation and the Hooks API use a set of unfamiliar terms. Use the lookup table below if you find yourself lost.
Guards are needed to perform loops in a Hook.
Hooks are deliberately not . 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 tells the ledger the maximum number of iterations a loop will make. Specifically the function takes two arguments:
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
(). 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).
❗️ Pay Attention
Guards must be set using numerical literals. You cannot use a variable or runtime value in a Guard.
Consider the following for-loop in C:
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) is 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.)
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:
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.
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
.
❗️ Warning
Failure to use guards correctly will cause an attempted
SetHook
transaction to be rejected.
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.
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.
Each TSH has either a weak or a strong connection to the transaction.
A Strong connection means:
The originating transaction must pay the fee for the execution of the TSH Hook Chain
The TSH has the right to rollback the whole transaction by calling rollback()
from their Hook during execution.
A Weak connection means:
The originating transaction does not pay for the execution of the TSH Hook Chain.
The TSH pays for the execution of their own Hook Chain through a feature called .
The TSH must have set an account flag asfTshCollect
prior to the execution of the originating transaction.
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.)
📘 Hint
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
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).
If a Transaction Type does not appear in the table then it has no TSHes other than its originating account.
AccountSet
AccountDelete
Check
ClaimReward
DepositPreauth
Escrow
GenesisMint
Import
Invoke
Offer
Payment
PaymentChannel
SetHook
SetRegularKey
SignersListSet
Ticket
TrustSet
URIToken
Chain multiple hooks together to do more useful tasks
👍 Hook Design Philosophy
Each Hook should do one thing, and do it really well.
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.
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 .
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 . When they are installed, the installer may specify install-time which may change the behaviour of the installed Hook.
cbak
execution if this was an Emitted Transaction.
Any Again as Weak (AAW) Hooks. Execution order for AAW is first numerically according to Account ID then numerically according to Hook position.
Strong TSHes have their hooks executed before the originating transaction is applied to the ledger. This means they have the ability to 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 but cannot prevent the transaction from occurring.
Strongly executed hooks can call to be executed a second time as a weak execution after the originating transaction has been applied.
2 means the Hook is being executed weakly after being executed strongly due to a call.
In addition to the install-time operations specified in the , Hooks have some runtime control over chain execution:
A Hook may determine its own HookHash
by calling .
A Hook may determine its location in the Hook Chain using .
A Hook may skip (or re-enable) another Hook further down the chain using .
A Hook may modify the of a Hook further down the chain using .
Hook Chains are . However any Hook in any chain may flag that it requires a second, Weak Execution by calling . 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:
Weak Transactional Stake Holders who have opted in to allow a . Execution order is first-come first-serve according to the event that caused the TSH to be flagged (such as pathing).
Hook
This term refers to a range of things depending on context 1. A webassembly binary uploadable to Xahau with the SetHook Transaction type. 2. A webassembly binary already uploaded to and set or configured onto an Xahau account. 3. The source code 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 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.
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.
SetHook
A new Transaction Type introduced in the Hooks ammendment which sets a Hook onto an Xahau account. See: SetHook Transaction.
Guards
A special control mechanism you need to use if you write a loop into in a Hook. See: 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).
Serialized Objects (STO)
The way xahaud transmits and stores ledger objects. See: Serialized Objects.
Slots and Keylets
Slots can contain ledger objects and keylets identify those objects. See: Slots and Keylets.
Trace
A way to print a log line to the xrpld output from a Hook. See: Debugging Hooks.
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
Account
Account
Strong
Account
Account
None
Account
Beneficiary
Strong
Account
Account
Strong
Strong
None
Account
Destination
Weak
Strong
None
Destination
Destination
Strong
None
Strong
Destination
Account
Weak
None
Weak
Account
Account
Strong
Account
Issuer
Strong
Account
Account
Strong
Account
Authorized
Strong
Account
Account
Strong
Strong
Strong
Account
Destination
Weak
Strong
Weak
Destination
Destination
Strong
None
Strong
Destination
Account
Weak
None
Weak
Account
Account
Strong
Account
Destination
Strong
Account
Beneficiary
Weak
Account
Account
Strong
Account
Issuer
Strong
Account
Account
Strong
Account
Destination
Weak
Account
Account
Strong
Strong
Account
Crossed
None
Weak
Account
Account
Strong
Account
Destination
Strong
Account
Crossed
Weak
Account
Account
Strong
Strong
Strong
Account
Destination
Weak
Strong
Weak
Destination
Destination
Strong
None
None
Destination
Account
Weak
None
None
Account
Account
Strong
Account
Account
Strong
Account
RegularKey
Strong
Account
Account
Strong
Account
Signer
Strong
Account
Account
Strong
Account
Account
Strong
Account
Issuer
Weak
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
Install-time parameters allow Hooks to be generic and flexible
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 the existing Hook Definition.)
Hook Parameters are a set of Key-Value pairs set during the 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 may define up to 16 Hook Parameters per installed Hook.
The HookParameters
array is optionally defined inside each Hook
in the Hooks
array as shown below:
The first user to set a novel Hook may define Hook Parameters which then become the Default Parameters for that Hook. This means any subsequent users who references the same HookDefinition 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.
Parameters can be read by the Hooks they are set on using hook_param.
If more than one Hook is installed in a Hook Chain, then 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.
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 API.
Prevent state clobbering by using the correct namespace
To avoid two or more Hooks installed on the same account unintentionally clobbering each-other's Hook State, 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.
The configured Namespace a Hook operates under alters the Keylets its State 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.
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.)
The first user to set a novel Hook defines a HookNamespace
which becomes the Default Namespace for that Hook. This means any subsequent users who reference the same HookDefinition will receive this originally set Namespace by default.
The subsequent user may specify their own Namespace, overriding the Default Namespace for their installation only.
Choice of HookNamespace affects the behaviour of the following Hook APIs:
See account_info and account_namespace for information about how to query the ledger regarding namespaces.
Hook Grants
❗️ Warning
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 then please re-check your design first to ensure you actually need to use one before continuing.
Grants provide a way for a Hook Installer to assign State Management permissions to a foreign Hook on other Xahau accounts.
A 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, the HookGrants
array is always set exactly as specified in the 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.
To delete all Grants submit an empty HookGrants
array.
🚧 Important
Unlike Parameters, the
HookGrants
array is always set exactly as specified in the 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.
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
To make use of a grant, a Hook modifies State objects on a foreign account by calling state_foreign_set.
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.
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) the Xahau has a lot to offer businesses and (creative) developers.
All Hooks are compiled to a single webassembly module 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 (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.
Here is an example Hook written in C. The Hook prints 0...3 to the trace log before accepting the originating transaction.
📘 Hint
For educational purposes the above example deliberately does not include
hookapi.h
(which developers would typically use.)
A variety of compilers 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.
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.
📘 Hint
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.
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 to strip out these out. Failure to do so will lead to your Hook being rejected.
❗️ Important
Don't forget to use the Hook Cleaner Utility or your Hooks will be rejected.
Hooks can read and save small pieces of on-ledger data 🚀
State 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
The below example uses the state_set Hook API to assign the value 0xC001CAFE
to the key 0x0..000001
(uint256 = 1) in the Hook State of the Hook Account.
In a subsequent Hook execution this value can now be retrieved using the same key:
After the above code has run the value
buffer will be populated with the value found at the key.
📘 Hint
The buffer
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 aTOO_SMALL
error.
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 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.
Please see Namespaces
What to expect when your Hook runs.
SetHook transactions are charged per byte of created webassembly. The rate is 10000 drops per byte. Thus a 1kib Hook will cost 10 XAH to create.
When Hooks are Strongly Executed 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.
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:
Open a websocket connection to the Hooks node you will be working with.
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.
Submit it as a hex blob to the RPC as follows:
For HTTP POST RPC submit it as follows:
The response should look something like
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.
Hooks have access to the same computation the Fee RPC Helper does. To use this simply call 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 to emplace it into the serialised transaction before emission. The relevant field is sfFee
.
Hook web assembly bytecode is installed onto an Xahau account using the SetHook
transaction.
An example appears below:
The transaction is deceptively simple, but hides significant complexity, described below.
The main body of the SetHook transaction is the hooks array:
This array mirrors the Hook Chain 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.
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.
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.
For more information see: Reference Counting
When a HookDefinition
is created it contains the initial Parameters, Namespace and 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.
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.
Occurs when:
The HookSet Object is empty
Behaviour:
No change of any kind is made.
Example:
Occurs when:
All of the following conditions are met:
The Corresponding Hook does not exist orFLAG_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:
Occurs when:
All of the following conditions are met:
The Corresponding Hook does not exist orFLAG_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:
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:
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:
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:
How to print "hello world" from your 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.
📘 Hint
At time of writing there is no interactive Hook Debugger. You must use the trace functions.
The following trace
functions are available in the Hooks API
Print a utf-8 message, followed by a user-specified buffer (this last optionally as hex.)
Print a utf-8 message, followed by an integer.
Print a utf-8 message, followed by an XFL Floating point number.
trace_slot
Print a utf-8 message, followed by the serialized contents of a slot.
The following code will print a single trace line then accept the Originating Transaction.
An example of the log-line produced by xahaud
when a payment is sent out of or into the Hook Account:
The above appears in the log as all-one-line, but split here for visibility.
👍 Use testnet
The Xahau Testnet is the perfect place to test your Hooks.
A breakdown of the log format appears in the table below
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 <account>
👍 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.
Again As Weak - Happens when a Strongly Executed Hook calls
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.
🚧 Warning
This is an advanced feature most Hook Developers will probably not use.
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.
Please note: you're reading the technical documentation of Hooks. This documentation is highly technical & assumes prior knowledge of programming and the Xahau Ledger. If you are looking for examples on what Hooks are, will bring to the Xahau Ledger and what they could do, please check this page.
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.
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.)
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.
Introducing Hooks: Enhancing XRP Ledger Protocol with Smart Contract Functionality
Hooks are small, efficient WebAssembly modules designed specifically for the XRPL. They could be referred to as Smart Contracts for the XRP Ledger Protocol.
Hooks can be written in any language (compilable with WebAssembly), and most business logic and smart contract concepts can be implemented in a hook.
Hooks allow the creation of customized logic and automation within the XRPL, 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.
There is a Hooks Builder site 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.
Simply put, Hooks add a robust smart contract functionality to the XRPL, 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.
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.
Showcasing the potential of Hooks with these concrete examples, each illustrating a unique application of smart contract functionality on the XRPL:
Auto-Savings Hook: Automate savings by configuring a Hook to transfer a set amount of XRP to a separate savings account on the ledger. This could be done to help save a portion of XRP 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.
XRPL 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 the XRP Ledger, 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: XRPL Hooks use guards to ensure maximum execution time is well-bounded and known ahead of time, improving efficiency.
Ripple and Peersyst announced that an EVM-compatible sidechain is now live on the company's devnet. 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 Layer 1 of the XRPL, 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 XRPL's functionality.
Hooks add native smart contract capabilities to the XRPL, 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 the XRPL 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.
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 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 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.
Specify which transaction types a Hook should be triggered on
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):
If we want to completely disable the hook:
If we want to disable the hook on everything except ttPAYMENT:
If we want to enable the hook on everything except ttHOOK_SET
If we want to enable hook firing on ttHOOK_SET (dangerous) and every other transaction type:
Running your own node: amazing. Hit the ground running? Use the public Xahau RPC nodes.
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, ...)
Websocket
wss://xahau-test.net
HTTP POST RPC
https://xahau-test.net
Network Definitions (Binary Codec, ...)
Inspect and manipulate on-ledger objects.
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 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.
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:
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.
🚧 Tip
The Hook APIs which accept a 34 byte keylet will also generally accept a 32 byte canonical transaction hash.
In the following example a 34 byte keylet for a signers
object is used to slot that object.
Manipulate raw serialized xahaud objects!
The XRP Ledger has canonical 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 .
For example an sfAmount
field serializes to a collection of bytes like 61D50F26109A32B7EC
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.
Where applicable these APIs return an offset and a length encoded into a single int64_t. See individual documentation for details.
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.
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.
Your Hook can do a lot more than just block or allow transactions!
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.
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 .
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 attacks on the ledger by exponentially increasing the cost of exponentially expanding emtited transactions.
It is important to note that the Hooks API follows the strict rule of no rewriting. You must present an emitted transaction in full, valid and canonically formed to xahaud for emission or it will be rejected. It is not xahaud's job to build your transaction for you. The Hook must do this itself.
As introduced in 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.
All emitted transactions must contain an sfEmitDetails
object correctly populated with the fields in the table below.
👍 Check the examples
High precision calculations are native to Hooks.
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 however xahaud
does not use this format. Instead Xahau uses a .
This custom format has three basic properties:
The format is inherently decimal, expressed as a decimal mantissa
multipled by 10
to the power of an exponent
.
All values expressed have 16 significant (decimal) figures.
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.
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.)
📘 Hint
Use the XFL-tool to compose and decompose XFLs in your browser!
Some example XFLs follow
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.
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
).
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.
❗️ Warning
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.
In the below example an exchange rate conversion is performed, followed by a high precision fraction multiplication.
🚧 Tip
If a float API returns a negative value and you do no check for negatives then feeding that negative value into another float API will also produce a negative value. In this way errors are propagated much as
NaN
(not a number) is propagated in other languages.If you ever end up with a negative enclosing number an error occured somewhere in your floating point calculations.
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:
Hooks use a serialized 34 byte keylet format which can be derrived using the important function. Without this looking up and slotting objects would be generally impossible.
The Hook API will enforce the following rules on a proposed (to be emitted) transaction.
The , in particular Peggy, Carbon and Doubler, demonstrate how to emit both simple and more complicated transactions.
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.
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.
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.
If the Originating Transaction was not an emitted transaction then 1
.
This should be populated using 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
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.
Create a float from an exponent and mantissa
Multiply two XFL numbers together
Multiply an XFL floating point by a non-XFL numerator and denominator
Negate an XFL floating point number
Perform a comparison on two XFL floating point numbers
Add two XFL numbers together
Output an XFL as a serialized object
Read a serialized amount into an XFL
Divide one by an XFL floating point number
Divide an XFL by another XFL floating point number
Return the number 1 represented in an XFL enclosing number
Get the exponent of an XFL enclosing number
Get the mantissa of an XFL enclosing number
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
Convert an XFL floating point into an integer (floor)
Compute the nth root of an XFL
Compute the decimal log of an XFL
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 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 changes the Hook made during execution.
Serialize and output a slotted object
Free up a currently occupied slot
Count the elements of an array object in a slot
slot_id
Compute the canonical hash of the slotted object and return it
Locate an object based on its keylet and place it into a slot
Index into a slotted array and assign a sub-object to another slot
Index into a slotted object and assign a sub-object to another slot
Retrieve the field code of an object in a slot and, optionally, some other information
Parse the STI_AMOUNT in the specified slot and return it as an XFL enclosed number
Compute the serialized size of an object in a slot
-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)
Index into a xrpld serialized object and return the location and length of a subfield
Index into a xrpld serialized array and return the location and length of an index
Emplace a field into an existing STObject at its canonical placement
Remove a field from an STObject
Validate an STObject
As Hooks-enabled networks require specific transaction fields & offer more transaction types, not all clients will work out of the box. `xrpl-accountlib`
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.
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)
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.
The npm 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
integrates nicely with xrpl-accountlib
(and comes as a dependency) to dynamically fetch the aforementioned network definitions and account values, helping submit the transaction.
Our Developer Tooling page covers Hooks Tools and Client Libraries, simplifying interacting with Hooks and the Xahau Ledger.
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 (see Transaction Signing), when building your own integrations with the Xahauy ledger, 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.
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.
Open a websocket connection to the Hooks node you will be working with.
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.
Submit it as a hex blob to the RPC as follows:
For HTTP POST RPC submit it as follows:
The response should look something like
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.
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.
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.
Flag Ledger -1: When xahaud
validators send validation messages, they also submit their amendment votes.
Flag Ledger: Servers interpret the votes from trusted validators.
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.
Flag Ledger +2: Enabled amendments apply to transactions on this ledger onwards.
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 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
.
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 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.
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.
Python
xrpl-py
XAH / XRP
JavaScript / TypeScript
xrpl.js (Patched)
XAH / XRP
JavaScript / TypeScript
XAH / XRP
C++
xahaud
Signing Library
Get Started
XRP
(Part of )
C#
XRPLCSharp
XRP
Swift
XRPLSwift
XRP
Tip: To add a client library not listed here, please suggest changes to this page!
These tools simplify some of the common work of accessing and processing Hooks.
Hooks Builder
Hooks Documentation
Hooks Toolkit
Xpop Toolkit
Hooks Blog
XFL Tools
Binary Visualizer
Keylet Tools
CTID Visualizer
C Hook Tx Builder
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.
The OfferCreate
transaction is used to place an offer in the decentralized exchange.
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.
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.
The AccountSet
transaction type allows users to modify the properties of their accounts. This includes settings such as transfer rate, account flags, and more.
The AccountDelete
transaction type enables users to delete their accounts from the Xahau network. This operation is irreversible and should be used with caution.
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.
The SignersListSet
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.
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.
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.
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.
The Hooks feature includes two types of transactions:
SetHook
This transaction type is used to set up a hook on an account.
Invoke
This transaction type is used to call or invoke the functionality of a hook.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
The Xahau Faucet & Explorers can be found here:
Faucet:
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:
XRPLF:
XRPL.org:
XRPLWin:
Homepage:
Explorers:
Xahauexplorer:
Xahscan:
XRPLF:
XRPL.org:
XRPLWin:
Hardware requirements for nodes (RPC, validator, ...) should be generally along the lines of the specs outlined below.
For specific node use cases (e.g. full history) specs may differ (and grow) over time.
CPU: 6+ cores
Memory: 16GB+ (32GB advised)
Disk IO: 10k random RW
Disk size: 100GB+
Filesystem: EXT4/XFS/...
Network IO: 100Mbit+
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.
The Escrow feature includes three types of transactions:
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.
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.
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.
CPU
16 cores
20+ cores
40+ cores
Memory
32GB
64GB
128GB+
Disk IO
15k random RW
20k random RW
30k random RW
Disk Size
500GB
1TB
2TB
Filesystem
XFS
XFS
XFS
Network IO
500Mbit+
1Gbit
10Gbit
Apple Clang
14.3.1
LLVM
14
LLD
14
Boost
1.86.0
CMake
3.23.1
Protobuf
3.20.0
WasmEdge
0.11.2
Download an older version of Xcode
Go to the https://developer.apple.com/download/more/ page. You will need to sign in with your Apple Developer account.
Search for the version of Xcode that includes Apple Clang 14. This is typically specified in the release notes for each Xcode version.
Download the Xcode `.xip` file for the version you need.
Install the older version of Xcode:
Once the download is complete, extract the `.xip` file, which will give you an Xcode application.
Rename this Xcode application if you want to keep multiple versions of Xcode on your system (e.g., `Xcode_14.3.1.app`).
Drag the Xcode application to your `/Applications` directory.
Switch to the desired version of the toolchain
If you want to use the newly installed version of Xcode and its toolchain by default, you can switch to it using the `xcode-select` command:
Replace `Xcode_14.3.1.app` with the actual name of the Xcode version you installed.
Open Terminal and run the following command to check the version of Clang:
clang --version
If you want to use a specific version of Apple Clang for command line builds you can use the following;
First make a dependency directory. I like to use ~/dependencies
Next we need to set the environment variables.
Install Protobuf
Install Boost
Install WasmEdge
From the root xahaud
directory:
Start the built node
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.
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.
Only two functions are allowed within a Hook: hook()
and cbak()
. Read about this here
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) or other data.
The parameters to a Hook API are always in the following order:
Writing pointer if any
Writing length if any
Reading pointer if any
Reading length if any
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.
All Hook APIs return a signed integer. Read about return codes here: Return codes
A Guide to Setting Up the Development Environment.
This section provides detailed instructions for setting up the build environment on both Ubuntu 22.04 and macOS 13.5.2.
The building Xahau chapter will guide you through the process of establishing environmental variables, installing core and Xahaud dependencies, and compiling the software, including the acquisition and setup of essential components like LLVM, Boost, WasmEdge, and Protobuf.
The steps explain why certain versions and configurations are needed to ensure compatibility and optimal performance. Ending with cloning the Xahau repository and creating the Xahaud target, which sets developers on the path to adding to or deploying the Xahau network.
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:
All Hook API functions return a signed integer.
All negative return codes are an error.
All return codes 0
or greater are a function specific output, usually but not always the number of bytes read or written.
Error codes are global across all Hook APIs and may be found in the table below.
The main function of your hook
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
.
C
C
The callback function of your hook
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.
C
C
Execution Order
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.
❗️WarningThe originating transaction will fail with
tecHOOK_REJECTED
and a fee will be charged. See: Execution Order.
C
C
Xahau Mainnet allows for running your own local node. You can run a Docker Container or connect with your own local running instance.
Accept the originating transaction and commit any changes the hook made.
Execution Order
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.
🚧CautionIf the originating transaction is stopped for some other reason then this accept becomes a rollback. See: Execution Order.
C
C
Xahau Testnet allows for running your own local node. You can run a Docker Container or connect with your own local running instance.
To connect to the Xahau Testnet (Hooks V3 testnet) you can use this Docker container:
Clone the repository
Run ./build
Run ./up
Connect using WebSockets or RPC:
WebSocket: ws://localhost:16006
RPC (HTTP POST): http://localhost:16007
To connect Xumm to the Hooks V3 staging net, scan this QR with the QR scanner in Xumm to add the endpoint (above) to the Xumm node list.
First make a dependency directory. I like to use ~/dependencies
Next we need to set the environment variables.
If you are using Ubuntu 20.04 change the `UBUNTU_VERSION=focal`
To Resolve the `E: The repository 'http://apt.llvm.org/ llvm-toolchain-- Release
error:
Install CMake
Install Protobuf
Install Boost
Install WasmEdge
From the root xahaud
directory:
Start the built node
Check the README for commands, etc.
Check the README for commands, etc.
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
reserved
uint32_t
Reserved for future use.
int64_t
An arbitrary return code you wish to return from your hook. This will be present in the metadata of the originating transaction.
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.
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.
what
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.
int64_t
An arbitrary return code you wish to return from your hook. This will be present in the metadata of the originating transaction.
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.
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.
Info
Explorer
Technical docs
WebSocket URL
Public peering
Network ID: 21337
- Hub (Cluster) 1: bacab.alloy.ee 21337
- Hub (Cluster) 2: hubs.xahau.as16089.net 21337
- Hub 3: xahau-1.cabbit.tech 21337
- Hub 4: xahau-2.cabbit.tech 21337
Binary & config
For ubuntu 22.04: Download:
For the latest release build numbers, see the Github Build Actions.
Extract, then run:
./xahaud --net --conf xahaud.cfg
Config file sample (to be saved as xahaud.cfg
):
https://github.com/Xahau/mainnet-docker/blob/main/store/etc/xahaud.cfg
Edit the database path, etc if needed.
In the same folder as the xahaud.cfg
config, the validators-xahau.txt
file should be stored:
https://github.com/Xahau/mainnet-docker/blob/main/store/etc/validators-xahau.txt
UNL (VL)
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
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.
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.
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.
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.
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.
Info & Faucet
Explorer
Technical docs
WebSocket URL
Public peering V4
Network ID: 21338
79.110.60.122
Port: 21338
79.110.60.124
Port: 21338
79.110.60.125
Port: 21338
79.110.60.121
Port: 21338
Public peering V4
2a0c:3bc0::1c74
Port: 21338
2a0c:3bc0::169d
Port: 21338
2a0c:3bc0::1aaf
Port: 21338
2a0c:3bc0::1d78
Port: 21338
Binary & config
For ubuntu 22.04: Download:
https://build.xahau.tech - fetch the latest RELEASE version
Extract, then run:
./xahaud --net --quorum=2 --conf xahaud.cfg
Config file sample (to be saved as xahaud.cfg
):
https://github.com/Xahau/Xahau-Testnet-Docker/blob/main/store/etc/xahaud.cfg
Edit the database path, etc if needed.
In the same folder as the xahaud.cfg
config, the validators-xahau.txt
file should be stored:
https://github.com/Xahau/Xahau-Testnet-Docker/blob/main/store/etc/validators-xahau.txt
Validators
[validators]
nHBoJCE3wPgkTcrNPMHyTJFQ2t77EyCAqcBRspFCpL6JhwCm94VZ
nHUVv4g47bFMySAZFUKVaXUYEmfiUExSoY4FzwXULNwJRzju4XnQ
nHBvr8avSFTz4TFxZvvi4rEJZZtyqE3J6KAAcVWVtifsE7edPM7q
nHUH3Z8TRU57zetHbEPr1ynyrJhxQCwrJvNjr4j1SMjYADyW1WWe
GCC / G++
14.0.3
LLVM
14.0.3
LLD
14.0.3
Boost
1.86.0
CMake
3.23.1
Protobuf
3.20.0
WasmEdge
0.11.2
Index into a xahaud serialized array and return the location and length of an index
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 encodingThe
sto_
apis accept afield_id
parameter encoded as follows:(type << 16U) + field
Thus type 1 field 2 would be0x10002U
.In the case of this array field ID is
array_id
.
C
C
📘hookmacro.h already contains the
SUB_OFFSET
andSUB_LENGTH
macros.
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.
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.
Emplace a field into an existing STObject at its canonical placement
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 encodingThe
sto_
apis accept afield_id
parameter encoded as follows:(type << 16U) + field
Thus type 1 field 2 would be0x10002U
.
C
C
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.
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.
Compute a serialized keylet of a given type
📘TipNot every Keylet type is supported by this utility function. If you need another Keylet type you can derive it yourself using util_sha512h and by checking the required fields here. A further Keylet tool may assist you.
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
C
C
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
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)
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.
Compute an sha512-half over some data
Compute an SHA512
hash over the data pointed to by read_ptr
Write the first half of the hash to write_ptr
C
C
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
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
Produce an sfEmitDetails suitable for a soon-to-be emitted transaction
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.
C
C
write_ptr
uint32_t
Pointer to the buffer receiving the sfEmitDetails record
write_len
uint32_t
Length of the buffer
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.
🚧 WarningFees on a Hooks-enabled ledger are non trivial. See: Hook Fees for details.
Return the amount of the fee in drops recommended for a to-be emitted transaction.
C
C
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.
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.)
Get the generation of a hypothetically emitted transaction
Return the generation an emitted transaction will carry.
C
C
None
int64_t
The generation an emitted transaction will need in order to be successfully passed to emit()
Remove a field from an STObject
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.
C
🚧Field ID encodingThe
sto_
apis accept afield_id
parameter encoded as follows:(type << 16U) + field
Thus type 1 field 2 would be0x10002U
.
C
📘Emplace equivalence
sto_erase
is the same assto_emplace
with0,0
forfield_ptr, field_len
parameters.
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
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.
Estimate the required fee for a txn to be emitted successfully
Specifies a number of emitted transactions this hook might emit during execution.
C
C
count
uint32_t
The largest number of transactions this hook might emit during the course of one execution.
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.
Validate an STObject
Parse an STObject pointed to by read_ptr
Return 1 if the serialization is valid, 0 otherwise.
C
C
read_ptr
uint32_t
The buffer to read the source STObject from
read_len
uint32_t
The Length of the source object
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.
Create a float from an exponent and mantissa
Compute an XFL (xls17) floating point from the provided exponent and mantissa
Return that XFL as an int64_t
C
C
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.
🚧CautionWhen 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 caseXFL canonical 0 is also 0 in the enclosing number. Thus there is never a need to call
float_set(0,0);
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.
Index into a xahaud serialized object and return the location and length of a subfield
Parse a STObject pointed to by read_ptr
Find the field specified by field_id
If the field is found, and:
It is an array, then return the start and length of the array including the leadin/leadout bytes, or
It is not an array, then return the start and length of the PAYLOAD of the field (excluding the leadin bytes).
🚧Field ID encodingThe
sto_
apis accept afield_id
parameter encoded as follows:(type << 16U) + field
Thus type 1 field 2 would be0x10002U
.
C
C
📘hookmacro.h already contains the
SUB_OFFSET
andSUB_LENGTH
macros.
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
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.
Multiply an XFL floating point by a non-XFL numerator and denominator
Compute the multiplication of an XFL (xls17) floating point number and the quotient of two integers
Return a new XFL as an int64_t
C
C
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
🚧CautionCertain multiplications may overflow, which return with an
INVALID_FLOAT
error. However an underflow returns as XFL Canonical Zero (i.e. enclosing number = 0).
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.
Get the burden of a hypothetically emitted transaction
Return the burden an emitted transaction will carry.
C
C
None
int64_t
The burden an emitted transaction will need in order to be successfully passed to emit()
Multiply two XFL numbers together
Compute the multiplication of two XFL (xls17) floating point numbers
Return a new XFL as an int64_t
C
C
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
🚧CautionCertain multiplications may overflow, which return with an
INVALID_FLOAT
error. However an underflow returns as XFL Canonical Zero (i.e. enclosing number = 0).
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.
Emit a new transaction from the hook
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
C
C
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
int64_t
On success, the number of bytes of transaction hash written (32), or:
If negative, an error:
OUT_OF_BOUNDS
- pointers/lengths specified outside of hook memory.
PREREQUISITE_NOT_MET
- emit_reserve
must be called first
TOO_MANY_EMITTED_TXN
- the number of emitted transactions is now greater than the promise made when emit_reserve
was called earlier
EMISSION_FAILURE
- the transaction was malformed according to the emission rules.
Generate a 32 byte nonce for use in an emitted transaction
Write the 32 byte Hash to the write_ptr
C
C
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.
int64_t
The number of bytes written
If negative, an error:
OUT_OF_BOUNDS
- pointers/lengths specified outside of hook memory.
Divide one by an XFL floating point number
Divide 1
by an XFL
Return a new XFL as an int64_t
C
C
float1
int64_t
An XFL floating point enclosing number
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.
Negate an XFL floating point number
Multiply an XFL by -1
Return a new XFL as an int64_t
C
C
📘Special caseThe negation of Canonical Zero is Canonical Zero. Unlike some floating point standards (such as IEEE) there is no "negative zero" in XFL.
float1
int64_t
An XFL floating point enclosing number
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
Return the number 1 represented in an XFL enclosing number
Return one(1
) as an XFL int64_t
C
C
This function has no parameters.
int64_t
The XFL (xls17) enclosing number
Add two XFL numbers together
Compute the addition of two XFL (xls17) floating point numbers
Return a new XFL as an int64_t
C
C
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
📘HintTo subtract two floats use
float_negate
on the second float then usefloat_sum
.
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.
Output an XFL as a serialized object
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
C
C
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.
📘HintTo output an
XAH
amount prepopulate the field code in the output buffer then pass the output buffer incremented to the new start and0
as field_code
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.
Divide an XFL by another XFL floating point number
Divide an XFL by another XFL
Return a new XFL as an int64_t
C
C
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
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.
Read a serialized amount into an XFL
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
C
C
read_ptr
uint32_t
Pointer to a buffer contianing the serialized XFL. May be null.
read_len
uint32_t
The length of the buffer.
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.
Perform a comparison on two XFL floating point numbers
Evaluate a comparison of two XFL floating point numbers
Return the result of the comparison as a boolean encoded in an int64_t.
C
C
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_LESS
COMPARE_EQUAL
COMPARE_GREATER
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
🚧CautionAlways verify the function returned
1
rather thannon-zero
, as negative error codes will be classed asnon-zero
.
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.
Get the exponent of an XFL enclosing number
🚧 Replaced by macroThis 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.
Return the exponent part of an XFL as a signed integer
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
C
float1
int64_t
An XFL floating point enclosing number
Get the mantissa of an XFL enclosing number
Return the mantissa part of an XFL as an unsigned integer
C
C
📘HintThe mantissa of a negative XFL is positive. Use
float_sign
to get the sign.
float1
int64_t
An XFL floating point enclosing number
int64_t
The mantissa of the XFL
If negative, an error:
INVALID_FLOAT
- the supplied parameter was not a valid XFL enclosing number
Get the sign of an XFL enclosing number
Return 1
if the XFL is negative, otherwise return 0
C
C
📘HintThe sign bit inside the XFL is the
0
when the XFL is negative, however this function follows the standard computing convention to return1
if it is negative.
float1
int64_t
An XFL floating point enclosing number
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
To easily test & replay, use NetworkID
with value 65535
(config: [network_id]
) to disable signature verification.
Added: https://github.com/Xahau/xahaud/pull/201
Server definitions can eas
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).
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.
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.
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.
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.
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.
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.