Skip to content
Testnet only: a reference implementation, not a production service.Tokens and bank transfers here are simulated and have no value.

Transfers and states

A transfer is one request to move value. There are three public kinds, plus one internal kind:

  • Mint — fiat arrives from the bank, and tokens are delivered to the organisation's wallet.
  • Redeem — tokens arrive from a holder, and fiat is paid out to the organisation's registered bank account.
  • On-chain — fiat the organisation already holds is delivered to a registered wallet as tokens. No new supply is created.
  • Treasury — an internal top-up of the distribution account's buffer. It is never returned by the public API.

Each transfer is one row with one state. States only move forward. An illegal move is refused with state_conflict, and a state that is terminal never changes again.

The state machine

Every kind follows its own chain of states. Read each row as "from this state, the transfer can move to these states".

FromAllowed moves
awaiting_fundsfunds_received (mint), tokens_received (redeem)
funds_receivedreserve_check
reserve_checksubmitted (mint and treasury)
tokens_receivedburn_submitted
burn_submittedburned
burnedpayout_initiated
payout_initiatedcompleted
createdsubmitted (on-chain)
submittedcompleted

The full chains are:

KindChain
Mintawaiting_funds → funds_received → reserve_check → submitted → completed
Redeemawaiting_funds → tokens_received → burn_submitted → burned → payout_initiated → completed
On-chaincreated → submitted → completed
Treasuryreserve_check → submitted → completed

From any state that isn't terminal, a transfer can also stop with one of the exceptions: returned, failed, canceled or expired. completed is the normal end; the exceptions are the other ends. A receipt placed in suspense never moves a transfer into a state of its own: the suspense item is a separate record, and attribution funds or resumes the waiting transfer through its normal path.

A mint that fails its reserve check stays in reserve_check with the reason insufficient_reserve_headroom. It waits there until headroom appears or someone cancels it.

For a redeem, the payout happens only after the burn is confirmed. Tokens are destroyed first, then fiat leaves.

One hash per transfer

The public transfer carries a single stellar_tx_hash: the delivery for a mint, the burn for a redeem, or the payment for an on-chain transfer. A treasury top-up behind a mint has its own hash, but the public transfer still reports the delivery.

Working with transfers

Reads hide other organisations' transfers, and treasury transfers, as a 404.

Edit on GitHub