Skip to content
Warrantv0.1

Stablecoin rails

Three assets have decimals defined. Custody is a Postgres ledger, not a chain.

USDC, USDT and ETH have decimal precision defined in the SDK. Settlement itself is a double-entry Postgres ledger — no stablecoin moves onchain today.

const DECIMALS = { USDC: 6, USDT: 6, ETH: 18 };

Custody is a ledger, not a rail

Money in Warrant moves between four accounts in Postgres: available, held, payee and external. Every movement is grouped by a tx_ref and every tx_ref must net to zero.

There is no onchain transfer, no token contract and no bridge. Trace anchoring against Rialo testnet is real — see Rialo — but that anchors the record, not the money. Do not read "USDC" here as an ERC-20 balance you could withdraw to a wallet.

What "asset" means today

asset is a string on the warrant, defaulting to "USDC". It selects decimal precision and labels the ledger entries. It does not select a settlement network, because there is only one settlement mechanism.

AssetDecimalsSmallest unit
USDC61 = 0.000001 USDC
USDT61 = 0.000001 USDT
ETH181 wei

An asset outside this list has no defined precision. The SDK's decimalsFor throws rather than guessing, because guessing wrong by three orders of magnitude is worse than failing.

Why 6 decimals matters for your integers

A 64-bit signed integer holds about 9.2×10^18. At 6 decimals that is roughly 9.2 trillion USDC, which is comfortable. At 18 decimals — ETH — it is about 9.2 ETH, which is not.

"8400000"              8.40 USDC          fine
"9200000000000000000"  9.2 ETH            at the edge of int64

This is why amounts are strings on the wire rather than JSON numbers. A double loses precision above 2^53, which at 6 decimals is around 9 billion USDC — and it does not survive a round trip through JSON.parse.

"8400000"    8.40 USDC
8400000      rejected — a JSON number
"8.40"       rejected — not the smallest unit

Validated against ^[0-9]+$ at the API boundary.

Deposits and withdrawals

The external ledger account is where funds enter and leave. In sandbox, balances are seeded directly. There is no deposit address, no withdrawal endpoint in the public API, and no onchain movement behind either.

What onchain settlement would need

So the gap is concrete:

  • a custody contract holding funds per organisation
  • a signer able to authorise a release, without becoming a key that can drain the pool
  • a mapping from tx_ref to an onchain transaction, both directions
  • reconciliation between the ledger and chain state, and a decision about which wins when they disagree
  • an answer to who pays network fees — see fees, which is also undecided

RialoLedger is written and requires an injected custody implementation by design; today that is the Postgres ledger. It anchors traces and delegates custody, and it does not pretend otherwise.