Skip to content

feat: add health, protocol-status, vote, and key-snapshot endpoints - #860

Merged
Chucks1093 merged 2 commits into
accesslayerorg:mainfrom
jajafwangshak86-ops:feat/health-protocol-status-vote-snapshot
Sep 8, 2026
Merged

feat: add health, protocol-status, vote, and key-snapshot endpoints#860
Chucks1093 merged 2 commits into
accesslayerorg:mainfrom
jajafwangshak86-ops:feat/health-protocol-status-vote-snapshot

Conversation

@jajafwangshak86-ops

Copy link
Copy Markdown
Contributor

Closes #796
Closes #834
Closes #840
Closes #848

Summary

Adds four new endpoint capabilities across the API:

GET /health (#796)

Probes the database (SELECT 1), Redis (PING), and Stellar Horizon (root endpoint fetch). Returns 200 when all dependencies are healthy and 503 when any is degraded, with per-dependency statuses and a degraded list. No authentication required — suitable for load balancers and uptime monitors.

GET /protocol/status (#848)

Returns protocol-wide config and global trading pause state from the get_protocol_status contract view: globalTradingPaused, protocolFeeBps, treasuryAddress, lockupDurationSeconds, and minInvestmentAmount. Includes pausedAt from the database when paused. Cached in Redis for 30 seconds (protocol:status) and invalidated whenever an admin updates any protocol config value via /admin/protocol/*.

POST /keys/:keyId/proposals/:proposalId/vote (#834)

Requires a valid JWT. Validates optionIndex is within the proposal's option range, checks the caller holds at least one key, rejects duplicate votes, submits the cast_vote contract call, and persists the vote to the new proposal_votes table.

  • 409 on duplicate vote
  • 422 on out-of-range optionIndex
  • 404 if the proposal doesn't exist or is already closed
  • 403 for a non-holder JWT

GET /admin/keys/:keyId/snapshot (#840)

Requires an admin JWT. Reads circulatingSupply, currentPrice, holderCount, tradingPaused, supplyCap, holderCapBps, and circuitBreakerThresholdBps from the Soroban contract (via the get_protocol_status-style RPC read scaffolding) and returns them alongside the matching database values with a per-field drift boolean. Returns 404 for unknown key IDs.

Migration

Adds pausedAt to protocol_config and creates the proposal_votes table (unique on keyId, proposalId, voter). Migration: 20260831000000_add_protocol_paused_and_proposal_votes.

Notes

  • On-chain Soroban contract calls follow the existing codebase pattern of TODO stubs (see key-sync.service.ts, soroban-rpc.utils.ts) — the endpoints are fully functional against the database with the RPC reads as documented scaffolding.
  • The health tests were updated to reflect the new dependency-probing contract.

Verification

  • pnpm run build — no new TypeScript errors (the 3 reported errors are pre-existing on main in error.constants.ts and creator.routes.ts).
  • pnpm exec jest src/modules/health/ — all 92 tests pass.
  • eslint passes on all changed/new files.

…ccesslayerorg#796, accesslayerorg#834, accesslayerorg#840, accesslayerorg#848)

- GET /health: probe database (SELECT 1), Redis (PING), and Stellar
  Horizon (root fetch). Returns 200 when all healthy, 503 when any
  dependency is degraded, with per-dependency statuses. (accesslayerorg#796)

- GET /protocol/status: return global trading pause state plus
  protocol-wide config from the get_protocol_status contract view.
  Cached in Redis for 30s; cache invalidated on any protocol config
  update. (accesslayerorg#848)

- POST /keys/:keyId/proposals/:proposalId/vote: require a valid JWT,
  validate optionIndex, check holder eligibility (403 for non-holders),
  reject duplicate votes (409), 404 for missing/closed proposals, 422
  for out-of-range options. Persists the vote to the new proposal_votes
  table. (accesslayerorg#834)

- GET /admin/keys/:keyId/snapshot: return on-chain Soroban fields
  (circulatingSupply, currentPrice, holderCount, tradingPaused,
  supplyCap, holderCapBps, circuitBreakerThresholdBps) alongside the
  matching database values with a per-field drift boolean. Requires an
  admin JWT; 404 for unknown keys. (accesslayerorg#840)
@drips-wave

drips-wave Bot commented Aug 31, 2026

Copy link
Copy Markdown

@jajafwangshak86-ops Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Chucks1093

Copy link
Copy Markdown
Member

❌ CI Failed — verify (Server CI)

The verify check is failing on this PR.

Likely causes:

  • TypeScript type error — a new type or interface doesn't match what's expected
  • Missing import after merge conflict resolution
  • Build fails due to unused variable or import (@typescript-eslint/no-unused-vars)
  • Jest test suite is failing — check if a new test was added without the proper mock setup

Steps to fix:

  1. Run npm run build locally and fix all TypeScript errors
  2. Run npm test and fix any failing tests
  3. Run npm run lint to catch ESLint issues
  4. Push — CI will re-run automatically

@Chucks1093
Chucks1093 merged commit b8c5c84 into accesslayerorg:main Sep 8, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment