Skip to content

fix(webhooks): wallet/transaction event emission, HMAC signing, retry/backoff queue - #628

Merged
Jambox11 merged 2 commits into
mux-labs:stagingfrom
priscaenoch:feature/480-483-webhook-events-signing-retry-queue
Jul 25, 2026
Merged

fix(webhooks): wallet/transaction event emission, HMAC signing, retry/backoff queue#628
Jambox11 merged 2 commits into
mux-labs:stagingfrom
priscaenoch:feature/480-483-webhook-events-signing-retry-queue

Conversation

@priscaenoch

Copy link
Copy Markdown
Contributor

Summary

Closes #480, closes #481, closes #482, closes #483.

Most of the webhook infrastructure required by these issues already existed on staging (event emission, HMAC signing, retry/backoff), but several files had unresolved merge conflicts — duplicated imports, orphaned code fragments, and missing methods — that left the webhooks module (and its transitive dependencies) unable to compile or pass its own tests. This PR repairs that damage and wires up the remaining behavior:

  • Emit wallet created webhook after orchestration #480 wallet.createdwallets.service.ts already called WebhookEventEmitterService.emitWalletCreated after orchestration, but the file had duplicate imports and a duplicated/detached updateWalletStatus status-transition guard, plus two missing helper methods (toPublicWallet, archiveWallet) referenced by findAll/findOne/archive. Fixed and restored.
  • Emit transaction confirmed webhook on status change #481 transaction.confirmedtransactions.service.ts already called emitTransactionConfirmed on status change, but create() had a syntactically broken emit call, a missing emitDomainEvent helper, and non-optional collaborators (webhook emitter/cache/metrics) that didn't match how tests construct the service. Fixed.
  • Sign outbound webhook payloads with HMAC #482 HMAC signing — already correctly implemented in webhook-signer.service.ts / webhook-dispatch.service.ts (HMAC-SHA256, timestamped, constant-time verification). No changes needed there.
  • Process webhook delivery queue with backoff #483 retry/backoff queue — already correctly implemented in webhook-retry.service.ts / webhook-dispatcher.service.ts / webhook-delivery-queue.worker.ts (exponential backoff, dead-letter after max attempts, periodic worker), but webhook-dispatcher.service.ts was missing a log helper and a maxRetries accessor that caused runtime failures in the exact delivery/backoff path this issue covers. Fixed (now delegates to WebhookRetryService.getMaxRetries()).

Also touched (forced by the same merge damage / build graph)

  • webhook.service.ts / webhook.controller.ts: reconciled two duplicated CRUD implementations into one, restoring endpoint caching and WebhookFilterDto-based pagination/filtering.
  • balance-indexer.service.ts / stellar-horizon.service.ts: transactions.service.ts imports BalanceIndexerService, so its merge damage blocked compilation of my actual target file. Reconciled to the BalanceRepository-based design that the existing (also-broken) test suite expects.
  • health.controller.ts / health.module.ts: a duplicated controller/module definition here broke the overall nest build, unrelated to webhooks but blocking CI regardless.

Testing / validation performed

  • npx tsc --noEmit — clean for every file touched in this PR.
  • npx jest src/webhooks — all 9 webhook spec files pass (signing, dispatch, retry, config, feature-flag, request-id propagation, CRUD service, dispatcher).
  • npx jest src/wallets/wallets.service.spec.ts — passes except one pre-existing, unrelated failure (see Risks).
  • npx jest src/transactions/transactions.service.spec.ts — passes except 7 pre-existing, unrelated failures (see Risks).
  • npx jest src/balance-indexer/balance-indexer.service.spec.ts — passes (16/16).
  • npx prettier --check — clean on all touched files.

Risks / follow-ups (pre-existing, out of scope for this PR)

staging currently has extensive pre-existing breakage unrelated to these 4 issues that I deliberately left untouched per scope:

  • transactions.service.spec.ts has 7 failing tests for a findAll filtering feature (assetType/assetCode/amount range/date range) that was never implemented — looks like unmerged work from a different ticket (Transactions API: Add filtering query params #341/Transactions API: Emit domain events #342 per branch history).
  • wallets.service.spec.ts has 1 failing test where findAll's default archived-wallet exclusion doesn't match its own test's expectation — looks like fallout from the separate wallet-archive feature (PR Graceful shutdown, log redaction, and wallet archiving #617).
  • balance-indexer.controller.spec.ts / balance-indexer.integration.spec.ts, plus several other unrelated suites (wallet-creation-orchestrator.*, limits.service.spec.ts, auth/*), fail for reasons unconnected to webhooks (missing DI providers, jest/babel parse errors, other pre-existing bugs).
  • A full tsc --noEmit across the whole repo still reports errors in ~40 files outside this PR's scope (auth, api-keys, supertest version mismatch, etc.) — staging does not currently build clean end-to-end.

None of the above are touched by this PR; they predate it and are unrelated to issues #480-#483. Recommend separate tickets for each.

Links:

…wallet/transaction event emission

Implements issues mux-labs#480-mux-labs#483: wallet.created and transaction.confirmed
webhook emission, HMAC-signed outbound payloads, and the retry/backoff
delivery queue.

Most of this infrastructure already existed on staging but several files
had unresolved merge conflicts (duplicated imports, orphaned code
fragments, and missing methods) that prevented the webhooks module,
and its transitive dependencies, from compiling or passing tests:

- webhook.service.ts / webhook.controller.ts: resolved duplicated
  CRUD implementations, restored caching (CacheService) and
  pagination/filtering (WebhookFilterDto) for endpoints and deliveries.
- webhook-dispatcher.service.ts: restored a missing `log` helper and a
  missing `maxRetries` accessor (delegates to WebhookRetryService),
  both of which caused runtime failures in the delivery/backoff path
  central to issue mux-labs#483. Rewrote its stale spec to match the current
  WebhookDispatchService/WebhookRetryService split.
- wallets.service.ts: resolved duplicated imports and a duplicated/
  detached status-transition guard in updateWalletStatus; added the
  missing toPublicWallet/archiveWallet helpers used by findAll/findOne/
  archive, which is where wallet.created (mux-labs#480) is emitted after
  orchestration.
- transactions.service.ts: resolved a malformed transaction.created
  emit call, a missing emitDomainEvent helper, and made the webhook
  emitter/cache/metrics collaborators optional to match existing DI
  usage — this is where transaction.confirmed (mux-labs#481) is emitted on
  status change.
- balance-indexer.service.ts / stellar-horizon.service.ts: fixed
  merge damage (duplicated methods importing two different data-access
  styles) that blocked compilation of transactions.service.ts, which
  imports BalanceIndexerService.
- health.controller.ts / health.module.ts: fixed a duplicated
  controller/module definition blocking the overall project build.

HMAC signing (mux-labs#482) and the retry/backoff queue (mux-labs#483) were otherwise
already implemented correctly in webhook-signer.service.ts,
webhook-dispatch.service.ts, webhook-retry.service.ts and
webhook-delivery-queue.worker.ts and did not require changes.

Testing:
- All webhook-*.spec.ts suites pass (signing, dispatch, retry, config,
  feature-flag, request-id, CRUD service).
- wallets.service.spec.ts and transactions.service.spec.ts pass except
  for pre-existing failures unrelated to this change (an out-of-scope
  wallet-archive default-filter mismatch and an unimplemented
  transaction-filtering feature from a different ticket).
- balance-indexer.service.spec.ts passes.
@drips-wave

drips-wave Bot commented Jul 24, 2026

Copy link
Copy Markdown

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

@Jambox11
Jambox11 merged commit 6fe216d into mux-labs:staging Jul 25, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants