Kaspa x402

Kaspa x402 Batch Settlement Binding v3

Status: v1 RC1, Testnet-10-only interoperability candidate

This document defines the active Kaspa network binding for x402 v2 batch-settlement.

Summary

batch-settlement amortizes on-chain settlement across repeated, fixed-price invocations. The payer funds one native KAS covenant lane, signs the exact cumulative value of accepted invocations, and separately signs a short-lived presentation for each request. The provider may claim part or all of the signed cumulative value while keeping the lane open.

The v3 binding deliberately has no provider-selected post-service charge. Once the payer presents an invocation, accepted.amount is its non-refundable fixed charge. A successful HTTP response, an application error, and a chargeable MCP isError result do not silently change that amount.

v1 RC1 is a clean cutover. Binding v2, escrow-v3, v2 vouchers, client-only top-ups, and batch payloads without a v1 presentation authorization are invalid. There is no compatibility reader, migration path, or dual runtime.

Use exact for a one-shot on-chain purchase. Batch v3 is not a post-priced or usage-metered scheme.

Identifiers

scheme       batch-settlement
binding      kaspa-escrow-v3
templateId   kaspa-x402-escrow-v4
network      kaspa:testnet-10
asset        KAS

kaspa:testnet-10 is the only v1 RC1 validation target. This profile MUST NOT be enabled on mainnet.

The signature and commitment domains are:

kaspa:x402:channel:v2
kaspa:x402:escrow-voucher:v3
kaspa:x402:batch-payment-requirements:v3
kaspa:x402:batch-payment-intent:v1
kaspa:x402:batch-presentation:v1
kaspa:x402:batch-commitment:v3

Claim, top-up, and refund transaction inputs use Kaspa transaction-v1 SIGHASH_ALL. They do not introduce an application transaction-signing domain.

PaymentRequirements

{
  "scheme": "batch-settlement",
  "network": "kaspa:testnet-10",
  "amount": "1000000",
  "asset": "KAS",
  "payTo": "kaspatest:...",
  "maxTimeoutSeconds": 60,
  "extra": {
    "binding": "kaspa-escrow-v3",
    "templateId": "kaspa-x402-escrow-v4",
    "serverPublicKey": "<32-byte x-only hex>",
    "minDepositSompi": "90000000",
    "claimReserveSompi": "2000000",
    "refundTimeoutDaa": "123456789",
    "securityContextHash": "<32-byte trusted context hash>",
    "mcpErrorChargeSompi": "1000000",
    "claimPolicy": {
      "claimWhenUnclaimedAmountExceeds": "100000000"
    }
  }
}
FieldRequiredRule
schemeyesMUST equal batch-settlement.
networkyesMUST equal kaspa:testnet-10.
amountyesFixed charge for this invocation, as positive canonical decimal sompi.
assetyesMUST equal KAS.
payToyesProvider payout address; it is not the lane address.
maxTimeoutSecondsyesMaximum presentation lifetime in seconds.
extra.bindingyesMUST equal kaspa-escrow-v3.
extra.templateIdyesMUST equal kaspa-x402-escrow-v4.
extra.serverPublicKeyyesProvider claim and top-up co-authorization key.
extra.minDepositSompiyesMinimum initial covenant value.
extra.claimReserveSompiyesRequired value beyond remaining authorization.
extra.refundTimeoutDaayesAbsolute DAA score for unilateral refund.
extra.securityContextHashyesHash of the host-derived principal, tenant, authorization scope, and other handler-relevant context.
extra.mcpErrorChargeSompiMCP onlyRequired for MCP and MUST equal amount.
extra.claimPolicynoNon-authorizing provider claim timing policy.
extra.channelStatenoCorrective current lane snapshot; it MUST NOT disclose a reusable voucher signature.

amount is not a maximum and cannot be lowered after service. The payer signs a cumulative value that increases by exactly this amount. A provider that wants post-priced, discounted, success-only, or zero-on-error semantics must use a different protocol with a payer-authenticated post-service amount.

For MCP, mcpErrorChargeSompi makes the error outcome explicit before the payer authorizes the invocation. Its only valid v3 value is amount; a missing, zero, or lower value cannot authorize a paid isError result. Implementations MUST reject an MCP batch offer without this equality rather than silently defaulting the error charge.

