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.
| Asset | Decimals | Smallest unit |
|---|---|---|
USDC | 6 | 1 = 0.000001 USDC |
USDT | 6 | 1 = 0.000001 USDT |
ETH | 18 | 1 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 int64This 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 unitValidated 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_refto 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.