Key flows
Issuance, buying and the transaction lifecycle.
Reserve and issuance
Two layers must agree: staff approval in the app, then the human signature on-chain. The backend holds no key that can issue.
sequenceDiagram actor RM as Reserve Manager actor RA as Reserve Approver actor TO as Treasury Operator participant P as Dara actor H as Human signer participant S as Stellar RM->>P: Record backing and attestation RA->>P: Approve (a different person) TO->>P: Request issuance P->>P: Check limit against backing and supply RA->>P: Approve issuance P->>P: Check again and build proposal, valid 24 h H->>P: Copy envelope from Signing H->>H: Decode and check H->>P: Upload signature only P->>S: Submit S-->>P: Applied in a closed ledger P->>P: Post to ledger and reconcile
Buying GOLD
sequenceDiagram actor C as Customer participant A as API participant L as Ledger participant W as Worker participant S as Stellar C->>A: Request quote A-->>C: Firm price for 30 s C->>A: Confirm A->>A: Gate open, customer active, price fresh, within limits A->>L: Hold cash and hot float A->>W: Intent W->>W: Lease channel, build envelope, sign with Vault W->>S: Payment from hot Treasury to customer S-->>W: Applied W->>L: Settle A-->>C: Completed, with transaction hash
If the transaction fails or expires, each hold is reversed exactly once.
Transaction lifecycle
A timeout is unknown, never failed. An unknown attempt isn't rebuilt until it's proven expired against a closed ledger, so a lost response can't pay twice.
stateDiagram-v2 [*] --> CREATED CREATED --> SIGNED CREATED --> AWAITING_SIGNATURES: human proposal AWAITING_SIGNATURES --> SIGNED: enough signature weight AWAITING_SIGNATURES --> EXPIRED SIGNED --> SUBMITTED SIGNED --> UNKNOWN: timeout SIGNED --> REJECTED SUBMITTED --> UNKNOWN UNKNOWN --> SUBMITTED: resend identical envelope SUBMITTED --> APPLIED SUBMITTED --> FAILED UNKNOWN --> APPLIED UNKNOWN --> FAILED UNKNOWN --> EXPIRED: proven against a closed ledger EXPIRED --> [*] APPLIED --> [*] FAILED --> [*]
The trading gate
flowchart LR
a["No healthy RPC node"] --> G{"Trading gate"}
b["Latest ledger too old"] --> G
c["Signer unavailable"] --> G
d["FUNDER below critical floor"] --> G
e["Too many unknown attempts"] --> G
f["Critical incident that blocks trading"] --> G
G -->|"all clear"| O["Open"]
G -->|"any failure"| X["Closed: reads continue"]
The rules behind these flows: invariants, ledger model.