All monetary and covenant-state values are in 0..9223372036854775807. Values used as charges, funding, reserve, or authorization MUST be positive where stated. Implementations MUST reject an out-of-range value before hashing, adding, signing, or building a transaction.

minDepositSompi MUST be at least amount + claimReserveSompi. The sum must remain in range. refundTimeoutDaa MUST remain below 500000000000, where Kaspa lock time changes to timestamp interpretation.

Accepted requirements hash

acceptedRequirementsHash is SHA-256 over the UTF-8 canonical JSON encoding of:

{
  "scope": "kaspa:x402:batch-payment-requirements:v3",
  "accepted": "<the complete selected PaymentRequirements object>"
}

Canonical JSON sorts object keys in ascending UTF-16 code-unit order, retains array order, uses compact JSON primitives, and rejects undefined, non-finite, cyclic, or non-JSON values. All fields, including recognized and unknown extension fields, are included. A parser MUST validate the selected binding before hashing it.

Payer-Controlled Batch Authorization

Protocol validity is not payer consent. Every client MUST expose a mandatory authorizeBatchPayment boundary owned by the payer or wallet. It is invoked for a new channel, every fixed-charge voucher increase, and every top-up before key generation, preparation, persistence, signing, or broadcast. Absence, rejection, or ambiguity fails closed.

The authorizer receives this complete immutable intent:

{
  "scope": "kaspa:x402:batch-payment-intent:v1",
  "operation": "open|charge|top-up",
  "origin": "https://api.example",
  "resource": "https://api.example/report",
  "network": "kaspa:testnet-10",
  "asset": "KAS",
  "payTo": "kaspatest:...",
  "serverPublicKey": "<32-byte x-only hex>",
  "clientPublicKey": "<32-byte x-only hex or null before approved key creation>",
  "requestFingerprint": "<32-byte hash>",
  "acceptedRequirementsHash": "<32-byte hash>",
  "securityContextHash": "<32-byte hash>",
  "fixedChargeSompi": "1000000",
  "mcpErrorChargeSompi": "1000000 or null",
  "authorizedCumulativeBefore": "2000000",
  "authorizedCumulativeAfter": "3000000",
  "claimedCumulativeAmount": "1700000",
  "initialDepositSompi": "0",
  "currentFundingSompi": "88300000",
  "topUpSompi": "0",
  "resultingFundingSompi": "88300000",
  "resultingExposureSompi": "90000000",
  "claimReserveSompi": "2000000",
  "refundTimeoutDaa": "123456789",
  "authoritativeCurrentDaa": "123450000",
  "refundDistanceDaa": "6789",
  "fundingSource": "external-wallet-adapter",
  "channelId": "<32-byte hash or null>",
  "covenantId": "<32-byte non-zero hash or null>",
  "paymentIdentifier": "request-123 or null"
}

For open, initialDepositSompi is the new lane value, currentFundingSompi and topUpSompi are zero, and the channel/covenant ids may be null until deterministic key/config construction is explicitly approved. For an existing lane, initialDepositSompi is zero. For top-up, topUpSompi = resultingFundingSompi - currentFundingSompi. resultingExposureSompi is claimedCumulativeAmount + resultingFundingSompi; it prevents repeated top-ups after claims from bypassing a current-balance cap.

Before invoking the authorizer, the payer implementation MUST enforce a complete payer-owned policy containing:

Every maximum is inclusive except the maximum refund horizon, which is an exclusive upper bound. All fields are mandatory for unattended operation. An interactive wallet MAY apply stricter limits but cannot omit the intent.

The client MUST obtain authoritativeCurrentDaa from a trusted Kaspa node or configured chain adapter, not from payment requirements or peer metadata. It then calculates, without unsigned overflow:

refundDistanceDaa = refundTimeoutDaa - authoritativeCurrentDaa
minimumRefundLeadDaa <= refundDistanceDaa < maximumRefundHorizonDaa

If current DAA is unavailable, the timeout is not in the future, or either bound fails, authorization stops before wallet or signer work. The check is repeated for every top-up and voucher increase.

The canonical intent digest is SHA-256 over canonical JSON of the complete object above. Any approval evidence MUST bind that digest. An approval for one operation, request, funding source, amount, or deadline is invalid after any field changes.

Channel Config And Identity

