Skip to content

feat(backend): SEP-0009 compliance & OFAC sanctions screening middleware (#1470) - #1570

Merged
K1NGD4VID merged 7 commits into
LabsCrypt:mainfrom
Aj-Kayvee:feat/sep0009-compliance-screening-1470
Oct 8, 2026
Merged

K1NGD4VID merged 7 commits into
LabsCrypt:mainfrom
Aj-Kayvee:feat/sep0009-compliance-screening-1470

Conversation

@Aj-Kayvee

Copy link
Copy Markdown
Contributor

Summary

Closes #1470

Adds an opt-in compliance / sanctions screening layer to the backend so institutional payroll and regulated token distributions can prove participating wallets were screened before funds move.

What's included

  • Screening middleware (backend/src/middleware/compliance.middleware.ts) guards stream creation, top-up (deposit) and withdrawal routes. Sanctioned or over-threshold addresses receive a structured 403:

    { "error": "COMPLIANCE_RESTRICTION", "message": "Address restricted under compliance policy" }
  • Screening service (backend/src/services/compliance.service.ts) returns the ScreeningResult shape from the issue, supports a local denylist/allowlist provider (inline env + optional JSON sanctions feed) and an external provider (Chainalysis / TRM Labs / Elliptic style HTTPS API) with an abort-based timeout, and caches results with a configurable TTL.

  • Config (backend/src/config/compliance.config.ts) — COMPLIANCE_ENFORCEMENT_ENABLED (default false, so local testing and self-hosted deployments stay permissive), risk threshold, fail-open / fail-closed mode, cache TTL and provider settings. All documented in backend/.env.example.

  • Audit trail — new ComplianceAuditLog Prisma model records every blocked interaction (address, request IP, risk score, tags, action) plus a structured logger.info line. KYC submissions are audited too.

  • SEP-0009 KYC — POST /v1/compliance/kyc-attestation accepts a SEP-0009 identity payload plus a cryptographic proof and stores it as a KycAttestation. POST /v1/compliance/screen and GET /v1/compliance/screen/{address} expose screening results for audit tooling.

  • Migration 20260928000000_add_compliance_tables, plus regenerated OpenAPI spec and frontend API types.

  • Tests — backend/tests/compliance.test.ts (31 tests) covers config parsing, allowlist/blocklist behaviour, the risk-threshold boundary, cache hits, external-provider success/failure, fail-open vs fail-closed, audit persistence and the SEP-0009 route.

Acceptance criteria

  • Compliance middleware intercepts stream creation and funding routes when enabled.
  • Sanctioned / high-risk addresses receive a structured 403 Forbidden response.
  • Screening results are cached with a configurable TTL to minimise external API cost.
  • Compliance events and blocked interactions generate structured audit logs.
  • Unit and mock tests verify allowlist/blocklist behaviour and fail-open/fail-closed modes.

Base branch note

upstream/main currently does not build: backend/prisma/schema.prisma defines IndexerDeadLetterEvent twice (fails prisma validate/generate) and there are pre-existing type errors across sorobanService, health.routes, indexerService and admin.routes. Because of that, this branch is stacked on feat/ledger-reorg-fork-recovery-1468, which carries the repair commits needed to make the tree green. The compliance changes themselves are self-contained (see the file list below) and can be rebased cleanly once main is repaired.

Files changed

  • backend/src/config/compliance.config.ts (new)
  • backend/src/services/compliance.service.ts (new)
  • backend/src/middleware/compliance.middleware.ts (new)
  • backend/src/routes/v1/compliance.routes.ts (new)
  • backend/tests/compliance.test.ts (new)
  • backend/prisma/schema.prisma, backend/prisma/migrations/20260928000000_add_compliance_tables/
  • backend/src/routes/v1/index.ts, backend/src/routes/v1/stream.routes.ts
  • backend/src/config/swagger.ts, backend/swagger/flowfi.openapi.json, frontend/src/lib/api-types.generated.ts
  • backend/.env.example

Verification

  • npx prisma generate — pass
  • npx tsc --noEmit (backend) — pass
  • npx vitest run --exclude='tests/integration/**' — 490 passed / 3 skipped
  • tests/compliance.test.ts — 31 passed

@Aj-Kayvee
Aj-Kayvee force-pushed the feat/sep0009-compliance-screening-1470 branch from 3ed4934 to 62b404f Compare September 28, 2026 14:40
Aj-Kayvee and others added 7 commits October 5, 2026 15:07
Merging main into this branch unioned both sides of every conflicting file
instead of combining them, so the tree did not build: `lib.rs` had an
unclosed `match`, `errors.rs`/`test.rs` declared duplicate variants and
fields, `sorobanService.ts` and `stream-simulation.test.ts` each contained
two copies of a function, `indexerService.ts`/`pg-pool.ts`/`health.routes.ts`
duplicated declarations, and several frontend files mixed both revisions
(duplicate JSX props, hooks and imports). The Docker and preview jobs also
failed on `EOVERRIDE` because the backend override pinned `@types/pg@8.23.1`
while main had added it as a direct `8.20.0` devDependency.

Take main's revision where it supersedes the branch's reconciliation
(sorobanService, pg-pool, health routes, and the matching test suites), keep
the branch's intentional fixes (actual-toast helper, useSyncExternalStore
network provider, `nativeToScVal` vec element type, webhook fetch cancellation),
and align the `@types/pg` override with the direct dependency so the
standalone container install resolves a single copy again.

cargo fmt/clippy/test, the wasm release build, backend build + vitest + OpenAPI
drift, and frontend lint/tsc/vitest are all green.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

# Conflicts:
#	contracts/stream_contract/src/errors.rs
#	contracts/stream_contract/src/lib.rs
#	frontend/src/app/streams/[id]/__tests__/stream-details-content.test.tsx
… 70%

The merge dropped `mod acceptance_tests`, so the seven tests that exercise
`batch_create_streams`, `create_stream_with_cliff`, `transfer_recipient` and
`extend_stream_ttl` stopped running and contract coverage fell to 67.85%,
below the 70% tarpaulin gate. The crate compiles and the whole 230-test suite
passes with the module restored, so re-declare it.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
The `ec79991f` merge unioned both sides of the contract crate again: `test.rs`
kept a duplicate fee test whose body lost its closing brace, `errors.rs`
redeclared variants 28–33, and `events.rs` re-emitted `StreamClosedEvent` at its
old position. `cargo fmt` aborted on the unterminated function, so Soroban
Contracts CI failed before running a single test.

The SEP-0009 feature is backend-only, so restore the contract crate to main's
already-green revision. `cargo fmt`/`clippy` and all 230 contract tests pass.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@K1NGD4VID
K1NGD4VID merged commit 110472d into LabsCrypt:main Oct 8, 2026
8 of 9 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.

[Backend] SEP-0009 Compliance & Real-Time Sanctions / OFAC Screening Middleware

2 participants