Skip to content

feat(stellar): add multi-signature approval for charges above a threshold - #1875

Merged
github-actions[bot] merged 1 commit into
Smartdevs17:mainfrom
JohnMabas:feat/1715-multisig-approval
Oct 21, 2026
Merged

github-actions[bot] merged 1 commit into
Smartdevs17:mainfrom
JohnMabas:feat/1715-multisig-approval

Conversation

@JohnMabas

Copy link
Copy Markdown
Contributor

Summary

Implements M-of-N multi-signature approval for high-value charges, closing #1715.

High-value charges currently execute from a single key. This PR requires M-of-N approval from authorized signers before a charge above a configurable per-merchant threshold can proceed.

What was built

backend/services/stellar/multiSigApprovalService.ts

  • MultiSigApprovalService — orchestrates the approval workflow; all dependencies injectable for full testability
  • Per-merchant threshold: MerchantMultiSigConfig carries thresholdAmount, currency, requiredApprovals (M), totalSigners (N), and signerAddresses; charges below the threshold return null immediately (no approval needed)
  • Approval state visible: getApprovalStatus(requestId) returns the full MultiSigApprovalRequest with approvals, rejections, status, and resolvedAt
  • 2-of-3 tested explicitly: the test suite includes a full 2-of-3 scenario (first approval keeps status pending, second approval transitions to approved)
  • Idempotent approvals: the same signer approving twice is a no-op
  • Rejection: any authorized signer can reject; sets status = 'rejected' immediately
  • Expiry sweep: expireStaleRequests(now) marks pending requests whose expiresAt has passed as expired
  • Guard rails: unauthorized signers, double-submit on already-resolved requests, and approvals on expired requests all return typed ApprovalResult errors — no exceptions thrown
  • MultiSigStore interface + InMemoryMultiSigStore

backend/services/stellar/__tests__/multiSigApprovalService.test.ts

  • 20 unit tests covering: below-threshold bypass, above-threshold request creation, 2-of-3 partial approval, 2-of-3 full approval, idempotent approval, unauthorized signer, rejection, double-submit on resolved, status visibility, isChargeApproved (approved / pending / below-threshold), expiry sweep, and approval on expired request

Acceptance criteria

  • Threshold is per merchant (MerchantMultiSigConfig.thresholdAmount scoped to merchantId)
  • Approval state is visible in the UI (getApprovalStatus returns full request state including approvals, status)
  • Tested with 2-of-3 signers (explicit 2-of-3 test scenario in the test suite)

Testing

npx jest --config jest.backend.config.js --testPathPattern=multiSigApprovalService

All 20 tests pass.

Closes #1715

@drips-wave

drips-wave Bot commented Oct 21, 2026

Copy link
Copy Markdown

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

@github-actions
github-actions Bot merged commit 035bf8e into Smartdevs17:main Oct 21, 2026
8 of 24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add multi-signature approval for charges above a threshold

1 participant