v0.2.0-alpha
Security hardening, bug fixes, and settlement service improvements.
v0.2.0-alpha
Release date: 2026-04-04 Status: Pre-release (Alpha)
Summary
Security hardening, 14 bug fixes, and Settlement Service completion. This release resolves all known limitations from v0.1.0-alpha edge-case testing and hardens the API gateway against injection and abuse.
Security Hardening
- Account ID validation – rejects Unicode homoglyphs, zero-width characters, SQL/CQL injection attempts. IDs must be ASCII-only, max 128 characters, allowed characters:
a-zA-Z0-9_.-: - Amount precision limits – amounts are validated to a maximum of 18 integer digits and 18 decimal digits
- Content-Type enforcement – POST endpoints reject non-
application/jsonbodies - Body size limit – reduced from 10 MB to 1 MB to match NATS max payload
- Error sanitization – internal error details (NATS, gocql, infrastructure) are never leaked in API responses. Downstream failures return 503 with a safe message.
- Error code matching – switched from substring (
Contains) to prefix (HasPrefix) matching to prevent partial-match information leaks - Query parameter validation –
account_id,amount_min,amount_max,date_from,date_to, andpage_tokenare validated on the transaction query endpoint. Dates must be RFC 3339; amounts must be valid decimals; page tokens are capped at 512 characters. - Pagination cap –
page_sizeis capped at 1000 across all list endpoints
Bug Fixes
- KMS DEK cache pointer aliasing – callers could mutate the shared cached DEK entry; now returns a copy
- NATS health check was a no-op – readiness endpoint always reported NATS as healthy; now wired to actual connection status via
IsConnected() - Unnecessary
ALLOW FILTERING– removed from partition-key-only ScyllaDB queries (GetTokenBySymbol,ListBalancesForAccount); added secondary indexes fortxn_id,symbol, andaccount_id GetTransactionfull-table scan – created a secondary index ontransactions(txn_id)to replaceALLOW FILTERING- NFT InsertInstance not idempotent – now uses
IF NOT EXISTS(LWT); duplicate mints return an error instead of silently succeeding - NFT class duplicate name – returns 409 Conflict instead of 500 Internal Server Error
- Shard consumer unbounded goroutines – per-account processing goroutines are now capped with a CPU-bound semaphore
- Status batch update not retried – added 3-attempt retry with 100ms backoff for status persistence
- Shard retry returned 404 – changed to 503
shard_unavailableduring ownership flux (404 is reserved for genuinely non-existent accounts) - Shard pool size – increased from 4 to 16 connections per shard session
- Debit from zero balance – no longer loops indefinitely; the transaction is acked and marked as failed
- Missing RPC handlers – added handlers for
RPC.account.query.transactions, attestation RPCs, and storage metrics
Settlement Service
The Settlement Service is no longer a skeleton. It now provides:
- Compound transaction registration – tracks expected legs by
group_id - Receipt tracking with deduplication – prevents double-counting of receipts using audit hash keys
- Settlement finalization – marks group as settled when all legs complete
- Partial revert – publishes compensating transactions for all completed legs; continues on individual failures and marks the group as
revertedwith a partial-failure report
Attestations
- Attestation list endpoint (
GET /v1/attestations) is now fully functional with filtering support (asset_class,source,status,subject_class,subject_instance) - NFT ownership history table is now populated on transfers
Metrics
TxPerSecond()andLatencyP99()metrics are now wired to actualWorkerMetricsrecording (were previously returning 0)
Breaking Changes
idempotency_keyis now required on all transaction submissions (was previously optional/recommended)- Request body limit reduced from 10 MB to 1 MB
Content-Type: application/jsonis now enforced on all POST endpoints- Shard unavailability during rebalancing now returns 503 instead of 404
- Duplicate NFT mints now return 409 Conflict instead of succeeding silently
Dependencies
No dependency changes from v0.1.0-alpha.