{
  "network": "kaspa:testnet-10",
  "asset": "KAS",
  "templateId": "kaspa-x402-escrow-v4",
  "clientPublicKey": "<32-byte x-only hex>",
  "serverPublicKey": "<32-byte x-only hex>",
  "payTo": "kaspatest:...",
  "refundAddress": "kaspatest:...",
  "refundTimeoutDaa": "123456789",
  "salt": "<32-byte hex>"
}

channelId is:

sha256(
  sha256("kaspa:x402:channel:v2") ||
  sha256(network utf8) ||
  sha256("KAS") ||
  sha256(templateId utf8) ||
  clientPublicKey32 ||
  serverPublicKey32 ||
  sha256(payTo utf8) ||
  sha256(refundAddress utf8) ||
  refundTimeoutDaa_le64 ||
  salt32
)

Strings are UTF-8 before hashing. Integers are unsigned little-endian. channelId identifies application configuration. covenantId identifies the on-chain KIP-20 lineage. They are different values, and neither locates the current UTXO.

Lifetime Accounting

The only charge variable is the payer-authenticated cumulative value:

SymbolWire valueMeaning
SclaimedCumulativeAmount and covenant stateLifetime gross value removed on-chain, including claim fees.
TauthorizedCumulativeAmount and voucher valueExact sum of fixed charges the payer has authorized.
VfundingAmountCurrent active covenant UTXO value.
RclaimReserveSompiRequired value beyond remaining authorization.

Every accepted snapshot satisfies:

0 <= S <= T <= 9223372036854775807
(T - S) + R <= V

For a new non-retry invocation:

T_after = T_before + accepted.amount

An identical retry reuses the same presentation, voucher, fixed charge, commitment, and cached result; it does not add the amount again. Claims and top-ups do not reset S or T.

R is funding safety margin, not provider entitlement. Claim fees are deducted from the provider payout and do not change T.

Channel State

{
  "channelId": "<32-byte channel id>",
  "covenantId": "<32-byte KIP-20 covenant id>",
  "activeOutpoint": { "txid": "<current txid>", "index": 1 },
  "activeScriptPublicKey": "<serialized script public key>",
  "fundingAmount": "88300000",
  "authorizedCumulativeAmount": "3000000",
  "claimedCumulativeAmount": "1700000"
}

Runtimes MUST persist and atomically advance the active outpoint, script, value, state, and covenant id. Standard RPC does not provide a covenant-id-to-UTXO reverse index. Recovery must verify unique same-id transaction lineage before adopting a successor.

Corrective public responses MAY include this snapshot but MUST NOT include a reusable voucher signature. Reusable voucher disclosure requires separate payer authentication outside this wire profile.

Chain Truth, Confirmation, And Recovery

Peers and adapters do not choose semantic finality. Trusted accepted evidence contains the transaction id, accepting-block hash and blue score, numeric confirmation count, and a stable selected-chain checkpoint (sink block hash, blue score, and DAA score). The confirmation count is the authoritative selected-parent distance from the selected-chain tip, including the accepting block. Blue-score difference MUST NOT be used as selected-chain depth.

The runtime applies deployment policy to that count. v1 RC1's reference kaspa:testnet-10 deployment requires 30 confirmations for covenant genesis, claim, top-up, refund, and recovered lineage. This is not a universal Kaspa consensus-finality constant. Accepted evidence below the threshold remains reserved and cannot authorize a state transition.

The reference adapter proves the threshold through GetVirtualChainFromBlockV2 with minConfirmationCount. A stable REST UTXO and selected-chain accepting block prove only a conservative lower bound of one; REST evidence alone cannot authorize 30-confirmation batch lineage.

The v1 RC1 reference deployment trusts one configured Testnet-10 evidence source at a time. Multiple configured endpoints provide failover, not independent corroboration. Mainnet requires independently corroborated chain evidence or another audited Byzantine-resilient design; unavailable or disagreeing evidence MUST fail closed.

absent means the exact transaction is permanently excluded by either a distinct confirmed spend of its input or stable consensus-rejection evidence. A missing index entry, UTXO observation, timeout, transport error, or pruned history is unknown; it never permits rebuilding or reusing the captured head.

Each lane begins with an immutable launch manifest containing:

Every later accepted claim, top-up, or refund is appended to a durable journal with its consumed outpoint, transaction, unique successor or terminal output, state, value, covenant binding, accepting block, confirmation evidence, and checkpoint. The current head is derived atomically from this manifest and journal; an adapter-supplied head is never authority.

