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/json bodies
  • 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 validationaccount_id, amount_min, amount_max, date_from, date_to, and page_token are validated on the transaction query endpoint. Dates must be RFC 3339; amounts must be valid decimals; page tokens are capped at 512 characters.
  • Pagination cappage_size is 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 for txn_id, symbol, and account_id
  • GetTransaction full-table scan – created a secondary index on transactions(txn_id) to replace ALLOW 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_unavailable during 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 reverted with 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() and LatencyP99() metrics are now wired to actual WorkerMetrics recording (were previously returning 0)

Breaking Changes

  • idempotency_key is now required on all transaction submissions (was previously optional/recommended)
  • Request body limit reduced from 10 MB to 1 MB
  • Content-Type: application/json is 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.