Skip to content

feat(marketplace): add authenticated Testnet purchase-to-access MVP flow #9

Description

@Joaco2603

Context

The current backend exposes catalog, wallet, and payment endpoints, but it has no production-grade authenticated purchase-to-access flow. Asset creation and wallet operations currently accept caller identity through query parameters, and token interactions remain simulated. That means the repository cannot demonstrate the MVP journey: an authenticated buyer purchases a published prompt, the Testnet transaction is verified, and the buyer receives the permitted content.

This issue deliberately does not define the encryption/privacy model. Backend #8 and Smart-contracts #19/#20 are design gates for that boundary.

Problem Description

Without a server-owned purchase/access record tied to the authenticated wallet and an on-chain payment reference, the marketplace has no reliable authorization boundary for delivery. A UI can browse assets, but it cannot complete a secure, auditable end-to-end purchase.

The flow also needs to be correct under real distributed-system failure modes: RPC timeouts, delayed ledger execution, duplicate confirmation requests, restarts, concurrent workers, and a transaction that is syntactically valid but does not represent the exact purchase intent.

Proposed Solution

Implement a non-custodial, Testnet-only purchase-to-access slice for one supported asset type (start with PROMPT):

Authenticated intent and durable state

  1. Require JWT authentication for asset creation, purchase, and access; derive user/wallet identity from the authenticated principal rather than query parameters.
  2. Add a durable purchase state machine with explicit terminal and retryable states, timestamps, immutable intent fields, expiry, and an idempotency key scoped to the authenticated buyer.
  3. Create a purchase intent that returns the exact Testnet Soroban transaction payload/requirements for the connected wallet to sign. The backend MUST NOT receive or store buyer secret keys.
  4. Bind the intent to an immutable snapshot of asset ID, atomic-unit price, buyer public key, configured contract ID, network passphrase, expected contract operation/arguments, and expiry. A later asset-price or configuration change must not reinterpret an existing intent.

Chain verification and settlement safety

  1. Verify the submitted transaction through Stellar RPC against the configured Testnet network and the persisted intent, not against mutable runtime values alone. Validate the full signed envelope semantics: source account, network passphrase, contract address, allowed operation count/order, entry point, arguments, expiry, and resulting success status.
  2. Verify the executed contract result/event or equivalent authoritative ledger evidence binds the payment to the expected asset and amount. Do not settle based only on a user-supplied transaction hash or a parsable envelope.
  3. Treat RPC transport errors, NOT_FOUND, and pending ledger execution as retryable/observable states; do not irreversibly mark a purchase failed merely because the backend could not observe Testnet. Define bounded polling/reconciliation and terminal-failure behavior.
  4. Make confirmation concurrency-safe with database-enforced transaction-hash uniqueness and an atomic compare-and-set/transactional state transition. Concurrent confirmation requests, retries after process restart, and duplicate workers must produce one settlement and a deterministic idempotent response.
  5. Allow content access only for the authenticated buyer of a settled purchase; return a delivery reference, not plaintext content or secrets in logs.
  6. Reject replayed/mismatched transaction hashes, buyer identities, assets, amounts, contract IDs, network passphrases, expired intents, and transaction envelopes containing unexpected operations.

Delivery boundary and operations

  1. Integrate the approved Backend Architecture: privacy trace audit for encrypted prompt delivery #8 delivery/replay guarantees without inventing a new encryption or privacy scheme. Persist only the minimum access/audit data needed for recovery and authorization.
  2. Add redacted structured audit events and metrics for intent creation, confirmation state transitions, RPC verification outcomes, replay attempts, and delivery authorization. Never log XDR, bearer tokens, prompt content, or secrets.
  3. Document API contracts, retry semantics, Testnet configuration, operator reconciliation procedure, retention policy, and the transition from development mocks to the required Testnet verifier.

Acceptance Criteria

Authentication and intent integrity

  • POST /api/marketplace/purchases is JWT-protected, creates an idempotent pending intent for a published PROMPT, and never accepts buyer identity from a query/body field.
  • The returned intent contains a wallet-signable Testnet transaction (or serialized unsigned XDR), explicit expiry, atomic-unit amount, and its immutable chain/configuration binding; no buyer/admin secret key is exposed or persisted.
  • An intent remains bound to the original asset, price, buyer, contract ID, network passphrase, entry point, and arguments even if catalog data or runtime configuration changes later.
  • Expired or terminal intents cannot be silently reused; repeated calls with the same idempotency key have documented, deterministic behavior.

Verification and atomic settlement

  • POST /api/marketplace/purchases/:id/confirm validates the complete signed envelope and executed Testnet result against the persisted intent before settlement.
  • Verification rejects a transaction from another buyer, network, contract, asset, amount, function, argument set, expiry window, or envelope with unexpected operations.
  • Settlement requires authoritative successful ledger evidence and expected payment/event semantics; a user-supplied hash or envelope alone is insufficient.
  • RPC outage, timeout, unknown hash, and pending-ledger states remain retryable and are reconciled without granting access or burning the intent's recoverability; definitive chain failures become terminal with a documented reason.
  • Database constraints and atomic transitions guarantee exactly one settlement and one transaction-hash binding under concurrent confirms, duplicate requests, and process restarts.
  • A valid retry after settlement returns the documented idempotent result; a replay or hash bound to another purchase fails.

Access, observability, and tests

  • GET /api/marketplace/purchases/:id/access permits only the settled purchase owner and returns a delivery reference without logging sensitive content, XDR, bearer tokens, or credentials.
  • Structured audit events/metrics provide correlation IDs and redacted state-transition evidence for support and reconciliation.
  • Unit and integration tests cover state transitions, idempotency, concurrent confirmation, configuration/price snapshotting, full-envelope mismatches, replay, retryable RPC states, terminal failures, authorization, and redaction.
  • The Testnet e2e test starts from a published fixture, signs with a buyer-owned Testnet key, confirms settlement from executed-ledger evidence, and proves that an unauthorized user cannot obtain access.
  • API documentation and operational runbooks document Testnet-only scope, required contract IDs, retry/reconciliation workflow, observability fields, and the approved Backend Architecture: privacy trace audit for encrypted prompt delivery #8 delivery boundary.

Dependencies and Non-goals

  • Blocked by Backend Architecture: privacy trace audit for encrypted prompt delivery #8 for the approved encryption, retention, logging, replay, and delivery-trace guarantees.
  • Coordinate the contract operation and event shape with Smart-contracts #19/#20; do not invent a privacy scheme here.
  • Not in scope: Mainnet, custody of buyer keys, credit-package simulation, general support for every asset type, webhooks/relayers as a replacement for ledger verification, or a custom privacy/ZK protocol.

Alternatives Considered

Keeping purchases as off-chain wallet-credit mutations would be faster but would not prove an end-to-end Stellar marketplace flow. Letting the backend sign for buyers would simplify implementation but creates a custodial key-management risk and is explicitly rejected for the MVP. Treating a single RPC lookup failure as a failed payment would be simpler but is unsafe under Testnet/RPC eventual consistency.

Metadata

Metadata

Assignees

No one assigned

    Labels

    GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardThird CampaignCampaign: Third CampaignenhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions