Key flows
These sequence diagrams show how a request travels across the web app, gateway, services, database, and chain. They are the fastest way to understand the system.
1. Login (SIWE → JWT)
Wallet‑based sign‑in. Privy provides the embedded wallet; the user proves ownership by signing a nonce; the backend issues a short‑lived access token plus a rotating refresh token.
sequenceDiagram
actor U as User
participant W as Web app
participant P as Privy
participant GW as Gateway
participant A as auth service
participant DB as Postgres
U->>W: Sign in (Google / email)
W->>P: Authenticate → embedded wallet (HD index 0)
W->>GW: GET /auth/nonce/:address
GW->>A: (public route)
A->>DB: store Nonce (single-use, short TTL)
A-->>W: nonce
W->>P: sign SIWE message(nonce)
W->>GW: POST /auth/login {address, signature}
GW->>A: (public route)
A->>A: verify signature, consume nonce (race-safe)
A->>DB: upsert User + Personal Profile
A-->>W: access JWT (~2h) + refresh token
W->>W: store token; load profiles
Note over W,GW: Every later call sends Authorization: Bearer <jwt><br/>and X-AXON-Profile-Id for the active profile
When the access token expires, the web app calls POST /auth/refresh; refresh tokens are single‑use and rotated (re‑using an old one revokes the family — reuse detection).
2. Agreement lifecycle (escrow)
A milestone agreement between two parties, custodied on‑chain. The pattern throughout is prepare → sign client‑side → confirm against chain.
sequenceDiagram
actor S as Sender
actor R as Recipient
participant W as Web app
participant GW as Gateway
participant AG as agreements
participant ES as AXONEscrow (Base)
participant SE as settlements
participant DB as Postgres
S->>W: Create agreement (milestones, terms)
W->>GW: POST /agreements → AG
AG->>DB: draft Agreement (+ AI-drafted contract)
S->>ES: sign createAgreement(...)
W->>GW: POST /agreements/:id/confirm (txHash)
AG->>ES: verify tx, read onChainId
AG->>DB: Agreement ACTIVE (draft) → store onChainId
R->>ES: sign acceptAgreement(id)
W->>GW: confirm → AG marks accepted
S->>ES: approve USDC + sign fundMilestone(id, i)
W->>GW: confirm → AG
AG->>DB: Milestone FUNDED + Transaction(ESCROW_FUND)
AG->>SE: record settlement (ESCROW_FUND)
R->>ES: sign markMilestoneComplete(id, i)
Note over ES: starts 5-day permissionless-release timeout
S->>ES: sign releaseMilestone(id, i)
W->>GW: confirm → AG
AG->>DB: Milestone RELEASED + Transaction(ESCROW_RELEASE)
AG->>SE: record settlement (ESCROW_RELEASE → recipient)
- Disputes freeze the agreement; either party can
raiseDispute, thenproposeResolution(recipientBps)and the otheracceptResolutionto split the funded pot. - After 5 days from "mark complete", anyone can trigger release (permissionless timeout), so funds can't be held hostage.
3. Instant Funding (coverage → payout → sweep)
A business with an active facility is paid the moment value lands, rather than waiting for fiat to clear. The collectionStatus dimension (added recently) ensures AXON actually collects the USDC it fronted.
sequenceDiagram
participant CW as CoverageWatcher (30s)
participant ES as USDC (Base)
participant FUND as funding
participant LY as Lydiam (fiat)
participant SW as CollectionSweeper
participant COLL as Collection wallet
participant SE as settlements
participant DB as Postgres
Note over CW,ES: business wallet has an ACTIVE facility
ES-->>CW: USDC Transfer → business wallet
CW->>FUND: coverInbound(tx) (idempotent on tx id)
FUND->>DB: FundingCoverage (status COVERED, collectionStatus PENDING)
FUND->>SE: record settlement (INSTANT_FUNDING)
FUND->>LY: pay business in fiat (simulation today)
LY-->>FUND: payout SETTLED → coverage status SETTLED
loop every 30s until collected
SW->>ES: check allowance + balance
alt authorised & funded
SW->>ES: transferFrom(business → collection)
SW->>COLL: USDC collected
SW->>DB: coverage collectionStatus = COLLECTED + CollectionLedgerEntry (IN)
else not yet authorised / insufficient
SW->>DB: leave PENDING, retry next pass (logs reason)
end
end
A coverage is only fully settled when the fiat side is SETTLED and collectionStatus = COLLECTED. Stranded sweeps (business hasn't authorised the facility, or wallet underfunded) are retried automatically until they clear, or flagged UNCOLLECTABLE for manual reconciliation.
4. Distribution → settlement
A batch payout split across corridors; each route settles independently and writes to the ledger.
sequenceDiagram
actor B as Business
participant W as Web app
participant DIST as distributions
participant RR as Ramp router (vendors)
participant SE as settlements
participant REC as reconciliation (30s)
B->>W: Plan distribution (corridors, amounts)
W->>DIST: POST /distributions
DIST->>RR: quote/auto-pick best vendor per route
DIST->>DIST: routes PLANNED
loop per route
DIST->>RR: start route (off-ramp)
RR-->>DIST: running → completed
DIST->>SE: record settlement (DISTRIBUTED_ROUTE)
end
REC->>DIST: reconcile stuck/stale routes (heal or alert)
Every settlement (escrow, distribution, instant funding) lands in the same hash‑chained ledger, whose head is periodically anchored to Base — see Data & on‑chain layer.