Skip to content

feat: encrypt provider credentials, payout idempotency, webhook verification, multi-currency balances (#1005 #1006 #1009 #1010) - #1302

Merged
github-actions[bot] merged 1 commit into
Smartdevs17:mainfrom
therealjhay:feat/issues-1005-1006-1009-1010
Oct 18, 2026
Merged

github-actions[bot] merged 1 commit into
Smartdevs17:mainfrom
therealjhay:feat/issues-1005-1006-1009-1010

Conversation

@therealjhay

Copy link
Copy Markdown
Contributor

Summary

Resolves four issues across credential storage, payout creation, inbound webhooks, and wallet balances.

Closes #1005 Closes #1006, Closes #1009 Closes #1010

#1010 — Encrypt provider credentials at rest

  • New encrypted vault backend/src/services/provider-credentials.ts, built on the shared AES-256-GCM column encryptor (backend/src/encryption/column-encryptor.ts). Values are sealed before they are retained; only $enc1$… ciphertext is kept, with HKDF-derived per-tenant DEKs and master-key rotation (rotateMasterKey).
  • Admin routes mounted at /api/v1/provider-credentials (list / put / get / reveal / delete / rotate-key), with every create, update, reveal, rotate and delete written to the audit trail (never the plaintext or ciphertext).
  • Registered Webhook.secret and PushSubscription.auth in the Prisma column-encryption PII_FIELDS registry so those persisted secrets are encrypted transparently.

#1005 — Idempotency keys on payout creation

  • New TTL-bounded, memory-capped store backend/src/services/payouts/payout-idempotency.ts (default 24h) that fingerprints the request body.
  • POST /api/v1/payouts/scheduled now passes the Idempotency-Key (or X-Idempotency-Key) header into PayoutBatcher.schedule(), which replays the original payout for a duplicate key and throws IDEMPOTENCY_KEY_REUSE_MISMATCH (mapped to 409) when a key is reused with a different body.
  • Exposes PayoutBatcher.purgeExpiredIdempotencyKeys() for scheduled cleanup.

#1006 — Webhook signature verification

  • Added verifyBankPartnerWebhook (backend/src/services/webhooks/providers.ts), verifying X-Bank-Signature / X-Bank-Timestamp with the same HMAC-SHA256, tolerance-window and constant-time comparison as other providers.
  • Extracted createWebhookVerifier and exported bankPartnerWebhookVerifier; mounted raw-body capture for /api/v1/fiat-payments/webhooks before the global JSON parser and applied the verifier to the bank-partner payout webhook.

#1009 — Multi-currency wallet balances

  • WalletAggregationService now returns a byCurrency breakdown (CurrencyBalance) alongside the USD total; added getBalancesByCurrency and getCurrencyBalance (returns undefined, never a coerced 0, when a currency is absent).
  • New GET /api/v1/wallet/balances (optionally ?currency=), and a Balances by Currency table in frontend/components/wallet/WalletManager.tsx; the previously-missing wallet slice was added to frontend/store/web3Store.ts.

Tests & docs

  • Unit tests: provider-credentials.test.ts, payout-idempotency.test.ts, wallet-multi-currency.test.ts, bank-partner-verification.test.ts, plus signed fixtures in backend/src/tests/fixtures/webhooks.ts.
  • Docs: docs/security/provider-credentials-encryption.md, docs/PAYOUT_IDEMPOTENCY.md, docs/MULTI_CURRENCY_BALANCES.md, an "Inbound provider webhooks" section in docs/security/webhook-signatures.md, and updated docs/README.md index.

…ication, multi-currency balances (Smartdevs17#1005 Smartdevs17#1006 Smartdevs17#1009 Smartdevs17#1010)

- Smartdevs17#1010: add an encrypted-at-rest provider credential vault
  (services/provider-credentials.ts + /api/v1/provider-credentials routes) on top
  of the shared AES-256-GCM column encryptor, with audited reveal and key rotation;
  register Webhook.secret and PushSubscription.auth in the Prisma PII field registry.
- Smartdevs17#1005: add a TTL-bounded service-level payout idempotency store and wire the
  Idempotency-Key header through POST /api/v1/payouts/scheduled, replaying the
  original payout and rejecting key reuse with a different body (409).
- Smartdevs17#1006: verify bank-partner payout webhooks with HMAC-SHA256 by extracting
  createWebhookVerifier and mounting raw-body capture before the JSON parser.
- Smartdevs17#1009: aggregate wallet balances per currency (byCurrency), add
  GET /api/v1/wallet/balances, and render a Balances by Currency table in the UI.

Adds unit tests, provider webhook fixtures, and docs.
@vercel

vercel Bot commented Oct 18, 2026

Copy link
Copy Markdown

@therealjhay is attempting to deploy a commit to the smartdevs17's projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions
github-actions Bot merged commit 0d68406 into Smartdevs17:main Oct 18, 2026
16 of 27 checks passed
@drips-wave

drips-wave Bot commented Oct 18, 2026

Copy link
Copy Markdown

@therealjhay 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant