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, then proposeResolution(recipientBps) and the other acceptResolution to 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.

results matching ""

    No results matching ""