You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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
Require JWT authentication for asset creation, purchase, and access; derive user/wallet identity from the authenticated principal rather than query parameters.
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.
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.
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
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.
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.
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.
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.
Allow content access only for the authenticated buyer of a settled purchase; return a delivery reference, not plaintext content or secrets in logs.
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.
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.
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.
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
Chain verification and settlement safety
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.Delivery boundary and operations
Acceptance Criteria
Authentication and intent integrity
POST /api/marketplace/purchasesis JWT-protected, creates an idempotent pending intent for a publishedPROMPT, and never accepts buyer identity from a query/body field.Verification and atomic settlement
POST /api/marketplace/purchases/:id/confirmvalidates the complete signed envelope and executed Testnet result against the persisted intent before settlement.Access, observability, and tests
GET /api/marketplace/purchases/:id/accesspermits only the settled purchase owner and returns a delivery reference without logging sensitive content, XDR, bearer tokens, or credentials.Dependencies and Non-goals
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.