Only this pageAll pages
Powered by GitBook
Couldn't generate the PDF for 247 pages, generation stopped at 100.
Extend with 50 more pages.
1 of 100

Xahau Network

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...

Features

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...

Infrastructure

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Technical

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...

Introduction

Hooks add smart contract functionality to the Xahau: layer one custom code to influence the behaviour and flow of transactions. Hooks are small, efficient pieces of code being defined on an Xahau account, allowing logic to be executed before and/or after Xahau transactions.

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.

Resources

  • Xahau Testnet

  • Xahau Testnet Explorer

  • Examples (source code)

  • Blogs (concepts)

Concepts

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.

XRPL/Xahau: What is Different?

A list of notable differences between the XRP Ledger and Xahau.

Not Documented

  • accounts on xahau start at a sequence that matches the timestamp of the previous ledger

  • Pseudo tx docs missing: UNLReport, EmitFailure, Etc

  • URIToken Size Limit

  • AccountDelete is still listed as a transaction but is disabled on Xahau

IOU Token Escrow & PayChannels

Xahau introduces IOU Token Escrow and PayChannels as unique features, enhancing transaction flexibility and security. They facilitate the temporary holding of IOU tokens under predefined conditions (escrow) and the establishment of payment channels for efficient, off-ledger transactions.

URITokens NOT NFTokens

Instead of using NFTokens like XRPL, Xahau employs URITokens. URITokens are a form of non-fungible digital assets with unique identifiers and metadata, offering a novel approach to asset representation on the blockchain.

Different Repo

Xahau and XRPL operate from different repositories, signifying that they are separate protocols with their own development trajectories and documentation. This distinction implies that Xahau may offer unique features and optimizations not found in XRPL.

https://github.com/Xahau/xahaud

Different Build Process (WASM & LLVM)

Xahau's build process incorporates WebAssembly (WASM) and the Low-Level Virtual Machine (LLVM), which is not described in the XRPL build process. Xahau is utilizing these technologies for enhanced smart contract capabilities and to improve the performance and cross-platform compatibility of its codebase.

Different Amendment Time (5 days)

The amendment process in Xahau has a specified time frame of 5 days, differing from XRPL's timeline. Amendments are protocol changes, and the 5-day period refers to the duration validators have to reach a consensus and implement these changes.

Different Starting Sequence

Xahau employs a different starting sequence for accounts than XRPL. The initial sequence on the account is the ripple epoch time when the account was create/imported into Xahau.

Import / Burn 2 Mint

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.

Balance Rewards (Rewards for using XAH)

Xahau offers balance rewards for utilizing XAH, a feature absent in XRPL. This is a reward system for holding or using Xahau's native token, XAH, to promote network engagement and stability.

Hooks

Hooks in Xahau, which are not present in XRPL, are programmable scripts or smart contract-like functions that can be attached to accounts. They add a layer of programmability and automation to the network's operations.

Governance Structure

Xahau's governance structure differs from XRPL's. Xahau has its own approach to decision-making, proposal systems, or validator roles, which could influence the network's evolution.

Node Requirements

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.

Native Token

Xahau's native token is XAH, distinct from XRPL's XRP. As the primary currency within the Xahau network, XAH likely serves as the main medium of exchange and a store of value, central to the network's economic framework.

Versioning (Uses Dates)

Xahau employs a date-based versioning system, unlike XRPL's versioning approach. This method may provide a more intuitive means of tracking the network's updates and historical development.

Collect Call

👍 Hook Design Philosophy

Every party affected by a transaction should have the opportunity to have their hooks executed.

When hooks are not Strongly Executed it is unfair to bill the originating transaction for their execution. For example an OfferCreate which crosses 20 offers on the DEX should not be forced to pay for the execution of each of those account's Hooks.

Therefore during typical Weak execution the fee for the execution is collected from the owner of the Hook. To enable this:

  • The Hook owner must have set asfTshCollect on their Xahau account using the AccountSet transaction.

  • The Hook owner must have set hsfCollect on the specific Hook they wish to be called as a Weak TSH.

Fee Responsibility Table

Type of Weak Execution
Fee

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.

Example Usage

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

Examples (scenarios)

1. Receiving Hook executes additional logic

2. Receiving Hook blocks incoming transaction

3. Sending Hook blocks outgoing transaction

4. Hook controls an institutional account

Payments
URIToken
Building Xahau (Dev)
Amendments
Burn 2 Mint (B2M)
Balance Rewards
🪝Hooks
Governance Game
Node Requirements
Currency Formats
Versioning Process
hook_again

Parameters

Install-time parameters allow Hooks to be generic and flexible

Parameters

