Before she starts
Amina is a Tier 2 account: passport, proof of address and selfie verified. Her per-transfer ceiling is €15,000 and all rails are available to her. She holds a EUR virtual account with a German IBAN, funded by salary transfer. Her mother is not an Arc customer. She is a beneficiary: an M-Pesa MSISDN Amina saved earlier, screened at the moment it was added and screened again on every transfer.Beneficiaries being screened at use rather than only at creation matters: sanctions lists change, and a beneficiary added six months ago may not be clear today.
The flow
Step by step
1
Quote: the price, and its expiry
Service: Movement · Amina sees: send €1,000.00, receive KES 138,254.00, with the €4.85 corridor fee and €6.06 FX margin shown as separate lines rather than folded into the rate.The quote expires in 30 seconds. Rates move; honouring a stale quote is an unhedged loss, and
QuoteEngine.quoteassertUsable throws on an expired one. The quote that aged →2
Compliance: the gate
Service: Risk ·
ScreeningService.screenTransferThree checks compose into one verdict:- Tier: €1,000 is inside her €15,000 Tier 2 ceiling, and mobile money is an allowed rail. Pass.
- Sanctions: sender legal name and beneficiary name screened by Jaro–Winkler against the synthetic list, including aliases. No match above threshold.
- AML: five rule families evaluated against her history. Monthly €1,000 transfers to the same beneficiary on the same corridor score low on velocity, low on structuring, zero on unusual corridor. Counterparty concentration is high, she sends to one person, but below the minimum count and window thresholds.
approved, risk score 12, no case opened. compliance.decided is published with the score and an empty reasons array.Had this returned
rejected or review, the saga would stop here: before reserve, before any money moves at all.3
Reserve: take the money and the fees
Service: Movement → Ledger ·
kind: transferArc now owes Amina €1,000 less. €989.09 sits in in-transit, committed but not yet paid out, and €10.91 has become revenue in two separately named accounts.Her balance would be rejected here if it could not fund the transfer:
reserve fails on the overdraft floor and nothing moves.4
Swap: a EUR obligation becomes a USDC asset
Service: Movement → Ledger ·
kind: fxTwo currencies, each balancing independently. Neither half references the other: the position accounts are the bridge, and the standing balance they now carry is Arc’s open FX exposure on this transfer.
5
Settle: pick a chain, broadcast, wait for finality
Service: Movement + Broadcast with an idempotency key derived from the transfer id, so a retry cannot double-send. Then, and this is the step that is easy to get wrong, the transaction is re-read and required to be
packages/chainselectChain scores the available chains on settlement time and fee. With a high speed preference this picks Base: 2-second blocks, 10 confirmations, a ~20-second settlement window. Polygon would have been cheaper and would have taken 256 seconds. Why →Why not Solana, which is faster still? On settlement time alone it wins: ~13 seconds against Base’s 20. It loses here on its drop rate, the highest in the set, because Solana transactions expire rather than waiting in a mempool.The trade inverts for a larger or more urgent transfer, and it is worth being precise about what a Solana drop actually costs. The transaction becomes permanently invalid rather than ambiguously pending, so the saga gets a definite answer and can retry cleanly with a fresh blockhash. A frequent, unambiguous failure is cheaper to handle than a rare, ambiguous one.
final, not merely submitted without error.Plus a separate, never-reversed journal for the gas actually spent:
settlement.confirmed is published with the chain, transaction hash, confirmation count and network fee.6
Payout: discharge the obligation on the local rail
Service: Movement ·
SimulatedRail (mpesa)M-Pesa is an instant rail with no cut-off, and the highest timeout rate of the six Arc simulates. Submitted with Amina’s transfer id as the idempotency key: resubmitting returns the original receipt rather than paying twice. The payout that paid twice →Float down, obligation gone.
7
Notify
transfer.settled is published. The notifications service consumes it and sends Amina a confirmation. Her mother’s phone shows an M-Pesa credit.Elapsed: roughly 25 seconds, dominated by the chain’s 20-second finality window.The state afterwards
Every intermediate account is back to zero. Arc kept €10.91 in gross revenue against a real gas expense, and the trial balance is zero in EUR, KES, USDC and ETH independently.
What it cost her
€10.91 on €1,000 is 1.09%, against a World Bank average of 8.78% for this region, and that comparison is fair only up to a point. Arc’s figure excludes the cost of the KES float that made instant payout possible, and the last-mile distribution economics are absorbed by M-Pesa rather than eliminated. Why corridors cost so much takes that apart honestly.If something had failed
Any step after compliance failing triggers compensation, walking completed steps backwards:
In every case the ledger ends balanced, Amina’s balance is exactly €1,000.00, and every intermediate account returns to zero. That is asserted by the chaos suite at each of the five steps.
Enterprise payout
The same rails, a different surface: NGN in, SEPA Instant out, with maker–checker.
A reversal, in full
What the table above looks like as actual compensating entries.