مستندات دارا
مرجع فنیشواهد آزمونشواهد
این صفحه فقط به انگلیسی موجود است.

Evidence: business modules, indexer and reconciliation end to end on local Stellar (Stage 14 parts 4–5)

Date: 2026-10-30. Network: Quickstart --local, protocol 30. Database: PostgreSQL 17.6. Command:

TEST_DATABASE_URL=… STELLAR_RPC_URL=http://localhost:8000/rpc REQUIRE_INTEGRATION=1 \
  go test -count=1 -race ./internal/e2e/

Result: PASS (-race, 43 s; part 4 alone: 32 s). The full backend suite (go test ./..., including the 7 transaction-manager tests) also passes after the handler-routing change.

TestPlatformLifecycle uses the production signer layout (issuer H1–H4 ×10 + AUTH ×1, thresholds 1/20/30; COLD T1–T4; HOT and SPONSOR online keys; FUNDER) and the real services, wired as the application will wire them. After each money-moving step it compares every on-chain balance (COLD, HOT, each customer) with its ledger position, and the on-chain total with TOKEN_SUPPLY.

StepProves
Register the COLD account as issuerRefused: ceremony.Verify finds signers/thresholds/flags that do not match the issuer layout
Register the real issuer, activateTreasury trustlines authorized by AUTH through the engine; activation refused without a unit definition (Q-04), then ACTIVE after on-chain verification
KYC approval ×2One sponsored transaction per customer; account ACTIVE; trustline authorized on-chain
Reserve propose / approveThe proposer's role cannot approve; four-eyes approval makes the snapshot EFFECTIVE
ISSUE 1000.001, then 1000Above backing refused (capacity_exceeded); within backing: four-eyes, then H1 + H3 sign; COLD = 1000 on-chain and in the ledger
REFILL 600, then sweepT2 + T4 sign COLD → HOT; the automatic sweep returns 500 (HOT 600 > ceiling 500, down to target 100)
Price, deposit, gateMaker-checker price and deposit; gate opens with every Stellar condition healthy
BUY 150, then BUY 10Above the HOT float refused before anything is signed (insufficient_treasury_inventory); BUY 10 settles
TRANSFER 3, SELL 1Customer-to-customer and customer-to-HOT payments signed by CUSTODY; bob = 2 on-chain
Freeze, unfreezeQuotes refused at once (account_frozen); trustline unauthorized on-chain; the requester cannot approve the unfreeze (self_approval); a second officer can, and the trustline is authorized again
BURN 200T1 + T3 sign COLD → issuer; supply 800 on-chain and in the ledger
Transfer to a trustline revoked behind the platform's backFails in the ledger (NOT_AUTHORIZED); order FAILED, alice's hold released, ledger still equals the chain
Reconciliation after the lifecycle (part 5)Indexer caught up from before the ceremony; every check PASS from one node at one ledger (recorded on the run); every indexed movement is linked to an intent; the ceremony's own setup transactions open no authority incident
Same trustline revocationtrustline_states_match FAILs (business view ACTIVE, chain unauthorized); after re-authorizing, all PASS
HOT key used outside the platform (no memo)Indexer: CRITICAL UNEXPLAINED_TOKEN_MOVEMENT, trading blocked. Reconciliation: exactly the HOT and alice balance checks FAIL; supply unchanged (a transfer)
CHANNEL key used to add a signerIndexer: CRITICAL UNEXPECTED_AUTHORITY_CHANGE
A third party deploys the asset's SACIndexer: WARNING SAC_DEPLOYED (no block)

