Skip to content

Implement a distributed idempotency layer for buy and sell endpoints using Redis to prevent double-execution across concurrent retries #725

Description

@Chucks1093

Summary

When a client retries a buy or sell request due to a network timeout, the server may process the same transaction twice — charging the buyer or crediting the seller multiple times. A distributed idempotency layer backed by Redis should detect duplicate requests within a configurable window and return the original response without re-executing the transaction.

Scope

  • Accept an Idempotency-Key header on POST /buy and POST /sell endpoints
  • On first request: execute the transaction, store { statusCode, body, resolvedAt } in Redis under the key with a 24-hour TTL, then return the response
  • On duplicate request (same key within TTL): return the stored response immediately without touching the database or Soroban
  • If the first request is still in-flight when a duplicate arrives, block the duplicate for up to 5 seconds then either return the in-progress result or a 409 request_in_progress
  • Reject requests missing the Idempotency-Key header with 400 missing_idempotency_key
  • Namespace keys by wallet address to prevent cross-wallet collisions: idempotency:{walletAddress}:{key}
  • Add integration tests covering: first execution stores result, duplicate returns stored result, in-flight duplicate returns 409, missing header returns 400, expired key allows re-execution

Acceptance Criteria

  • First request executes and stores result in Redis with 24-hour TTL
  • Duplicate key within TTL returns stored response without re-executing
  • In-flight duplicate blocked up to 5 seconds then returns 409
  • Missing header returns 400 with missing_idempotency_key
  • Keys namespaced by wallet to prevent cross-wallet collisions
  • Expired key allows a fresh execution (TTL enforced correctly)
  • No Soroban transaction submitted on a duplicate request

ETA: 24 hours


Coordinate on Telegram

Metadata

Metadata

Assignees

No one assigned

    Labels

    GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions