Skip to content

feat(hooks): add useHighValueCargoApproval hook for multi-sig transactions - #910

Merged
johdanike merged 2 commits into
SwiftChainn:mainfrom
AdaBliss:feat/use-high-value-cargo-approval
Sep 30, 2026
Merged

johdanike merged 2 commits into
SwiftChainn:mainfrom
AdaBliss:feat/use-high-value-cargo-approval

Conversation

@AdaBliss

Copy link
Copy Markdown
Contributor

closes #792

Summary

Adds useHighValueCargoApproval, a hook that manages the multi-signature approval flow for high-value cargo escrows. It resolves signers and weights, verifies the weighted threshold, checks signer authorization, collects the signature through Freighter, and handles expired approval windows. It follows the Component -> Hook -> Service pattern.

Changes

  • services/cargoApprovalService.ts (new)
    • getApproval(escrowId) calls GET /api/escrow/{escrowId}/approvals.
    • submitSignature(escrowId, { signerPublicKey, signedTransactionXdr }) calls POST /api/escrow/{escrowId}/approvals/signatures.
    • Throws CargoApprovalServiceError, mapping HTTP 403 / 409 / 410 to unauthorized_signer / already_signed / expired.
  • types/cargoApproval.ts (new): the approval shape, with weighted signers, threshold, transaction envelope, window end and status.
  • hooks/useHighValueCargoApproval.ts (new)
    • signers: each signer with weight, approved, signedAt and isCurrentUser.
    • Threshold: currentWeight is the sum of signed weights, following Stellar threshold semantics. isThresholdMet is true when that weight reaches the threshold or the service reports threshold_met / executed. It is intended for submit enablement.
    • Authorization: isAuthorizedSigner checks the connected wallet against the signer set. Before signing, the Freighter account is re-checked against the connected wallet.
    • Already-signed state: hasSigned blocks a second signature. A 409 from the backend shows an info toast and resyncs.
    • Expired windows: signing is blocked when the service reports expired, when the deadline is already past, or when the deadline passes while the view is open. The last case uses a single timer, not a ticking interval. A 410 from the backend shows an error toast and resyncs.
    • canSign and signBlockedReason (wallet_disconnected, unauthorized, already_signed, threshold_met, expired, closed) let the UI explain why signing is disabled.
    • Polls every 15s while the approval is pending so co-signer progress stays current.

Tests

  • services/__tests__/cargoApprovalService.test.ts: endpoints, path encoding, envelope handling, status-code mapping.
  • hooks/__tests__/useHighValueCargoApproval.test.tsx: signer list with approved status, weighted threshold accuracy, authorized and unauthorized signers, Freighter account mismatch, signing flow, already-signed state (local and 409), expired windows (reported, past deadline, deadline passing live, 410).
PASS services/__tests__/cargoApprovalService.test.ts
PASS hooks/__tests__/useHighValueCargoApproval.test.tsx
Tests: 28 passed, 28 total

Fixtures live under hooks/__tests__/fixtures and use valid, checksummed Stellar public keys. The hook and service contain no inline mock data.

Checks

  • ESLint on changed files: 0 errors, 0 warnings.
  • TypeScript: the changed files type-check cleanly. Project-wide pnpm type-check currently fails on main because of parse errors in app/page.tsx and components/escrow/__tests__/CheckoutFlow.keyboard.test.tsx, which this PR does not touch.
  • Full pnpm test: this PR adds no new failing suites. The suites that fail on main are unchanged.

Note for maintainers

Open PR #901 (for the multi-sig modal issue) also creates hooks/useHighValueCargoApproval.ts, with a modal-specific contract: risk acknowledgement, countdown and a count-based threshold. The two PRs will conflict on that file. This PR follows the #792 spec: weighted signers from the escrow service, authorized-signer validation, isThresholdMet, and expired-window handling.

Screenshots

Unit test run output is included above.

…tions

- Add cargoApprovalService for GET /api/escrow/{id}/approvals and
  POST /api/escrow/{id}/approvals/signatures, mapping 403/409/410 to
  typed error codes
- Add CargoApproval types with weighted signers and approval window
- Add useHighValueCargoApproval hook: resolves signers and weights,
  verifies the weighted threshold, checks the connected wallet is an
  authorized signer that has not signed, signs via Freighter and exposes
  isThresholdMet for submit enablement
- Block signing once the approval window expires, whether reported by
  the backend or reached while the view is open
- Add service and hook unit tests
@drips-wave

drips-wave Bot commented Sep 29, 2026

Copy link
Copy Markdown

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

@johdanike
johdanike merged commit 1ef0526 into SwiftChainn:main Sep 30, 2026
0 of 2 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.

Hook: useHighValueCargoApproval for Multi-Sig Transaction Management

2 participants