Skip to content

Add approval workflows & multi-signature governance (#314) - #381

Merged
robertocarlous merged 5 commits into
Neurowealth:mainfrom
B-Hands:feature/314-approval-workflows
Aug 27, 2026
Merged

Add approval workflows & multi-signature governance (#314)#381
robertocarlous merged 5 commits into
Neurowealth:mainfrom
B-Hands:feature/314-approval-workflows

Conversation

@Anuoluwapo25

@Anuoluwapo25 Anuoluwapo25 commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Summary

  • High-value/sensitive WITHDRAW and DEPOSIT operations can now be gated behind an ApprovalPolicy requiring minApprovers independent co-signers, with a full PENDING → APPROVED → EXECUTED (or REJECTED/EXPIRED/CANCELLED) audit trail.
  • guardOperation is called from inside executeDeposit/executeWithdraw (src/controllers/transaction-controller.ts), so the withdraw/deposit HTTP routes and the recurring-deposit job are all covered by one interception point — no per-caller duplication.
  • Eligible approvers are derived from the existing SubAccount graph (the policy owner plus their ACTIVE children), matching the issue's "parent + child, or two children" co-sign example with no new approver-list concept.
  • Every status transition after PENDING is a conditional updateMany, never read-then-write, so two concurrent approvals can't double-execute.
  • New expiry sweep job, full REST surface (GET/POST /api/v1/approvals, /api/v1/approval-policies, admin cancel under approvals:write), and 6 new webhook events.
  • Deliberately not gated in v1 (documented in docs/APPROVALS.md): the agent rebalance loop (moves funds protocol-to-protocol inside the vault, no egress) and referral payouts (platform credits to the user, not the user moving funds out) — neither fits the delegated-authority threat model this issue targets.

Test plan

  • npx tsc --noEmit clean
  • npx eslint clean on all new/touched files
  • Full unit suite green (997 tests, including 38 new tests covering guardOperation, decide's approve/reject/cancel/race-safety paths, the route layer, and the executeDeposit/executeWithdraw gate wiring)
  • Migration applied cleanly against a local Postgres instance (prisma migrate reset + migrate dev, no drift)
  • Manual exercise against a running server: create a low-highValueThreshold policy, hit POST /withdraw above it, confirm 202 PENDING_APPROVAL, approve from a second user, confirm the withdrawal executes with executedTxId linkage

closes #314

Anuoluwapo25 and others added 5 commits August 24, 2026 22:53
High-value withdrawals and deposits can now be gated behind an
ApprovalPolicy requiring minApprovers independent co-signers, with
expiry, cancellation, and a full audit trail via ApprovalRequest/Approval.

guardOperation is called from inside executeDeposit/executeWithdraw
(src/controllers/transaction-controller.ts), so the HTTP routes and the
recurring-deposit job are covered by a single interception point. All
status transitions after PENDING are conditional updateManys, so
concurrent approvals can never double-execute. See docs/APPROVALS.md
for the full design, including what's deliberately out of scope for v1
(agent-loop rebalances, referral payouts) and why.
…l-workflows

# Conflicts:
#	prisma/schema.prisma
#	src/controllers/transaction-controller.ts
#	src/index.ts
#	src/jobs/recurringDeposits.ts
#	src/routes/admin.ts
… migration rollback

- executeWithdraw now publishes through the new user-event bridge
  (publishUserEvent) instead of the removed dispatchWebhookEvent, matching
  executeDeposit — the merge had left a call to an import that no longer
  exists.
- EVENT_TYPE_TOPIC is exhaustive over UserEventType by design (fails the
  build otherwise); the 6 new approval.* webhook events needed an entry —
  routed to the 'transactions' topic alongside recurring_deposit.*.
- Added the required rollback.sql for the approval_workflows migration.
- Updated the recurring-deposit approval test to mock publishUserEvent
  instead of the now-removed dispatchWebhookEvent.
…into feature/314-approval-workflows

# Conflicts:
#	src/controllers/transaction-controller.ts
#	src/jobs/recurringDeposits.ts
#	src/routes/admin.ts
@robertocarlous
robertocarlous merged commit 6fb73ed into Neurowealth:main Aug 27, 2026
8 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.

Approval Workflows & Multi-Signature Governance for High-Value Transactions

2 participants