Kaspa x402

Server Store Contract

The reference MemoryServerChannelStore is for tests and examples. Production servers need a durable implementation of ServerStateStore with the semantics below.

Required Guarantees

Runtime serialization is a separate adapter contract. Deployments with multiple server processes must also provide a shared ChannelLockManager as described in server-runtime-lock-contract.md.

Replay And Idempotency

commitExactPayment consumes a transaction id once per server or facilitator trust domain. paymentOutputIndex remains receipt evidence, but a second output from the same transaction is a replay conflict. A cached exact retry is the same verifier-derived transaction id, same output index, and same request fingerprint; payload byte equality is not required because the accepted transaction id and output index are the replay evidence.

PaymentIdentifierRecord.id must be globally unique inside the same trust domain. Reusing an id with a different request fingerprint, payload hash, or payment scope must fail atomically.

Additive Exact Heads

registerExactHead must enforce unique head ids and unique current outpoints. selectExactHead is read-only: issuing a 402 must not reserve, retire, or otherwise mutate a head. claimExactSettlement must atomically compare the advertised head id, version, and current outpoint before marking one settlement attempt as the claimant. acceptExactSettlement must atomically replace that outpoint and amount with the verifier-derived same-script successor, increment the version, and commit replay/idempotency state. A losing concurrent claimant must fail and refresh from the current head. Crash recovery must preserve broadcast uncertainty rather than reopening the old outpoint for protected work.

Settlement State

commitSettlement must atomically write the batch commitment, optional payment identifier, and next channel state only when the current channel still matches the expected snapshot.

saveClaimAttempt must allow only one open claim attempt per channel. applyClaimAttempt must update channel state only when the channel still matches the attempt snapshot.

Handler Side Effects

Payment verification happens before the protected handler. Durable payment commit happens after the handler returns, and a commit failure can return 500 after application work has already run.

Handlers that perform non-repeatable work should require payment-identifier and keep an application-owned idempotency or outbox table keyed by paymentIdentifier and requestFingerprint. The handler should return the cached application result on retry, while the server store retries payment settlement or replay commit.

Source: /docs/server-store-contract.md