An observer resumes from the durable checkpoint using a complete selected-chain delta. Removed blocks MUST be processed and journaled before added blocks. All affected derived state is rolled back first; replacement transactions may then extend only the restored head. Missing or ambiguous predecessors, multiple spends or successors, wrong covenant/template bindings, and inconsistent state or value changes fail closed. If pruning prevents continuity proof, the lane is unavailable until an authoritative complete history can be supplied.

Selected-chain retrieval MUST enforce cumulative response-byte, block-count, and page-count limits across the complete traversal, plus a finite deadline for each remote operation. A limit breach or non-converging traversal fails closed; an implementation MUST NOT silently truncate a delta and treat it as complete.

Clients and servers reconcile this lineage before lane reuse, top-up, claim, retirement, or refund. A suspicious client lane may become refundable after its unique live head is verified, but it MUST NOT become chargeable again. If a confirmed terminal refund is removed, its applied attempt and terminal status roll back atomically to refund-only state before another refund can be built. An implementation MUST NOT advertise or select batch-settlement unless this authoritative lineage-discovery capability is configured.

Voucher

{
  "covenantId": "<32-byte non-zero covenant id>",
  "authorizedCumulativeAmount": "3000000",
  "signature": "<64-byte Schnorr signature>"
}

The payer signs:

sha256(
  sha256("kaspa:x402:escrow-voucher:v3") ||
  sha256(network utf8) ||
  covenantId32 ||
  T_le64
)

The signature is raw 64-byte Schnorr over the raw 32-byte digest. T is lifetime cumulative authorization. It MUST equal the previous authorized value plus the fixed amount for a new request and MUST NOT decrease or reset. Network, covenant id, and previous T come from trusted lane state.

The voucher is intentionally reusable on-chain across same-id successors. It does not authorize a request; that is the presentation's job.

Request Presentation Authorization

Every deposit-voucher and voucher payment payload includes:

{
  "version": "kaspa-x402-batch-presentation-v1",
  "requestFingerprint": "<32-byte canonical HTTP or MCP fingerprint>",
  "acceptedRequirementsHash": "<32-byte hash>",
  "securityContextHash": "<32-byte trusted context hash>",
  "channelId": "<32-byte channel id>",
  "covenantId": "<32-byte non-zero covenant id>",
  "voucherDigest": "<32-byte v3 voucher digest>",
  "paymentIdentifier": "request-123 or null",
  "nonce": "<32-byte unique nonce>",
  "expiresAt": "2026-09-09T02:00:00.000Z",
  "digest": "<32-byte presentation digest>",
  "signature": "<64-byte Schnorr signature>"
}

To compute digest, canonical-JSON serialize and SHA-256 this object without digest and signature:

{
  "scope": "kaspa:x402:batch-presentation:v1",
  "requestFingerprint": "<lowercase hash>",
  "acceptedRequirementsHash": "<lowercase hash>",
  "securityContextHash": "<lowercase hash>",
  "channelId": "<lowercase hash>",
  "covenantId": "<lowercase non-zero hash>",
  "voucherDigest": "<lowercase hash>",
  "paymentIdentifier": "request-123 or null",
  "nonce": "<lowercase hash>",
  "expiresAt": "2026-09-09T02:00:00.000Z"
}

The channel client key signs the raw digest. The verifier independently computes the request fingerprint, accepted-requirements hash, trusted security context hash, channel id, covenant id, and voucher digest. Payload copies are evidence only.

expiresAt MUST be strictly after the verification clock and no later than now + accepted.maxTimeoutSeconds. Expiry is rechecked after awaited verification and immediately before protected work. An expired presentation may identify an exactly matching immutable attempt whose handler had already been durably admitted. That attempt may resume only its persisted result or commit state. If expiry occurs after durable admission but before the handler starts, the attempt becomes recovery-required and the handler MUST NOT run; the server returns a retryable unavailable response until an operator supplies a known durable result. Expiry never creates new work or authorization.

nonce is unique per logical request. paymentIdentifier is the validated x402 identifier or explicit null; both fields are signed. The server durably consumes the presentation digest with the request fingerprint. Changed request, requirements, security context, channel, covenant, voucher, identifier, nonce, or expiry fails before protected work.

PaymentPayload

