Skip to content

Fix/issue 1640 idempotency key middleware - #1755

Open
udeachudivine-spec wants to merge 2 commits into
Arena1X:mainfrom
udeachudivine-spec:fix/issue-1640-idempotency-key-middleware
Open

Fix/issue 1640 idempotency key middleware#1755
udeachudivine-spec wants to merge 2 commits into
Arena1X:mainfrom
udeachudivine-spec:fix/issue-1640-idempotency-key-middleware

Conversation

@udeachudivine-spec

@udeachudivine-spec udeachudivine-spec commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Closes #1642


Fixes the first-depositor share-inflation / full-drain vulnerability
in add_liquidity's bootstrap branch.

Changes:
- Add isqrt_i128() private helper (Babylonian method, i128 flavour of
  the existing isqrt_u128 used for IL math)
- Bootstrap branch now computes:
    product          = per_outcome_amount.checked_mul(per_outcome_amount)
    initial_liquidity = isqrt_i128(product)
    lp_tokens_to_mint = initial_liquidity - MIN_LIQUIDITY  (1_000)
  total_supply is set to initial_liquidity so MIN_LIQUIDITY is
  permanently counted but never credited to any account
- Dust deposits where isqrt(a*b) <= MIN_LIQUIDITY are rejected with
  StakeTooLow (error enum is at its 50-case XDR cap; no new variant
  can be added — StakeTooLow is semantically the closest fit)
- All arithmetic uses checked_mul / checked_sub / checked_add only;
  no raw operators, no unwrap/expect

Tests:
- test_first_deposit_locks_minimum_liquidity  (new)
- test_dust_deposit_rejected                  (new)
- test_full_drain_prevented                   (new)
- Updated 8 existing tests whose assertions assumed the old 1:1
  bootstrap behaviour; logic is correct, only expected values changed
- Add IdempotencyInterceptor to backend/src/common/interceptors/
  - Only activates for POST/PUT/PATCH/DELETE; GET passes through untouched
  - Header is optional: requests without Idempotency-Key pass through normally
  - Keys scoped by (userId, route-pattern, client-key) — folds route pattern
    into stored key value as 'METHOD:/route/pattern:client-key' so the
    existing (key, userId) unique index enforces per-route scoping without
    a schema change
  - Uses req.route.path (matched Express route pattern, not raw URL) to
    prevent /resources/1 and /resources/2 colliding or not-colliding wrongly
  - First request: executes handler, persists status_code + response_body
  - Replay with same (user, route, key) + same body: returns stored response
    with Idempotency-Replayed: true header, handler not re-executed
  - Replay with different body: 422 UnprocessableEntityException
  - Concurrent in-progress request: 409 ConflictException
  - Handler error: releases the key via IdempotencyService.release so client
    can safely retry
  - No new dependencies; reuses IdempotencyService/IdempotencyKey from
    common/idempotency (TypeORM, already wired in CommonModule)

- Register as APP_INTERCEPTOR in app.module.ts (global, same pattern as
  existing APP_GUARD registrations); IdempotencyService is resolvable via
  CommonModule which is already imported in AppModule

- Add idempotency.interceptor.spec.ts with 9 tests covering:
  - No header → passthrough, service never called
  - GET → passthrough regardless of header
  - First request executes handler and calls complete()
  - Handler error → release() called, complete() not called
  - Replay returns stored response, handler called exactly once total
  - Different user same key → both handlers execute independently
  - Different route same key same user → stored keys differ, both execute
  - Same key different body → 422
  - Concurrent in-progress → 409

No migration needed: existing schema (key, userId, request_hash, status_code,
response_body, in_progress) already stores everything needed for faithful
replay.
@vercel

vercel Bot commented Aug 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
insight-arena-4rll Ready Ready Preview Aug 27, 2026 4:13pm

@udeachudivine-spec

Copy link
Copy Markdown
Contributor Author

close #1640

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] — User Follows Feed Endpoint

1 participant