Appearance
Float and Amount APIs
This page documents the sixteen float-and-amount Hook APIs: the float_* family that lets a hook do arbitrary-precision decimal arithmetic on token amounts and serialize the result into (or read it out of) the ledger's Amount format.
All function signatures on this page match the Hook API. Return codes reference the shared error table in ../../glossary, and the descriptions below reflect the API's behavior.
What an XFL is
For the full format explainer (bit layout, valid range, relationship to the ledger's Amount encoding), see ../../xfl. This section covers just enough to read the function reference below.
An XFL (the hooks floating-point format) is a single int64_t that encodes a decimal number the same way the ledger encodes IOU (token) amounts: a sign, a normalized mantissa, and a base-10 exponent. Its valid ranges are fixed:
- Mantissa — exactly 16 significant digits:
1000000000000000(minMantissa) to9999999999999999(maxMantissa). Non-zero values are always normalized to this width. - Exponent —
-96(minExponent) to80(maxExponent). - Zero — represented by the literal
int64_tvalue0(the one XFL with no mantissa).
A value's XFL bit-pattern is a positive int64_t; the number's own sign lives inside that encoding, not in the sign of the int64_t. As a result any negative int64_t is not a valid XFL — passing one (for example -1) returns INVALID_FLOAT. This is why the "invalid float" sentinel has the unusual value INVALID_FLOAT = -10024 (deliberately not -24): it is a number chosen so it can never itself be mistaken for a valid XFL or a valid exponent. Most functions on this page validate their XFL arguments up front and return -10024 if the argument does not decode to a legal mantissa/exponent.
Because XFLs are opaque encoded integers, you never read the mantissa or exponent by shifting bits yourself — use float_mantissa, float_sign, and the arithmetic functions. To move a value between XFL form and the ledger wire format, use float_sto / float_sto_set. To turn an XFL into a plain integer (e.g. drops), use float_int.
Working with amounts: reading and comparing
Two idioms cover almost every hook that inspects a transaction amount.
1. Native XAH via AMOUNT_TO_DROPS. When the amount is native, the sfAmount field is 8 bytes of drops. The AMOUNT_TO_DROPS macro decodes those bytes to an integer number of drops without going through XFL at all — cheaper when you only need an integer comparison:
c
// Reject a native Payment below 10 XAH (10,000,000 drops).
uint8_t amt[48];
int64_t len = otxn_field((uint32_t)amt, sizeof(amt), sfAmount); // sfAmount = (6<<16)|1
if (len != 8)
rollback(SBUF("expected a native amount"), 1); // 8 bytes == native XAH
int64_t drops = AMOUNT_TO_DROPS(amt); // negative on error
if (drops < 0 || drops < 10000000LL)
rollback(SBUF("amount too small"), 2);
accept(SBUF("ok"), 0);2. IOU via float_sto_set + float_compare. For a token amount, decode the serialized Amount field into an XFL and compare against an XFL threshold:
c
// Reject an IOU Payment below a 100.0 threshold.
uint8_t amt[48];
int64_t len = otxn_field((uint32_t)amt, sizeof(amt), sfAmount);
if (len != 48)
rollback(SBUF("expected an IOU amount"), 1); // 48 bytes == IOU (8 + 20 + 20)
int64_t value = float_sto_set((uint32_t)amt, len);
int64_t threshold = float_set(0, 100); // 100.0
if (float_compare(value, threshold, COMPARE_LESS) == 1)
rollback(SBUF("amount below threshold"), 2);
accept(SBUF("ok"), 0);Percentage calculation. To take a percentage of an amount — for a fee, a reward split, etc. — scale the XFL with float_mulratio:
c
// Compute a 1.5% fee on an XFL amount, rounded down (15 / 1000).
int64_t fee = float_mulratio(amount, 0, 15, 1000);
if (fee < 0)
rollback(SBUF("fee calc failed"), fee);The number of bytes returned by otxn_field for sfAmount distinguishes the two cases at runtime: 8 for native XAH, 48 for an IOU (8-byte amount + 20-byte currency + 20-byte issuer).
Index
| Function | Purpose |
|---|---|
float_set | Build an XFL from an exponent and mantissa. |
float_one | The XFL constant 1.0. |
float_mantissa | Extract the mantissa of an XFL. |
float_sign | Extract the sign of an XFL. |
float_negate | Flip the sign of an XFL. |
float_sum | Add two XFLs. |
float_multiply | Multiply two XFLs. |
float_mulratio | Multiply an XFL by an integer ratio (numerator/denominator). |
float_divide | Divide one XFL by another. |
float_invert | Reciprocal 1/x of an XFL. |
float_compare | Compare two XFLs (equal / less / greater). |
float_log | Base-10 logarithm of an XFL. |
float_root | n-th root of an XFL. |
float_int | Convert an XFL to a scaled integer. |
float_sto | Serialize an XFL into an Amount STO field. |
float_sto_set | Parse an Amount STO back into an XFL. |
Related documents
- ../../xfl — the XFL format explainer: bit encoding, valid range, and relationship to the ledger's
Amountformat. - ../../README — documentation index.
- ../../overview — hook execution model.
- ../../glossary — full error-code and term reference (including the
INVALID_FLOAT = -10024andXFL_OVERFLOWentries). - ../../macros —
AMOUNT_TO_DROPS,SBUF,TRACEXFL, and the field-code helpers. - ../../best-practices — validating amounts and avoiding precision surprises.
- transaction —
otxn_fieldfor reading thesfAmountfield. - ledger-and-slot —
slot_floatreads a slotted amount directly as an XFL. - emit-and-etxn — building the amounts you serialize into emitted transactions.
- utility —
sto_subfieldand the other STO helpers. - ../../examples/payment-filter — a threshold-check hook end to end.