Hook developers may opt to use install-time parameters (called Hook Parameters) in their Hook. This allows subsequent installers of the Hook to change certain behaviours the programmer defines without recompiling or re-uploading the Hook (assuming at least one account still references 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.

Setting Parameters

The HookParameters array is optionally defined inside each Hook in the Hooks array as shown below:

TransactionType: "SetHook",
Hooks:
[   
    {   
        Hook: {
            ...,
            HookParameters:
            [   
                {   
                    HookParameter:
                    {   
                        HookParameterName:  "ABCDEF12",
                        HookParameterValue: "12345678"
                    }   
                },  
                ...  // optionally up to 15 more Hook Parameters
            ]   
        }   
    }   
],  
... 

Default Parameters

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.

Using Parameters in Hooks

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.

Runtime Parameters

On Xahau and the Xahau testnet, HookParameters may also be included at the top level of any transaction type according to the foregoing rules and size limits. These parameters can be accessed inside a hook using the otxn_param API.

Hooks Functions

Developer Tooling

Our Developer Tooling page covers Hooks Tools and Client Libraries, simplifying interacting with Hooks and the Xahau Ledger.

Network Features

Overview

Float

Utilities

Balance Rewards

The Balance Rewards feature is a unique aspect of the Xahau network that allows users to accumulate and claim rewards based on their account balance. This feature is implemented through a combination of native code (BalanceRewards Amendment) and hook code (Genesis Account's Reward Hook).

Transaction Types

ClaimReward

A ClaimReward transaction allows an account to claim the rewards it has accumulated. The rewards can be claimed by the account owner or by a specified issuer. The account can also opt-out of rewards by setting the Flags field to 1.

GenesisMint

The GenesisMint transaction type is also associated with the Balance Rewards feature. This is an Emitted transaction that is executed through the Reward Hook every time a user claims balance rewards.

Escrow

The Escrow feature is a crucial part of the Xahau network. It provides a secure and trustless method for transactions between parties. The Escrow feature ensures that the assets involved in a transaction are held securely until all the conditions of the transaction are met.

Transaction Types

The Escrow feature includes three types of transactions:

EscrowCreate

The EscrowCreate transaction is used to create a new escrow agreement. This transaction specifies the terms of the escrow, including the parties involved, the assets to be held in escrow, and the conditions under which the assets will be released.

EscrowFinish

The EscrowFinish transaction is used to complete an escrow agreement. This transaction is executed when all the conditions of the escrow are met. Upon execution, the assets held in escrow are released to the appropriate party.

EscrowCancel

The EscrowCancel transaction is used to cancel an escrow agreement. This transaction can be executed if the conditions of the escrow are not met within a specified time frame. Upon cancellation, the assets held in escrow are returned to the party that initiated the escrow.

Execution Metadata

What to expect when your Hook runs.

When Hooks execute they leave behind information about the status of that execution. This appears in the Originating Transaction metadata as an sfHookExecutions block. This block contains the following fields:

Field
Description

Data API's

Nice API's to fetch Xahau ledger information

XRPLF Data API

@nixerFFM ()

Developer Tricks

Wildcard signing

To easily test & replay, use NetworkID with value 65535 (config: [network_id]) to disable signature verification.

Added:

Server Definitions

Server definitions can eas

ClaimReward
GenesisMint - (Emitted Txn)
EscrowCreate
EscrowFinish
EscrowCancel

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.

https://data.xahau.network/v1/ledgers/supply_info
x
https://api.xahaudata.com/api/v1/ledgerdata
https://api.xahaudata.com/api/v1/hook/hooks
https://api.xahaudata.com/api/v1/hook/hookdefinitions
https://api.xahaudata.com/api/v1/hook/hookstates
https://github.com/Xahau/xahaud/pull/201

Hook Fees

What to expect when your Hook runs.

Hook Creation Fees

SetHook transactions are charged per byte of created webassembly. The rate is 500 drops per byte. Thus a 1kib Hook will cost 0.5 XAH to create.

Hook Execution Fees

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.

Fee RPC Helper

Transaction fees on a ledger with the Hooks Amendment enabled become non-trivial to compute for end-users and/or wallet applications. This is because strong hooks must be paid for by the originator of a transaction, and there may be as many as 4 strong hooks on the sending account and 4 on the receiving account, as well as any other strong transactional stakeholders involved (as can be the case with some exotic transaction types). Further, if the transaction is a SetHook then the size of the parameters, the size of the code and whether it is a create operation or an install operation all determine the size of the fee.

Therefore it is highly recommended that all transactions be run through the updated fee RPC call before they are submitted to the ledger.

To invoke the RPC call:

  1. Open a websocket connection to the Hooks node you will be working with.

  2. Compose the serialized transaction you wish to know the fee for with the following:

  • Fee: "0"

  • SigningPubKey: "" (That is: 0 byte VL of type 0x73. In hex:0x7300.)

  • Do not sign the transaction.

  1. Submit it as a hex blob to the RPC as follows:

{"command":"fee", "tx_blob":"<hex blob>"}

For HTTP POST RPC submit it as follows:

{"method":"fee", "params": [{"tx_blob":"<hex blob>"}] }

The response should look something like

{
  result: {
    drops: {
      base_fee: '130520',
    },
  //...
  },
  type: 'response'
}

Take the base fee and set it as the Fee field in the transaction. Now sign and submit it as per the normal transaction submission process.

If there is an invalid value for tx_blob or tx_blob is missing, a regular JSON result will be returned with a base_fee of 10.

Emission Fees

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.

Considerations

Markers

Some methods return more data than can fit efficiently into a single response. When the results exceed the response limit, a marker field is included in the response. This field allows you to retrieve additional pages of data through subsequent requests. To continue fetching data, include the marker value from the previous response in your next request. If a response does not include a marker, it means you have reached the end of the data set.

The format of the marker field is intentionally unspecified. Each server can define the marker as needed, meaning it could be a string, a nested object, or another type. The marker format may vary between servers and even between methods on the same server. Each marker is temporary and may become invalid after approximately 10 minutes.

Rate Limit

The xahaud server enforces rate limits on API clients using public APIs to prevent excessive requests. Rate limiting is applied based on the client’s IP address, meaning multiple clients sharing a network address translation (NAT) will share the same rate limit associated with their public IP.

When a client is nearing the rate limit, the server includes a "warning": "load" field at the top level of an API response. This warning does not appear on every response but may be sent several times before the server disconnects the client. Clients connected as an admin are exempt from rate limiting.

If a client exceeds the rate limit, the server disconnects the client and temporarily blocks further requests from that IP address. The WebSocket and JSON-RPC APIs handle disconnects differently, as described below.

Serialization

Emitted Transaction

sto_to_json

Format an STO object (binary encoded ledger data) as JSON format.

Concepts

  • Serialized Objects

Behaviour

  • Format an STO object (binary encoded ledger data) as JSON format.

    This function takes a serialized transaction blob and converts it into a human-readable JSON format.

  • Returns Decoded JSON representation of the STO object, or an error code if the conversion fails.

Definition

function sto_to_json(
    blob: ByteArray | HexString
  ): ErrorCode | Record<string, any> | Transaction

Example

const jsonSto = sto_to_json(stoBlob)

Parameters

Name
Type
Description

blob

ByteArray | HexString

The blob (e.g. serialized transaction) to be converted.

Return Code

Type
Description

ErrorCode | Record<string, any> | Transaction

Decoded JSON representation of the STO object, or an error code if the conversion fails.

Control

Building Xahau (Dev)

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.

Xahau Documentation

Welcome to the Xahau Documentation. This is your comprehensive guide to understanding and working with Xahau. This documentation is divided into three main categories: Features, Infrastructure, and Technical.

Each category is designed to provide you with detailed insights and instructions about different aspects of Xahau.

Features

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.

Infrastructure

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.

Technical

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!

Amendments

Amendments represent new features or other changes to transaction processing.

The amendment system uses the consensus process to approve any changes that affect transaction processing on Xahau. Fully-functional, transaction process changes are introduced as amendments; validators then vote on these changes. If an amendment receives more than 80% support for five days, the amendment passes and the change applies permanently to all subsequent ledger versions. Disabling a passed amendment requires a new amendment to do so.

Note: Bug fixes that change transaction processes also require amendments.

Amendment Process

The Contributing Code to Xahau topic walks through the workflow to develop an amendment from an idea to activation on Xahau.

After the code for an amendment is built into a software release, the process to enable it happens within the Xahau network, which checks the status of amendments every flag ledger (typically about 15 minutes apart).

Every 256th ledger is called a flag ledger. The flag ledger doesn't have special contents, but the amendment process happens around it.

  1. Flag Ledger -1: When xahaud validators send validation messages, they also submit their amendment votes.

  2. Flag Ledger: Servers interpret the votes from trusted validators.

  3. Flag Ledger +1: Servers insert an EnableAmendment pseudo-transaction and flag based on what they think happened:

    • The tfGotMajority flag means the amendment has more than 80% support.

    • The tfLostMajority flag means support for the amendment has decreased to 80% or less.

    • No flag means the amendment is enabled.

    Note: It's possible for an amendment to lose 80% support on the same ledger it reaches the required five day period to be enabled. In these cases, an EnableAmendment pseudo-transactions is added for both scenarios, but the amendment is ultimately enabled.

  4. Flag Ledger +2: Enabled amendments apply to transactions on this ledger onwards.

Amendment Voting

Each version of xahaud is compiled with a list of known amendments and the code to implement those amendments. Operators of xahaud validators configure their servers to vote on each amendment and can change it at any time. If the operator doesn't choose a vote, the server uses a default vote defined by the source code.

Note: The default vote can change between software releases. [Updated in: rippled 1.8.1][]

Amendments must maintain five days of support from more than 80% of trusted validators to be enabled. If support drops below 80%, the amendment is temporarily rejected, and the two week period restarts. Amendments can gain and lose a majority any number of times before they become permanently enabled.

Amendments that have had their source code removed without being enabled are considered Vetoed by the network.

Amendment Blocked Servers

Amendment blocking is a security feature to protect the accuracy of Xahau's data. When an amendment is enabled, servers running earlier versions of xahaud without the amendment's source code no longer understand the rules of the network. Rather than guess and misinterpret ledger data, these servers become amendment blocked and can't:

  • Determine the validity of a ledger.

  • Submit or process transactions.

  • Participate in the consensus process.

  • Vote on future amendments.

The voting configuration of a xahaud server has no impact on it becoming amendment blocked. A xahaud server always follows the amendments enabled by the rest of the network, so blockages are based solely on having the code to understand rule changes. This means you can also become amendment blocked if you connect your server to a parallel network with different amendments enabled. For example, the Xahau Testnet typically has experimental amendments enabled. If you are using the latest production release, your server likely won't have the code for those experimental amendments.

You can unblock amendment blocked servers by upgrading to the newest version of xahaud.

Retiring Amendments

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 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.

Namespaces

Prevent state clobbering by using the correct namespace

Namespaces

To avoid two or more Hooks installed on the same account unintentionally clobbering each-other's , 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 .

The configured Namespace a Hook operates under alters the its is stored under. Therefore two Hooks under two different Namespaces installed on the same Xahau account may use the same state key to refer to different state objects. Conversely, two different Hooks using the same Namespace on the same Xahau account can access and modify eachother's state objects using the same state keys.

Example

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.)

Default Namespace

The first user to defines a HookNamespace which becomes the Default Namespace for that Hook. This means any subsequent users who will receive this originally set Namespace by default.

The subsequent user may specify their own Namespace, overriding the Default Namespace for their installation only.

Hook APIs Affected

Choice of HookNamespace affects the behaviour of the following Hook APIs:

Namespace API Helper

See and for information about how to query the ledger regarding namespaces.

Transaction Fees

Xahau smart contracts (Hooks) need transaction & destination specific fees. You can easily get the required fee from the `fee` RPC command.

While libraries may deal with fee determination for you (see ), 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.

Fee RPC Helper

Transaction fees on a ledger with the Hooks Amendment enabled become non-trivial to compute for end-users and/or wallet applications. This is because strong hooks must be paid for by the originator of a transaction, and there may be as many as 4 strong hooks on the sending account and 4 on the receiving account, as well as any other strong transactional stakeholders involved (as can be the case with some exotic transaction types). Further, if the transaction is a SetHook then the size of the parameters, the size of the code and whether it is a create operation or an install operation all determine the size of the fee.

Therefore it is highly recommended that all transactions be run through the updated fee RPC call before they are submitted to the ledger.

To invoke the RPC call:

  1. Open a websocket connection to the Hooks node you will be working with.

  2. Compose the serialized transaction you wish to know the fee for with the following:

  • Fee: 0

  • SigningPubKey: "" (That is: 0 byte VL of type 0x73. In hex:0x7300.)

  • Do not sign the transaction.

  1. 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.

Source:

Curated Tooling

These tools simplify some of the common work of accessing and processing Hooks.

Tool
Reference Link

Faucet & Explorers

The Xahau Faucet & Explorers can be found here:

Testnet

  • 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:

Mainnet

  • Homepage:

  • Explorers:

    • Xahauexplorer:

    • Xahscan:

    • XRPLF:

    • XRPL.org:

    • XRPLWin:

Public Nodes (RPC)

Running your own node: amazing. Hit the ground running? Use the public Xahau RPC nodes.

Mainnet (network 21337)

  • Websocket

    • wss://xahau.network

    • wss://xahau.org (alias, some ad-blockers block .network)

  • HTTP POST RPC

    • https://xahau.network

    • https://xahau.org (alias, some ad-blockers block .network)

  • Network Definitions (Binary Codec, ...)

Testnet (network 21338)

  • Websocket

    • wss://xahau-test.net

  • HTTP POST RPC

    • https://xahau-test.net

  • Network Definitions (Binary Codec, ...)

JSHooks-Testnet (network 31338)

  • Websocket

    • wss://jshooks.xahau-test.net

  • HTTP POST RPC

    • https://jshooks.xahau-test.net

  • Network Definitions (Binary Codec, ...)

URIToken

URITokens are the Non-Fungible Token (NFT) implementation native to the Xahau network. They exist as first-class on-ledger objects, uniquely identified by the hash of their issuer and Uniform Resource Identifier (URI). URITokens can point to any digital content, with only one object per URI per account existing on the ledger.

The issuer has the ability to set a flag to enable the burning of the object in the future. Each owner's reserve is locked up as well upon ownership of the URIToken.

Transaction Types

URITokenMint

The URITokenMint transaction mints a new URIToken and assigns ownership to the specified account. The minted URIToken represents a unique digital asset that can be used in various applications. The issuer can choose to allow the minted URIToken to be destroyed in the future.

URITokenBurn

The URITokenBurn transaction is used to burn a URIToken in Xahau. Burning a URIToken permanently removes it from circulation. The transaction does not have any special transaction cost requirements. The account that owns the URIToken to be burned is required for this transaction.

URITokenBuy

The URITokenBuy transaction allows a user to buy a URIToken from the issuer. This transaction is used to transfer ownership of a URIToken from the issuer to the buyer. The buyer's account, the unique identifier of the URIToken to be bought, and the amount of currency to pay for the URIToken are required for this transaction.

Offer

The Offer feature in the Xahau network is a crucial component of the decentralized exchange system. It allows users to create and cancel offers, facilitating a dynamic and responsive trading environment.

Transaction Types

OfferCreate

The OfferCreate transaction is used to place an offer in the decentralized exchange.

OfferCancel

The OfferCancel transaction is used to cancel an existing offer. The documentation for this transaction type is referenced in the Xahau Documentation but not provided in the given context.

Payments

The Payments feature in the Xahau network is a crucial component that enables the transfer of assets and funds within the network. This feature is designed to facilitate seamless transactions, ensuring a smooth and efficient operation of the network.

Transaction Types

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.

prepare

Prepares a JSON transaction for emission.

Concepts

Behaviour

  • This function takes a transaction JSON object and prepares it for emission.

  • The transaction must be complete except for the Account field, which should always be the Hook account.

Definition

Example

Parameters

Name
Type
Description

Return Code

Type
Description

etxn_generation

Get the generation of a hypothetically emitted transaction

Concepts

Behaviour

  • Return the generation an emitted transaction will carry.

Definition

Example

Parameters

None

Return Code

Type
Description

Type
Description

Features
Infrastructure
📐Technical

Hooks Builder

Builder Link

Hooks Documentation

Reference Link

Hooks Toolkit

Toolkit Link

Xpop Toolkit

Toolkit Link

Hooks Blog

Blog Link

XFL Tools

Tool Link

Binary Visualizer

Tool Link

Keylet Tools

Tool Link

CTID Visualizer

Tool Link

C Hook Tx Builder

Tool Link

XRP Ledger Standard 11d
HookNamespace: addr.codec.sha256('carbon').toString('hex')
Hook State
executing a SetHook transaction
Keylets
State
set a novel Hook
reference the same HookDefinition
state
state_set
account_info
account_namespace
{"command":"fee", "tx_blob":"<hex blob>"}
{"method":"fee", "params": [{"tx_blob":"<hex blob>"}] }
{
  result: {
    drops: {
      base_fee: '130520',
    },
  //...
  },
  type: 'response'
}
Transaction Signing
https://xrpl-hooks.readme.io/docs/hook-fees
https://xahau-test.net
https://xahau-test.net/accounts
https://test.xahauexplorer.com
https://explorer.xahau-test.net
https://xahau-testnet.xrpl.org
https://xahau-testnet.xrplwin.com
https://xahau.network
https://xahauexplorer.com
https://xahscan.com/
https://explorer.xahau.network
https://xahau.xrpl.org
https://xahau.xrplwin.com
https://xahau.network/server_definitions.json
https://xahau-test.net/server_definitions.json
https://jshooks.xahau-test.net/server_definitions.json

txJson

Record<string, any> | Transaction

The transaction JSON, must be a complete transaction except for Account (always the Hook account).

ErrorCode | Record<string, any> | Transaction

Returns an ErrorCode if there is an error, or the prepared transaction JSON or Transaction object.

Transactions
function prepare(
    txJson: Record<string, any> | Transaction
  ): ErrorCode | Record<string, any> | Transaction
const prepared_txn = prepare({
                TransactionType: "Payment",
                Destination: util_raddr(p1address_ns),
                Amount: parseFloat(drops_sent)*2
            })

Grants

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

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.

Example

Account: "rALicebv3hMYNBWtu1VEEWkToArgYsYERs",
TransactionType: "SetHook",
Hooks:
[   
    {   
        Hook: {
            ...,
            HookNamespace: "3963ADEB1B0E8934C0963680531202FD511FF1E16D5864402C2DA63861C420A8",
            HookGrants:
            [   
                {   
                    HookGrant:    // first grant
                    {   
                        HookHash:  "78CAF69EEE950A6C55A450AC2A980DE434D624CD1B13148E007E28B7B6461CC8"
                    },
                    HookGrant:    // second grant
                    {   
                        Authorize: "rCLairev2ma2gNZdcHJeTk7fCQ1ki84vr9",
                        HookHash:  "A5B8D62154DA1C329BE13582086B52612476720CEBD097EB85CEE1455E1C70A6"
                    }
                },  
            ]   
        }   
    }   
],  
... 

The first grant above allows:

  • any instance of the Hook whose code that hashes to 78CAF69EEE950A6C55A450AC2A980DE434D624CD1B13148E007E28B7B6461CC8

  • executing on any account

  • to modify the Hook State of account rALicebv3hMYNBWtu1VEEWkToArgYsYERs

  • inside the Namespace 3963ADEB1B0E8934C0963680531202FD511FF1E16D5864402C2DA63861C420A8

The second grant above allows:

  • any instance of the Hook whose code that hashes to A5B8D62154DA1C329BE13582086B52612476720CEBD097EB85CEE1455E1C70A6

  • but only when executed on account rCLairev2ma2gNZdcHJeTk7fCQ1ki84vr9

  • to modify the Hook State of account rALicebv3hMYNBWtu1VEEWkToArgYsYERs

  • inside the Namespace 3963ADEB1B0E8934C0963680531202FD511FF1E16D5864402C2DA63861C420A8

Using the Grant

To make use of a grant, a Hook modifies State objects on a foreign account by calling state_foreign_set.

Request Formatting Guide

Public Servers

  • wss://xahau.network or https://xahau.network (Mainnet)

  • wss://xahau-test.net or https://xahau-test.net (Testnet)

Sample Requests

To send a sample request to the API, use the following commands.

Websocket

{
  "id": 3,
  "command": "account_info",
  "account": "rhBDFMmr3jSjgsWMqBAYaATLy3PuXy395y",
  "strict": true,
  "ledger_index": "validated",
  "api_version": 1
}

WebSocket Request Structure

Once you establish a WebSocket connection to the xahaud server, you can send commands as JSON objects with these fields:

Field
Type
Description

command

String

The name of the API method

id

(Multiple)

(Optional) Unique identifier for the request.

api_version

Number

(Optional) Specifies the API version.

JSON-RPC

POST https://xahau.network/
Content-Type: application/json

{
    "method": "account_info",
    "params": [
        {
            "account": "rhBDFMmr3jSjgsWMqBAYaATLy3PuXy395y",
            "strict": true,
            "ledger_index": "validated",
            "api_version": 1
        }
    ]
}

JSON-RPC Request Structure

Field
Type
Description

method

String

The name of the API method

params

Array

(Optional) A one-item array containing a JSON object with the parameters of the method.

Comandline

xahaud account_info rhBDFMmr3jSjgsWMqBAYaATLy3PuXy395y validated strict

Commandline Request Structure

Field
Description

xahaud

Start calling the service xahaud

method

The name of the API method

params

(Optional)

Response Formatting Guide

Responses are structured differently based on whether the request is made through the WebSocket, JSON-RPC, or Commandline interfaces. The JSON-RPC and Commandline interfaces share the same format, as the Commandline interface internally uses JSON-RPC.

Fields

Field

Type

Description

id

(Varies)

(For WebSocket) The ID from the original request.

status

String

(For WebSocket) Indicates success when the request was received and processed correctly.

result.status

String

(For JSON-RPC and Commandline) Indicates success when the request was successfully processed.

type

String

(For WebSocket) The value response is used for direct replies to API requests. Asynchronous notifications use other values, such as ledgerClosed or transaction.

result

Object

Contains the query result, with content that varies by command.

warning

String

(Optional) If present, the value is load, indicating the client is nearing the rate limit threshold where the server may disconnect.

warnings

Array

(Optional) A list of Warning Objects with important server warnings. For more details, see API Warnings.

forwarded

Boolean

(Optional) true indicates the request was forwarded from a Reporting Mode server to a P2P server to fulfill the request. Default is false.

API Warnings

When a response contains a warnings array, each entry represents a specific warning from the server. Each Warning Object includes the following fields:

Field
Type
Description

id

Number

A unique numeric code identifying this warning message.

message

String

A human-readable explanation of the warning. Avoid writing code that relies on the content of this field; use the id (and details, if available) to interpret the warning instead.

details

Object

(Optional) Additional context about the warning. The content varies by warning type.

Hook API Conventions

Naming conventions

All Hook APIs follow a standard naming convention:

namespace

[ _ noun #1 ]

[ _ verb ]

[ _ noun #2 ]

This may look confusing at first but is actually quite simple:

  • If the first noun is missing then it is implicitly the same as the namespace

  • If the verb is missing then it is implicitly get

Thus:

  • state() means: fetch a hook state.

  • state_set() means: set a hook.

  • state_foreign() means: fetch a foreign hook state.

Memory model

Each Hook executes as a singular stack frame. All working memory must exist within this stackframe. There is no heap and no dynamic memory.

When Hooks communicate with xahaud they can only pass integer values. Typically these integers are pointers within the Hook's memory. Since the Hook runs within xahaud, these points can then be resolved by xahaud and written to or read from as needed to perform the Hook API function.

Allowed functions

Only two functions are allowed within a Hook: hook() and cbak(). Read about this here

Parameters

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:

  1. Writing pointer if any

  2. Writing length if any

  3. Reading pointer if any

  4. Reading length if any

  5. Specifics / other fields if any

Some Hook APIs may only write or may only read from memory, and some might not do either and return a value only by return code.

All parameters passed to a Hook API must be one of: string, number[], bigint(xfl), object(json). Typically these are pointers and lengths of buffers within the Hook's stack frame. Sometimes they are Integer Encoded Floating Point Numbers (XFL) or other data.

The parameters to a Hook API are always in the following order:

  1. Writing variable if any

  2. Reading variable if any

  3. Specifics / other fields if any

Some Hook APIs may only write or may only read from memory, and some might not do either and return a value only by return code.

Return codes

All Hook APIs return a signed integer. Read about return codes here: Return codes

sto_from_json

Format JSON as an STO object (binary encoded ledger data).

Concepts

  • Serialized Objects

Behaviour

  • Takes a JSON object and converts it into a binary encoded ledger data format.

  • Returns STO Object in binary encoded ledger data format, or an error code if the conversion fails.

Definition

function sto_from_json(
    jsonobj: Record<string, any> | Transaction
  ): ErrorCode | ByteArray

Example

const stoBlob = sto_from_json(stoJson)

Parameters

Name
Type
Description

jsonobj

Record<string, any> | Transaction

JSON object to be converted into an STO object.

Return Code

Type
Description

ErrorCode | ByteArray

STO Object in binary encoded ledger data format, or an error code if the conversion fails.

Developer Defined

URITokenMint
URITokenBurn
URITokenBuy
URITokenCreateSellOffer
URITokenCancelSellOffer
OfferCreate
OfferCancel
DepositPreauth
TrustSet
Payment
PaymentChannelCreate
PaymentChannelFund
PaymentChannelClaim

int64_t

The generation an emitted transaction will need in order to be successfully passed to emit()

number

Returns An ErrorCode if there is an error, or a number indicating the generation result on success.

Emitted Transactions
function etxn_generation(): ErrorCode | number
const generation = etxn_generation()

cbak / Callback

The callback function of your hook

Concepts

  • Compiling Hooks

Behaviour

  • cbak is a user defined function called by xahaud in order to inform your hook about the status of a previously emitted transaction

  • State changes and further emit calls can be made from cbak but it cannot rollback a transaction.

  • When cbak is executed the emitted transaction to which the callback relates is now the originating transaction.

Definition

type Callback = (reserved: number) => number

Example

const Callback = (reserved: number) => {
  return 0
}

Parameters

Name
Type
Description

reserved

uint32_t

if 0: - the emittted transaction to which this callback relates was successfully accepted into a ledger. If 1 - the emitted transaction to which the callback relates was NOT successfully accepted into a ledger before it expired.

Name
Type
Description

reserved

number

if 0: - the emittted transaction to which this callback relates was successfully accepted into a ledger. If 1 - the emitted transaction to which the callback relates was NOT successfully accepted into a ledger before it expired.

Return Code

Type
Description

int64_t

An arbitrary return code you wish to return from your hook. This will be present in the metadata of the originating transaction.

Type
Description

number

An arbitrary return code you wish to return from your hook. This will be present in the metadata of the originating transaction.

etxn_reserve

Estimate the required fee for a txn to be emitted successfully

Concepts

  • Emitted Transactions

Behaviour

  • Specifies a number of emitted transactions this hook might emit during execution.

Definition

function etxn_reserve(count: number): ErrorCode | number

Example

etxn_reserve(2)

Parameters

Name
Type
Description

count

uint32_t

The largest number of transactions this hook might emit during the course of one execution.

Name
Type
Description

count

number

The maximum amount of transactions this Hook is allowed to emit.

Return Code

Type
Description

int64_t

The maximum number of emitted transactions this hook may emit. This will always be the same as the count parameter or an error as below. If negative, an error: ALREADY_SET - The hook already called this function earlier. TOO_BIG - The specified number of emitted transactions is too large.

Type
Description

number

An ErrorCode if there is an error, or the configured transaction count on success.

etxn_burden

Get the burden of a hypothetically emitted transaction

Concepts

  • Emitted Transactions

Behaviour

  • Return the burden an emitted transaction will carry.

Definition

function etxn_burden(): ErrorCode | number

Example

const burden = etxn_burden()

Parameters

None

Return Code

Type
Description

int64_t

The burden an emitted transaction will need in order to be successfully passed to emit()

Type
Description

number

An ErrorCode if there is an error, or the current burden value on success.

Check

The Check feature in the Xahau network is a deferred payment system that allows for the creation, cancellation, and cashing of checks within the ledger. This feature is designed to facilitate secure and efficient transactions between parties.

Transaction Types

CheckCreate

The CheckCreate transaction is used to create a Check object in the ledger. This represents a deferred payment that can be cashed by its intended destination.

CheckCancel

The CheckCancel transaction is used to cancel a Check that has been created but not yet cashed. This allows the sender to stop the payment from being processed if necessary.

CheckCash

The CheckCash transaction is used to cash a Check that has been created. This allows the recipient to receive the funds that have been deferred.

Chaining

Chain multiple hooks together to do more useful tasks

👍 Hook Design Philosophy

Each Hook should do one thing, and do it really well.

History

In the early days of Hooks it was only possible to install one Hook per account. This meant users were forced to produce omnibus Hooks if they wanted to do more than one thing: for example offset carbon and firewall at the same time.

This was counter to the Hook Design Philosophy, so Hook Chaining was introduced.

Chaining

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.

Chain Manipulation

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 .

Weak Executions

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:

  1. cbak execution if this was an Emitted Transaction.

  2. 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).

  3. Any Again as Weak (AAW) Hooks. Execution order for AAW is first numerically according to Account ID then numerically according to Hook position.

Emitted Transactions

Your Hook can do a lot more than just block or allow transactions!

Background

All changes made to Xahau must be the result of applying a valid transaction to the ledger. Thus if some change X is made then some transaction Y is responsible.

When designing the Hooks API we needed a way for Hooks to make changes to the ledger beyond simply accepting or rejecting a transaction. However attaching these changes to the Originating Transaction was confusing and resulted in a large increase in the general complexity of the system.

Suppose for example that a Hook needs to send you some funds... the send operation would be effectively enacted onto the ledger by the Originating Transaction which might have been something completely unrelated such as an Account Set transaction. Additionally this send operation would need to be able to potentially trigger another Hook on the receiving end of a payment.

The solution: Emitted Transactions. We allow the Originating Transaction to do exactly what the contents of the Transaction say it will do. If our Hook needs to make an additional change to the ledger such as sending a payment, it creates and then emits a brand new transaction.

What are Emitted Transactions?

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.

Callbacks

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.

Emission Rules

The Hook API will enforce the following rules on a proposed (to be emitted) transaction.

#
Emission Rule
Explanation

EmitDetails block

All emitted transactions must contain an sfEmitDetails object correctly populated with the fields in the table below.

Field
Required Value
Description

👍 Check the examples

The , in particular Peggy, Carbon and Doubler, demonstrate how to emit both simple and more complicated transactions.

Loops and Guarding

Guards are needed to perform loops in a Hook.

What are guards?

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

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.

Guard enforcement

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.)

Nested Loops

When using nested loops the maxiter argument must reflect the total number of times the guard will be hit. This means you must multiply the nestings together.

Consider the example below:

Notice the inner-loop's guard is set to 15. You must multiply the loops together to compute the maximum number of times an inner guard will be hit during Hook execution.

No recursion

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.

Admin API Methods

These methods are intended exclusively for trusted personnel responsible for maintaining xahaud server operations.

Key Generation Methods

Method
Description

Logging and Data Management Methods

Method
Description

Server Control Methods

Method
Description

Signing Methods

Method
Description

Peer Management Methods

Method
Description

Status/Debugging Methods

Method
Description

Node Requirements

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.

Nodes should run (reasonably) well for own use with:

  • CPU: 6+ cores

  • Memory: 16GB+ (32GB advised)

  • Disk IO: 10k random RW

  • Disk size: 100GB+

  • Filesystem: EXT4/XFS/...

  • Network IO: 100Mbit+

Nodes for future (network growth) production use:

Minimum
Preferred
Ideal

rollback

Concepts

  • Execution Order

Behaviour

End the execution of the hook with status: reject.

  • Record a return string and return code in transaction metadata.

  • Discard all state changes.

  • Discard all emit() transactions.

  • Disallow originating transaction to continue.

❗️Warning

The originating transaction will fail with tecHOOK_REJECTED and a fee will be charged. See: Execution Order.

Definition

Example

Parameters

Name
Type
Description

Name
Type
Description

Return Code

Type
Description

Type
Description

accept

Accept the originating transaction and commit any changes the hook made.

Concepts

  • Execution Order

Behaviour

End the execution of the hook with status: success.

  • Record a return string and return code in transaction metadata.

  • Commit all state changes.

  • Submit all emit() transactions.

  • Allow originating transaction to continue.

🚧Caution

If the originating transaction is stopped for some other reason then this accept becomes a rollback. See: Execution Order.

Definition

Example

Parameters

Name
Type
Description
Name
Type
Description

Return Code

Type
Description
Type
Description

etxn_fee_base

🚧 Warning

Fees on a Hooks-enabled ledger are non trivial. See: for details.

Concepts

Behaviour

  • Return the amount of the fee in drops recommended for a to-be emitted transaction.

Definition

Example

Parameters

Name
Type
Description

Name
Type
Description

Return Code

Type
Description

Type
Description

float_set

Create a float from an exponent and mantissa

Concepts

Behaviour

  • Compute an XFL (xls17) floating point from the provided exponent and mantissa

  • Return that XFL as an int64_t

  • Sets the exponent and mantissa for a float representation.

  • Returns an error code or a new XFL as a bigint.

Definition

Example

Parameters

Name
Type
Description

🚧Caution

When setting a mantissa that is greater or fewer than 16 decimal digits the exponent will be adjusted to ensure the mantissa is exactly 16 digits. This adjustment may result in an INVALID_FLOAT in some circumstances.

📘Special case

XFL canonical 0 is also 0 in the enclosing number. Thus there is never a need to call float_set(0,0);

Name
Type
Description

Return Code

Type
Description

Type
Description

sto_erase

Remove a field from an STObject

Concepts

Behaviour

  • 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.

  • It will look for the STO object (binary encoded ledger data) from which the field will be removed.

  • It will look for the ID of the field to be erased.

  • Returns the updated STO object in binary encoded ledger data format, or an error code if the operation fails.

Definition

🚧Field ID encoding

The sto_ apis accept a field_id parameter encoded as follows: (type << 16U) + field Thus type 1 field 2 would be 0x10002U.

Example

📘Emplace equivalence

sto_erase is the same as sto_emplace with 0,0 for field_ptr, field_len parameters.

Parameters

Name
Type
Description

Name
Type
Description

Return Code

Type
Description

Type
Description

Client Libraries

These client libraries simplify some of the common work of accessing and processing XAH Ledger data and present it in a form that matches the native conventions of their respective programming languages.

For other programming languages, you can access the XAH Ledger through the HTTP APIs.

Language
Library Name
Get Started
Protocol
Source Code

Tip: To add a client library not listed here, please suggest changes to this page!

Hooks

Hooks are a powerful feature of the XRPL network, providing robust smart contract functionality. They are small, efficient WebAssembly modules designed specifically for the XRPL, and can be referred to as Smart Contracts for the XRP Ledger Protocol. Hooks can be written in any language that is compilable with WebAssembly, allowing for a wide range of business logic and smart contract concepts to be implemented.

Transaction Types

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.

Serialized Objects

Manipulate raw serialized xahaud objects!

What are Serialized 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

Serialized Object API

To assist Hook developers in working with serialized objects the sto namespace was created within the Hooks API. These functions manipulate pointers within a Hook-provided buffer. See table below.

Hook API
at it does

Where applicable these APIs return an offset and a length encoded into a single int64_t. See individual documentation for details.

Example

At typical scenario in which you would use the STO API is in processing memos on an Originating Transaction. Since you will likely need access to the whole memo anyway, an efficient way to process a set of memos is simply to dump the whole sfMemos field into a buffer then index around within it. While it is also possible to use the slot API to do this by slotting the Originating Transaction it would result in additional code and additional copying.

Overlap with slots

You may notice some overlap between slot APIs and STO APIs. The key difference here is who owns the underlying data:

  • If you are using slots then xrpld owns the object you are interacting with.

  • If you are using the STO API then the Hook owns the buffer you are interacting with.

Both sets of functions index into a Serialized Object without unnecessary copying.

Account Managment

The Account Management features in the Xahau network are a crucial component for users to manage their accounts effectively.

This includes several transaction types that enable users to perform various operations on their accounts.

Transaction Types

AccountSet

The AccountSet transaction type allows users to modify the properties of their accounts. This includes settings such as transfer rate, account flags, and more.

AccountDelete

The AccountDelete transaction type enables users to delete their accounts from the Xahau network. This operation is irreversible and should be used with caution.

SetRegularKey

The SetRegularKey transaction type allows users to set a regular key pair for their account. This key pair can be used as an alternative to the master key pair for signing transactions.

SignersListSet

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.

Import

The Import transaction type is used to import transactions from other networks. This feature is especially useful for issuers who need to import transactions for their asset holders. It's recommended to key your accounts first before attempting to import transactions.

Please note that the process of importing for the issuer involves specific transaction types and requires careful configuration. Always ensure that the hooks are correctly set up and that the transactions are valid for the intended operations.

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.

CheckCreate
CheckCancel
CheckCash

validation_create

Generate a formatted key pair for xhaud nodes. (Validators should use tokens instead of keys from this method.)

wallet_propose

Generate keys for a new account.

can_delete

Enable online deletion of ledgers up to a specified ledger.

download_shard

Download a specific shard of ledger history.

ledger_cleaner

Set up the ledger cleaner to detect and resolve corrupted data.

ledger_request

Query a peer server for a specific ledger version.

log_level

View or change log verbosity levels.

logrotate

Reopen the log file.

node_to_shard

Transfer data from the ledger store to the shard store.

ledger_accept

Close and advance the ledger in stand-alone mode.

stop

Shut down the xahaud server.

sign

Cryptographically sign a transaction.

sign_for

Contribute to a multi-signature.

connect

Force the server to connect to a specific peer.

peer_reservations_add

Add or update a reserved slot for a specific peer.

peer_reservations_del

Remove a reserved slot for a specific peer.

peer_reservations_list

View all reserved peer slots.

peers

Retrieve information about connected peers

consensus_info

View the current state of the consensus process.

feature

Retrieve information about protocol amendments.

fetch_info

Check the server’s synchronization status with the network.

get_counts

View statistics about server internals and memory usage.

manifest

Retrieve public key details for a known validator.

print

Access information about internal subsystems.

validator_info

Get the server's validator configuration details.

validator_list_sites

View sites that publish validator lists.

validators

Retrieve information about the current validators.

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

Python

xahau-py

Get Started

XAH / XRP

Repo

JavaScript / TypeScript

xahau.js

Get Started

XAH / XRP

Repo

JavaScript / TypeScript

xrpl-accountlib

Get started Sample

XAH / XRP

Repo

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.

emit
Fork bomb
Introduction and Terminology
emit
Example Hooks
int32_t _g (uint32_t id, uint32_t maxiter);
#define GUARD(maxiter) _g(__LINE__, (maxiter)+1)
for (int i = 0; GUARD(3), i < 3; ++i)
{
  ...
}
    block  ;; label = @1
      loop  ;; label = @2
        i32.const 3
        i32.const 14
=====>  call $_g          <=====
        drop
        ...
#define GUARD(maxiter) _g(__LINE__, (maxiter)+1)
for (int i = 0; GUARD(3), i < 3; ++i)
{
  for (int j = 0; GUARD(15), j < 5; ++j)
  {
    ...
  }
}
Turing Complete
Hook API return codes

sto_subfield

Index into a xrpld serialized object and return the location and length of a subfield

sto_subarray

Index into a xrpld serialized array and return the location and length of an index

sto_emplace

Emplace a field into an existing STObject at its canonical placement

sto_erase

Remove a field from an STObject

sto_validate

Validate an STObject

#define SUB_OFFSET(x) ((int32_t)(x >> 32))
#define SUB_LENGTH(x) ((int32_t)(x & 0xFFFFFFFFULL))
#define SBUF(str) (uint32_t)(str), sizeof(str)

uint8_t memos[2048];
int64_t memos_len = otxn_field(SBUF(memos), sfMemos);
for (int i = 0; GUARD(3), i < 3; ++i)
{
    int64_t memo_lookup = sto_subarray(memos, memos_len, i);
    if (memo_lookup < 0)
        rollback(SBUF("Memo lookup error"), 1);
    uint8_t*  memo_ptr = SUB_OFFSET(memo_lookup) + memos;
    uint32_t  memo_len = SUB_LENGTH(memo_lookup);
    // the above now point at the memo ... do something here
}
serialized
XRPL-Binary-Visualiser
accept
SetHook Transaction
Parameters
SetHook Transaction
hook_hash
hook_pos
hook_skip
Parameters
hook_param_set
Strongly Executed
hook_again
Collect Call
Example: Execution flow for a transaction passing through two Hook Chains

Compiling Hooks

Constraints

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.

Example

Here is an example Hook written in C. The Hook prints 0...3 to the trace log before accepting the originating transaction.

#include <stdint.h>
#define GUARD(maxiter) _g(__LINE__, (maxiter)+1)
extern int32_t _g (uint32_t id, uint32_t maxiter);
extern int64_t accept (uint32_t read_ptr, uint32_t read_len, int64_t error_code);
extern int64_t trace_num (uint32_t read_ptr, uint32_t read_len, int64_t number);

int64_t hook(uint32_t ctx)
{
    for (int i = 0; GUARD(3), i < 3; ++i)
    {
        trace_num("test", 4, i);
    }
    accept (0,0,0); 
    return 0;
}

📘 Hint

For educational purposes the above example deliberately does not include hookapi.h (which developers would typically use.)

Compilation

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.

(module
  (type (;0;) (func (param i32 i32) (result i32)))
  (type (;1;) (func (param i32 i32 i64) (result i64)))
  (type (;2;) (func))
  (type (;3;) (func (param i32) (result i64)))
  (import "env" "_g" (func $_g (type 0)))
  (import "env" "trace_num" (func $trace_num (type 1)))
  (import "env" "accept" (func $accept (type 1)))
  (func $__wasm_call_ctors (type 2))
  (func $cbak (type 3) (param i32) (result i64)
    (local i32 i32 i32 i64)
    global.get 0
    local.set 1
    i32.const 16
    local.set 2
    local.get 1
    local.get 2
    i32.sub
    local.set 3
    i64.const 0
    local.set 4
    local.get 3
    local.get 0
    i64.store offset=8
    local.get 4
    return)
  (func $hook (type 3) (param i32) (result i64)
    (local i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i64 i32 i32 i32 i64 i32 i32 i32)
    global.get 0
    local.set 1
    i32.const 16
    local.set 2
    local.get 1
    local.get 2
    i32.sub
    local.set 3
    local.get 3
    global.set 0
    i32.const 0
    local.set 4
    local.get 3
    local.get 0
    i64.store offset=8
    local.get 3
    local.get 4
    i32.store offset=4
    block  ;; label = @1
      loop  ;; label = @2
        i32.const 3
        local.set 5
        i32.const 14
        local.set 6
        i32.const 4
        local.set 7
        local.get 6
        local.get 7
        call $_g
        drop
        local.get 3
        i32.load offset=4
        local.set 8
        local.get 8
        local.set 9
        local.get 5
        local.set 10
        local.get 9
        local.get 10
        i32.lt_s
        local.set 11
        i32.const 1
        local.set 12
        local.get 11
        local.get 12
        i32.and
        local.set 13
        local.get 13
        i32.eqz
        br_if 1 (;@1;)
        i32.const 1024
        local.set 14
        i32.const 4
        local.set 15
        local.get 3
        i32.load offset=4
        local.set 16
        local.get 16
        local.set 17
        local.get 17
        i64.extend_i32_s
        local.set 18
        local.get 14
        local.get 15
        local.get 18
        call $trace_num
        drop
        local.get 3
        i32.load offset=4
        local.set 19
        i32.const 1
        local.set 20
        local.get 19
        local.get 20
        i32.add
        local.set 21
        local.get 3
        local.get 21
        i32.store offset=4
        br 0 (;@2;)
      end
    end
    i64.const 0
    local.set 22
    i32.const 0
    local.set 23
    local.get 23
    local.get 23
    local.get 22
    call $accept
    drop
    i32.const 16
    local.set 24
    local.get 3
    local.get 24
    i32.add
    local.set 25
    local.get 25
    global.set 0
    local.get 22
    return)
  (table (;0;) 1 1 funcref)
  (memory (;0;) 2)
  (global (;0;) (mut i32) (i32.const 66576))
  (global (;1;) i32 (i32.const 1029))
  (global (;2;) i32 (i32.const 1024))
  (global (;3;) i32 (i32.const 66576))
  (global (;4;) i32 (i32.const 1024))
  (export "memory" (memory 0))
  (export "__wasm_call_ctors" (func $__wasm_call_ctors))
  (export "__data_end" (global 1))
  (export "__global_base" (global 2))
  (export "__heap_base" (global 3))
  (export "__dso_handle" (global 4))
  (export "cbak" (func $cbak))
  (export "hook" (func $hook))
  (data (;0;) (i32.const 1024) "test\00"))

The average Hook developer will never need to examine webassembly directly. However it is a useful conceptual exercise to review the contents of the sample Hook.

Above we can see:

  • Three functions are imported from the Hooks API (_g, accept, trace_num)

  • Two functions are defined by the hook (cbak, hook)

  • Two functions are exported by the hook (again: cbak, hook)

  • Some static (constant) data is recorded in the hook (see data at the bottom).

It is very important to note that a Hook must only import functions available to it from the Hooks API and must only export the cbak and hook functions. In additional all hooks must import _g from the Hooks API, which is the guard function.

📘 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.

Unwanted Exports

Most webassembly compilers (including the one above) produce additional exports for their own linking purposes. In many cases the generation of these is difficult or impossible to disable.

Unwanted exports will lead to an otherwise valid Hook being rejected. Therefore after compilation developers should use the Hook Cleaner Utility 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.

Transaction Signing

As Hooks-enabled networks require specific transaction fields & offer more transaction types, not all clients will work out of the box. `xrpl-accountlib`

Main differences

  1. Hooks-enabled networks allow getting network definitions dynamically. Allowing clients to adapt available transaction types, ledger objects, properties, and value types. When implemented correctly, signing and encoding libraries don't have to be updated when the network adds transaction/object types/properties. The libraries below implement this and will handle this for you.

  2. Hooks-enabled networks require a NetworkID with every transaction to prevent transaction replay on another chain. The NetworkID will also be returned by a server_info RPC command in the network_id field (e.g. 21338 for Hooks V3 testnet)

  3. Transactions on a Hooks-enabled network may need higher fees to deliver a transaction to another account, based on the Hooks that will be executed sending out of the sending account and receiving on the destination account. A reasonable fee to satisfy the Hooks execution can be dynamically fetched from a node by issuing the fee command while providing a transaction as tx_blob. The libraries below implement this and will handle this for you.

Javascript/Typescript

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.

Code Sample

import {
  derive,
  utils,
  signAndSubmit,
} from "xrpl-accountlib"

const wss = 'wss://xahau-test.net'
const account = derive.familySeed("s...")

const networkInfo = await utils.txNetworkAndAccountValues(wss, account)

const tx = {
  TransactionType: "SetHook",
  Hooks: [ { Hook: {
    CreateCode: "0061736D01000000011C0460057F7F7F7F7F017E60037F7F7E017E60027F7F017F60017F017E02230303656E76057472616365000003656E7606616363657074000103656E76025F670002030201030503010002062B077F0141B088040B7F004180080B7F0041A6080B7F004180080B7F0041B088040B7F0041000B7F0041010B07080104686F6F6B00030AC4800001C0800001017F230041106B220124002001200036020C41920841134180084112410010001A410022002000420010011A41012200200010021A200141106A240042000B0B2C01004180080B254163636570742E633A2043616C6C65642E00224163636570742E633A2043616C6C65642E22",
    Flags: 1,
    HookApiVersion: 0,
    HookNamespace: "F".repeat(64),
    HookOn: "F".repeat(58) + "BFFFFE",
  }
  }],
  ...networkInfo.txValues,
  // ^^ This adds autmatically fetched values for you:
  // Sequence, Account, LastLedgerSequence,
  // Fee (Hooks enabled: autodetect (from ledger))
}

/**
 * Note: the code above and `signAndSubmit` results in automatically
 * fetching and setting a fee for you. If you want to check the fee
 * for min/max/..., get your own fee (string in drops) using:
 *    utils.networkTxFee(wss, tx)
 * 
 * e.g.
 *    const Fee = await utils.networkTxFee(wss, tx)
 *    assert(Number(Fee) < 50_000, "Auto fee above 50k drops, abort")
 *    Object.assign(tx, { Fee, })
 */

const submitted = await signAndSubmit(tx, wss, account)

console.log(submitted)

util_accid

Convert an r-address into a 20 byte Account ID

Behaviour

  • Read an r-address from the read_ptr

  • Write a 20 byte Account ID to the write_ptr

  • Read an r-address from the raddress

  • Returns a 20 byte Account ID or an ErrorCode

Definition

int64_t util_accid (
    uint32_t write_ptr,
    uint32_t write_len,
    uint32_t read_ptr,
    uint32_t read_len
);
function util_accid(raddress: string): ErrorCode | ByteArray

Example

uint8_t accid_out[20];
uint8_t raddr_in[] = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";

int64_t bytes_written = 
    util_accid(accid_out, 20, raddr_in, sizeof(raddr_in)-1);
// NB: if specified as a c-string as above, account for the nul char

const accId = util_accid('rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh')

Parameters

Name
Type
Description

write_ptr

uint32_t

Pointer to a buffer of a suitable size to store the output Account ID. Must be at least 20 bytes.

write_len

uint32_t

Length of the output buffer.

read_ptr

uint32_t

Pointer to the r-address.

read_len

uint32_t

The length of the r-address.

Name
Type
Description

raddress

string

The r-address to format as HEX account ID.

Return Code

Type
Description

int64_t

The number of bytes written (the length of the output r-address). If negative, an error: OUT_OF_BOUNDS - pointers/lengths specified outside of hook memory. INVALID_ARGUMENT - read_ptr pointed at something which wasn't a valid r-address. TOO_SMALL - write_len was not large enough to store produced Account ID. (Should be 20 bytes). TOO_BIG - read_len was longer than an r-address can be.

Type
Description

string / number

If there is an error in formatting, otherwise returns the HEX Account ID as an array of numbers.

util_sha512h

Compute an sha512-half over some data

Behaviour

  • Compute an SHA512 hash over the data pointed to by read_ptr

  • Write the first half of the hash to write_ptr

  • Compute an SHA512 hash over the data pointed to by data

  • Return the first half of the hash

Definition

int64_t util_sha512h (
    uint32_t write_ptr,
    uint32_t write_len,
    uint32_t read_ptr,
    uint32_t read_len
);
function util_sha512h(data: ByteArray | HexString): ErrorCode | ByteArray

Example

C

uint8_t hash_out[32];
if (util_sha512h(hash_out, 32, data_in_ptr, data_in_len) < 0)
	rollback("Could not generate Hash", 23, 1);

if (util_sha512h(data) < 0)
    rollback("Could not generate Hash", 1)

Parameters

Name
Type
Description

write_ptr

uint32_t

Pointer to a buffer the hash will be written to

write_len

uint32_t

Length of output buffer, should be at least 32.

read_ptr

uint32_t

Pointer to the buffer data will be read from (to compute the hash over)

read_len

uint32_t

Length of input data

Name
Type
Description

data

ByteArray or HexString

The data to compute the hash over, can be provided as an array of numbers or a string.

Return Code

Type
Description

int64_t

The number of bytes written, should always be 32. If negative, an error: OUT_OF_BOUNDS - pointers/lengths specified outside of hook memory. TOO_SMALL - Output buffer isn't large enough

Type
Description

ByteArray

ErrorCode if there is an error in computing the hash, otherwise returns the SHA512-half hash as an array of numbers.

float_multiply

Multiply two XFL numbers together

Concepts

  • Floating Point Numbers (XFL)

Behaviour

  • Compute the multiplication of two XFL (xls17) floating point numbers

  • Return a new XFL as an int64_t

  • Compute the multiplication of two XFL (xls17) floating point numbers

  • Return n error code or new XFL as a bigint.

Definition

int64_t float_multiply (
    int64_t float1,
    int64_t float2
);

function float_multiply(f1: bigint, f2: bigint): ErrorCode | bigint

Example

int64_t max_vault_pusd =
    float_multiply(vault_xrp, exchange_rate);

const max_vault_pusd =
    float_multiply(vault_xrp, exchange_rate)

Parameters

Name
Type
Description

float1

int64_t

An XFL floating point enclosing number representing the first operand to the multiplication

float2

int64_t

An XFL floating point enclosing number representing the second operand to the multiplication

🚧Caution

Certain multiplications may overflow, which return with an INVALID_FLOAT error. However an underflow returns as XFL Canonical Zero (i.e. enclosing number = 0).

Name
Type
Description

f1

bigint

An XFL floating point enclosing number representing the first operand to the multiplication

f2

bigint

An XFL floating point enclosing number representing the second operand to the multiplication

Return Code

Type
Description

int64_t

The XFL (xls17) enclosing number If negative, an error: INVALID_FLOAT - one of the supplied parameters was not a valid XFL enclosing number OVERFLOW - the result of the multiplication was too large to store in an XFL.

Type
Description

Errorcor or bigint

An error code or The XFL (xls17) enclosing number

float_compare

Perform a comparison on two XFL floating point numbers

Concepts

  • Floating Point Numbers (XFL)

Behaviour

  • Evaluate a comparison of two XFL floating point numbers

  • Return the result of the comparison as a boolean encoded in an int64_t.

  • Evaluate a comparison of two XFL floating point numbers

  • Returns an error code or the comparison result as a number.

Definition

int64_t float_compare (
    int64_t float1,
    int64_t float2,
    uint32_t mode
);
function float_compare(
    f1: bigint,
    f2: bigint,
    mode: number
  ): ErrorCode | number

Example

if (float_compare(pusd_to_send, 0, COMPARE_LESS) == 1)
{
  // pusd_to_send is less than 0
}

if (float_compare(pusd_to_send, 0n, COMPARE_LESS) == 1)
{
  // pusd_to_send is less than 0
}

Parameters

Name
Type
Description

float1

int64_t

An XFL floating point enclosing number representing the first operand to the comparison

float2

int64_t

An XFL floating point enclosing number representing the second operand to the comparison

mode

uint32_t

A bit-flag field consisting of any of (or any logically valid combination of) the following flags: COMPARE_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

🚧Caution

Always verify the function returned 1 rather than non-zero, as negative error codes will be classed as non-zero.

Name
Type
Description

f1

bigint

The first float to compare.

f2

bigint

The second float to compare.

mode

number

The comparison mode (e.g., less than, equal to, greater than).

Return Code

Type
Description

int64_t

0 if the comparison was logically false. 1 if the comparison was logically true. If negative, an error: INVALID_FLOAT - one of the supplied parameters was not a valid XFL enclosing number INVALID_ARGUMENT - invalid combination of supplied comparison flags.

Type
Description

ErrorCode or number

Returns an error code or the comparison result as a number.

float_mulratio

Multiply an XFL floating point by a non-XFL numerator and denominator

Concepts

  • Floating Point Numbers (XFL)

Behaviour

  • Compute the multiplication of an XFL (xls17) floating point number and the quotient of two integers

  • Return a new XFL as an int64_t

  • Multiplies a float by a ratio defined by a numerator and denominator.

  • Returns an error code or new XFL as a bigint.

Definition

int64_t float_mulratio (
    int64_t float1,
    uint32_t round_up,
    uint32_t numerator,
    uint32_t denominator
);
function float_mulratio(
    f1: bigint,
    round_up: number,
    numerator: number,
    denominator: number
  ): ErrorCode | bigint

Example

int64_t max_vault_pusd =
    float_mulratio(max_vault_pusd, 0,
        COLLATERALIZATION_NUMERATOR, COLLATERALIZATION_DENOMINATOR);
const max_vault_pusd =
    float_mulratio(max_vault_pusd, 0,
        COLLATERALIZATION_NUMERATOR, COLLATERALIZATION_DENOMINATOR);

Parameters

Name
Type
Description

float1

int64_t

An XFL floating point enclosing number representing the first operand to the multiplication

round_up

uint32_t

If non-zero all computations will be rounded up

numerator

uint32_t

The numerator of the quotient that the float will be multiplied by

denominator

uint32_t

The denominator of the quotient that the float will be multiplied by

🚧Caution

Certain multiplications may overflow, which return with an INVALID_FLOAT error. However an underflow returns as XFL Canonical Zero (i.e. enclosing number = 0).

Name
Type
Description

f1

bigint

An XFL floating point enclosing number representing the first operand to the multiplication

round_up

number

If non-zero all computations will be rounded up

numerator

number

The numerator of the quotient that the float will be multiplied by

denominator

number

The denominator of the quotient that the float will be multiplied by

Return Code

Type
Description

int64_t

The XFL (xls17) enclosing number If negative, an error: INVALID_FLOAT - one of the supplied parameters was not a valid XFL enclosing number OVERFLOW - the result of the multiplication was too large to store in an XFL. DIVISION_BY_ZERO - the supplied denominator was zero.

Type
Description

ErrorCode or bigint

Returns an error code or tThe XFL (xls17) enclosing number.

etxn_details

Produce an sfEmitDetails suitable for a soon-to-be emitted transaction

Concepts

  • Emitted Transactions

Behaviour

  • 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.

  • This function provides detailed information about the transaction.

  • Returns an ErrorCode if there is an error, or an array of transaction details on success.

Definition

int64_t etxn_details (
    uint32_t write_ptr,
    uint32_t write_len
);

function etxn_details(): ErrorCode | ByteArray

Example

uint8_t emitdet[105];
int64_t result =
    etxn_details(emitdet, 105);
if (result != 105)
    rollback("Etxndetails failed.", 19, 1);

const emitdet = etxn_details()
if (typeof emitdet === 'string || emitdet.length != 105)
    rollback("Etxndetails failed.", 1)

Parameters

Name
Type
Description

write_ptr

uint32_t

Pointer to the buffer receiving the sfEmitDetails record

write_len

uint32_t

Length of the buffer

No parameters for Javascript

Return Code

Type
Description

int64_t

The number of bytes written. If negative, an error: OUT_OF_BOUNDS - pointers/lengths specified outside of hook memory. TOO_SMALL - Buffer isn't large enough to receive record PREREQUISITE_NOT_MET - The hook failed to call etxn_reserve(n) first FEE_TOO_LARGE - The burden would be too high for the network to allow. INTERNAL_ERROR - A generic error in which rippled had trouble generating the required field.

Type
Description

ErrorCode | ByteArray

An ErrorCode if there is an error, or an array of transaction details on success.

SetHook
Invoke
AccountSet
AccountDelete
SetRegularKey
SignerListSet
Import
int64_t etxn_generation (
    void
);
int64_t generation = 
  etxn_generation();
int64_t cbak (
    uint32_t what
)
int64_t cbak(uint32_t reserved)
{
    return 0;
}
int64_t etxn_fee_base (
    uint32_t count
);
etxn_reserve(2);
int64_t etxn_burden (
    void
);
int64_t burden = etxn_burden();
rollback("Rejected!", 9, 100);
rollback('Rejected!', 100)

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.

error_msg

string

String to be stored in execution metadata. This is any string the hook-developer wishes to return with the acceptance. May be null.

error_code

number

A return code specific to this hook to be stored in execution metadata. Similar to the return code of an application on a *nix system. By convention non-success is non-zero.

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.

number

Rollback ends the hook, therefore no value is returned to the caller. By convention all Hook APIs return number, but in this case nothing is returned.

Introduction
function rollback(error_msg: string, error_code: number): number
int64_t rollback (
    uint32_t read_ptr,
    uint32_t read_len,
    uint64_t error_code
);
accept("Success", 7, 100);
accept('Success', 100)

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.

msg

string

String to be stored in execution metadata. This is any string the hook-developer wishes to return with the acceptance. May be null.

code

number

A return code specific to this hook to be stored in execution metadata. Similar to the return code of an application on a *nix system. By convention success is zero.

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.

number

Accept ends the hook, therefore no value is returned to the caller. By convention all Hook APIs return a number, but in this case nothing is returned.

Introduction
function accept(msg: string, code: number): number
int64_t accept (
    uint32_t read_ptr,
    uint32_t read_len,
    uint64_t error_code
);

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.

txblob

ByteArray | HexString

The transaction blob, which can be an array of numbers or a string.

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.)

number

An ErrorCode if there is an error, or the calculated base fee on success.

Hook Fees
Emitted Transactions
function etxn_fee_base(txblob: ByteArray | HexString): ErrorCode | number
const fee_to_pay = etxn_fee_base(tx_blob)
int64_t etxn_fee_base (
    uint32_t read_ptr,
    uint32_t read_len
);
int64_t fee_to_pay =
    etxn_fee_base(tx_blob, tx_blob_len);
int64_t small_amount =
  float_set(-81, 1);
const small_amount = float_set(-81, 1);

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.

exponent

bigint

An exponent in the range -96 to 80

mantissa

bigint

A mantissa. If negative then the sign of the float is negative.

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.

ErrorCode | bigint

An error code or the XFL (xls17) enclosing number.

Floating Point Numbers (XFL)
function float_set(exponent: number, mantissa: number): ErrorCode | bigint
int64_t float_set (
    int32_t exponent,
    int64_t mantissa
);
int64_t result = 
  sto_erase(tx_out, sizeof(tx_out),
            tx_in, tx_len, sfSigners);

if (tx_len <= 0)
    rollback("Erasing failed.", 15, 1);
const tx_out = sto_erase(tx_in, sfSigners)

if (typeof tx_out === 'number')
    rollback("Erasing failed.", 1)

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

sto

ByteArray | HexString

The STO object (binary encoded ledger data) from which the field will be removed.

field_id

number

The ID of the field to be erased.

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.

ErrorCode | ByteArray

The updated STO object in binary encoded ledger data format, or an error code if the operation fails.

Serialized Objects
function sto_erase(
    sto: ByteArray | HexString,
    field_id: number
  ): ErrorCode | ByteArray
int64_t sto_erase (
    uint32_t write_ptr,
    uint32_t write_len,
    uint32_t read_ptr,
    uint32_t read_len,
    uint32_t field_id
);

Debugging Hooks

How to print "hello world" from your Hook!

How can I debug a Hook?

The Hook API provides a set of functions in the namespace trace which write output to the xrpld log file when xrpld is configured with the trace log-level. These functions, generally speaking, allow you to see the value of variables, buffers and otherwise trace the execution and state of a Hook at runtime.

📘 Hint

At time of writing there is no interactive Hook Debugger. You must use the trace functions.

Trace APIs

The following trace functions are available in the Hooks API

Hook API
What it does

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.

Example

The following code will print a single trace line then accept the Originating Transaction.

#include "../hookapi.h"
int64_t hook(int64_t reserved)
{
  trace_num(SBUF("A number"), 10);
  accept(0,0,0);
  return 0;
}

An example of the log-line produced by xahaud when a payment is sent out of or into the Hook Account:

2021-Apr-13 13:59:11.083700726 UTC View:TRC
    HookTrace[rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh-rE3SfnjwfzZFL3JK9cLVfJuy8Ar1XnCqPw]:
        A number 10

The above appears in the log as all-one-line, but split here for visibility.

👍 Use testnet

The Xahau Testnet is the perfect place to test your Hooks.

Log format

A breakdown of the log format appears in the table below

Part
Description
#

2021-Apr-13 13:59:11.083700726 UTC View:TRC

xahaud's prefix to the log line

1

HookTrace

This is a trace initiated by the Hook itself not some other information about the Hook. Other information is available on tags HookError, HookEmit and HookInfo.

2

[rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh

The first account in the square brackets is the Hook Account.

3

-rE3SfnjwfzZFL3JK9cLVfJuy8Ar1XnCqPw]:

The second account in the square brackets is the Originating Account.

4

A number

This is the message the Hook was told to deliver before the trace payload

5

10

This is the trace payload

6

🚧 Tip

Xahaud produces a lot of output. It is therefore generally advisible to grep logs for the account/s you are interested in. For example use: tail -f log | grep HookTrace | grep <account>

Slots and Keylets

Inspect and manipulate on-ledger objects.

Background

Xahau contains numerous heterogenous object types which a Hook has read-access to. For example: transactions, accounts, ledgers, and the subcomponents of each of these, to name just a few.

It is very easy to carelessly program a computer to do a lot of needless copy operations when disciplined access to the same underlying data (i.e. through a view) would suffice. The deliberate avoidance of copy operations in programming is referred to as Zero copy in programming.

With Hooks the same principle applies. We want to avoid copying where possible. In particular we want to avoid as much as possible needlessly copying large objects such as whole ledgers, we also want to avoid serializaing and unserializing these where possible.

What are slots?

Slots are part of the Hook API and provide a zero-copy heterogenous access system for on-ledger objects and transactions.

  • Each Hook has access to 255 slots during runtime.

  • Each slot may be empty or may contain a slotted object.

  • The slot API allows traversal into inner objects, and allows these inner objects themselves to be slotted.

  • The slot API allows slotted objects to be dumped to a buffer or otherwise read by the Hook.

The avilable slot APIs are:

Hook API
What it does

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

What are keylets?

Keylets are used to locate (point to) on-ledger objects. In brief they are a hash of identifying information from the object, which is the canonical handle for that object.

Hooks use a serialized 34 byte keylet format which can be derrived using the important util_keylet function. Without this looking up and slotting objects would be generally impossible.

🚧 Tip

The Hook APIs which accept a 34 byte keylet will also generally accept a 32 byte canonical transaction hash.

Example

In the following example a 34 byte keylet for a signers object is used to slot that object.

uint8_t keylet[34];
if (util_keylet(SBUF(keylet), KEYLET_SIGNERS, SBUF(hook_accid), 0, 0, 0, 0) != 34)
    rollback(SBUF("Notary: Internal error, could not generate keylet"), 10);

// then requesting XRPLD slot that keylet into a new slot for us
int64_t slot_no = slot_set(SBUF(keylet), 0);
if (slot_no < 0)
   rollback(SBUF("Notary: Could not set keylet in slot"), 10);

Running a Testnet Node

Xahau Testnet allows for running your own local node. You can run a Docker Container or connect with your own local running instance.

Connecting to the Xahau Testnet with Docker

To connect to the Xahau Testnet (Hooks V3 testnet) you can use this Docker container:

  1. Clone the repository

  2. Run ./build

  3. Run ./up

  4. Check the README for commands, etc.

  5. Connect using WebSockets or RPC: WebSocket: ws://localhost:16006 RPC (HTTP POST): http://localhost:16007

Local instance

Peering info

Integrating Xumm with Hooks V3

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.

sto_emplace

Emplace a field into an existing STObject at its canonical placement

Concepts

Behaviour

  • Parse an STObject S (source object) pointed to by sread_ptr

  • Parse an STObject F (to inject/emplace) pointed to by fread_ptr

  • Write a new STObject to write_ptr which places F into S at the canonical position field_id

🚧Field ID encoding

The sto_ apis accept a field_id parameter encoded as follows: (type << 16U) + field Thus type 1 field 2 would be 0x10002U.

  • Ask for the STO object by the param sto

  • Ask for the bytes representing the field to be added by the param field_bytes

  • Ask for the ID of the field to be added by the param field_id

  • Return the updated STO object in binary encoded ledger data format, or an error code if the operation fails.

Definition

C

Example

Parameters

Name
Type
Description

Name
Type
Description

Return Code

Type
Description

Type
Description

emit

Emit a new transaction from the hook

Concepts

Behaviour

  • Read a transaction from read_ptr

  • Validate the transaction against the emission rules

  • Emit the transaction into consensus when valid

  • Write canonical transaction hash to write_ptr

  • This function emits the provided transaction JSON.

  • On success, it returns the number of emitted transaction hashes.

  • If there is an error, it returns an error code.

Definition

Example

Parameters

Name
Type
Description

Name
Type
Description

Return Code

Type
Description

Type
Description

State Management

Hooks can read and save small pieces of on-ledger data 🚀

What is Hook 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

Storing and fetching

The below example uses the 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 a TOO_SMALL error.

Foreign state

From time to time it may be advantageous for one Hook running on one account to read the Hook State of another Hook running on another account. The Hook API does exactly this. Because the ledger is public there is no reasonable expectation of privacy anyway. Any Hook may therefore read (but not write) the Hook State of any other Hook.

Namespaces and querying

Please see

hook

The main function of your hook

Concepts

Behaviour

  • hook is a user defined function called by xahaud in order to fire your hook.

  • Your hook function calls either accept or reject to pass or reject the originating transaction.

  • If execution reaches the end of the function it is implicitly an accept.

Definition

Example

Parameters

Name
Type
Description

Name
Type
Description

Return Code

Type
Description

Type
Description

etxn_nonce

Generate a 32 byte nonce for use in an emitted transaction

Concepts

Behaviour

  • Write the 32 byte Hash to the write_ptr

  • Returns an ErrorCode if there is an error, or an array containing the nonce value on success.

Definition

Example

Parameters

Name
Type
Description

No parameters

Return Code

Type
Description
Type
Description

HookOn Field

Specify which transaction types a Hook should be triggered on

Understanding the HookOn field

Each bit in this unsigned 256-bit integer indicates whether the Hook should execute on a particular transaction type. All bits are active low except bit 22 which is active high. Since 22 is ttHOOK_SET this means the default value of all 0's will not fire on a SetHook transaction but will fire on every other transaction type. This is a deliberate design choice to help people avoid bricking their Xahau account with a misbehaving hook.

Bits are numbered from right to left:

  • bit 0 - right most, i.e. the least significant bit.

  • bit 63 - the left-most, i.e. the most significant bit.

Examples (assuming a 256-bit unsigned integer type):

  1. If we want to completely disable the hook:

  1. If we want to disable the hook on everything except ttPAYMENT:

  1. If we want to enable the hook on everything except ttHOOK_SET

  1. If we want to enable hook firing on ttHOOK_SET (dangerous) and every other transaction type:

HookOn Calculator

float_negate

Negate an XFL floating point number

Concepts

Behaviour

  • Multiply an XFL by -1

  • Return a new XFL as an int64_t

  • Negates a float representation.

  • Returns an error code or the negated float as a bigint.

Definition

Example

📘Special case

The negation of Canonical Zero is Canonical Zero. Unlike some floating point standards (such as IEEE) there is no "negative zero" in XFL.

Parameters

Name
Type
Description

Name
Type
Description

Return Code

Type
Description

Type
Description

trace
trace_num
trace_float
slot
slot_clear
slot_count
slot_set
slot_subarray
slot_subfield
slot_type
slot_float
slot_size
uint8_t key[32] = {
    0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
    0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
    0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
    0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U
};
uint8_t value[4] = { 0xC0U, 0x01U, 0xCAU, 0xFEU };
if (state_set(value, 4, key, 32) == 4)
{
    // ... state successfully saved
}
uint8_t value[4];
uint8_t key[32] = {
    0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
    0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
    0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
    0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U
};
if (state(value, 4, key, 32) < 0)
{
    // ... state fetch failed
}
State
state
state_set
state_foreign
state_set
state_foreign
Namespaces
uint8_t tx_out[1024];

int64_t tx_len =
    sto_emplace(tx_out, sizeof(tx_out),
                tx_in, tx_len,
                sequence_field, 5, sfSequence);

if (tx_len <= 0)
    rollback("Emplacing failed.", 17, 1);
const tx_out = sto_emplace(tx_in, sequence_field, sfSequence)
if (typeof tx_out === 'number')
    rollback("Emplacing failed.", 1)

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.

sto

ByteArray | HexString

The STO object (binary encoded ledger data) to which the field will be added.

field_bytes

ByteArray | HexString

The bytes representing the field to be added.

field_id

number

The ID of the field to be added.

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.

ErrorCode | ByteArray

The updated STO object in binary encoded ledger data format, or an error code if the operation fails.

Serialized Objects
int64_t sto_emplace (
    uint32_t write_ptr,
    uint32_t write_len,
    uint32_t sread_ptr,
    uint32_t sread_len,
    uint32_t fread_ptr,
    uint32_t fread_len,
    uint32_t field_id
);
function sto_emplace(
    sto: ByteArray | HexString,
    field_bytes: ByteArray | HexString,
    field_id: number
  ): ErrorCode | ByteArray
if (emit(tx, tx_len) < 0)
    rollback("Failed to emit!", 15, 1);
const emitResult = emit(txJson)
if(typeof emitResult === 'number')
    rollback("Failed to emit!", 1)

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

txJson

Record<string, any> | Transaction

The TX JSON to emit.

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.

ErrorCode | ByteArray

Returns an ErrorCode if there is an error, or an array of emitted transaction hashes on success.

Emitted Transactions
int64_t emit (
    uint32_t write_ptr,
    uint32_t write_len,
    uint32_t read_ptr,
    uint32_t read_len
);
function emit(
    txJson: Record<string, any> | Transaction
  ): ErrorCode | ByteArray

reserved

uint32_t

Reserved for future use.

reserved

number

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.

number

An arbitrary return code you wish to return from your hook. This will be present in the metadata of the originating transaction.

Compiling Hooks
int64_t hook (
    uint32_t reserved
)
type Hook = (reserved: number) => number
int64_t hook(uint32_t reserved)
{
  return 0;
}
const Hook = (reserved: number) => {
    return 0
}

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.

ErrorCode | ByteArray

Returns an ErrorCode if there is an error, or an array containing the nonce value on success.

Emitted Transactions
int64_t etxn_nonce (
    uint32_t write_ptr,
    uint32_t write_len
);
function etxn_nonce(): ErrorCode | ByteArray
uint8_t n[32];
int64_t bytes_written = 
    etxn_nonce(n, 32);
const nonce = etxn_nonce()

float1

int64_t

An XFL floating point enclosing number

f1

bigint

The float to negate.

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

ErrorCode or bigint

An error code or The XFL (xls17) enclosing number.

Floating Point Numbers (XFL)
int64_t float_negate (
    int64_t float1
);
function float_negate(f1: bigint): ErrorCode | bigint
int64_t negative_one =
    float_negate(float_one());
const negative_one =
    float_negate(float_one());

Running a Node

Info & Faucet

https://xahau-test.net

Explorer

https://explorer.xahau-test.net

Technical docs

https://xrpl-hooks.readme.io

WebSocket URL

wss://xahau-test.net

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

https://github.com/Xahau/Xahau-Testnet-Docker/blob/main/README.md
~(1ULL << 22) /* every bit is 1 except bit 22 which is 0 */
~(1ULL << 22) & ~(1ULL)
0
(1ULL << 22)

SetHook Transaction

SetHook Transaction

Hook web assembly bytecode is installed onto an Xahau account using the SetHook transaction.

An example appears below:

{ 
    Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
    TransactionType: "SetHook",
    Fee: "2000000",
    Hooks:
    [        
        {                        
            Hook: {                
                CreateCode: fs.readFileSync('accept.wasm').toString('hex').toUpperCase(),
                HookOn: '0000000000000000',
                HookNamespace: addr.codec.sha256('accept').toString('hex').toUpperCase(),
                HookApiVersion: 0
            }
        }
    ]
}

The transaction is deceptively simple, but hides significant complexity, described below.

Hooks Array

The main body of the SetHook transaction is the hooks array:

{
    Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
    TransactionType: "SetHook",
    Hooks:                         // This is the Hooks Array
    [            
          {  Hook: { ... }  },     // HookSet Object (position 0)
          {  Hook: { ... }  },  
          {  Hook: { ... }  },  
          {  Hook: { ... }  }.     // HookSet Object (position 3)
    ]
}

This array mirrors the Hook Chain installed on the account:

  • Position 0 in the array corresponds to position 0 in the Hook Chain.

  • Position 3 in the array corresponds to position 3 in the Hook Chain, etc.

HookSet Object and Corresponding Hook

Each entry in the Hooks Array (in the SetHook Transaction) is called a HookSet Object, and its corresponding Hook in the account's Hook Chain is called the Corresponding Hook.

Example: A user performs an operation on each Hook in his/her Hook chain with a SetHook transaction.

HookDefinition

Each Corresponding Hook is an object containing a reference (pointer) to a HookDefinition object.

The HookDefinition object is an unowned reference-counted ledger object that provides for de-duplication of identical web assembly bytecode. Two users using an identical hook will both point to the same HookDefinition.

Example: Hook Definitions on Xahau

For more information see: Reference Counting

Hook Defaults

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.

HookSet Operations

There are six possible operations: No Operation, Create, Update, Delete, Install and Namespace Delete

Each operation is specified by the inclusion or omission of certain HookSet Object fields. This might seem confusing at first but by working through a few examples the reader should find it intuitive; Essentially HookSet operations are a type of diff between a specific Hook's defaults, existing and newly specified fields.

Achieving each type of operation is explained in a subsection below.

No Operation

Occurs when:

  • The HookSet Object is empty

Behaviour:

  • No change of any kind is made.

Example:

{ 
    Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
    TransactionType: "SetHook",
    Fee: "2000000",
    Hooks:
    [        
        {                        
            Hook: {}
        }
    ]
}

Create Operation

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:

{ 
    Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
    TransactionType: "SetHook",
    Fee: "2000000",
    Hooks:
    [        
        {                        
            Hook: {                
                CreateCode: fs.readFileSync('accept.wasm').toString('hex').toUpperCase(),
                HookOn: '0000000000000000',
                HookNamespace: addr.codec.sha256('accept').toString('hex').toUpperCase(),
                HookApiVersion: 0
            }
        }
    ]
}

Install Operation

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:

{ 
    Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
    TransactionType: "SetHook",
    Fee: "2000000",
    Hooks:
    [        
        {                        
            Hook: {                
                HookHash: "A5663784D04ED1B4408C6B97193464D27C9C3334AAF8BBB4FA5EB8E557FC4A2C",
                HookOn: '0000000000000000',
                HookNamespace: addr.codec.sha256('accept').toString('hex').toUpperCase(),
            }
        }
    ]
}

Update Operation

Occurs when:

All of the following conditions are met:

  • The Corresponding Hook exists.

  • HookHash is absent.

  • CreateCode is absent.

  • One or more of HookNamespace, HookParameters or HookGrants is present.

General Behaviour:

  • The Corresponding Hook is updated in such a way that the desired changes are reflected in the Corresponding Hook.

Specific Behaviour:

If HookNamespace is specified and differs from the Corresponding Hook's Namespace:

  • the Corresponding Hook's HookNamespace is updated, and

  • if the hsfNSDELETE flag is specified all HookState entires in the old namespace are deleted.

If HookParameters is specified, then for each entry:

  • If HookParameterName exists but HookParameterValue is absent and the Corresponding Hook's Parameters (either specifically or via defaults) contains this HookParameterName then the parameter is marked as deleted on the Corresponding Hook.

  • If HookParameterName exists and HookParameterValue exists then the Corresponding Hook's Parameters are modified to include the new or updated parameter.

If HookGrants is specified then:

  • The Corresponding Hook's HookGrants array is replaced with the array.

Example:

{ 
    Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
    TransactionType: "SetHook",
    Fee: "2000000",
    Hooks:
    [        
        {                        
            Hook: {
                HookNamespace: addr.codec.sha256('new_accept').toString('hex').toUpperCase(),
            }
        }
    ]
}

Delete Operation

Occurs when:

All of the following conditions are met:

  • The Corresponding Hook exists.

  • hsfOVERRIDE is specified.

  • optionally hsfNSDELETE is also specified.

  • HookHash is absent.

  • CreateCode is present but empty.

Behaviour:

  • The reference count of the HookDefinition object is decremented.

  • If the reference count is now zero the HookDefintion is removed from the ledger.

  • The Hook object in the Corresponding Hook position is deleted, leaving an empty position.

  • If hsfNSDELETE is specified the namespace and all HookState entries are also deleted.

Example:

{ 
    Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
    TransactionType: "SetHook",
    Fee: "2000000",
    Hooks:
    [        
        {                        
            Hook: {
                CreateCode: "",
                Flags: 1,
            }
        }
    ]
}

Namespace Reset

Occurs when:

All of the following conditions are met:

  • flags is present and hsfNSDELETE is set. hsfOVERRIDE can optionally also be specified if the Hook at this position is to be deleted.

  • HookNamespace is specified.

  • CreateCode is absent.

  • HookHash is absent.

  • HookGrants, HookParameters, HookOn and HookApiVersion are absent.

Behaviour:

  • If the Corresponding Hook exists, it remains, nothing happens to it.

  • A subset of HookState objects and the HookState directory for the specified namespace are removed from the ledger, up to the defined limit of 512. Further transactions are needed to continue the deletion process until all relevant records are removed.

Example:

{ 
    Account: "r4GDFMLGJUKMjNhhycgt2d5LXCdXzCYPoc",
    TransactionType: "SetHook",
    Fee: "2000000",
    Hooks:
    [        
        {                        
            Hook: {
              	HookNamespace: addr.codec.sha256('accept').toString('hex').toUpperCase(),
                Flags: 3,
            }
        }
    ]
}

Terminology

Welcome to Hooks 👋

What are Hooks?

Hooks are small, efficient web assembly modules designed specifically for Xahau. Hooks can be written in any language (compilable to WebAssembly) and most business logic and most smart contract concepts can be implemented in a hook. Typically Hooks are written in C.

Hooks are set onto an Xahau account using a SetHook transaction. Once installed on an account, a hook can:

  1. Block or allow incoming and outgoing transactions on the account,

  2. Modify and maintain internal state and logic specific to the hook on that account, and

  3. Emit new transactions on behalf of the account.

Glossary

This Hooks documentation and the Hooks API use a set of unfamiliar terms. Use the lookup table below if you find yourself lost.

Term
Explanation

Hook

This term refers to a range of things depending on context 1. A webassembly binary uploadable to Xahau with the type. 2. A webassembly binary already uploaded to and set or configured onto an Xahau account. 3. The 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 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: .

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: .

SetHook

A new Transaction Type introduced in the Hooks ammendment which sets a Hook onto an Xahau account. See: .

Guards

A special control mechanism you need to use if you write a loop into in a Hook. See: .

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: .

Serialized Objects (STO)

The way xahaud transmits and stores ledger objects. See: .

Slots and Keylets

Slots can contain ledger objects and keylets identify those objects. See: .

Trace

A way to print a log line to the xrpld output from a Hook. See: .

HTTP / WebSocket APIs

You can interact with Xahau via the publicly accessible APIs provided by the xahaud servers.

Reference Counted Hook Definitions

Avoid re-uploading the same bytecode to the ledger

When a novel Hook's web assembly byte-code is uploaded to Xahau, a significant storage burden is imposed on the network. This storage burden is reflected in the Hook Fees 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.

Floating Point Numbers (XFL)

High precision calculations are native to Hooks.

Background

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:

  1. The format is inherently decimal, expressed as a decimal mantissa multipled by 10 to the power of an exponent.

  2. All values expressed have 16 significant (decimal) figures.

  3. The range of exponents is -96 to +80

When serialized the mantissa is 54 bits, and the exponent is 8 bits, with a final sign bit bringing the total size of the serialized floating point to 63 bits.

What is XFL?

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

loating Point Value
Enclosing Number
Representation

This format is very convenient for Hooks, as Hooks can only exchange integer values with xrpld. By enclosing the floating point inside an integer in a well defined way it becomes possible to do complex floating point computations from a Hook. This is useful for computing exchange rates.

Canonical Zero

Floating point regimes typically have a number of different ways to express zero, which can be a problem for testing for zero. For example 0 x 10 ^ 1 is zero and 0 x 10 ^ 2 is also zero. For this reason there is a canonical zero enforced by the standard and the Hook API. The canonical zero is also enclosing number zero (0).

Hook Float API

Once you have an XFL you can use the Float API to do various computations. The Float API appears in the table below. Each API takes one or more XFL enclosing numbers and returns an XFL enclosing number. Negative return values always represent a computational error (such as division by zero). There are no valid negative enclosing numbers.

Hook API
What it does

❗️ 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.

Example

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.

Hooks

Introducing Hooks: The Smart Contract Functionality for Xahau.

Hooks are small, efficient WebAssembly modules designed specifically for Xahau.

Hooks can be written in any language (compilable with WebAssembly), and most business logic and smart contract concepts can be implemented in a hook.

What are Hooks?

Hooks allow the creation of customized logic and automation within the Xahau, making transactions smarter and more convenient. These small, efficient modules add custom on-ledger functionality, such as creating custom triggers for specific events on the ledger.

These triggers can be used to send on-ledger actions or execute other actions in response to the specified event. Hooks are currently available on the .

To learn more about the theoretical concepts of Hooks you can visit the section.

To learn how to code Hooks in C and its functions, visit .

There is a 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.

There is an upcoming development to allow writing Hooks in Javascript, also known as JSHooks. At the moment it can be tested using repo.

Why are Hooks a Big Deal?

Simply put, Hooks add a robust smart contract functionality to Xahau, empowering you to construct and deploy applications with bespoke functionalities aligning with your specific needs and requirements.

Hooks provide a versatile platform as they can be used for implementing a broad spectrum of business logic and smart contract paradigms. Once a hook is set up on an account, it enables you to do the following:

  • Block or allow transactions to and from the account.

  • Change and keep track of the hook’s internal state and logic to inform programmatic choices.

  • Autonomously initiate new transactions on the account’s behalf.

Hooks can be written in C or any other preferred language and then compiled into WebAssembly.

The Hooks Builder serves as an integrated development environment, facilitating the crafting, testing, debugging, and deployment of your Hooks on our testnet.

Whether you're utilizing our examples or building from scratch, Hooks Builder provides a helpful environment for honing and deploying your smart contract solutions.

Some Examples of specific Hooks and Use Cases

Showcasing the potential of Hooks with these concrete examples, each illustrating a unique application of smart contract functionality on Xahau:

  • Auto-Savings Hook: Automate savings by configuring a Hook to transfer a set amount of XAH to a separate savings account on the ledger. This could be done to help save a portion of XAH and build up savings at specified intervals—daily, weekly, or monthly. This recurring transfer mechanism can be a base for developing personal finance applications or subscription-based models.

  • Carbon-Offset Hook: Each transaction triggers an additional transfer of 1% of the amount to a carbon offset account managed by a trusted non-governmental organization (NGO) using the money for a good cause. This feature can be used as a base for building applications that contribute to environmental sustainability with every transaction made.

  • Firewall Hook: By filtering incoming and outgoing transactions. The Firewall Hook can block malicious transactions originating from known scam accounts or containing suspicious memos. By retrieving an updated blocklist from a Hook on a different account, the firewall maintains a robust defense against fraud without the need for manual intervention. Additionally, implementing spending limits to deny high-value unauthorized withdrawals could be a crucial feature for financial applications.

Distinguishing Hooks from Ethereum Virtual Machine (EVM)

Xahau Hooks and the EVM allow developers to build and deploy custom logic and automation within their platforms. However, some key differences between these two technologies set them apart.

  • Platform Compatibility: Hooks are tailored for Xahau, while EVM smart contracts are designed for Ethereum-based blockchains.

  • Execution Efficiency: Hooks utilize WebAssembly (WASM), outperforming the bytecode used by the EVM in terms of speed and efficiency.

  • Predictable Execution Time: Xahau Hooks use guards to ensure maximum execution time is well-bounded and known ahead of time, improving efficiency.

Alternatives to Hooks on the XRPL ecosystem

Ripple and Peersyst announced that an EVM-compatible sidechain is now live . This sidechain functions as an autonomous blockchain, complete with its unique consensus protocol and transaction rules. The EVM sidechain is an alternative to Hooks, adding smart contract functionality to the ecosystem.

However, it's essential to note that EVM sidechain contracts function on Layer 2, which requires a two-step process where XRP is transitioned onto the sidechain for contract execution and then back to the main ledger. Once on the sidechain, then again on the XRPL, meaning Layer 2 smart contracts cannot influence the flow. Hooks can decide if a transaction is allowed in the first place. Layer 2 can make a retroactive decision, but the initial transaction has already happened.

Hooks are more closely integrated with XRPL, operating directly on Xahau, an Layer 1 XRPL-core fork, so they are more tightly integrated with the underlying blockchain technology than the EVM-compatible sidechain to take advantage of the specific features and capabilities of the XRPL platform. With the inherent scalability and performance of WebAssembly, Hooks are optimal to enhance Xahau's functionality.

Hooks Will Expand the On-ledger Functionality and Help Xahau Grow

Hooks add native smart contract capabilities to Xahau, enabling the crafting of custom applications that meet the unique needs of users, bringing new functionalities, and opening up whole new domains of functionality. With Hooks, the possibilities are virtually unlimited.

As Xahau continues to grow, there is no doubt that Hooks will play a significant role in driving further innovation and adoption of the platform by retail and enterprise users.

Public API Methods

Interact directly with an xahaud server using public API methods. These methods are not necessarily intended for general public use but are accessible to any client connected to the server.

Account Methods

Method
Description

Ledger Methods

Method
Description

Transaction Methods

Method
Description

Order Book Methods

Method
Description

Payment Channel Methods

Method
Description

Subscription Methods

Method
Description

Server Info Methods

Method
Description

Utility Methods

Method
Description

Ubuntu - 22.04

Xahaud now supports building using Conan. We recommend using Conan to build the repository. The build instructions for Conan can be found in the file in the source code.

CMake Legacy Building

Dependency
Working Version

Set Build Env Variables

First make a dependency directory. I like to use ~/dependencies

Next we need to set the environment variables.

Set Versions Env Variables

If you are using Ubuntu 20.04 change the `UBUNTU_VERSION=focal`

Set Build Env Variables

Install Core Dependencies

To Resolve the `E: The repository 'http://apt.llvm.org/ llvm-toolchain-- Release error:

Install Rippled Dependencies

Install CMake

Install Protobuf

Install Boost

Install WasmEdge

Clone the repository

Build Xahaud

From the root xahaud directory:

Start the built node

util_raddr

Convert a 20 byte Account ID to an r-address

Behaviour

  • Read a 20 byte Account ID from the read_ptr

  • Write the equivalent r-address for that Account ID to write_ptr

  • Read a 20 byte Account ID from the accountid

  • Return the equivalent r-address for that Account ID

Definition

Example

Parameters

Name
Type
Description
Name
Type
Description

Return Code

Type
Description
Type
Description

sto_validate

Validate an STObject

Concepts

Behaviour

  • Parse an STObject pointed to by read_ptr

  • Return 1 if the serialization is valid, 0 otherwise.

  • The blob (e.g. serialized transaction) is provided to be validated.

  • Returns number 1 if the STObject is valid, 0 if it isn't, or an error code if validation fails.

Definition

Example

Parameters

Name
Type
Description

Name
Type
Description

Return Code

Type
Description

Type
Description

Request Formatting Guide
Response Formatting Guide
Considerations
Public API Methods
Admin API Methods

account_channels

List payment channels where the account is the channel source.

account_currencies

List currencies the account can send or receive.

account_info

Retrieve basic information about an account.

account_lines

Access trust line information for an account.

account_objects

Retrieve all ledger objects owned by an account.

account_offers

View an account’s currency exchange offers.

account_tx

Retrieve transaction history for an account.

gateway_balances

Calculate total issued amounts for an account.

noripple_check

Suggest changes to an account's Default Ripple and No Ripple settings.

ledger

Get information about a specific ledger version.

ledger_closed

Retrieve the most recently closed ledger version.

ledger_current

Retrieve the current working ledger version.

ledger_data

Access raw ledger content.

ledger_entry

Retrieve a specific element from a ledger version.

submit

Submit a transaction to the network.

submit_multisigned

Submit a multi-signed transaction.

transaction_entry

Retrieve details about a transaction in a specific ledger.

tx

Retrieve transaction information across all ledgers.

sign

(Admin) Cryptographically sign a transaction.

sign_for

(Admin) Contribute to a multi-signature.

book_offers

View offers for exchanging two currencies.

deposit_authorized

Check if one account can send payments directly to another.

channel_authorize

Sign a claim for a payment channel

channel_verify

Verify a payment channel claim signature.

subscribe

Listen for updates on a subject

unsubscribe

Stop receiving updates

fee

Retrieve information about transaction costs.

server_info

Get server status in human-readable format.

server_state

Get server status in machine-readable format.

manifest

Retrieve public key details for a validator.

json

Proxy for running commands with JSON parameters. (Commandline only.)

ping

Verify server connectivity.

random

Generate random numbers.

SetHook Transaction
source code
SetHook Transaction
Emitted Transactions
State Management
SetHook Transaction
Loops and Guarding
Floating Point Numbers (XFL)
Serialized Objects
Slots and Keylets
Debugging Hooks

-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)

float_set

Create a float from an exponent and mantissa

float_multiply

Multiply two XFL numbers together

float_mulratio

Multiply an XFL floating point by a non-XFL numerator and denominator

float_negate

Negate an XFL floating point number

float_compare

Perform a comparison on two XFL floating point numbers

float_sum

Add two XFL numbers together

float_sto

Output an XFL as a serialized object

float_sto_set

Read a serialized amount into an XFL

float_invert

Divide one by an XFL floating point number

float_divide

Divide an XFL by another XFL floating point number

float_one

Return the number 1 represented in an XFL enclosing number

float_exponent

Get the exponent of an XFL enclosing number

float_mantissa

Get the mantissa of an XFL enclosing number

float_sign

Get the sign of an XFL enclosing number

float_exponent_set

Set the exponent of an XFL enclosing number

float_mantissa_set

Set the mantissa of an XFL enclosing number

float_sign_set

Set the sign of an XFL enclosing number

float_int

Convert an XFL floating point into an integer (floor)

float_root

Compute the nth root of an XFL

float_log

Compute the decimal log of an XFL

int64_t max_vault_pusd =
    float_multiply(vault_xrp, exchange_rate);

max_vault_pusd = 
    float_mulratio(max_vault_pusd, 0,
        NEW_COLLATERALIZATION_NUMERATOR, NEW_COLLATERALIZATION_DENOMINATOR);
Floating point numbers
IEEE binary floating point standard
bespoke decimal floating point standard
XLS-17d
here

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

mkdir ~/dependencies
export UBUNTU_VERSION=jammy
export LLVM_VERSION=14
export CMAKE_VERSION=3.23.1
export BOOST_VERSION=1.86.0
export WASMEDGE_VERSION=0.11.2
export PROTOBUF_VERSION=3.20.0
export DEP_DIR=~/dependencies
export BOOST_FOLDER_NAME="boost_$(echo "$BOOST_VERSION" | sed 's/\./_/g')"
export BOOST_ROOT=$DEP_DIR/$BOOST_FOLDER_NAME
export Boost_LIBRARY_DIRS=$BOOST_ROOT/libs
export BOOST_INCLUDEDIR=$BOOST_ROOT/boost
export Boost_INCLUDE_DIRS=$BOOST_ROOT/boost
export LLVM_DIR=/usr/lib/llvm-$LLVM_VERSION/lib/cmake/llvm
export LLVM_LIBRARY_DIR=/usr/lib/llvm-$LLVM_VERSION/lib
export LLD_DIR=/usr/lib/llvm-$LLVM_VERSION/lib/cmake/lld
export CC=gcc
export CXX=g++
export CFLAGS="-DBOOST_ASIO_HAS_STD_INVOKE_RESULT"
export CXXFLAGS="-DBOOST_ASIO_HAS_STD_INVOKE_RESULT"
export BOOST_CXXFLAGS="-DBOOST_ASIO_HAS_STD_INVOKE_RESULT"
export LDFLAGS="-L$BOOST_ROOT/lib"
export CPPFLAGS="-I$BOOST_ROOT/include"
export LDFLAGS="-L/usr/lib/llvm-$LLVM_VERSION/lib"
export CPPFLAGS="-I/usr/lib/llvm-$LLVM_VERSION/include"
apt update && \
apt install -y build-essential software-properties-common wget curl git pkg-config zlib1g-dev libssl-dev autoconf libtool unzip gcc g++ ninja-build && \
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc && \
add-apt-repository "deb http://apt.llvm.org/$UBUNTU_VERSION/ llvm-toolchain-$UBUNTU_VERSION-$LLVM_VERSION main" && \
add-apt-repository ppa:deadsnakes/ppa && \
apt-cache policy python3.9 && \
apt install -y python3.9 python3-pip llvm-$LLVM_VERSION-dev liblld-$LLVM_VERSION-dev libpolly-$LLVM_VERSION-dev
sudo nano /etc/apt/sources.list
# Scroll down and remove
deb http://apt.llvm.org/ llvm-toolchain-- main
# Add the apt-repo directly with add-apt-repository "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-14 main"
cd $DEP_DIR && \
wget https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION-Linux-x86_64.sh && \
sudo sh cmake-$CMAKE_VERSION-Linux-x86_64.sh --prefix=/usr/local --exclude-subdir
cd $DEP_DIR && \
wget -nc https://github.com/protocolbuffers/protobuf/releases/download/v$PROTOBUF_VERSION/protobuf-all-$PROTOBUF_VERSION.tar.gz && \
tar -xzf protobuf-all-$PROTOBUF_VERSION.tar.gz && \
cd protobuf-$PROTOBUF_VERSION/ && \
./autogen.sh && \
./configure --prefix=/usr --disable-shared link=static && \
make -j$(nproc) && \
sudo make install
cd $DEP_DIR && \
wget https://boostorg.jfrog.io/artifactory/main/release/$BOOST_VERSION/source/$BOOST_FOLDER_NAME.tar.gz && \
tar -xvzf $BOOST_FOLDER_NAME.tar.gz && \
cd $BOOST_FOLDER_NAME && \
./bootstrap.sh && \
./b2 -j$(nproc)
cd $DEP_DIR && \
wget -nc -q https://github.com/WasmEdge/WasmEdge/archive/refs/tags/$WASMEDGE_VERSION.zip && \
unzip -o $WASMEDGE_VERSION.zip && \
cd WasmEdge-$WASMEDGE_VERSION && \
mkdir build && \
cd build && \
cmake -DCMAKE_BUILD_TYPE=Release -DWASMEDGE_BUILD_SHARED_LIB=OFF -DWASMEDGE_BUILD_STATIC_LIB=ON -DWASMEDGE_BUILD_AOT_RUNTIME=ON -DWASMEDGE_FORCE_DISABLE_LTO=ON -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DWASMEDGE_LINK_LLVM_STATIC=ON -DWASMEDGE_BUILD_PLUGINS=OFF -DWASMEDGE_LINK_TOOLS_STATIC=ON .. && \
make -j$(nproc) && \
sudo make install
mkdir ~/projects && \
cd ~/projects && \
git clone https://github.com/Xahau/xahaud.git && \
cd xahaud && \
git checkout dev
mkdir build && \
cd build && \
cmake -DCMAKE_BUILD_TYPE=Debug -DLLVM_DIR=$LLVM_DIR -DLLVM_LIBRARY_DIR=$LLVM_LIBRARY_DIR .. && \
cmake --build . --target rippled --parallel -j$(nproc)
./rippled
BUILD.md

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.

accountid

number[]/string

The HEX account ID to return as r-address, can be provided as an array of numbers or a string.

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.

string/number

ErrorCode if there is an error in formatting, otherwise returns the r-address as a string

int64_t util_raddr (
    uint32_t write_ptr,
    uint32_t write_len,
    uint32_t read_ptr,
    uint32_t read_len
);
function util_raddr(accountid: ByteArray | HexString): ErrorCode | string
uint8_t raddr_out[40];
uint8_t acc_id[20] =
{
    0x2dU, 0xd8U, 0xaaU, 0xdbU, 0x4eU, 0x15U,               
    0xebU, 0xeaU,  0xeU, 0xfdU, 0x78U, 0xd1U, 0xb0U,
    0x35U, 0x91U,  0x4U, 0x7bU, 0xfaU, 0x1eU,  0xeU
};
int64_t bytes_written = 
    util_raddr(raddr_out, sizeof(raddr_out), acc_id, 20);
const raddr = util_raddr('8D329C03074A98EF0488AB6ABBF5883F68CCFD4E')
// or
const raddr = util_raddr([
    0x8D, 0x32, 0x9C, 0x03, 0x07, 0x4A, 0x98, 0xEF, 0x04, 0x88,
    0xAB, 0x6A, 0xBB, 0xF5, 0x88, 0x3F, 0x68, 0xCC, 0xFD, 0x4E
])

read_ptr

uint32_t

The buffer to read the source STObject from

read_len

uint32_t

The Length of the source object

blob

ByteArray | HexString

The blob (e.g. serialized transaction) to be validated.

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.

ErrorCode | number

Returns number 1 if the STObject is valid, 0 if it isn't, or an error code if validation fails.

Serialized Objects
int64_t sto_validate (
    uint32_t read_ptr,
    uint32_t read_len
);
function sto_validate(blob: ByteArray | HexString): ErrorCode | number
int64_t result = 
  sto_validate(tx_out, sizeof(tx_out));

if (tx_len <= 0)
    rollback("Invalid STO.", 12, 1);
const result = sto_validate(tx_out)

if (result <= 0)
    rollback("Invalid STO.", 1)
Development by XRPL Labs
Xahau network
Concepts
Hooks C-Functions
Hooks Builder site
JSHooks
on the company's devnet

util_keylet

Compute a serialized keylet of a given type

Concepts

📘Tip

Not every Keylet type is supported by this utility function. If you need another Keylet type you can derive it yourself using and by checking the required fields . A further Keylet tool may

Behaviour

  • Compute a keylet of the specified keylet_type according to the parameters a through f depending on type.

  • Write the serialized 34 byte keylet into write_ptr

Definition

Example

Parameters

Name
Type
Description

Name
Type
Description

Keylet Table

Keylet Type
Parameters

Return Code

Type
Description

Type
Description

sto_subarray

Index into a xahaud serialized array and return the location and length of an index

Concepts

Behaviour

  • Parse a STArray pointed to by read_ptr

  • Find the array index specified by array_id

  • Return the byte offset and length of the serialized field within the STObject, if it is found

🚧Field ID encoding

The sto_ apis accept a field_id parameter encoded as follows: (type << 16U) + field Thus type 1 field 2 would be 0x10002U.

In the case of this array field ID is array_id.

  • Ask for the STO object (binary encoded ledger data) from which to extract the subarray.

  • Find the array index specified by array_id

  • Return a subarray from an STO object.

Definition

C

Example

📘

hookmacro.h already contains the SUB_OFFSET and SUB_LENGTH macros.

Parameters

Name
Type
Description

Name
Type
Description

Return Code

Type
Description

Type
Description

uint8_t keylet[34];
if (util_keylet(keylet, 34, KEYLET_LINE,
              hook_accid, 20,
              account_field, 20,
              currency_code, 20) != 34)
	rollback("Keylet Failed.", 14, 1);
if (util_keylet(
        KEYLET_LINE, hook_accid, account_field, currency_code
        ).length < 34) 
    rollback("Keylet Failed.", 1)

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_type

The type of the keylet to create

accountid

(Optional) First piece of data for the keylet, can be an array of numbers, a string, or a number.

statekey

(Optional) Second piece of data for the keylet, can be an array of numbers, a string, or a number.

namespace

(Optional) Third piece of data for the keylet, can be an array of numbers, a string, or a number.

KEYLET_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.

number

ErrorCode if there is an error in creating the keylet, otherwise returns the generated keylet as an array of numbers.

Slots and Keylets
util_sha512h
here
assist you.
int64_t util_keylet (
    uint32_t write_ptr,
    uint32_t write_len,
    uint32_t keylet_type,
    uint32_t a,
    uint32_t b,
    uint32_t c,
    uint32_t d,
    uint32_t e,
    uint32_t f
);
function util_keylet(
    keylet_type: number,
    accountid: ByteArray | HexString,
    statekey: ByteArray | HexString,
    namespace: ByteArray | HexString
  ): ErrorCode | ByteArray
#define SUB_OFFSET(x) ((int32_t)(x >> 32))
#define SUB_LENGTH(x) ((int32_t)(x & 0xFFFFFFFFULL))

  int64_t memo_lookup =
    sto_subarray(memos, memos_len, 0);

if (memo_lookup < 0)
{
    // sfMemo was not found in the STObject pointed at by memo_ptr
}
else
{
    // 0th index of the STArray was found and its location is as follows:
    uint8_t*  memo_ptr = SUB_OFFSET(memo_lookup) + memos;
    uint32_t  memo_len = SUB_LENGTH(memo_lookup);
}
const SUB_OFFSET = (x) => Number(x >> 32n)
const SUB_LENGTH = (x) => Number(x & 0xFFFFFFFFn)

const memo_lookup = sto_subarray(memos, 0)

if (typeof memo_lookup === 'number')
{
    // sfMemo was not found in the STObject pointed at
}
else
{
    // 0th index of the STArray was found and its location is as follows:
    const memo_start = SUB_OFFSET(memo_lookup)
    const memo_len = SUB_LENGTH(memo_lookup)
    const memo = memos.slice(memo_start, memo_len)
}

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.

sto

ByteArray | HexString

The STO object (binary encoded ledger data) from which to extract the subarray.

array_id

number

The ID of the array to be extracted.

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.

bigint / ErrorCode

The location of the field within the specified buffer: - The high 32 bits are the offset location. - The low 32 bits are the length. or an error code if the extraction fails.

Serialized Objects
int64_t sto_subarray (
    uint32_t read_ptr,
    uint32_t read_len,
    uint32_t array_id
);
function sto_subarray(
    sto: ByteArray | HexString,
    array_id: number
  ): bigint | number

util_verify

Verify a cryptographic signature

Behaviour

Verify a cryptographic signature

  • If the public key is prefixed with 0xED then use ED25519

  • Otherwise assume SECP256k1

Definition

int64_t util_verify (
    uint32_t dread_ptr,
    uint32_t dread_len,
    uint32_t sread_ptr,
    uint32_t sread_len,
    uint32_t kread_ptr,
    uint32_t kread_len
);

function util_verify(
    signedData: ByteArray | HexString,
    signature: ByteArray | HexString,
    pubkey: ByteArray | HexString
  ): 0 | 1

Example

if (!util_verify(payload_ptr,    payload_len,
                 signature_ptr,  signature_len,
                 publickey_ptr,  publickey_len))
	rollback("Invalid Signature", 17, 60);
if (util_verify(signedData,signature,pubkey))
    rollback("Invalid Signature", 60)

Parameters

Name
Type
Description

dread_ptr

uint32_t

Pointer to the signed data

dread_len

uint32_t

Length of the signed data

sread_ptr

uint32_t

Pointer to the signature

sread_len

uint32_t

Length of the signature

kread_ptr

uint32_t

Pointer to the public key

kread_len

uint32_t

Length of the public key

Name
Type
Description

signedData

number / string

The signed data to verify, can be provided as an array of numbers or a string.

signature

number / string

The signature to verify, can be provided as an array of numbers or a string.

pubkey

number / string

The public key responsible for the signature, can be provided as an array of numbers or a string.

Return Code

Type
Description

int64_t

0 - validation failed, the signature is invalid. 1 - validation succeeded, the signature is valid. If negative, an error: OUT_OF_BOUNDS - pointers/lengths specified outside of hook memory.

Type
Description

number

0 - validation failed, the signature is invalid. 1 - validation succeeded, the signature is valid.

https://richardah.github.io/xrpl-hookon-calculator/
GitHub - Xahau/Xahau-Testnet-Docker: Xahau testnet (NetworkID 21338) Docker Container with xPOP generationGitHub

Running a Mainnet Node

Xahau Mainnet allows for running your own local node. You can run a Docker Container or connect with your own local running instance.

Connecting to the Xahau Mainnet with Docker

To connect to the Xahau Mainnet you can use this docker container:

  1. Clone the repository

  2. Run ./build

  3. Run ./up

  4. Check the README for commands, etc.

  5. Connect using WebSockets or RPC: WebSocket: ws://localhost:16006 RPC (HTTP POST): http://localhost:16007

Local instance

Peering info

Return Codes

Return code design

Web assembly allows for exceptions (traps) however this language feature is not used for Hooks. Instead there is only one way to return from any Hook API (you may think of every Hook API as being noexcept).

To provide for efficient error handling:

  1. All Hook API functions return a signed integer.

  2. All negative return codes are an error.

  3. All return codes 0 or greater are a function specific output, usually but not always the number of bytes read or written.

Error codes

Error codes are global across all Hook APIs and may be found in the table below.

Name
Value
Description

SUCCESS

>= 0

Non-negative return codes refer always to success and usually indicate the number of bytes written or events performed, depending on the specific API.

OUT_OF_BOUNDS

-1

A pointer or buffer length provided as a parameter described memory outside of the Hook's allowed memory region.

INTERNAL_ERROR

-2

Reserved for internal invariant trips, generally unrelated to inputs. These should be reported with an issue.

TOO_BIG

-3

Attempted to set a parameter or value larger than the allowed space.

TOO_SMALL

-4

The API was unable to produce output to the write_ptr because the specified write_len was too small.

DOESNT_EXIST

-5

The requested object or item wasn't found.

NO_FREE_SLOTS

-6

The Hook attempted to allocate an item into a slot, but there were no slots free. To avoid ensure re-use of existing slots. The maximum number of slots is 255.

INVALID_ARGUMENT

-7

One or more of the parameters to the API were invalid according to the individual API's specification.

ALREADY_SET

-8

Some APIs allow for a once-per-execution parameter to be set. A second attempt to set a once-per-execution parameter results in this error.

PREREQUISITE_NOT_MET

-9

An API required the Hook to do something before the API is allowed to be called. Check the API's documentation.

FEE_TOO_LARGE

-10

During fee calculation if an absurdly large fee is calculated this error is returned.

EMISSION_FAILURE

-11

An attempt to emit() a TXN was unsccessful for any of a number of reasons. Check the trace log of the rippled to which you are submitting the originating TXN.

TOO_MANY_NONCES

-12

A Hook may only use up to 256 calls to nonce() per execution. Further calls result in this error code.

TOO_MANY_EMITTED_TXN

-13

A Hook must declare ahead of time how many TXN it intends to emit(). If it emits fewer than this many, this is allowed. If it emits more than this many this error is returned.

NOT_IMPLEMENTED

-14

While Hooks is/was in development an API may return this if some or all of that API is planned but not yet implemented.

INVALID_ACCOUNT

-15

An API which accepts a 20 byte Account ID may return this if, in its opinion, the Account ID was not valid for any reason.

GUARD_VIOLATION

-16

All loops inside a Hook must declare at the top of the loop, as the first non trivial instruction, before any branch instruction, the promised maximum number of iterations of the loop. If this promise is violated the hook terminates immediately with this error code.

INVALID_FIELD

-17

The requested serialized field could not be found in the specified object.

PARSE_ERROR

-18

While parsing serialized content an error was encountered (typically indicating an invalidly serialized object).

RC_ROLLBACK

-19

Used internally to communicate a rollback event.

RC_ACCEPT

-20

Used internally to communicate an accept event.

NO_SUCH_KEYLET

-21

Specified keylet could not be found, or keylet is invalid

NOT_AN_ARRAY

-22

API was asked to assume object under analysis is an STArray but it was not.

NOT_AN_OBJECT

-23

API was asked to assume object under analysis is an STObject but it was not.

INVALID_FLOAT

-10024

A floating point operation resulted in Not-A-Number or API call attempted to specify an XFL floating point number outside of the expressible range of XFL.

DIVISION_BY_ZERO

-25

API call would result in a division by zero, so API ended early.

MANITSSA_OVERSIZED

-26

When attempting to create an XFL the mantissa must be 16 decimal digits.

MANTISSA_UNDERSIZED

-27

When attempting to create an XFL the mantissa must be 16 decimal digits.

EXPONENT_OVERSIZED

-28

When attempting to create an XFL the exponent must not exceed 80.

EXPONENT_UNDERSIZED

-29

When attempting to create an XFL the exponent must not be less than -96.

OVERFLOW

-30

A floating point operation done on an XFL resulted in a value larger than XFL format is able to represent.

NOT_IOU_AMOUNT

-31

An API assumed an STAmount was an IOU when in fact it was XRP.

NOT_AN_AMOUNT

-32

An API assumed an STObject was an STAmount when in fact it was not.

CANT_RETURN_NEGATIVE

-33

An API would have returned a negative integer except that negative integers are reserved for error codes (i.e. what you are reading.)

NOT_AUTHORIZED

-34

Hook attempted to set foreign state but was not authorized to do so (grant was missing or invalid.)

PREVIOUS_FAILURE_PREVENTS_RETRY

-35

Hook previously received a NOT_AUTHORIZED return code and is not allowed to retry.

TOO_MANY_PARAMS

-36

Attempted to set a hook parameter for a later hook in the chain, but there are now too many parameters.

INVALID_TXN

-37

Serialized transaction was not a valid transaction (usually because of a missing required field or data corruption / truncation.)

RESERVE_INSUFFICIENT

-38

Setting an additional state object on this account would cause the reserve requirements to exceed the account's balance.

COMPLEX_NOT_SUPPORTED

-39

Hook API would be forced to return a complex number, which it cannot do.

DOES_NOT_MATCH

-40

Two arguments were required to be of the same type but are not.

INVALID_KEY

-41

The provided public key was not valid.

NOT_A_STRING

-42

The buffer did not contain a nul terminated string.

MEM_OVERLAP

-43

The writing pointer points to a buffer that overlaps with the reading pointer.

TOO_MANY_STATE_MODIFICATIONS

-44

More than 5000 modified state entries in the combined hook chains

TOO_MANY_NAMESPACES

-45

More than 256 namespaces on this account

Info

https://xahau.network/

Explorer

https://explorer.xahau.network/

Technical docs

https://xrpl-hooks.readme.io

WebSocket URL

wss://xahau.network

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:

https://build.xahau.tech

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)

https://vl.xahau.org/

https://github.com/Xahau/mainnet-docker/blob/main/README.md

sto_subfield

Index into a xahaud serialized object and return the location and length of a subfield

Concepts

  • Serialized Objects

Behaviour

  • Parse a STObject pointed to by read_ptr

  • Find the field specified by field_id

  • If the field is found, and:

    1. It is an array, then return the start and length of the array including the leadin/leadout bytes, or

    1. It is not an array, then return the start and length of the PAYLOAD of the field (excluding the leadin bytes).

🚧Field ID encoding

The sto_ apis accept a field_id parameter encoded as follows: (type << 16U) + field Thus type 1 field 2 would be 0x10002U.

  • Parse a STObject into sto variable

  • Find the field specified by field_id

Definition

int64_t sto_subfield (
    uint32_t read_ptr,
    uint32_t read_len,
    uint32_t field_id
);

function sto_subfield(
    sto: ByteArray | HexString,
    field_id: number
  ): ErrorCode | bigint

Example

#define SUB_OFFSET(x) ((int32_t)(x >> 32))
#define SUB_LENGTH(x) ((int32_t)(x & 0xFFFFFFFFULL))
int64_t memos_lookup =
    sto_subfield(txn_ptr, txn_len, sfMemos);
if (memos_lookup < 0)
{
    // sfMemos was not found in the STObject pointed at by memo_ptr
}
else
{
    // sfMemos was found and its location is as follows:
    uint8_t* memos_ptr = SUB_OFFSET(memos_lookup) + memos_ptr;
    int64_t  memos_len = SUB_LENGTH(memos_lookup);
}

📘

hookmacro.h already contains the SUB_OFFSET and SUB_LENGTH macros.

const SUB_OFFSET = (x) => Number(x >> 32n)
const SUB_LENGTH = (x) => Number(x & 0xFFFFFFFFn)
const memos_lookup = sto_subfield(txn, sfMemos);
if (typeof memos_lookup === 'number')
{
    // sfMemos was not found in the STObject pointed at by memo_ptr
}
else
{
    // sfMemos was found and its location is as follows:
    const memo_start = SUB_OFFSET(memos_lookup)
    const memo_len = SUB_LENGTH(memos_lookup)
    const memo = txn.slice(memo_start, memo_len)
}

Parameters

Name
Type
Description

read_ptr

uint32_t

Pointer to the buffer containing the STObject

read_len

uint32_t

Length of STObject

field_id

uint32_t

The sf code of the field you are searching for. To compute this manually take the serialized type and shift it into the 16 highest bits of uint32_t, then take the field and place it in the 16 lowest bits. For example: sfEmitNonce has type 5 and field 11 thus its value is 0x050BU

Name
Type
Description

sto

ByteArray or HexString

The STO object (binary encoded ledger data) from which to extract the subfield.

field_id

number

The ID of the field to be extracted.

Return Code

Type
Description

int64_t

The location of the field within the specified buffer: - The high 32 bits are the offset location. - The low 32 bits are the length. If negative, an error: OUT_OF_BOUNDS - pointers/lengths specified outside of hook memory. TOO_SMALL - Input buffer isn't large enough to possibly contain a valid STObject. DOESNT_EXIST - The searched for field isn't present in the supplied STObject. PARSE_ERROR - The supplied STObject is malformed or not an STObject.

Type
Description

bigint / ErrorCode

The location of the field within the specified buffer: - The high 32 bits are the offset location. - The low 32 bits are the length.

or an error code if the extraction fails.

Using Hooks Builder, you can develop, test, debug and deploy your own Hooks on our testnet, using our examples or building your own from scratch.
Logo

Mac OS - 15.3.2 (24D81)

Xahaud now supports building using Conan. We recommend using Conan to build the repository. The build instructions for Conan can be found in the BUILD.md file in the source code.

CMake Legacy Building

Dependency
Working Versions

Apple Clang

14.3.1, 16.0.0

LLVM

14, 16

LLD

14, 16

Boost

1.86.0

CMake

3.23.1

Protobuf

3.20.0

WasmEdge

0.11.2

Using Apple Clang 14.3.1

  1. Download an older version of Xcode

    1. Go to the https://developer.apple.com/download/more/ page. You will need to sign in with your Apple Developer account.

    2. Search for the version of Xcode that includes Apple Clang 14. This is typically specified in the release notes for each Xcode version.

    3. Download the Xcode `.xip` file for the version you need.

  2. Install the older version of Xcode:

    1. Once the download is complete, extract the `.xip` file, which will give you an Xcode application.

    2. Rename this Xcode application if you want to keep multiple versions of Xcode on your system (e.g., `Xcode_14.3.1.app`).

    3. Drag the Xcode application to your `/Applications` directory.

  3. Switch to the desired version of the toolchain

    1. 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:

      sudo xcode-select -s /Applications/Xcode_14.3.1.app/Contents/Developer
    2. Replace `Xcode_14.3.1.app` with the actual name of the Xcode version you installed.

    3. 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;

export DEVELOPER_DIR=/Applications/Xcode_14.3.1.app/Contents/Developer
clang --version

Set Build Env Variables

First make a dependency directory. I like to use ~/dependencies

mkdir ~/dependencies

Next we need to set the environment variables.

Set Version Env Variables

export LLVM_VERSION=14
export BOOST_VERSION=1.86.0
export WASMEDGE_VERSION=0.11.2
export PROTOBUF_VERSION=3.20.0

Set Build Env Variables

export DEP_DIR=~/dependencies
export BOOST_FOLDER_NAME="boost_$(echo "$BOOST_VERSION" | sed 's/\./_/g')"
export BOOST_ROOT="$DEP_DIR/$BOOST_FOLDER_NAME"
export BOOST_LIBRARY_DIRS="$BOOST_ROOT/libs"
export BOOST_INCLUDE_DIR="$BOOST_ROOT/boost"
export BOOST_CXXFLAGS="${BOOST_CXXFLAGS:-} -DBOOST_ASIO_HAS_STD_INVOKE_RESULT"
export LLVM_PREFIX=`brew --prefix llvm@$LLVM_VERSION`
export LLVM_DIR="$LLVM_PREFIX/lib/cmake/llvm"
export LLVM_LIBRARY_DIR="$LLVM_PREFIX/lib"
export LLD_DIR="$LLVM_PREFIX/lib/cmake/lld"
export CC=clang
export CXX=clang++
export LDFLAGS="${LDFLAGS:-} -L$BOOST_LIBRARY_DIRS -L$LLVM_PREFIX/lib"
export CPPFLAGS="${CPPFLAGS:-} -I$BOOST_ROOT/include -I$LLVM_PREFIX/include"
export CFLAGS="${CFLAGS:-} -DBOOST_ASIO_HAS_STD_INVOKE_RESULT"
export CXXFLAGS="${CXXFLAGS:-} -DBOOST_ASIO_HAS_STD_INVOKE_RESULT"

Install Core Dependencies

brew update
brew install automake \
             wget \
             curl \
             git \
             pkg-config \
             openssl \
             autoconf \
             libtool \
             unzip \
             cmake \
             "llvm@$LLVM_VERSION"

Install Rippled Dependencies

Install Protobuf

cd $DEP_DIR && \
wget -nc https://github.com/protocolbuffers/protobuf/releases/download/v$PROTOBUF_VERSION/protobuf-all-$PROTOBUF_VERSION.tar.gz && \
tar -xzf protobuf-all-$PROTOBUF_VERSION.tar.gz && \
cd protobuf-$PROTOBUF_VERSION/ && \
./autogen.sh && \
./configure --disable-shared link=static && \
make -j$(sysctl -n hw.logicalcpu) && \
sudo make install

Note that it's currently necessary to remove any homebrew installations of protobuf otherwise cmake will mix up both installations. There would of course be better workarounds for this, but simply removing the homebrew installations is a quick fix.

Install Boost

cd $DEP_DIR && \
wget https://archives.boost.io/release/$BOOST_VERSION/source/$BOOST_FOLDER_NAME.tar.gz && \
tar -xvzf $BOOST_FOLDER_NAME.tar.gz && \
cd $BOOST_FOLDER_NAME && \
./bootstrap.sh && \
./b2 -j$(sysctl -n hw.logicalcpu)

Install WasmEdge

cd $DEP_DIR && \
wget -nc -q https://github.com/WasmEdge/WasmEdge/archive/refs/tags/$WASMEDGE_VERSION.zip && \
unzip -o $WASMEDGE_VERSION.zip && \
cd WasmEdge-$WASMEDGE_VERSION && \
sed -i '' \
  's|https://boostorg\.jfrog\.io/artifactory/main/release/|https://archives.boost.io/release/|g' CMakeLists.txt && \
mkdir build && \
cd build && \
cmake -DCMAKE_BUILD_TYPE=Release \
  -DWASMEDGE_BUILD_SHARED_LIB=OFF \
  -DWASMEDGE_BUILD_STATIC_LIB=ON \
  -DWASMEDGE_BUILD_AOT_RUNTIME=ON \
  -DWASMEDGE_FORCE_DISABLE_LTO=ON \
  -DCMAKE_POSITION_INDEPENDENT_CODE=ON \
  -DWASMEDGE_LINK_LLVM_STATIC=ON \
  -DWASMEDGE_BUILD_PLUGINS=OFF \
  -DWASMEDGE_LINK_TOOLS_STATIC=ON \
  .. && \
make -j$(sysctl -n hw.logicalcpu) && \
sudo make install

Clone the repository

mkdir ~/projects && \
cd ~/projects && \
git clone https://github.com/Xahau/xahaud.git && \
cd xahaud && \
git checkout dev

Build Xahaud

From the root xahaud directory:

mkdir build && \
cd build && \
cmake -DCMAKE_BUILD_TYPE=Debug -DLLVM_DIR=$LLVM_DIR -DLLVM_LIBRARY_DIR=$LLVM_LIBRARY_DIR .. && \
cmake --build . --target rippled --parallel -j$(sysctl -n hw.logicalcpu)

Start the built node

./rippled
GitHub - Xahau/mainnet-docker: Xahau mainnet (network ID 21337) Docker container (x86_64)GitHub

Weak and Strong

Which Hooks are allowed to run and when?

👍 Hook Design Philosophy

Every party affected by a transaction should have the opportunity to have their Hooks executed.

Transactional Stake Holders (TSH) are parties that somehow have a stake in or are otherwise affected by a transaction. Their particular stake may be a weak or strong. The degree of connection with the transaction dictates whether the party has the right to have their Hooks executed and who has to pay for that execution.

For example:

  • In a conventional direct XAH Payment transaction the two TSH are the originating account and the destination account.

  • In a SetSignerList transaction the TSH are the originating account and each account whose address appears in the signer list, where such accounts are active on the ledger.

  • In an OfferCreate transaction, other account's offers which are crossed by the originating transaction are all weak TSH and may opt for weak execution.

Due to the heterogenous nature of transactions on Xahau, TSH come in all shapes and sizes and can be exotic and non-intuitive. This becomes more true as time passes and more transaction types are added to the Ledger.

Weak and Strong

Each TSH has either a weak or a strong connection to the transaction.

A Strong connection means:

  1. The originating transaction must pay the fee for the execution of the TSH Hook Chain

  2. The TSH has the right to rollback the whole transaction by calling rollback() from their Hook during execution.

A Weak connection means:

  1. The originating transaction does not pay for the execution of the TSH Hook Chain.

  2. The TSH pays for the execution of their own Hook Chain through a feature called Collect Call Hooks.

  3. The TSH must have set an account flag asfTshCollect prior to the execution of the originating transaction.

  4. The TSH does not have the right to rollback the whole transaction by calling rollback() from their Hook during execution (but can still modify their own Hook state and Emit transactions.)

Before or After

Strong TSHes have their hooks executed before the originating transaction is applied to the ledger. This means they have the ability to rollback the transaction (because it hasn't yet been applied.) This gives strongly executed hooks the ability to completely block a transaction from occurring.

Weak TSHes have their hooks executed after the originating transaction has been applied to the ledger. This means they have access to the transaction metadata but cannot prevent the transaction from occurring.

📘 Hint

Strongly executed hooks can call hook_again to be executed a second time as a weak execution after the originating transaction has been applied.

Execution Context

The uint32_t parameter in hook(uint32_t) and cbak(uint32_t) carries important context information from the Hooks Amendment to your Hook.

During the execution of hook:

  • 0 means the Hook is being executed strongly

  • 1 means the Hook is being executed weakly

  • 2 means the Hook is being executed weakly after being executed strongly due to a hook_again call.

During the execution of cbak:

  • 0 means the Hook is being called back after a transaction it emitted was successfully accepted into a ledger.

  • 1 means the Hook is being called back after a transaction it emitted was marked as never able to be applied to any ledger (EmitFailure).

Reference Table

If a Transaction Type does not appear in the table then it has no TSHes other than its originating account.

Transaction Type
TSH Type
Who is the TSH

AccountDelete

Strong

Destination account funds are paid out to after deletion

AccountSet

None

N/A

CheckCancel

Weak

Destination account

CheckCash

None

N/A

CheckCreate

Strong

Destination account

ClaimReward

Strong

Issuer Account

DepositPreauth

Strong

Authorized account

EscrowCancel

Weak

Destination account

EscrowCreate

Strong

Destination account

EscrowFinish

Strong

Destination account

GenesisMint

Weak

Each Destination in the GenesisMints Array

Import

Strong

Issuer Account

Invoke

Strong

Destination account

OfferCancel

None

N/A

OfferCreate

Weak

Accounts whose offers were crossed by this action.

Payment

Strong + Weak

Strong: Destination account. Weak: Any non-issuer the payment is rippled through.

PaymentChannelClaim

Weak

Destination account

PaymentChannelCreate

Strong

Destination account

PaymentChannelFund

Weak

Destination account

SetHook

None

N/A

SetRegularKey

Strong

The account whose address is being set as the key.

SignerListSet

Strong

Accounts whose addresses are set as signing keys (if they exist and have Hooks set on them).

TicketCreate

None

N/A

TrustSet

Weak

Issuer account

URITokenCancelSellOffer

None

N/A

URITokenCreateSellOffer

Strong

Destination account, Issuer if tfBurnable Flag is set

URITokenBurn

Strong

Issuer if tfBurnable Flag is set

URITokenBuy

Strong

Owner account, Issuer if tfBurnable Flag is set

URITokenMint

None

N/A

AccountSet

OTXN
TSH
AccountSet

Account

Account

Strong

AccountDelete

OTXN
TSH
AccountDelete

Account

Account

None

Account

Beneficiary

Strong

Check

OTXN
TSH
CheckCancel
CheckCreate
CheckCash

Account

Account

Strong

Strong

None

Account

Destination

Weak

Strong

None

Destination

Destination

Strong

None

Strong

Destination

Account

Weak

None

Weak

ClaimReward

OTXN
TSH
ClaimReward

Account

Account

Strong

Account

Issuer

Strong

DepositPreauth

OTXN
TSH
DepositPreauth

Account

Account

Strong

Account

Authorized

Strong

Escrow

OTXN
TSH
EscrowCancel
EscrowCreate
EscrowFinish

Account

Account

Strong

Strong

Strong

Account

Destination

Weak

Strong

Weak

Destination

Destination

Strong

None

Strong

Destination

Account

Weak

None

Weak

GenesisMint

OTXN
TSH
GenesisMint

Account

Account

Strong

Account

Destination

Strong

Account

Beneficiary

Weak

Import

OTXN
TSH
Import

Account

Account

Strong

Account

Issuer

Strong

Invoke

OTXN
TSH
Invoke

Account

Account

Strong

Account

Destination

Weak

Offer

OTXN
TSH
OfferCancel
OfferCreate

Account

Account

Strong

Strong

Account

Crossed

None

Weak

Payment

OTXN
TSH
Payment

Account

Account

Strong

Account

Destination

Strong

Account

Crossed

Weak

PaymentChannel

OTXN
TSH
PaymentChannelClaim
PaymentChannelCreate
PaymentChannelFund

Account

Account

Strong

Strong

Strong

Account

Destination

Weak

Strong

Weak

Destination

Destination

Strong

None

None

Destination

Account

Weak

None

None

SetHook

OTXN
TSH
SetHook

Account

Account

Strong

SetRegularKey

OTXN
TSH
SetRegularKey

Account

Account

Strong

Account

RegularKey

Strong

SignersListSet

OTXN
TSH
SignerListSet

Account

Account

Strong

Account

Signer

Strong

Ticket

OTXN
TSH
TicketCreate

Account

Account

Strong

TrustSet

OTXN
TSH
TrustSet

Account

Account

Strong

Account

Issuer

Weak

URIToken

OTXN
Burnable
TSH
Mint
Burn
Buy
Sell
Cancel

Owner

False

Owner

None

Strong

Strong

Strong

Strong

Owner

False

Issuer

None

Weak

Weak

Weak

None

Owner

False

Buyer

None

None

None

Strong

Weak

Owner

True

Buyer

None

None

None

Strong

Weak

Owner

True

Owner

None

Strong

Strong

Strong

Strong

Owner

True

Issuer

None

Weak

Strong

Strong

None

Issuer

False

Owner

None

None

None

None

None

Issuer

False

Issuer

Strong

None

None

None

None

Issuer

False

Buyer

Weak

None

None

None

None

Issuer

True

Owner

None

Weak

None

None

None

Issuer

True

Issuer

Strong

Strong

None

None

None

Issuer

True

Buyer

Weak

None

None

None

None

Buyer

True

Buyer

None

None

Strong

None

None

Buyer

True

Owner

None

None

Weak

None

None

Logo