Not covered here (later parts): a claimable balance, liquidity pool or SAC contract balance actually created in our asset (the platform's accounts cannot create one, and an outsider cannot hold the asset: it would need the leaked AUTH key first), the data-lake backfill source against a real bucket, stellar.toml on a non-local network, HTTP API and RBAC at the edge, and fault injection for the business handlers (RECONCILIATION_REQUIRED parking).

Binary smoke run (Stage 14 part 6)

The real dara binary against Quickstart and a fresh PostgreSQL database, driven with curl:

StepResult
dara migrate7 migrations applied
dara bootstrap-local (GOLD, 2 + 1 channels)Issuer, COLD, HOT, sponsor, funder and channels created with the production layouts; manifest written. Never overwrites a manifest: one that matches the chain is a no-op (part 7), one that does not is an error
dara allStartup verifies every manifest account's layout on-chain and registers it; /readyz ready; gate opens after the hold-down; restart against the same manifest and database is clean
Admin bootstrap, TOTP enrollment, loginMFA-pending session until TOTP is confirmed; then full session
Asset over the API: create → register-issuer → unit-definition → activateDRAFT → CONFIGURING → ACTIVE, with the Treasury trustlines authorized by the running worker
Manual reconciliation runPASS, recording node local and the ledger read; indexer 0 ledgers behind
Customer register / login on the public listenerKYC PENDING; assets listed
Staff email + right password on the public listenerBefore the fix: mfa_required (account and password confirmed). After: unauthenticated, identical to a wrong password or an unknown email (TestStaffLoginOnCustomerListenerRevealsNothing)

make demo in containers (Stage 14 part 7)

make demo on rootless Podman (docker-compose v5): Stellar Quickstart --local, PostgreSQL, migrate, bootstrap (the ceremony with stand-in human signers), worker, api, api-admin, then dara demo. Staff and customers act through the customer and admin HTTP APIs; the stand-in signers verify each proposal's envelope (network, and that the hash shown is the hash of the envelope) before signing, and upload signatures through POST /v1/admin/treasury/proposals/{id}/signatures, as people would.

StepChecked against chain, ledger and API
1GOLD created, the manifest's issuer registered, unit definition set, activated once the worker authorized the COLD and HOT trustlines
2Reserve snapshot of 1,000,000 g proposed and approved by two people: EFFECTIVE
3–4ISSUE 1,000,000 to COLD (four-eyes + 2 of 4 issuer signers), REFILL 1,000 to HOT (four-eyes + 2 of 4 Treasury signers)
5Supply 1,000,000 on-chain and in the ledger; COLD 999,000 and HOT 1,000 on both
6–8User A registered, KYC → sponsored account with an authorized trustline, funded; BUY 100 from HOT; amounts to the unit
9–11User B; TRANSFER 20 A → B; SELL 30 to HOT; every balance on both sides
12Supply unchanged; fee revenue 32,587,500
13Freeze B: trustline revoked on-chain. Unfreeze: the requesting officer's own approval is refused (403); a second officer's re-authorizes on-chain
14Reconciliation (after the indexer caught up): 15 checks PASS (ledger, COLD/HOT/customer balances, trustline states, supply, backing, indexer, issuer layout)
15Gate open, both listeners ready, no open incidents

Result: DEMO PASS: 67 checks. Also verified: make demo-down and up resume the same network (the bootstrap finds a matching manifest and does nothing; the worker starts clean; the gate reopens); make demo-seed seeds GOLD and SILVER, nine staff and two funded customers, and a later scheduled reconciliation passes; alice logs in from the host and sees both assets tradable; the admin listener is not published to the host.

Problems found and fixed while getting here:

ProblemFix
docker-compose run recreated every dependency, Quickstart included, although their configuration was unchanged (compose v5 with Podman). That reset the network under the manifest; bootstrap then refused the stale manifest, as designedrun --rm --no-deps after up -d
A freshly started Quickstart answered getLedgerEntries with "could not query captive core (404)" shortly after reporting healthy, so dara demo failed its startup verificationseed and demo retry startup until their wait deadline; the long-running services already restart
The demo polled POST …/activate every 500 ms while trustlines were authorized and hit the per-user mutation limit (30/min)The demo waits on reads (GET /v1/admin/blockchain-operations) and activates once
seed retried activation with a variable the failed call had zeroed, then reported "already present" on the half-seeded databaseFixed; a part-way seed is now reported as such

Web apps on the platform (Stage 14 part 8)

Production builds of the admin console and the wallet (next start), against dara all on a seeded database and local Quickstart, driven in Chrome:

CheckResult
Staff sign-in with TOTP through the console's same-origin proxySigned in; the admin API is reached only through the console
A REFILL proposed (treasury.a) and approved (reserve.approver) through the proxyListed on Signing with network passphrase, hash, envelope, and "weight 0 of 20 (Medium threshold)" for COLD
T1 then T2 signatures pasted into the Signing page (computed with the stand-in keys)"weight 10 of 20" after T1; after T2 the proposal left the queue and Supply showed the refill COMPLETED with its transaction
An ISSUE above the effective backingRefused: capacity_exceeded (available_to_issue 0)
Overview, System, CustomersHot and cold Treasury on ledger and chain agree; RPC node HEALTHY; indexer 1 ledger behind; customers with their Stellar accounts
Wallet (Persian, RTL): account page"حساب استلار شما", QR of the G… account, custodial note, issuer powers incl. clawback
Wallet trade with a stale price"Not tradable" with the stale-price reason (the seeded price was older than max_price_age)
Wallet trade after a fresh priceQuote 2 g: 20,100,000 + fee 50,250 = 20,150,250 Toman; confirmed; order COMPLETED, "final on Stellar", hash linked to Dara Scan

Found while doing it: the console's two-key navigation shortcuts fire when typing lands outside an input (a mis-aimed click moved between pages, and the theme toggled). This is upstream starter behaviour, not a data risk (no shortcut submits anything), but the signing fields now carry explicit accessible names. Workspace checks: pnpm -r typecheck, lint, test, check:deps, check:rtl all pass; pnpm build builds the three apps.

در این صفحه