The request-bearing discriminators are deposit-voucher and voucher. claim and refund remain operation payloads.

A deposit or accepted top-up successor uses:

{
  "type": "deposit-voucher",
  "channelConfig": { "...": "v4 config" },
  "channelId": "<32-byte channel id>",
  "escrowAddress": "kaspatest:...",
  "fundingTransaction": "<optional opaque transaction evidence>",
  "fundingOutpoint": { "txid": "<current txid>", "index": 0 },
  "fundingAmountSompi": "90000000",
  "activeScriptPublicKey": "<serialized active script public key>",
  "voucher": {
    "covenantId": "<32-byte covenant id>",
    "authorizedCumulativeAmount": "1000000",
    "signature": "<64-byte signature>"
  },
  "presentation": { "...": "v1 presentation" }
}

An existing lane uses:

{
  "type": "voucher",
  "channelId": "<32-byte channel id>",
  "clientPublicKey": "<32-byte x-only key>",
  "fundingOutpoint": { "txid": "<current txid>", "index": 1 },
  "activeScriptPublicKey": "<serialized active script public key>",
  "voucher": {
    "covenantId": "<32-byte covenant id>",
    "authorizedCumulativeAmount": "3000000",
    "signature": "<64-byte signature>"
  },
  "presentation": { "...": "v1 presentation" }
}

Outpoints and scripts synchronize the head but are not voucher or presentation authority. A verifier obtains authoritative UTXO and lineage facts independently.

Escrow-v4 Template

kaspa-x402-escrow-v4 is the byte-exact stateful KIP-20 contract compiled from the normative SilverScript source and pinned by its language-neutral byte fixture. Constructor material is:

clientKey                  = hex_decode(clientPublicKey)
serverKey                  = hex_decode(serverPublicKey)
networkHash                = sha256(network utf8)
payoutScriptPublicKeyHash  = sha256(serialized_script_public_key(payTo))
refundScriptPublicKeyHash  = sha256(serialized_script_public_key(refundAddress))
timeoutLe                  = refundTimeoutDaa_le64
initial state S            = 0

timeoutLe is exactly eight bytes. Implementations reconstruct and verify the full redeem script and version-0 P2SH script public key. Client-provided addresses, hashes, scripts, and compiler output are never authority.

An accepted claim advances embedded state S and changes the successor script/address. A top-up preserves state and script but advances outpoint and value.

Singleton genesis

The accepted genesis transaction has exactly one output: the expected v4 covenant with non-zero id, state S = 0, and value at least minDepositSompi. Inputs equal escrow value plus fee. The complete transaction must be verified and recorded before it can be pruned.

Claim

input[0]  = current covenant head (id C, state S, value V)
output[0] = unbound provider payout, value P
output[1] = sole authorized same-id successor, state S + D, value V - D

The covenant arguments are:

push(provider_transaction_signature_65) ||
push(client_voucher_signature_64) ||
push(T_le64) ||
push(D_le64) ||
claim_selector ||
push(redeem_script)

The covenant enforces:

0 < D <= T - S
successor state = S + D
successor value = V - D > 0
0 < P <= D
fee = D - P

It also enforces one same-id input and successor, the configured payout script hash, fixed output positions, and provider SIGHASH_ALL. Because T is the exact sum of payer-approved fixed charges, a direct provider claim cannot exceed those charges.

Provider-co-authorized top-up

input[0]  = current covenant head (id C, state S, value V)
input[1+] = payer funding inputs
output[0] = sole authorized same-id successor, state S, value V' > V
output[1] = optional unbound configured payer change

The active covenant input arguments are:

push(client_transaction_signature_65) ||
push(provider_transaction_signature_65) ||
top_up_selector ||
push(redeem_script)

Both signatures MUST use SIGHASH_ALL and validate against the configured client and provider keys. Each therefore covers the complete ordered inputs, UTXO commitments, outputs, covenant bindings, values, scripts, lock time, subnetwork, gas, payload, mass, and compute commitments defined by Kaspa's transaction-v1 sighash.

The provider MUST derive the sighash from the fully populated intended transaction after verifying the authoritative current head, exact singleton successor, unchanged state/script, increased value, optional configured change, fee, and funding inputs. It MUST NOT sign a digest or transaction summary supplied by the client without reproducing it.

