Skip to content

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) to 9999999999999999 (maxMantissa). Non-zero values are always normalized to this width.
  • Exponent-96 (minExponent) to 80 (maxExponent).
  • Zero — represented by the literal int64_t value 0 (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

FunctionPurpose
float_setBuild an XFL from an exponent and mantissa.
float_oneThe XFL constant 1.0.
float_mantissaExtract the mantissa of an XFL.
float_signExtract the sign of an XFL.
float_negateFlip the sign of an XFL.
float_sumAdd two XFLs.
float_multiplyMultiply two XFLs.
float_mulratioMultiply an XFL by an integer ratio (numerator/denominator).
float_divideDivide one XFL by another.
float_invertReciprocal 1/x of an XFL.
float_compareCompare two XFLs (equal / less / greater).
float_logBase-10 logarithm of an XFL.
float_rootn-th root of an XFL.
float_intConvert an XFL to a scaled integer.
float_stoSerialize an XFL into an Amount STO field.
float_sto_setParse an Amount STO back into an XFL.
  • ../../xfl — the XFL format explainer: bit encoding, valid range, and relationship to the ledger's Amount format.
  • ../../README — documentation index.
  • ../../overview — hook execution model.
  • ../../glossary — full error-code and term reference (including the INVALID_FLOAT = -10024 and XFL_OVERFLOW entries).
  • ../../macrosAMOUNT_TO_DROPS, SBUF, TRACEXFL, and the field-code helpers.
  • ../../best-practices — validating amounts and avoiding precision surprises.
  • transactionotxn_field for reading the sfAmount field.
  • ledger-and-slotslot_float reads a slotted amount directly as an XFL.
  • emit-and-etxn — building the amounts you serialize into emitted transactions.
  • utilitysto_subfield and the other STO helpers.
  • ../../examples/payment-filter — a threshold-check hook end to end.