A client signature alone cannot satisfy escrow-v4. The provider signature is not optional, substitutable by a voucher, or reusable after any transaction field changes.

Refund

After refundTimeoutDaa, one client SIGHASH_ALL input terminates the lineage and pays the configured unbound refund script. No same-id successor is allowed. Refund readiness uses authoritative current DAA and requires it to be strictly greater than the transaction lock time.

Transaction-v1 Verification

Before broadcast, a builder or facilitator:

1. loads the authoritative current UTXO and persisted head; 2. verifies its id, script, value, state, and outpoint; 3. constructs the exact singleton topology; 4. recomputes transaction id, hash, every sighash, storage mass, script units, and compute budget under active consensus rules; 5. executes the covenant input against the pinned consensus implementation.

Adapter-returned identifiers, fees, scripts, states, masses, and finality are evidence to verify, not authority.

Request Processing

For a new batch invocation, implementations perform:

1. bounded side-effect-free envelope, extension, identifier, binding, and accepted-requirements validation; 2. authoritative current DAA lookup and payer policy checks; 3. mandatory approval of the complete payer intent; 4. any approved genesis or provider-co-signed top-up transition; 5. calculation of T_after = T_before + accepted.amount; 6. v3 voucher and v1 presentation signing; 7. server verification and durable consumption of the presentation; 8. a final presentation-expiry check at the actual protected-handler invocation, followed by handler execution only while still live; 9. atomic persistence of T_after, the voucher proof, fixed charge, commitment, identifier, and bounded result before release.

An identical retry resumes the same durable attempt and result. A changed fingerprint, requirements hash, context, payment identifier, or presentation cannot enter the handler.

The fixed charge amount becomes immutable when the protected invocation is admitted, but A and the request commitment advance only after the invocation completes and its result is durably staged. The provider MUST NOT record or return a different charge based on handler output. An MCP isError result is chargeable only under the explicit equal mcpErrorChargeSompi term.

Commitment

The durable request commitment is:

sha256(
  sha256("kaspa:x402:batch-commitment:v3") ||
  channelId32 ||
  covenantId32 ||
  presentationDigest32 ||
  requestFingerprint32 ||
  acceptedRequirementsHash32 ||
  activeOutpointTxid32 ||
  activeOutpointIndex_le32 ||
  authorizedCumulativeBefore_le64 ||
  authorizedCumulativeAfter_le64 ||
  sha256(voucherSignature64) ||
  fixedCharge_le64 ||
  S_le64
)

authorizedCumulativeAfter MUST equal authorizedCumulativeBefore + fixedCharge and the voucher must sign that same after-value. The record includes all preimage fields, voucher and presentation proofs, payment identifier, and cached response metadata.

SettlementResponse

Voucher-only success uses the commitment id in transaction. Top-level amount and extensions.kaspa.chargedAmount both equal accepted.amount:

{
  "success": true,
  "transaction": "<commitment id>",
  "network": "kaspa:testnet-10",
  "amount": "1000000",
  "extensions": {
    "kaspa": {
      "commitmentId": "<commitment id>",
      "covenantId": "<covenant id>",
      "chargedAmount": "1000000",
      "channelState": { "...": "current v3 state" }
    }
  }
}

For deposit-voucher, fundingAmount reports escrow principal separately. Claims and refunds return their independently recomputed transaction ids.

Trust Boundary

The covenant enforces the payer-signed cumulative fixed-charge total, payout destination, singleton same-id lineage, provider-co-signed top-ups, state and value transitions, and refund destination/timeout. The presentation proves that the channel key authorized one request context. The payer-controlled intent gates wallet and funding side effects.

The covenant does not prove that off-chain service was delivered. Like exact payment, a signed non-refundable fixed charge trusts the provider for delivery. This profile makes that economic meaning explicit and does not claim a provider-local lower charge that the covenant cannot enforce.

Fail-Closed Cutover And Evidence

Implementations MUST reject:

Interop evidence covers the v2 channel id, v3 voucher, payer intent, presentation, requirements hash, fixed-charge commitment, singleton genesis, partial/direct claims, provider-co-signed top-up, refund, old-domain rejection, client-only top-up rejection, and positive/negative execution against the pinned Rusty-Kaspa consensus checkout.

Testnet-10 or local consensus evidence is alpha validation only. It is not mainnet or production proof.

Source: /spec/kaspa-batch-settlement-v3.md