Formal interop specification

The byte-exact interoperability specification

F1–F10: the wire objects, the entry and channel state machines, the fee arithmetic, and the conformance vectors an implementation conforms to. The whitepaper describes the protocol; this defines the exact bytes.

The formal specification is authored and frozen against a pinned commit; the reference implementation is checked against the F10 conformance-vector corpus.

PayTP Formal Interop Specification#

Status: draft. Nothing here is frozen until the F10 conformance corpus passes end-to-end against an implementation and a second independent decoder (F10.4).

Tracks: PayTP whitepaper v0.30 / protocol v0.1. This specification's version follows the whitepaper's document version; the pervasive v0.1 / PayTPv1-* below is the protocol version (§20), a separate axis. Where this specification lags a whitepaper change, SPEC-SYNC.md tracks the open divergence.

This is the document the whitepaper defers to. Whitepaper §5.2: "exact octet layouts belong to the formal specification that will accompany the reference implementation." The whitepaper states what and why; this specification states the bytes.

Relationship to the whitepaper. The whitepaper (spec/, chapters 1–20) is normative on design and is the source of truth for intent; this specification is normative on encoding and MUST NOT contradict it. It is a superset of the whitepaper's implementation detail — every wire, byte, and arithmetic rule the whitepaper defers. The whitepaper leads: where this specification has not yet caught up to a whitepaper change, the whitepaper governs and this specification is corrected up to it, never the reverse.

Self-contained. This specification references only the whitepaper and external standards (the RFCs, CAIP, UTS #46, the Public Suffix List, and the x402 specification named in the sections). It carries no dependency on any other project document — an implementer needs only this specification and the whitepaper it points to.

Notation and cryptography are defined in F1 (TLV wire encoding, integer/string/bytes rules, canonical JSON, the signing envelope, the crypto suite) and referenced by every later section.

Sections#

§SectionCoversWhitepaper anchors
F1FoundationsNotation, TLV wire encoding, integer/string/bytes rules, canonical JSON (JCS), the signing envelope, crypto suite (Ed25519, Poly1305 one-time-key construction, HPKE, HKDF, hashes), key derivation§5.2, §5.5, §5.3
F2Identity & bindingMerchant key + binding artifact, payer-key derivation (merchant key × registrable domain), transport-independent channel-binding salt BindSalt = SHA-256(payer‖merchant), H(s) session-secret sealing, control-endpoint resource map§5.5, §6.2
F3Tier 0 objectsThe x402 paytp extension: quote (mirror rule), MEED_VECTOR, PayTP-Roles, receipt, attestation/cancellation TLVs — JSON property names, signature coverage, idempotency§5.6, §10.1
F4Entry machineSplit-address & entry-id derivation, entry state machine with absolute rail-clock deadlines, claim-record kind, merchant durable orders, wallet funding order, batch operations§5.6, ch 11 §11.1
F5Channel messagesCHANNEL_AUTH/ACK, slice carriage grammar, checkpoint (chain via PREV_REF), settlement messages, TLV layouts, role-fixed signature slots§5.4, §6.2–6.4
F6Channel state machineStates, canonical acceptance order, checkpoint chain + tiebreaker, B equations, settlement rounds, chaining import, all-or-close, error mapping§5.7, §6.1–6.4
F7Fee arithmeticNumerator accrual, conversion grains, floor extinguishment + canonical attribution, instance claimable_d rule, dust§10.2
F8Timeouts & clocksThe protocol constants, skew, three-clock model, window arithmetic, finality-time semantics§5.6, §6.3–6.4
F9Registry snapshotSnapshot format + lifecycle, destination-pointer grammar (CAIP-10), identifier grammars, fallback algorithm§10.1, §10.5
F10Conformance vectorsCorpus format, canonicalization discipline, required coverage, hand-derived seed vectorsch 11 §11.1

The order is dependency-driven: F1 is referenced by everything; F2–F4 are Tier 0; F5–F6 are the channel plane; F7–F9 are cross-cutting; F10 is the conformance corpus that binds the sections to running code.


F1 — Foundations#

Encoding primitives, canonical forms, the signing envelope, and the cryptographic suite. F1 formalizes what Chapter 5 §5.2/§5.3/§5.5 already fix; it does not change them. Where the whitepaper leaves a detail open ("a variable-length integer", "how the wallet derives it is internal"), F1 fills it; nothing here contradicts the whitepaper.

F1.0 Conventions#

F1.1 TLV encoding (formalizes §5.2)#

Each field is type ‖ length ‖ value:

Canonical form (§5.2), the bytes over which tags, transcript hashes, and signatures are computed:

  1. Fields sorted by type number (the low 7 bits) ascending — the critical flag does not participate in ordering. Duplicate type numbers are forbidden (rule 2), so this order is total.
  2. Duplicate types are forbidden (§5.2). A structure with repeated items (a meed vector's roles, a batch's entry ids) is therefore one TLV whose value is a count-prefixed ordered list — never repeated top-level types; the prefix is the item count as a canonical LEB128, followed by the items back-to-back, each item's byte layout and order fixed by its defining section (F3/F4/F5). A count that does not consume the value exactly is rejected. This removes any "which order is canonical" ambiguity: there is exactly one top-level occurrence of each type.
  3. Integer values use minimal-length big-endian (no leading 0x00; zero is exactly the single byte 0x00 — an empty, zero-length integer value is rejected, for signed integers equally), except where a field definition pins a fixed width — the slice's SEQ (8) and AMT_µ (6) are fixed by §5.3 and are always full width. A parser MUST reject a non-minimal variable-width integer.
  4. F1-b (signed integers): a value that can be negative — the checkpoint balance B (§6.1, −L_prepay ≤ B ≤ +L_credit) — is encoded as two's-complement big-endian, minimal-length, where minimal means the shortest encoding that preserves the sign bit (reject a redundant leading 0x00/0xFF). A field definition states whether it is unsigned or signed; the two never share a type.
  5. F1-g (signed text): text values (host names, pointer URIs) are UTF-8, NFC-normalized, no BOM, and contain no NUL and no other C0/C1 control characters anywhere — an embedded NUL is a truncation attack on every C-string consumer downstream, and a signature over host\x00evil must be unwritable, not merely inadvisable; non-conforming text is rejected, not normalized (canonicalization is validation, never transformation — the property that makes a signature over the bytes unambiguous). The whitepaper fixes no text-encoding rule; this fills it. IDNA/punycode/lowercasing rules for host fields are pinned in F2, before payer keys derive from them.
  6. A parser MUST reject: out-of-order types, any duplicate type, a non-minimal length or integer, a length overrunning the buffer, trailing bytes, or a recognized type number carried with a critical flag other than its defined one (a field defined non-critical never validly appears with the top bit set, and vice versa).
  7. F1-l (integer field domains — the min/max F1 promises, for TLV): every PayTP TLV integer field has a per-field maximum, and a value exceeding it is rejected. Three domains cover every defined integer field — none is left unbounded: time and duration fields — Unix seconds and second-durations (TIMESTAMP, TH_TIME, RATE_TIME/RATE_EXP/RATE_GRACE, the artifact's NOT_BEFORE/NOT_AFTER, and every window handed to F8) — are ≤ 2⁵³ − 1 (matching the Tier 0 pins of F3-g, IEEE-safe and past year 285 000 000); µ-unit value fields (LIMIT_L, LIMIT_E, TH_VALUE, AMOUNT, balances by magnitude) are ≤ 2¹²⁸ − 1 (F7-a's exact-arithmetic domain); and identifier, version, and basis-point fieldsSCHEMA, REGISTRY_V, CONTRACT, the registry snapshot's VERSION/WINDOW_FLOOR/revoked version numbers (F9), and RATE_DEV basis points — are ≤ 2³² − 1 (small monotone counters and shares no real deployment approaches; RATE_DEV, a basis-point deviation, is in practice ≤ 10 000 but the field's hard cap is 2³²). A field carrying a value above its domain is rejected, so a bignum encoder can never sign a CONTRACT = 2⁴⁰⁹⁶ or RATE_DEV = 2¹²⁸ that a fixed-width decoder would wrap or reject differently. Consequence: every F8 sum or comparison a builder forms (RATE_EXP + RATE_GRACE, a TH_TIME deadline, T_open + reclaim) is a handful of ≤ 2⁵³ terms and cannot overflow any 64-bit or bignum implementation, and no amount escapes F7's domain — so no two implementations diverge by one wrapping a huge TLV integer while another computes a far-future or out-of-range result. (SEQ's own ≤ 2⁶³ cap, F1-e, is unchanged.)

Coverage (§5.2): authenticator TLVs — TAG and every signature TLV — are excluded from the covered bytes of the object that carries them. F1-i (coverage is computable without recognizing every field): type numbers 0x700x7F are reserved for authenticator TLVs in every object registry (F2/F3/F5 comply); the slice's TAG at 0x02 is the one §5.3-pinned exception, defined an authenticator by the slice's own registry. A verifier reconstructing covered bytes excludes exactly the authenticator TLVs its object registry (plus any establishment-negotiated suite, §5.8) defines; every other TLV — including an unrecognized non-critical one — is covered content, and an unrecognized type in the reserved range MUST be rejected, never skipped — an authenticator the receiver cannot verify is not an ignorable extension, and a new authenticator type only ever arrives by negotiation (§5.8), so an unnegotiated one is a protocol violation. "Ignored" (§5.2) means not interpreted, never removed from coverage: an extension rides inside the authenticated bytes, so nothing unauthenticated can be injected beside a signature or tag — an injected unknown TLV either changes the covered bytes (outside the range) or is rejected outright (inside it).

Carriage (§5.2): Base64url without padding in an HTTP header field; raw binary as application/paytp+tlv on the control endpoint. PayTP header fields are sensitive: never-indexed encoding where available, Cache-Control: no-store on PayTP-authenticated responses and quote-bearing 402s, and Vary on the PayTP capability and role headers.

F1-m (transport security — a global rule, every tier): PayTP requires TLS 1.3 (or 1.2) and MUST NOT run over plaintext HTTP (§5.1). This is not merely the channel plane's concern (F2's BindSalt/sealing assume it): it applies to every PayTP flow, the stateless Tier 0 exchange (F3) included, so an implementer building Tier 0 from F3 alone still finds the rule here. A PayTP object presented over plaintext HTTP is invalid regardless of its own signatures. A header-stripping intermediary can only deny the capability — both sides fall back to legacy checkout — never forge or alter a payment, because every object is authenticated end-to-end at the PayTP layer (§5.1).

F1.2 Canonical JSON — Tier 0 (formalizes §5.2/§5.6)#

The paytp extension and its signed sub-objects use JCS (RFC 8785). Signature coverage: **the serialization root is the paytp object itself** — never the enclosing x402 envelope — JCS-serialized with its signature member absent (§5.2's paytp.signature is a path: the member named signature inside the object named paytp, never a literal member name containing a dot), signed under the object's domain label (F1.3), signature then inserted (§5.2). The same rule holds for every signed JSON object: the root is the object that carries the signature member, nothing outside it. A verifier MUST reject a JSON document containing duplicate member names anywhere in the text it parses — the enclosing envelope included, not merely the signed subtree — before extracting any object from it: two paytp members in one envelope would otherwise let first-wins and last-wins parsers verify different signed objects from the same bytes.

F1-c (exact numerics): every PayTP-defined amount, basis-point, and timestamp is a JSON string, never a JSON number, carrying a fixed decimal grammar per field; opaque byte identifiers — the nonce and the idem key — are JSON strings too, never numbers, but carry the Base64url grammar their own field defines (F3), not this decimal one. Every grammar in this specification is anchored: the entire value must match, ^…$, so a substring match never passes. Unsigned integers match ^(0|[1-9][0-9]*)$ (no leading zero, no sign, no point, no exponent, no whitespace); the one signed field (a balance, if surfaced in JSON) matches ^-?(0|[1-9][0-9]*)$ with no -0. Each field states its min/max and unit. This closes the "1" vs "01" vs "1.0" ambiguity Poly-JCS numbers would leave open. Scope: this rule binds PayTP's own members only. Where a PayTP object mirrors a member of the surrounding x402 envelope (F3-a's offers mirror), the mirror preserves the x402 value verbatim in x402's own JSON type — if x402 encodes a field as a JSON number, the mirror carries that number — because the mirror's job is byte-for-value equality with the accepts entry it prices (F3-a); imposing PayTP's string-numeric rule on a mirrored x402 field would break that equality. PayTP never defines a member as a number; x402 compatibility is why the exception exists.

F1.3 The signing envelope and domain separation (formalizes §5.2)#

Every Ed25519 signature and the slice MAC cover:

COVERED = DOMAIN_LABEL ‖ 0x00 ‖ canonical_bytes(object, authenticators excluded)

F1-h (label delimiter): the single 0x00 byte terminates the label inside COVERED. Labels are ASCII and never contain 0x00, so the label's end is unambiguous — without it, a registry label that is a string prefix of another (PayTPv1-ckpt / PayTPv1-ckpt-req) would let one object type's signature verify as another's over crafted bytes. The whitepaper fixes the labels and the prefixing; this pins the byte construction.

DOMAIN_LABEL is the exact §5.2 registry, "PayTPv1-<object>":

PayTPv1-slice, PayTPv1-chan-auth, PayTPv1-chan-ack, PayTPv1-ckpt, PayTPv1-ckpt-req, PayTPv1-funding, PayTPv1-settle-propose, PayTPv1-settle-proof, PayTPv1-settle-confirm, PayTPv1-close, PayTPv1-prepay-draw (the prepay interim-draw completion notice, F5-o/F6-n), PayTPv1-reqs (the Tier 0 quote/challenge), PayTPv1-receipt (the Tier 0 receipt), PayTPv1-artifact (the merchant binding artifact, §5.5), PayTPv1-ack-req (the payer-signed acknowledgment-retrieval request, §5.4), PayTPv1-attest (the redemption attestation, §5.6), PayTPv1-cancel (the cancellation, §5.6), PayTPv1-registry (the Foundation-published role-registry snapshot, §10.1/§10.5; F9). No two object types share a label, so no signature or tag replays as another — in particular, the attestation and the cancellation are two signatures over the same nonce and entry identifier that must never pass for one another (§5.2), which is exactly what their distinct labels enforce. canonical_bytes is F1.1 for TLV objects and the JCS bytes of F1.2 for the two JSON objects (PayTPv1-reqs, PayTPv1-receipt); the artifact, attestation, and cancellation are TLV objects (their layouts: F2 for the artifact, F3/F4 for the attestation and cancellation). A verifier reconstructs COVERED from the received object; it never trusts transmitted covered bytes.

F1.4 Cryptographic suite (formalizes §5.5; one suite, no v0.1 negotiation)#

PurposeAlgorithmReference
Signatures (merchant, payer, checkpoints)Ed25519, strict verificationRFC 8032
Hash (all uses)SHA-256FIPS 180-4
Slice authenticationPoly1305 under a per-slice subkey (F1.5)RFC 8439 §2.5
Channel-secret sealingHPKE base mode, DHKEM(X25519,HKDF-SHA256)/HKDF-SHA256/ChaCha20-Poly1305RFC 9180
Key derivationHKDF-SHA256RFC 5869

F1.5 The slice authenticator (formalizes §5.3/§5.5 exactly)#

The whitepaper fixes this construction; F1 restates it precisely:

K_session   = HKDF-SHA256(ikm = s, salt = BindSalt,
                          info = "PayTPv1-slice" ‖ channel_id, L = 32)   # §5.5, F1.6
subkey(SEQ) = HKDF-SHA256(ikm = K_session, salt = "",
                          info = LE64(SEQ), L = 32)                      # one 32-byte key per slice, §5.5
TAG         = Poly1305(subkey(SEQ),
                       COVERED(slice))          # F1.3: "PayTPv1-slice" ‖ 0x00 ‖
                                                #   canonical_bytes(slice, authenticators excluded)

HKDF is RFC 5869 (extract-then-expand); L = 32 gives the 32-byte Poly1305 one-time key and the 32-byte K_session. LE64(SEQ) is the HKDF info, so each SEQ yields an independent subkey. In K_session's info, channel_id is byte-exact: the 8 raw bytes of the §5.4 identifier, unsigned big-endian — never a TLV encoding, never minimal-length; both parts of the info are fixed-length, so the concatenation is unambiguous without a delimiter, matching §5.5's formula literally.

The MAC covers COVERED(slice) — for a v0.1 slice exactly the domain label, delimiter, and the SEQ and AMT_µ TLVs in canonical form (type bytes 0x00/0x01, fixed widths 8/6), with TAG itself excluded (F1.1 coverage). Nothing unauthenticated can ride a slice twice over: an injected unknown TLV is rejected by the closed-object rule (F1-k) before any MAC check, and coverage is all non-authenticator content (F1-i), so even a negotiated future extension is MAC-covered. A **fresh subkey per SEQ** makes raw Poly1305 safe — its one-time-key requirement is met by derivation, not by a nonce (this is why §5.5 derives subkey(SEQ) rather than reusing K_session). The verifier recomputes and compares in constant time. The tag proves integrity, continuity, and channel binding, and nothing to a third party (§6.3) — it is never a signature.

The slice is a closed object. Its registry is §5.3's table exactly: 0x00 SEQ (8 bytes) · 0x01 AMT_µ (6 bytes) · 0x02 TAG (16 bytes, the authenticator). F1-k: a v0.1 receiver MUST reject a slice carrying any other type number — F1.1's ignore rule is for extensible objects, and the slice is not one: §5.3 fixes it at three TLVs, the hot path parses a fixed shape, and a future slice extension arrives only by negotiation (§5.8), never unannounced. (For the v0.1 slice, MAC coverage below is therefore exactly the SEQ and AMT_µ TLVs.)

Carriage names the channel (§5.3): a PayTP-Slice header field value names the channel identifier its slices belong to — one channel per request — and a metering batch body is channel-identified, so a receiver always knows which channel's K_session verifies a slice, whatever connection carried it. The slice object itself carries no channel field: its channel binding is cryptographic, through K_session. The field-value grammar — how the channel identifier and the Base64url slice bytes combine, repeated-field and comma-combined equivalence (§5.3), and the batch body's channel identification — is pinned in F5. Slices MUST NOT be sent in TLS 0-RTT early data, and a receiver MUST NOT account a slice its TLS layer reports as delivered in early data (§5.3) — the rule binds both ends, so neither can waive it for the other.

**SEQ lifecycle (§5.3, plus F1-e — so a subkey never repeats):** SEQ is the 8-byte unsigned integer of §5.3, per channel unique, never reused, minted in increasing order. A sender therefore MUST NOT emit two slices with the same SEQ and differing content; retransmitting a byte-identical slice is not a second mint, and a dropped slice's value is re-minted once under a single fresh higher SEQ — the dropped number itself is never reissued (§5.3). "Dropped" is checkpoint-proven, never guessed: a slice counts as dropped only when a bilateral checkpoint's accepted ranges show it unaccounted below their high-water mark, and that same checkpoint's floor bars the original's late arrival — so a re-mint and its original can never both be accepted (§5.3). Acceptance is by uniqueness above the checkpoint floor, not arrival order (§5.3); F5/F6 formalize it. F1-e: the starting value is fixed in F5; SEQ never wraps, testably — a sender MUST NOT mint SEQ above 2^63 and a receiver MUST reject a slice whose SEQ exceeds it (headroom beyond any real channel's life; a channel closes and chains, §6.2, long before). The one-time-key argument's freshness conditions are local MUSTs, not assumptions: s is freshly generated per channel and never reused across channels (F2.5); the channel identifier is fresh per channel — §6.2's fresh-identifier-and-session-key rule — a merchant rejects a CHANNEL_OPEN reusing a live identifier (§5.4), and a wallet MUST NOT reuse an identifier with the same s. Under these, K_session is fresh per channel and subkeys never collide across channels.

F1.6 Channel-binding salt and payer key (formalizes §5.5)#

BindSalt = SHA-256(payer_key ‖ merchant_key)   # §5.5: the two raw 32-byte Ed25519 public keys, in that order —
                                               # 64 bytes hashed to a 32-byte digest, used directly as the K_session salt (F1.5)

In this context — and wherever F1 pairs a payer key with a merchant key, the payer-key scope below included — merchant_key is the merchant's Ed25519 identity key (§5.5's "merchant key"), never the X25519 channel-encryption key the binding artifact carries (F2); both are raw 32-byte public keys, concatenated in that order as the plain SHA-256 preimage — there is no TLS exporter API and no context-hashing layer, so the 64-byte concatenation is the preimage — the channel-binding salt is transport-independent. **BindSalt is public** — it is the payer↔merchant relationship digest, and its only role is to domain-separate K_session across relationships; K_session secrecy rests **entirely on s** (the fresh, HPKE-sealed per-channel secret, F2.5), never on BindSalt, and merchant authenticity + s confidentiality come from the CHANNEL_AUTH signature and the HPKE seal (F2), both unchanged.

BindSalt is the same for a given payer↔merchant relationship (a digest of their two public keys), so it no longer ties a channel to a particular connection — the channel's lifetime is now a protocol rule, not a key property (§5.5, F6): a channel still ends when its establishing connection — the one that carries CHANNEL_OPEN — closes, and continuity across connections is chaining, never resumption, but this is stated as an explicit state-machine transition (F6.1's connection-close → SETTLING), not a consequence of a connection-bound key. While the channel is open, a carried object (header slice, metering batch, control object) names its channel and authenticates by that channel's K_session on whatever connection delivers it. After the establishing connection closes, only the control plane continues — a checkpoint, settlement, or chaining exchange completes on any connection, while a slice or batch arriving late meters consumption the closed channel can no longer account (§5.5). A slice still cannot move to a different channel: it verifies only under the K_session its own channel_id and the shared per-channel s derive (BindSalt, being relationship-wide, provides none of that isolation — the fresh s and the channel_id do). Letting a channel survive a reconnect is explicitly out of v0.1 scope.

Erasure at close (§5.5): endpoints MUST erase the session secret s and the session keys (K_session and every derived subkey) at channel close — every copy under the endpoint's control, logs, traces, and diagnostic captures included, not merely the live channel state (BindSalt is public and needs no erasure). Chapter 7 §7.5's past-session protection rests on that erasure. Erasure is a conformance and certification obligation, verifiable in a lab against an implementation, never observable on the wire — the same class as every other wallet-internal rule.

Payer key (§5.5): the whitepaper requires the merchant-scoped payer key to be stable per (merchant key, registrable domain) and unlinkable across merchants, and states the derivation is internal to the wallet. F1 therefore specifies the requirement, not a mandated derivation. **F1-f (the property is a MUST; only the derivation is RECOMMENDED): a conforming wallet MUST produce payer keys that are stable per (merchant key, registrable domain) and unlinkable across merchants — the property is normative. What is RECOMMENDED, not mandated**, is the specific derivation: payer_seed = HKDF-SHA256(ikm = wallet_master_secret, salt = merchant_key, info = "PayTPv1-payer" ‖ registrable_domain, L = 32), generating the Ed25519 key from it — deterministic (hence stable) and a PRF of a secret (hence unlinkable without it). A wallet MAY use any other derivation that meets stability + unlinkability, where unlinkability means: without the wallet's secret, the payer keys one wallet presents to two different merchant scopes are computationally indistinguishable from independently generated keys — a definition a certification lab can test against a wallet's declared derivation. Stability and unlinkability are normative wallet-conformance properties a conforming wallet MUST satisfy, never observable on the wire by any single merchant (each sees only its own scope); a wallet that presents one global key everywhere interoperates but is non-conformant (fails certification) — the same lab-testable class as erasure above: a shared global payer key across merchants is a privacy regression the certification regime rejects, even though no single merchant can observe it. Registrable domain is computed per the PSL rule pinned in F2, and the wallet scopes to the registrable domain it verifies for the connection itself, never one an interaction layer or relay reports (§5.5). The master secret and seed never leave the wallet.

F1-f-ptr (destination-pointer hygiene — RECOMMENDED, the destination-side sibling of the payer-key rule): §8.1's cross-merchant unlinkability is conditioned not on the payer key alone but on the payer-side destinations being unlinkable too (§8.4). A conforming wallet SHOULD keep its payer-side destination pointers — the MEED_VECTOR role destinations and the refund pointer — brand-level, never encoding per-user, per-device, or otherwise cross-merchant-stable values; and a self-custody wallet (whose wallet-role destination is the user's own) SHOULD derive per-merchant destinations where the rail permits, scoping the destination exactly as this rule scopes the payer key above. This is a SHOULD (privacy hygiene), not the payer-key MUST — a per-user pointer interoperates and moves value correctly; it is a privacy regression, not a conformance-breaking wire fault — and it has no per-merchant wire observable (a single merchant sees only its own scope), so it is a certification-level obligation, enumerated with the other §8 hygiene SHOULDs in F10.5. The pointer bytes ride in the signed MEED_VECTOR (F5), so the rule is wire-adjacent, but the "not per-user" property is testable only against a wallet's declared destination derivation (F10.6), exactly as F1-f's unlinkability is.

F1.7 Open items handed forward#


F2 — Identity & Binding#

Merchant identity and the binding artifact, payer-key scoping, the transport-independent channel-binding salt (BindSalt — the public relationship digest that replaced the TLS exporter), and the session-secret commitment and seal. F2 formalizes what Chapter 5 §5.1/§5.4/§5.5 (and Chapter 6 §6.2) already fix; it does not change them. Encoding primitives, the signing envelope, and the crypto suite are F1's and are used here without restatement.

F2.1 Merchant identity (formalizes §5.5)#

The merchant key is a stable Ed25519 public key (32 bytes), independent of TLS certificates, advertised Base64url-unpadded in PayTP-Merchant-Key (§5.1). It only ever signs (§5.5): channel confidentiality rides the separate channel-encryption key, an X25519 public key (32 bytes) carried in the binding artifact and rotated by republishing it. There is no key-rotation handover: a new merchant key is a new merchant identity (Chapter 7 §7.5), and everything scoped to the old key — chaining, receipts, payer-key derivation — ends with it.

F2.2 The binding artifact (formalizes §5.5)#

The artifact is a TLV object (F1.1), signed by the merchant key under PayTPv1-artifact (F1.3). Type registry (all fields REQUIRED, emitted with the critical bit clear — the v0.1 convention F1.1 implies and F5 restates):

TypeNameValue
0x00HOSTThe origin host this artifact binds, normalized per F2.4.
0x01CERT_HASHSHA-256 over the DER encoding of the TLS leaf certificate exactly as presented in the handshake (32 bytes). F2-j (resumption): a connection's leaf certificate is the one authenticated for its TLS session — directly by a certificate handshake, or inherited through session resumption from the session in which it was authenticated (what a TLS stack reports as the peer certificate). A connection whose session carries no such certificate (an external-PSK session) MUST NOT carry channel establishment.
0x02ENC_KEYThe merchant's channel-encryption X25519 public key (32 bytes).
0x03NOT_BEFOREValidity start, unsigned seconds since the Unix epoch, minimal-length encoding (F1.1).
0x04NOT_AFTERValidity end, same encoding. An artifact is current at time t iff NOT_BEFORE ≤ t ≤ NOT_AFTER.
0x70SIGEd25519 signature by the merchant key over COVERED (F1.3); an authenticator TLV in the reserved range (F1-i), excluded from its own coverage (F1.1).

The artifact does not carry the merchant key: the verifier uses the key it discovered (§5.1) — a signature that fails under that key is a different merchant, not a malformed artifact. A merchant with several live certificates (rotation overlap, multi-CDN) publishes one artifact per certificate; the response body is a sequence of length-prefixed artifact objects per F1-j's framing rule.

Fetch and acceptance (§5.5): before CHANNEL_OPEN, the client fetches the artifact set with an ordinary unauthenticated GET from the control endpoint (resource map, F2.6), on the very connection the channel will bind to. F2-i: artifact responses MUST carry Cache-Control: no-store — §5.2 mandates it only for authenticated and quote-bearing responses, but a cached artifact set can serve a superseded ENC_KEY or a set missing the connection's certificate, and freshness is free on a live connection. The client accepts the merchant key for this connection iff at least one received artifact (a) verifies under the discovered merchant key, (b) is current (client clock, skew allowance per F8), (c) has CERT_HASH equal to the hash of the leaf certificate the client itself verified for the establishing connection (F2-j), and (d) — F2-h — names a HOST equal, after F2.4 normalization, to the host the client verified for that connection (the reference identity it validated against the certificate). Otherwise it MUST NOT open a channel on this connection. §5.5 states check (c) explicitly; the HOST check is the strengthening that makes the artifact's own host field load-bearing where certificates are shared: on a wildcard or multi-SAN certificate covering many tenants, CERT_HASH alone would let one tenant's artifact answer for another's origin; exact host equality closes that, and a merchant that serves several hosts publishes one artifact per (host, certificate) pair. The check binds to the establishing connection's certificate no matter where the bytes came from; fetching on that same connection is what makes the answer authoritative for its termination point. The ENC_KEY used for sealing (F2.5) MUST come from an artifact that passed this acceptance.

F2-k (Tier 0 origin binding). The same fetch-and-acceptance gates a Tier 0 quote, not only a channel. Before honoring (funding) a Tier 0 quote (§5.6), a PayTP-aware wallet fetches the artifact set on the very connection it will pay over and accepts the discovered merchant key iff an artifact satisfies (a)–(d) above against that connection's verified leaf certificate and host; otherwise it MUST NOT fund the quote. This is what makes the signed quote origin-authenticated rather than merely signed by whoever the wallet is talking to: without it a hostile in-path interaction layer that terminates TLS could present its own merchant key and its own signed quote and be paid. The authenticated host MUST be the origin of the resource being paid for: the wallet honors a quote only if the accepted artifact's HOST equals the F2.4-normalized host of the requested resource — it binds which origin was authenticated to which resource the payment settles. Authenticating merely some origin the wallet happens to reach, without tying it to the requested resource, still funds the attacker: an in-path party can present its own valid key + artifact for its own host together with a quote whose resource names the victim's origin, and pass a signature-only check. The host↔resource bind is the check that closes it. Tier 0 carries no payer key (F2.3) and performs no seal, so it uses checks (a)–(d) but not ENC_KEY (F2.5 is channel-only); a Tier 0-only merchant still publishes the artifact set (ENC_KEY present but unused for Tier 0). The guarantee is only as strong as the wallet's authentication of the intended origin: a wallet that authenticates a TLS-terminating in-path proxy as its endpoint verifies the proxy's certificate, and the proxy's own valid artifact for the proxy's host passes (a)–(d) — so origin binding protects a wallet that authenticates the merchant it means to pay, never whichever endpoint it happens to reach. Where a wallet cannot authenticate the intended origin (full delegation to an unauthenticated in-path party), the on-chain payment→quote binding of the two-leg (F4-c) or paying the merchant directly is the fallback.

F2.3 Payer key (formalizes §5.5)#

The requirement is F1.6's, restated once: a conforming wallet MUST make the payer key stable per (merchant key, registrable domain) and unlinkable across merchants (the property is normative — F1-f); the derivation is internal to the wallet, with F1.6's RECOMMENDED (not mandated) derivation. A wallet presenting one global key across merchant scopes interoperates but fails certification. The payer key is an Ed25519 key; its public key travels only inside CHANNEL_AUTH (§5.4). Tier 0 involves no payer key at all (§5.5).

The wallet derives from the registrable domain it verified for the establishing connection itself — the server identity it validated against the certificate — never a host an interaction layer or relay reports (§5.5). A relay that lies about the host can therefore deny a channel, never coax one domain's key onto another.

F2.4 Host normalization and registrable domain (F2-a)#

The whitepaper pins the scope — the registrable domain, "the site, not the subdomain" (§5.5) — and leaves the algorithm to this spec. Both the artifact HOST and payer-key derivation use the same rules:

  1. Normalize: the host is lowercased and converted to IDNA A-label (Punycode) form per RFC 5890, applying UTS #46 with Transitional_Processing = false, UseSTD3ASCIIRules = true, and CheckHyphens, CheckBidi, CheckJoiners all enforced; the result is ASCII. The UTS #46 / Unicode table edition ships with the software exactly as the PSL snapshot does (F2-c), with the same honest consequence for the rare mapping change. A host that fails IDNA processing aborts — no channel, no key. Normalization happens before signing (artifact) and before derivation (wallet); per F1.1 rule 5, a received HOST not already in this form is rejected, never repaired.
  2. Registrable domain: the longest matching rule of the Public Suffix List, ICANN and private sections both, plus one label (the "registrable domain" / eTLD+1 the PSL algorithm defines). The private section is load-bearing: it is what keeps user1.example-pages.io and user2.example-pages.io — different customer sites behind one operator — from sharing a payer key, which §5.5 requires.
  3. IP literals: a host that is an IPv4/IPv6 literal has no registrable domain; the normalized literal itself is the scope. Canonical forms: IPv4 as four decimal octets with no leading zeros; IPv6 as the RFC 5952 canonical text representation (lowercase hexadecimal, mandatory :: compression rules), with URI brackets stripped and zone identifiers (%…) rejected. F2-b: the alternative (refusing PayTP identity to IP-literal hosts entirely) costs lab and intranet deployments for no privacy gain.

F2-c (PSL snapshot policy): the wallet computes against the PSL snapshot shipped with its software release, updated with ordinary software updates; no live fetch, no per-relationship pinning. Consequence: a PSL edit that moves a domain's registrable boundary changes the payer key derived for it from that update on — the relationship re-keys (chaining from old checkpoints fails its parties-identical check, §6.2, and postpay credit standing resets, §6.1). This is rare, safe (nothing signed becomes invalid; open channels are unaffected), and cheaper than any pinning scheme that would let two wallets disagree about scope indefinitely.

F2.5 Channel-binding salt, commitment, and seal (formalizes §5.4/§5.5)#

Channel-binding salt. BindSalt = SHA-256(payer_key ‖ merchant_key) is F1.6's public relationship digest — the 64-byte concatenation of the two raw 32-byte Ed25519 public keys (payer then merchant) hashed to 32 bytes — used directly as the K_session salt (F1.5). **No TLS exporter, no per-connection keying material, no TLS-version constraint, and no extended_master_secret requirement** (§5.1: TLS 1.3 or TLS 1.2, with no exporter/EMS requirement) — the binding does not depend on a TLS exporter. BindSalt is public; the channel's security rests on the commitment and seal below — merchant authenticity + s confidentiality — not on the salt.

Session secret and commitment. s is a fresh 32-byte secret from a cryptographically secure RNG, generated by the wallet per channel (§5.4). F2-e: the CHANNEL_AUTH commitment is H(s) = SHA-256("PayTPv1-hs" ‖ s) — its own derivation label per F1.4, distinct from every registry label and derivation info string.

Seal. The sealed session secret accompanying CHANNEL_OPEN (§5.4) is a single-shot HPKE seal (F1.4 suite: mode_base, DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, ChaCha20-Poly1305): recipient key pkR = the accepted artifact's ENC_KEY; info = "PayTPv1-seal"; aad = the canonical CHANNEL_AUTH bytes as F1.4 pins them — canonical_bytes(CHANNEL_AUTH, authenticators excluded), without the domain label; plaintext = s (32 bytes). The seal is single-shot — no context-export or secondary key is derived from it (the public BindSalt needs none; this is what makes the channel binding transport-independent). F2-f (wire layout): the sealed value is enc ‖ ct — the 32-byte encapsulated key followed by the 48-byte ciphertext (32 + 16 AEAD tag), 80 bytes total; F5 assigns its TLV in CHANNEL_OPEN. X25519 point validation per RFC 7748: any 32-byte string is a valid public-key encoding after masking, and a Diffie-Hellman evaluation yielding the all-zero output MUST abort the seal or unseal.

Unseal order (§5.4): the merchant unseals only after the artifact and signature checks pass (there is no ConnBinding step), recomputes H(s) over the plaintext, and rejects the CHANNEL_OPEN on mismatch — a wrong commitment and a wrong seal are the same failure: no channel. Erasure at close is F1.6's MUST.

F2.6 Control-endpoint resource map (F2-g)#

§5.1 advertises one control path (PayTP-Control, default /.well-known/paytp); the objects §5.4/§5.6 route through it need distinct addresses, and the whitepaper deliberately leaves the addressing to this spec. F2-g defines the complete map once, used by F3–F5. Path joining is deterministic: the advertised control path MUST NOT end in /; each resource is the control path with the listed suffix appended, so the default control path yields /.well-known/paytp/artifact, /.well-known/paytp/channel, and so on — the suffixes are never origin-absolute paths.

Resource (control path + suffix)MethodCarries
/artifactGET (unauthenticated)The current binding-artifact set (F2.2).
/channelPOSTChannel control objects: CHANNEL_OPEN, CHECKPOINT_REQUEST, FUNDING_PROOF, settlement messages, CLOSE (F5).
/batchPOSTMetering batches — channel-identified concatenated slices (§5.3, F5).
/ackPOSTThe payer-key-signed CHANNEL_ACK retrieval request (§5.4, F5).
/attestGET (unauthenticated)The signed redemption attestation (§5.6, F3/F4), addressed by query: ?entry=<Base64url entry identifier>&nonce=<Base64url nonce>, both REQUIRED, values Base64url-unpadded over the raw bytes (F3/F4 fix the widths). Response: the attestation TLV, or plain HTTP 404 while none exists.
/cancelPOST (unauthenticated)The Tier 0 cancellation request (§5.6, F3/F4).

All POST bodies and object-bearing responses are application/paytp+tlv (F1.1 carriage); every response carrying a PayTP object follows §5.2's caching rules. Method or resource mismatches are ordinary HTTP errors, not PayTP errors — the PayTP error registry (§5.7) speaks only from correctly addressed handlers.

F2.7 Open items handed forward#


F3 — Tier 0 Objects#

The per-payment profile's wire objects: the paytp quote extension, the PayTP-Roles header, the receipt, and the two rail-facing TLV objects (redemption attestation, cancellation). F3 formalizes what Chapter 5 §5.6 (with §5.2's JSON rules and Chapter 10 §10.1's schema) already fixes; it does not change them. Encoding and signing rules are F1's; the control-endpoint resource map is F2.6's. Entry/split address derivation, window enforcement, and the merchant's redemption state machine are F4's — F3 defines the objects those machines exchange.

F3.1 The x402 envelope (formalizes §5.6)#

Tier 0 is an x402 V2 flow: PAYMENT-REQUIRED, PAYMENT-SIGNATURE, and PAYMENT-RESPONSE headers carrying Base64-encoded JSON; a PaymentRequired object (accepts[], with x402Version and resource handled per the live shape — F3-j, where x402Version may be absent and resource is requirement-local); accepts entries naming scheme, network, an amount, asset, payTo, maxTimeoutSeconds — the exact amount field name, the network encoding, and the resource placement follow x402's live shipped shape, which is not the V2 spec document's (F3-j). PayTP defines none of these — it defines the paytp member carried in x402's extensions mechanism, and the client's copy-back of that member in the PaymentPayload. The extension's registration accompanies the reference implementation (§5.6); PayTP emits the shape the live x402 tooling accepts and the registration tracks it as x402 converges (F3-j) — the paytp member's own content, below, is what this section fixes regardless of the envelope's shell.

**F3-i (the extensions.paytp embedding).** x402 V2 structures each extensions value as an object {info, schema}, both REQUIRED — info the extension's server-provided data, schema a JSON Schema describing info — and, when a client echoes an extension into the PaymentPayload, it "MUST include at least the info received" and "may append additional info but cannot delete or overwrite existing info." PayTP embeds the **signed paytp object of F3.2 as extensions.paytp.info verbatim** — the object is the info, not a member nested inside a wrapper — with extensions.paytp.schema the JSON Schema describing it (the schema is descriptive only; the merchant signature, not the schema, is what validates a quote). The client's copy-back (F3.4) echoes paytp.info member-for-member unchanged and appends nothing to it: PayTP does not exercise x402's optional info append for this extension. This is safe and fail-closed, not merely a convention — the paytp signature covers every member but signature (F3.2) and is re-verified over the received info (F1.2/F1.3 reconstruct COVERED from what arrived, never trusting transmitted bytes), so any appended, deleted, or overwritten member makes the merchant's own signature check fail, exactly the mirror rule's posture (F3-a: nothing outside the merchant signature changes what executes or where it pays). A client with its own data to convey uses a separate extension or the payload's own fields, never paytp.info. Declining the append keeps PayTP x402-conformant: the client includes precisely "at least the info received," and the append is a MAY it does not take.

**F3-j (PayTP emits the live x402 envelope shape). The x402 envelope is x402's, not PayTP's, and the shipped** reference tooling — [email protected], the schema a real client and facilitator actually validate against — is still V1-protocol-shaped, diverging from the x402 V2 spec document the rest of F3 tracks: the requirement's amount field is **maxAmountRequired** (not amount), the network is a named enum ("solana", "solana-devnet", "base", …) rather than a CAIP-2 string, resource/description/mimeType sit inside each requirement rather than in a hoisted top-level ResourceInfo. (The top-level x402Version is required — the shipped x402ResponseSchema rejects a 402 without it, and it discriminates the protocol version — so PayTP always emits it; it is not a V1/V2 shape divergence.) Because the "a plain x402 client pays the split" property is only real against tooling that exists, PayTP emits the shape the live x402 schema accepts — the shipped V1 shape today — and re-shapes as the ecosystem converges on the V2 document (the V2-doc shape stays the forward target). The mirror (F3-a) preserves the accepts entry verbatim in x402's own JSON types, so these field names and encodings ride through the signed mirror unchanged.

**The paytp object is a hybrid, not CAIP-throughout:** PayTP's own identifiers stay CAIP — baseline is CAIP-2 (F3-f), MEED_VECTOR destinations are CAIP-10 (F9) — while the mirrored accepts entries carry x402's live vocabulary (the named-enum network, maxAmountRequired) inside the signed bytes. Security is unaffected: it rests on the merchant signature over paytp (which carries the CAIP-2 baseline), never on the envelope's network encoding.

Rail check — baseline offers only. For a baseline offer (no twoLeg; its payTo is the split, meaningful only on the baseline rail) the wallet MUST confirm the offer's named network maps to paytp.baseline, refusing otherwise — the anti-substitution check that keeps the looser envelope vocabulary from pointing a split payment at a rail the signed quote did not name. A two-leg offer's network names its net leg's rail, which need not be the baseline (the meed instance is bound to paytp.baseline by derivation, F4.1, not by the envelope network), so the map-to-baseline MUST does not apply to it.

The mapping is normative. The named-network → CAIP-2 mapping is a fixed, one-to-one table owned by the PayTP extension registration and versioned with it, strictly distinguishing mainnet from testnet ("solana" → the mainnet genesis chain id, "solana-devnet" → the devnet chain id — never conflated). An envelope network unknown to the table, or (on a baseline offer) mapping to a chain id **≠ paytp.baseline, MUST fail closed** — the offer is refused, never guessed.

Resource matching. Under the shipped shape resource is requirement-local; the wallet's resource check (F3.2/F3.4) is that the selected requirement's resource equals the signed paytp.resource and the requested resource, mismatches rejecting — it depends on neither a top-level resource nor a top-level x402Version. **For a two-leg offer the authoritative resource is paytp.resource itself:** a two-leg offer carries no separate per-offer resource that overrides paytp.resource, so the wallet binds the operator-requested resource against **paytp.resource** (never a two-leg accept.resource, which is not the binding). This is what stops a compromised interaction layer from substituting a valid merchant-signed two-leg quote for a different resource than the one requested — the wallet enforces paytp.resource == requested before funding, the net leg and meed entry being otherwise resource-agnostic.

(PayTP does not dual-emit or version-negotiate per client — it emits the single shape the shipped x402 tooling accepts. x402Version is present and discriminates the version, so per-client shape selection is possible but unnecessary while the deployed tooling is uniformly V1-shaped; revisit if that diverges.)

F3.2 The paytp quote extension (formalizes §5.6 step 1)#

One paytp object per PaymentRequired. JSON per F1.2: JCS canonicalization, every numeric quantity a string under F1-c's exact grammar, duplicate members rejected. Members, all REQUIRED unless stated:

MemberValue
vExtension version, "1".
resourceThe resource this quote prices: the envelope resource's URL string, repeated inside the signed object so the signature binds it.
nonceThe challenge nonce. F3-d: 32 random bytes from a CSPRNG, Base64url-unpadded (§5.6's "enough entropy that unobserved retrieval routes cannot be guessed").
expQuote expiry, unsigned seconds since the Unix epoch.
idemThe idempotency key: merchant-chosen opaque bytes, 1–64, Base64url-unpadded. Re-issuing an unchanged purchase MUST reuse it; a fresh key for an unchanged purchase is a refusal (§5.6, Chapter 10 §10.5 governance polices it).
schemaMEED_SCHEMA_ID, decimal string (schema 0x01 is "1").
contractThe Foundation contract-kit version the quote's addresses derive from (§5.6, §11.1) — one version names both published forms; which form applies is the offer's shape (split for baseline offers, meed instance for two-leg).
registryThe role-registry version the vector was built against (§10.5: signed vectors name it; validators accept the governance window).
baselineThe baseline rail's network identifier. F3-f: CAIP-2 chain identifiers (the vocabulary x402 V2's own network field uses), e.g. "solana:<genesis-hash>".
graceAdvertised redemption grace, seconds, decimal string (§5.6).
retryAdvertised retry window, seconds, decimal string (§5.6).
vectorThe MEED_VECTOR: an array of {"role","bp","dest"} — role id and basis points as decimal strings ("16""19" for 0x100x13; F3-b: decimal everywhere, one integer grammar, hex forms are documentation only), dest a destination pointer (grammar: F9). Cardinality is exact: one entry per role the quoted schema prices — no more, no fewer, ascending role id — because split and instance addresses derive from these bytes (F4), representation must be unique for given role facts. An absent or unasserted role keeps its own entry with its own role id and share, destination redirected to its role's pinned fallback (§5.6, §10.1: absences redirect, nothing reduces the total, the share stays attributed to its role) — **payer-side roles (0x10/0x12) to the Development Fund, an absent or unlisted OS (0x11) to the distinct independent open-source fund** (§10.1, F9.4); two absent payer-side entries sharing the Development Fund destination is the normal fallback shape, while an absent OS names its own distinct destination.
offersThe PayTP-priced payment options (below).
signatureBase64url-unpadded 64-byte Ed25519 by the merchant key over the JCS bytes of this object with signature absent, under PayTPv1-reqs (F1.2/F1.3).

Offers — F3-a (the mirror rule). offers is an array, one object per PayTP-priced accepts[] entry, each: {"accept": …, …} where accept is a verbatim mirror of the entire accepts entry it prices — every member the entry carries, known or future, extra included — inside the signed bytes. The mirror preserves the accepts entry verbatim in x402's own JSON types — a field x402 encodes as a number stays a number; F1-c's PayTP-native string-numeric rule does not reach mirrored x402 values (F1.2 scope note), because the match below is equality against the x402 entry as x402 wrote it. A PayTP-aware client matches an accepts entry against an offer by equality of the parsed JSON values (compare the JCS forms), and MUST NOT apply PayTP execution — split re-derivation and payment, two-leg funding, redemption under this quote's nonce, receipt expectation — to an accepts entry no offer mirrors, or one whose mirror differs in any member. An unmirrored entry MAY still be completed as what it is: a plain x402 payment carrying no PayTP terms (§5.6 permits the side-by-side menu; selection, never capture). Scope of the claim, precisely: for a conformant client, nothing outside the merchant signature — a cache, a proxy, a menu edit — can change which option it completes as a PayTP payment or where that payment goes (the published x402 cross-resource/substitution and menu-tampering attacks on the client side die here); what the mirror does not and cannot close — a dishonest merchant, a buggy facilitator a payer chose, loss of merchant durable state — is what §5.6's merchant-side verification, the consumed-nonce record (F4), and the mandates-no-facilitator posture address. A baseline offer — an offer carrying **no twoLeg** (F3-c: its payTo is the split address) — carries "finality": the required finality level (the rail adapter's declared token, §11.1) the single split payment MUST reach for delivery. It is REQUIRED — without it a baseline split's "quoted finality" (relied on by F4.4 delivery, F7.4 completeness, F8.1's honor rule) would be undefined, letting two merchants pick different private thresholds and leaving the wallet unable to preflight exp + grace headroom (§5.6 step 2) or know whether the honor boundary was met. (On the exact-svm baseline rail the baseline offer's payTo is the split program's PDA; the SVM rendering, and the settlement-to-quote binding — the merchant's durable consumed-settlement record, not an on-chain marker — are F4-d.) **A baseline offer also carries "merchantNet":** the merchant's net (~99%) destination — an F1-g pointer — committed in the split's ADDRESS_INPUTS (0x05 MERCHANT_NET, F4-a) so the split address binds the net seat as tightly as the meed destinations, and a substituted net seat derives a different address the wallet refuses (F4-d — the net-seat front-run closure). It is REQUIRED for a baseline offer and MUST be absent from a two-leg offer (whose net leg pays accept.payTo directly — there is no split, hence no committed merchant seat). It is the merchant's own receiving pointer, not a governed meed destination, so its baseline-payability is the merchant's own concern (its well-formed-text is checked at derivation, F1-g); a baseline offer lacking it is invalid (its split address would not bind the net seat). (A two-leg offer instead carries its two levels inside twoLeg.finality, below.) A non-baseline (two-leg) offer — one carrying the twoLeg object — additionally carries the two-leg terms of §5.6. **The baseline↔two-leg distinction is the presence of twoLeg, never the network value** (F3-h): a baseline offer's accept.network is a real payable rail — x402's live encoding of the quote's baseline (a named enum in shipped x402, mapping to the CAIP-2 baseline, F3-j) — precisely because a plain x402 client completes a baseline offer by paying its payTo on that rail (client-independence), which a sentinel network value would make unpayable; and a two-leg net leg MAY itself settle on the baseline rail, so a network comparison could not separate the two. The two-leg terms:

"twoLeg": {"asset":    <baseline settlement asset id, CAIP-scoped>,
           "meed":  <the meed amount, baseline minimum units, decimal string>,
           "rate":     <the pinned conversion rate — REQUIRED positive>,
           "rateSource": <the named public source, an identifier F9's registry grammar covers>,
           "reclaim":  <the entry's reclaim window, seconds, decimal string>,
           "contest":  <the entry's contest delay, seconds, decimal string>,
           "finality": {"meed": <required finality level>, "net": <required finality level>}}

F3-c (rate grammar and direction): rate is a canonical decimal string — (0|[1-9][0-9]*)(\.[0-9]*[1-9])? — no sign, no exponent, no trailing zeros; a zero rate is invalid (no public source quotes one, and the meed arithmetic degenerates). Direction and units: rate denotes **baseline-asset minimum units per one minimum unit of the offer's asset**, so both ends are integer-grained and F7's floor arithmetic is bit-reproducible. Finality levels are the rail adapter's declared identifiers (§11.1), opaque tokens here. A baseline offer carries no twoLeg: its payTo is the split address, which the wallet MUST re-derive from the signed quote (merchant key, asset, schema, vector, contract version — derivation in F4) and refuse on mismatch (§5.6). PayTP-priced accepts entries carry their network in x402's live envelope vocabulary (F3-j: the shipped named-enum today, the CAIP-2 V2-doc form when the tooling adopts it — the extension registration binds the live shape); for a baseline offer the wallet maps it to paytp.baseline's CAIP-2 (F3-f) by the fixed table and refuses one whose network does not name the baseline rail (F3-j), while a two-leg offer's network is its net leg's rail, not necessarily the baseline. The baseline↔two-leg distinction stays twoLeg-presence (F3-a/F3-h), never a network value. PayTP's own identifiers stay CAIPpaytp.baseline CAIP-2, F9.1 baseline-payable destinations CAIP-10, never F9.1's adapter (x-) rail form — while the mirrored accepts entries ride in x402's live vocabulary (F3-a/F3-j); Tier 0's signed rail identity is CAIP even where the envelope shell is not. Non-CAIP adapter rails — custodial ledgers, instant bank rails, Lightning (§6.2/§11.1) — are a channel-plane capability (F5.2's DENOM, F5.4, F5.6), where the metering/net/funding rail need not be a smart-contract chain; the channel meed still settles to its on-chain instance on the CAIP baseline (F5.2 BASELINE_ASSET). Two-leg quotes are served only to clients that advertised PayTP support, never plain-selectable (§5.6); the advertise-first and Vary rules (§5.2, §8.4) are load-bearing.

Client validation before paying (§5.4/§5.6): authenticate the discovered merchant key to the intended origin (F2-k — a PayTP-aware wallet fetches and accepts the F2.2 binding artifact on the connection it will pay over, refusing a quote whose key it cannot so bind, and whose accepted HOST is not the F2.4-normalized origin of the requested resource); verify the merchant signature; check resource matches the envelope; validate the vector against schema and registry (including fallback entries for roles it left unasserted); validate the windows fit together — a quote whose reclaim window closes before the instance's execution gate opens is invalid (§5.4); re-derive the split (baseline) or check the two-leg terms complete (non-baseline); confirm expiry headroom for the required finality — the baseline offer's finality for a split, both legs' twoLeg.finality for a two-leg (§5.6 step 2).

F3-g (numeric bounds — the F1-c min/max F1 promises): every Tier 0 time quantity — exp, grace, retry, reclaim, contest — is an unsigned integer ≤ 2⁵³ − 1, and a quote naming any larger value is rejected (PAYTP_PAYMENT_EXPIRED/malformed per §5.7). The bound is IEEE-754-safe (so a parser that transits the decimal string through a double never rounds) and astronomically generous for a Unix second or a window (year ≈ 285 000 000), and it guarantees the F8 derived boundaries — T_open = exp + grace, T_lapse = T_open + reclaim, T_exec = opening + contest, the retention max(exp + retry, T_lapse + contest) — are each a sum of a handful of ≤ 2⁵³ terms and so cannot overflow any 64-bit or bignum implementation, closing the divergence where one implementation wraps and another computes a far-future deadline. rate's reduced numerator and denominator (F3-c) are each ≤ 2⁶⁴ − 1 (a rate outside that is rejected). The conversion product N × p can reach ≈ 2¹⁹⁸ (with the round total N = Σ N_r up to MAX_ROLES · 2¹²⁸ = 2¹³⁴ — not a single numerator's 2¹²⁸ — and p near 2⁶⁴; F7.2 states the full MAX_ROLES-bounded domain, including the E · N_r ≈ 2²⁶² per-role attribution), which implementations MUST compute exactly, in arithmetic wide enough for that domain (the F7-a exact-integer mandate — arbitrary-precision, or a fixed width sized for it), so the wide product is not optional — and the **result P MUST fit the 16-byte AMT domain, P < 2¹²⁸**: a round whose computed P ≥ 2¹²⁸ is invalid and rejected (F7.2), a magnitude a channel settles and closes long before it could reach (F7-a's same close-long-before guard). The earlier claim that p,q ≤ 2⁶⁴ alone keeps P inside 2¹²⁸ was wrong — it is the explicit P < 2¹²⁸ domain check, not the input bounds, that prevents an implementation from wrapping or truncating P into a divergent INSTANCE_LEG.AMOUNT or claim_record_id (the surviving notice identifier over target_P, F5-o).

F3.3 The PayTP-Roles header (formalizes §5.6 step 1)#

A request header sent only to origins that advertised PayTP support (§5.6, §8.4). Value: Base64url-unpadded TLV object (F1.1) — unsigned; it is an assertion input the merchant bakes into the quote it signs, not an authenticated object. F3-e (layout): one TLV, type 0x00 ROLES, whose value is a count-prefixed ordered list (F1.1 rule 2, the same shape every other list-bearing value uses): the item count as a canonical LEB128, then fixed-shape items back-to-back, ascending role id, at most one item per role, each role_id (1 byte) ‖ len (canonical LEB128) ‖ value; a count that does not consume the value exactly is rejected. For roles 0x10 (interaction layer) and 0x12 (wallet): value is the destination pointer, UTF-8 per F1-g, grammar per F9. For role 0x11 (OS): value is the asserted registry recipient identifier (F9's registry grammar) — the merchant resolves its canonical destination from the registry version it quotes (§5.4, §10.1). A merchant ignores items for roles the quoted schema does not price and rejects a header that fails TLV or list canonicality; an absent header, or absent items, route those shares to the fallback (§5.6) — absence is never an error.

F3.4 Payment presentation and the receipt (formalizes §5.6 steps 3–4)#

Presentation. The client's retry (PAYMENT-SIGNATURE, the PaymentPayload) MUST carry the complete signed paytp object back as extensions.paytp.info (F3-i), member-preserved and nothing appended — every member and value unchanged, and none added, dropped, or overwritten (F3-i: the client declines x402's optional info append for this extension); since verification is over the JCS form (F1.2), incidental re-serialization is harmless and raw-byte preservation is not required — but a changed member set fails the merchant's own signature check, recomputed over the received info (F1.2/F1.3), so tampering fails closed — this is §5.6's "the client presents the signed quote": the merchant re-verifies its own signature from the presented copy and recomputes addresses from it, storing nothing before redemption (§5.6). Failure handling is not one case (§5.6/§5.7): a presentation failing signature, mirror, or resource validation is an ordinary HTTP client error, no PayTP-Error — §5.7 deliberately has no code for a malformed quote, which only a buggy or hostile client presents; a quote past exp whose leg nonetheless reached the quoted finality within exp + grace MUST be honored (§5.6's honor rule; window arithmetic in F8); only a quote past expiry without such a leg is answered PAYTP_PAYMENT_EXPIRED and re-issues.

Receipt. Inside the PAYMENT-RESPONSE settlement response's extensions, the paytp member is the merchant-signed receipt over the challenge tuple and payment references (§5.6 step 4):

MemberValue
v"1".
nonce, idem, resourceEchoed from the consumed quote.
acceptThe completed offer's mirror (F3.2) — which option was paid.
paidArray of {"leg","network","ref"}: exactly one "split" element (baseline), or exactly two elements in execution order — "meed" then "net" (two-leg); no duplicates, no extras. ref is the rail transaction reference as the adapter binds it (§11.1).
entryTwo-leg only: the meed entry identifier, Base64url-unpadded (width from F4).
tsMerchant timestamp, unsigned seconds, informational.
signatureEd25519 by the merchant key over JCS-minus-signature, under PayTPv1-receipt.

The receipt is the purchaser's durable evidence for exactly this purchase (§5.6); it never leaves the transaction's parties (§5.6, Chapter 8).

F3.5 The attestation and the cancellation (formalizes §5.6; TLV)#

Two merchant-key signatures over the same pair that MUST never pass for one another (§5.2) — separated by their domain labels (F1.3). Both are TLV objects (F1.1):

TypeFieldValue
0x00NONCEThe quote's challenge nonce, 32 bytes (F3-d).
0x01ENTRY_IDThe meed entry identifier (width and derivation: F4).
0x70SIGEd25519 by the merchant key; label PayTPv1-attest for the attestation, PayTPv1-cancel for the cancellation.

F3-k (one canonical F3.5 message). The signed message is covered(label) = label ‖ 0x00 ‖ canonical_bytes(content) over the TLV content object above0x00 NONCE(32) · 0x01 ENTRY_ID(32), each field type ‖ LEB128(len) ‖ value (F1.1) — 83 bytes for the attestation ("PayTPv1-attest"0x000x00 20 NONCE0x01 20 ENTRY_ID). This is the one F3.5 message: an on-chain detached attestation the instance verifies (F4.3 — e.g. via an Ed25519 precompile) MUST verify this exact message, committing the NONCE as well as the ENTRY_ID, never a short entry-id-only form. So a signature a merchant's off-chain tooling produces and one an on-chain verifier checks are the same object, cross-implementation verifiable; signing ENTRY_ID alone would leave the nonce uncommitted and split on-chain and core into two non-interoperable "F3.5" messages.

The attestation is the receipt's core the instance checks (§5.6): posted to the instance it releases the entry to the recipients, blocks reclaim forever, and cancels an opened, unexecuted reclaim within the contest delay. The merchant's control endpoint MUST serve it unauthenticated at /attest (F2.6) by nonce and entry identifier until the entry's windows have passed (§5.6). The cancellation refunds the entry to its recorded pointer at once, with no contest delay, and closes it (§5.6). The cancellation request (client → merchant, POST /cancel, unauthenticated, §5.6) is the same two fields with no SIG; the merchant answers with the signed cancellation after its §5.6 checks (own durable order, then the rails), or refuses with the applicable §5.7 error. Because the request is unauthenticated and the nonce is on-chain-public once the entry is funded, the merchant's signature is discretionary and payer-attributed, never compelled by nonce-knowledge alone (F4.4), and declining traps no funds — the payer's backstop is the permissionless reclaim path (F4.3). Instance-side verification of both signatures against the merchant key bound at funding, and every window rule, is F4's.

F3.6 Error carriage and the code registry (formalizes §5.7)#

PayTP-Error, on 402/409 responses, carries exactly one code as its ASCII name from the closed v0.1 registry below (the §5.7 error registry, made authoritative here — the whitepaper defers to it). An unrecognized code is treated as the closest generic failure and retried per its class, never a parse error.

CodeMeaning
PAYTP_VERSION_UNSUPPORTEDNo common protocol version.
PAYTP_WINDOW_EXCEEDEDSlice would breach the window bound (§6.1, F6.1).
PAYTP_EVIDENCE_REQUIREDUnevidenced value at E; checkpoint needed (§6.3).
PAYTP_CHECKPOINT_TIMEOUTCounterparty failed to sign within CKPT_TIMEOUT (F8).
PAYTP_STATE_MISMATCHPeers disagree on channel state; recover per §6.3/F6.3.
PAYTP_SEQ_INVALIDReplayed sequence number, or one at or below the last checkpoint's floor (F1.5).
PAYTP_DENOMINATION_MISMATCHSlice or settlement asset differs from the channel's.
PAYTP_CHAIN_REJECTEDPredecessor reference failed chaining validation (F6.6).
PAYTP_SETTLE_TIMEOUTSettlement exchange incomplete within SETTLE_TIMEOUT; channel closes (§6.4, F6.5).
PAYTP_PAYMENT_PROOF_REPLAYEDTier 0 proof already consumed against a nonce (F4).
PAYTP_PAYMENT_EXPIREDTier 0 challenge past expiry; re-request.
PAYTP_MEED_LEG_MISSINGTier 0 two-leg quote: no meed leg found at redemption (F4).
PAYTP_MEED_AMOUNT_INSUFFICIENTTier 0 meed leg below the quoted amount.
PAYTP_MEED_INSTANCE_MISMATCHPayment sent to an address that does not match the quote's split, or a meed leg to an address that does not match the quote's meed instance (F4.1).
PAYTP_LEG_FINALITY_INSUFFICIENTA Tier 0 payment leg has not reached the finality the quote requires (F8.1).

F3.7 Open items handed forward#


F4 — The Entry Machine#

Split and meed-instance address derivation, the meed entry's on-instance state machine, and the merchant-side durable orders that gate Tier 0 delivery. F4 formalizes what Chapter 5 §5.6, Chapter 10 §10.2, and Chapter 11 §11.1/§11.5 already fix; it does not change them. Objects are F3's; encodings F1's. The channel-side settlement exchange that pays an instance is F5/F6's — F4 owns what the instance itself verifies and what the merchant must decide durably.

F4.1 Address derivation (formalizes §5.6/§11.1)#

Both contract forms derive from the same inputs — merchant, settlement asset, schema, the complete vector, contract version (§5.6) — in two forms that never share an address. F4-a (the canonical seed): the rail-agnostic derivation input is

seed_split    = SHA-256("PayTPv1-split"    ‖ 0x00 ‖ canonical_bytes(ADDRESS_INPUTS))
seed_instance = SHA-256("PayTPv1-instance" ‖ 0x00 ‖ canonical_bytes(ADDRESS_INPUTS))

where ADDRESS_INPUTS is a TLV object (F1.1): 0x00 MERCHANT_KEY (32, the Ed25519 identity key) · 0x01 ASSET (the settlement asset identifier, UTF-8 per F1-g, CAIP-scoped as in F3) · 0x02 SCHEMA (unsigned, minimal) · 0x03 VECTOR (the canonical meed-vector list, below — carrying exactly the roles the schema prices, F3.2's cardinality rule, fallback entries under their own role ids) · 0x04 CONTRACT (the kit version, unsigned, minimal) · **0x05 MERCHANT_NET (the merchant's net destination, an F1-g pointer). MERCHANT_NET is present in the split form's inputs and absent from the meed-instance form's:** the split carries the merchant seat (the ~99% net) and MUST commit it, so a substituted net destination derives a different split address the wallet refuses (F4-d — closing the net-seat front-run: without it two different net destinations collapse to one split); the meed instance is meed-only (no merchant seat) and carries no 0x05 — a channel's ADDRESS_INPUTS (F4.2), being an instance, likewise never carries it. The two labels are the two contract forms (§5.6); the same inputs under different labels can never collide. The rail adapter maps the 32-byte seed to a rail address by the contract kit's published mechanism (a CREATE2-class salt, a program-derived-address seed — rail-specific by necessity, §11.1); what the protocol fixes is that the seed commits to the published code and the complete division, and no other code can occupy the derived address — the §11.2 invariant the §5.6 verification rule rests on.

F4-b (canonical meed vector): VECTOR's value is a count-prefixed ordered list (F1.1 rule 2), ascending role id, exactly one item per schema-priced role: role (1 byte) ‖ bp (2 bytes unsigned) ‖ len (canonical LEB128) ‖ dest (UTF-8 pointer, F9 grammar). A Tier 0 JSON vector (F3.2) maps member-for-member onto this form — same roles, basis points, and destinations give the same bytes, so the same division funds the same address from either tier, which is what lets channel legs and Tier 0 legs share instances and lets recipients watch one address set (§11.1 indexing).

Verification is re-derivation (§5.6): the wallet re-derives the split address from the signed quote and refuses a payTo mismatch; the merchant re-derives split or instance from its own quote at redemption; a two-leg wallet re-derives the instance before funding. Nobody trusts a transmitted address.

F4-d (the baseline split on the exact-svm rail — the SVM rendering). On Solana's exact scheme (the reference implementation's baseline rail — the protocol's baseline-rail identity is open, ch2 §2.2 / ch11 §11.2) a plain x402 client settles by an SPL/Token-2022 TransferChecked whose destination MUST be the associated token account ATA(owner = payTo, mint = asset) for the exact quoted amount, with the facilitator as fee-payer. So a PayTP baseline split renders as a program-derived account: the payTo the wallet re-derives from the signed quote (F4.1 — ADDRESS_INPUTS are the PDA's seeds under the split program of the quoted contract version) is the split PDA (the owner), the payment lands in ATA(split_PDA, asset), and a **permissionless distribute instruction divides the received balance among the merchant-net destination and the meed destinations pro-rata by the signed vector (F7). The merchant-net destination is committed in the split's ADDRESS_INPUTS (0x05 MERCHANT_NET, F4-a) — bound into the PDA seed exactly as the meed destinations are:** the split can pay the merchant seat only that committed destination, and a party deploying the split with a different net seat derives a different PDA the wallet never re-derives or pays (the net-seat front-run closure — without committing it, two merchant-net destinations would collapse to one split address and a front-runner could seat itself the ~99%). The split is the sibling on-chain form to the meed instance under the one contract version (F3.2: "split for baseline offers, meed instance for two-leg") — the instance is meed-only, the split adds the merchant seat; both are real on-chain baseline-rail programs, the split the required sibling of the instance. Baseline atomicity holds under this rendering: funds committed to the split PDA can leave only by distribute per the fixed vector, so the merchant cannot draw its net without the meed recipients drawing theirs — the payment commits the meed and the permissionless distribute (any recipient may call it) executes it, exactly as the instance's distribution does (§10.2); "delivery" (F4.4) triggers on the payment reaching ATA(split_PDA, asset) at the quoted finality, the split being unconditional custody bound only by its vector. Settlement-to-quote binding (baseline). The shipped exact-svm rail carries no per-quote on-chain marker a plain client can place: its facilitator admits exactly three instructions (compute-limit, compute-price, a single TransferChecked) and honors no extra.memo. The baseline split's binding to a quote is therefore the merchant's durable consumed-settlement record (F4.4): each confirmed settlement reference credits the first accepted matching quote and no other (a reference already credited to another quote is not payment), enforcing §5.6's one-settlement-one-quote free-ride/replay closure without an on-chain marker. This closure holds only under three assumptions, each of which MUST hold: (i) the rail's canonical settlement reference is injective (one settlement, one reference, no collisions); (ii) a single durable consumed-settlement store is authoritative across every replica serving the merchant (F4.4's exactly-once-across-whatever-serves-the-traffic); (iii) exact-svm's one-transfer-per-transaction shape, so one settlement is one credit. The closure is merchant-durable, not client-agnostic, and protocol-accounting-safe, not business-safe: it guarantees one payment yields one credit and the meed is paid once, but not that the party that funded a settlement is the party that redeems it. Because the split address is shared across a merchant's quotes (amount and resource are not in ADDRESS_INPUTS, F4-a) and Tier 0 carries no payer identity, an observer of the public settlement could otherwise redeem any of its own quotes whose amount is ≤ the observed payment against a stranger's payment (a payer-vs-payer misattribution: accounting-safe, but the funding payer may recover nothing and the merchant may owe support, refund, or re-delivery). The redemption model closes this: the merchant settles the payer's presented signed transaction itself and refuses an already-settled transaction for a fresh quote, so the payer's unforgeable TransferChecked authority signature is the binding; a confirm-by-reference redemption instead requires the redeemer to prove control of that authority account. Settlement-to-quote binding (secure two-leg). The two-leg's meed leg is nonce-committed on-chain by construction — entry_id (F4-c) commits the quote nonce together with the meed AMT and the window deadlines — so a meed funding satisfies only the quote whose nonce derives it. But entry_id binds the meed leg only: the net leg (the merchant's ~99% payout, the bulk of value) pays accept.payTo directly — a two-leg offer has no split and no committed merchantNet seat (F3-a) — and no entry_id covers it. The secure two-leg therefore **MUST bind its net leg to the quote nonce independently**, on a rail able to carry that commitment: the PayTP native on-chain plane that already funds the meed entry and carries the channel binding memos (F6-h), via a nonce-carrying memo, a per-nonce net object, or an atomic bundle committing the nonce/entry_id. The shipped-x402 three-instruction facilitator cannot carry that commitment (no extra.memo, as above) — which is exactly why the secure two-leg is a PayTP-native-plane construct, not an x402-facilitator flow, the mechanism that separates it from the compat single-leg baseline. Without the net-leg binding the staple attack opens: an in-path party funds only its own cheap meed leg for a same-merchant quote B (net_amount_B ≤ the victim's net), staples the victim's unbound net leg, and redeems B — delivered to the attacker for ~1% and funded by the victim — and, were the consumed-settlement record keyed only on the combined meed | net reference, the victim's honest quote could still redeem too (double-delivery). The merchant closes both: the net leg MUST carry the quote nonce (a net reference bound to a different nonce is not payment for this quote), and the merchant records the net reference consumed independently of the combined meed | net key, so one net settlement backs exactly one delivery.

F4-e (the two Tier 0 binding modes). A Tier 0 offer binds payment to quote in one of two ways. The compat single-leg baseline is a single split payment bound to its quote by the merchant's durable consumed-settlement record (F4-d above): origin-authenticated (F2-k) and settlement-authoritative (F4.4), but not on-chain-bound to the specific quote, so it carries the payer-vs-payer redirect residual — protocol-accounting-safe, not business-safe (the meed still divides and the merchant and recipients are made whole, but the funding payer can be redirected and the merchant may owe support, refund, or re-delivery). The secure two-leg binds both legs to the nonce on the native plane (entry_id for the meed leg, the independent net-leg commitment above), closing the redirect on-chain. A wallet SHOULD use the secure two-leg whenever a single bearer payment is not self-securing — a delegated or in-path intermediary could redirect it, or the good is scarce, personalized, or high-value — and MAY use the compat single-leg for low-stakes, fungible, direct-to-merchant purchases where the residual is economically irrelevant. Neither mode is silent about its guarantee: the compat residual is a stated, bounded property, not an unstated hole.

F4.2 The entry identifier (formalizes §5.6)#

One quote, one entry, one nonce (§5.6). F4-c: entry_id = SHA-256("PayTPv1-entry" ‖ 0x00 ‖ seed_instance ‖ nonce ‖ AMT ‖ T_open ‖ T_lapse ‖ contest) — 32 bytes; nonce is the quote's 32-byte challenge nonce (F3-d), AMT is the entry's amount as a 16-byte unsigned big-endian (baseline minimum units, the F7-a 2¹²⁸ domain — the quoted twoLeg.meed for a Tier 0 entry), and T_open/T_lapse/contest are the entry's two absolute rail-second deadlines and its contest duration (each an 8-byte unsigned big-endian, F4.3/F8). **The id commits to every entry parameter the merchant and instance check — amount and the window deadlines — which makes the instance record fully front-running-resistant (the mempool-squat closure):** an observer who copies a pending funding transaction and races it can either replicate all parameters (creating the honest entry with the recipients paid in full — self-defeating) or alter any of them — a dust amount, a short T_open/T_lapse, a different contest — and thereby derive a different, orphaned entry_id that never occupies the honest funder's id. So the earlier dust squat and the full-amount-with-wrong-deadlines squat (where a poisoned entry would be duplicate-blocking yet merchant-rejected) both die here: the honest funder's id is reachable only by the honest full parameter set, and any deviation is a harmless orphan. (The refund pointer is deliberately not committed — it is the funder's own recovery address, never checked by the merchant, and moot on a delivered entry: a conformant wallet completes against an already-correctly-funded entry rather than abandoning it, F4.5, so a copy that keeps the honest parameters but swaps the pointer still delivers and still pays the recipients.) Both parties compute the honest id from the quote alone — the merchant's own twoLeg.meed is the AMT (§5.6 "the meed entry … it can derive from its own quote") — and the instance keys attestations and cancellations on it; the nonce each carries is evidence for the parties, never the matching rule (§5.6). The channel case is not a windowed entry at all but a per-channel cumulative-meed record — a **ChannelMeed** keyed (seed_instance, CHANNEL_ID) alone (no nonce, no ckpt_ref, no deadline terms): exactly one record per channel on the instance, holding the channel's cumulative funded aggregate funded_p (baseline µ-units, monotone) and its per-destination cumulative paid_d (F6-o), rendered on the baseline rail as its own program-derived account addressed by (seed_instance, CHANNEL_ID) (the §11.1 kit mapping, exactly as F4.1 maps a seed to a rail address). It is windowless (no T_open/T_lapse/contest) and, because its key omits ckpt_ref and P, stable across every round of the channel's life, so identical checkpoint references on different channels sharing an instance can never collide (F5 fixes CHANNEL_ID's bytes) and — there being now exactly one record per channel — a dust squat cannot derive an orphan to block it: a squatter advancing this same (seed_instance, CHANNEL_ID) hits the same record, non-blocking because the honest advance later moves only the residual to the monotone funded_p (an unsolicited over-advance is non-refundable prefunding that may satisfy a future absolute target, never a blocking orphan). A channel's ADDRESS_INPUTS (F4.1) are all fixed at establishment — MERCHANT_KEY, ASSET = CHANNEL_AUTH.BASELINE_ASSET, SCHEMA, VECTOR, CONTRACT = CHANNEL_AUTH.CONTRACT (F5.2) — so the channel's meed instance address is determined the moment the channel opens, exactly as a Tier 0 split address is determined by its quote; no settlement round can name a different asset or contract and redirect the leg. A channel-meed record is a different kind, not a reclaimable entry (§6.4 gives channel legs no reclaim, no attestation, no cancellation — the countersigned proposal is the parties' agreement and the rail record is the proof): the advance call for a channel-meed record carries the per-channel key (seed_instance, CHANNEL_ID) and the round's cumulative target_P and no windows and no refund pointer — the call's shape selects the kind — and each advance's distribution is immediately claimable by the recipients on arrival, irreversible (no reclaim), with every purchase-entry transition (F4.3) inapplicable; the record itself is not a terminal entry but the monotone funded_p watermark, which only ever advances (F6-o). **Every channel settlement round that makes extinguishment progress — one whose E ≥ 1 (F7.3) — ADVANCES the channel's cumulative meed watermark (F6-o, F6-f, §6.4) to that round's own-cumulative target** target_P = floor((Σ ACCRUALS_r(operative checkpoint) − Σ imported_settled_r) / 10 000) — the cumulative meed this channel owes, excluding what a predecessor already settled (imported_settled_r = 0 for an unchained channel, so target_P = floor(Σ ACCRUALS_r / 10 000)). The advance distributes only the delta ΔP = target_P − funded_pexactly the F6.2 difference-of-cumulative-floors the settlement already computes — among the establishment-bound meed destinations, and is idempotent by absolute position: an advance whose target_P ≤ funded_p distributes nothing (a no-op), so the monotone funded_p is the on-chain exactly-once guarantee — a round's leg re-issued after an outage, reorg, restart, OR across the interim-draw-then-close boundary never double-pays, because both the interim advance to target_P₁ and the close advance to target_P_final ≥ target_P₁ move the SAME funded_p and the close moves only the residual, whatever checkpoint each names. A round with E = 0 — nothing accrued, P = 0, or the sub-extinguishment trap where P ≥ 1 but E floors to 0 (F7.3) — advances nothing (ΔP = 0, target_P unchanged) and carries no INSTANCE_LEG (F5.6): there is no zero-value transfer to post and a zero-E leg would make no debt progress (the infinite-loop trap F7.3 closes), so the numerators carry; a net-only round with meed dust settles its net leg alone, and this is not a missing advance, because an E = 0 round extinguishes nothing to move funded_p for. A channel's meed watermark is rail-discoverable evidence of the cumulative meed funded (keyed (seed_instance, CHANNEL_ID), funded_p monotone, never lost to a checkpoint crossing) — but it is not the authoritative numerator log: the per-role numerators a round extinguished (E_r) live in that round's countersigned (or deterministic) settlement proposal (F5.6), which both parties hold and which is un-poisonable (the creditor countersigned the E_r, or it is recomputable from the named checkpoint). An advance MAY record E_r on-chain as a non-authoritative recovery hint; reconciliation (F6-f) reads E_r from the held signed proposal for each round whose advance the rail shows reached funded_p ≥ target_P — the debtor cannot inflate the settled meed by writing a false E_r into calldata the contract cannot check. A debtor holds no path whatsoever to pull a distributed advance back; without this kind distinction the entry machine's reclaim path would let a settling debtor fund the aggregate leg, complete the round on the proof, and reclaim the recipients' money — the kind exists to make that unwritable. Division and residue arithmetic per F7.3; F5/F6 own the exchange that advances it.

F4.3 What the instance enforces (formalizes §5.6)#

The meed-instance contract holds meed-only entries and divides each among the meed destinations alone, pro-rata by their shares — no merchant share, which is what distinguishes it from a split (§5.6). Per entry, recorded at funding and immutable after: entry_id, the nonce, the amount (baseline minimum units), the payer's refund pointer, two absolute rail-clock deadlines the funding wallet computes from the quote (F8 owns the conversion) — T_open, when the reclaim window opens (the quote's expiry plus its finality grace), and T_lapse, when it closes (T_open plus the reclaim window) — the contest delay as a duration, and the division from ADDRESS_INPUTS — all fixed the moment the money arrives (§5.6). The instance evaluates only values it holds: absolute deadlines, never the quote's own fields. The merchant recomputes the same deadlines from its own quote — but this is now enforced by the id, not a separate reject: because entry_id commits T_open/T_lapse/contest (F4.2), an entry recorded with different deadlines has a different id the merchant never derives, so a wrong-deadline funding is an orphan rather than a duplicate-blocking poison (the merchant simply finds — or does not find — the entry at the id its quote derives; §5.6's "recomputing the … meed entry from the quote itself" is realized in the derivation). A funding call that names no nonce, whose entry_id — now over nonce ‖ AMT (F4.2), so the amount is part of the key — already exists, or whose T_lapse is already past MUST be rejected atomically — the transfer does not execute and no value enters the instance outside an entry (one settlement credits one quote, §5.6; the free-riding closure; a stillborn entry is refused, not born lapsed). A dust squat therefore creates only its own orphaned entry_id and never a duplicate of the honest funder's amount-committed id (F4.2); the honest funding of AMT is never rejected as a duplicate by a prior underfunding.

State machine, all transitions on the rail's own clock (§5.6), T_exec = the reclaim opening's rail time plus the contest delay:

FUNDED ──(valid attestation, PayTPv1-attest)───────────────────────▶ ATTESTED   [terminal: shares claimable at once; reclaim blocked forever]
FUNDED ──(valid cancellation, PayTPv1-cancel)──────────────────────▶ CANCELLED  [terminal: full refund to the recorded pointer at once, no contest delay]
FUNDED ──(reclaim opened at rail time t, T_open ≤ t ≤ T_lapse:
          permissionless, no destination argument)─────────────────▶ RECLAIM_OPEN
RECLAIM_OPEN ──(valid attestation before execution)────────────────▶ ATTESTED   [the reclaim is cancelled]
RECLAIM_OPEN ──(valid cancellation before execution)───────────────▶ CANCELLED  [refund at once — cancellation never waits on the contest delay]
RECLAIM_OPEN ──(executed permissionlessly at rail time > T_exec,
                no attestation, no cancellation)───────────────────▶ RECLAIMED  [terminal: refund to the recorded pointer, less rail costs]
FUNDED ──(rail time > T_lapse with no attestation, cancellation,
          or open reclaim)─────────────────────────────────────────▶ LAPSED     [terminal: claimable by the recipients — §10.2's "past it the
                                                                                 entry is claimable"; the contest delay plays no part here, it
                                                                                 runs only behind an opened reclaim]

Boundaries are strict and the rail's own total order is the tiebreaker: execution requires rail time strictly greater than T_exec, and an attestation or cancellation the rail orders anywhere before the execution transaction — the same ordering unit included — takes effect first. Guards the instance MUST check: an attestation or cancellation verifies as the F3.5 object under its own label against the merchant key bound in the entry's division (the vector's provenance — the MERCHANT_KEY in ADDRESS_INPUTS); reclaim opening outside [T_open, T_lapse] is rejected (§5.6's "rejects execution until expiry, finality grace, and the contest delay have passed" decomposes as: opening waits for T_open, execution additionally for the contest delay); execution and every refund pay only the pointer recorded at funding — the caller supplies no destination, ever, batch calls included (§5.6); batch reclaim and batch attestation-posting take entry identifiers only, each entry checked under the single-entry rules (§5.6); a batch attestation-posting MUST silently skip an entry already in a terminal state — attested, lapsed, reclaimed, or cancelled — rather than revert the whole batch (the front-run-DoS guard): otherwise an adversary who settles one named entry first could revert the merchant's batch and strip the meed from all the rest. Executor compensation is off-protocol (§5.6). An entry in any terminal state answers every further attestation, cancellation, reclaim, or funding replay with rejection: terminal is terminal, and an entry already refunded is not payment (§5.6).

F4.4 The merchant's durable orders (formalizes §5.6)#

Two records, each one durable decision per key, made exactly once across whatever serves the traffic (§5.6, §11.5) — durable-or-fail: an operator that loses this state refuses what it can no longer adjudicate, never guesses (§11.5).

The consumed-nonce record (key: the challenge nonce). Written atomically before delivery, holding: the payment proof or both legs' proofs, the split address and its configuration, the entry_id on two-leg quotes, the idempotency key, the resource binding, and the delivered response's receipt (§5.6). Kept until quote expiry plus the retry window, or until the entry's reclaim and contest windows close, whichever is later (§5.6). Verification precedes the write; the write precedes delivery: (baseline) the full amount reached the quoted payTo as an ordinary, unconditional split payment the merchant's durable record credits to this quote and no other — value parked in any reclaimable or conditional form, or a settlement already credited to another quote, is not payment (§5.6); (two-leg) both legs at the quoted finality: the net amount on the agreed rail **carrying the quote nonce** (F4-d — the secure two-leg binds its net leg to the nonce independently, since entry_id binds the meed leg only), and the derived entry FUNDED at the derived instance — the entry_id the merchant derives **commits to the quoted twoLeg.meed as its AMT** (F4.2), so a FUNDED entry at that id necessarily holds the full quoted meed; the hostile-wallet-funds-a-token-amount attack is closed at the derivation itself (a token amount lands a different, unrecognized entry_id, never the one the merchant looks for), so the merchant delivers on finding the entry FUNDED at the amount-committed id — no separate on-chain amount comparison is needed (§5.6). **The amount check on the value legs — the baseline split payment, and the two-leg net leg — is , not =:** a payment reaching the quoted payTo/net destination for at least the quoted amount satisfies it, and the merchant rejects only an underpayment as unpaid. An overpayment is accepted as payer self-forfeit — bounded, non-conformant-payer self-harm (the merchant nets more than gross-minus-meed; the payer over-sent its own funds), the same lightweight-forfeit class as the postpay over-transfer (F6.4), for which PayTP adds no refund path (an exactly-conformant client sends the exact quoted amount, F4-d — the is the merchant's honor rule, not a licence to overpay). The meed leg admits no such slack — its AMT is committed into entry_id (F4.2), so an over- or under-funded meed lands a different, unrecognized id, never the amount-committed one. A retry matching the record exactly returns the stored response and receipt with no second charge; any mismatch against a consumed nonce is PAYTP_PAYMENT_PROOF_REPLAYED (§5.6). A leg reaching quoted finality within expiry + grace MUST be honored, whichever leg it is (§5.6). No facilitator holds any of this authority: the merchant confirms rail arrival and finality itself and owns this record (§5.6) — the k-atomicity attack surface of facilitator-mediated designs does not exist here.

The entry order (key: the entry identifier; each entry ever names one nonce, §5.6). Outcomes, not attempts (§5.6): a redemption that begins verification marks the entry redeeming and cancellation becomes unavailable; a verification that ends unredeemed releases the mark; a cancellation that wins makes later redemption against that entry rejectable. Before signing a cancellation the merchant checks, in order: its own record (not redeemed, not redeeming, no receipt issued for that nonce), then its rails — what bars cancellation is a redeemable payment: the net leg at quoted finality inside the honor window, which it MUST then still honor; the meed leg's own finality never bars it, being the ordinary state a cancellation exists to unwind (§5.6). Cancellation-signing is discretionary, never compelled by a bare request: the /cancel request is unauthenticated and the nonce it carries is on-chain-public the moment the entry is funded (F4.3 records the nonce in the entry), so nonce-knowledge proves only that the requester watched the chain, never that it is the payer. A merchant therefore MUST NOT treat a bare request as payer authorization: it signs on its own policy — when it will not deliver, or on a request it can attribute to the payer (the paying x402 session, or a merchant-issued cancellation capability) — and MAY decline one it cannot attribute. Declining traps no funds: the payer's trustless recovery is the permissionless reclaim path (F4.3 — RECLAIM_OPEN at T_open, refund to the recorded pointer), and cancellation is only the faster courtesy that skips the contest delay. This closes the griefing vector where a chain observer races a /cancel to abort an in-flight two-leg purchase before its net leg reaches finality — the observer can neither redirect value (refund goes only to the payer's recorded pointer) nor deny recovery (reclaim stands). The merchant MUST post the delivery attestation on every delivered two-leg purchase. A Tier 0 two-leg meed entry stays reclaimable for payer protection — unlike the windowless per-channel meed record (F4.2), which is not reclaimable and needs no such rule — so a delivered purchase whose attestation is never posted can be reclaimed by the payer, clawing the meed back after receiving the good (a wallet could even automate the strip as a "keep the 1%" feature). Therefore: for every two-leg purchase it delivers, the merchant MUST cause its signed PayTPv1-attest (F3.5) to be posted to the meed instance — driving FUNDED/RECLAIM_OPENATTESTED (F4.3), closing the entry to the recipients and barring reclaim forever. This is a normative obligation, not merely the F2.6 /attest serving (which continues, as the purchaser's durable evidence) nor only a reaction to a contested reclaim. Submission is delegable — a poster/relayer service MAY submit it — but the obligation stays with the merchant, and posting moves no funds (a signed message, so §5.6's no-custody posture is preserved). The window ordering makes it always achievable: an opened reclaim executes only strictly after T_exec = opening + contest, and opening cannot precede T_open = exp + grace, so execution is never before (exp + grace) + contest — the merchant holds the full contest delay after the honor boundary to post, and an attestation the rail orders anywhere before the execution transaction wins (F4.3). Before relying on that margin against an entry already under reclaim, the merchant confirms the entry unrefunded and remaining contest ≥ the F8-f margin (twice the adapter's declared inclusion latency), then posts promptly. The contest delay stays a per-quote value — no governed floor in v0.1 (the ordering is self-enforced: the deadlines are committed into the entry_id, F4-c, and the F8-f margin is the merchant's own posting-time check; a protocol-mandated minimum contest is a later hardening if real deployments show merchants under-setting it — the reference construction is per-quote with an eager per-delivery posting check). A delivered two-leg entry that ends RECLAIMED or CANCELLED instead of ATTESTED is merchant non-conformance — detected off-chain by the instance's funded-to-reclaimed/cancelled ratio together with the payer's signed receipt (an evidence/certification rule, §7.8, never a cryptographic bar; the payer keeps the receipt regardless of what the merchant does). A net leg landing after a cancellation is returned off-protocol — the signed quote and both rail records are the payer's evidence (§5.6).

F4.5 The wallet's funding order (formalizes §5.6/§11.1)#

Two-leg, meed first — and first means final: the wallet MUST NOT start the net leg before the meed leg shows the quoted finality (§5.6). Before starting: funds, route, and expiry headroom for both legs' finality (§5.6). The wallet sources the baseline asset itself at the quote's pinned rate; the payer never holds it (§11.2). Instance liveness is the funding wallet's duty: it holds the derivation inputs, deploys the instance if absent, and never funds an entry into code that does not exist (§5.6) — windows against an empty address are meaningless. A transient net-leg failure retries under the same idempotency key; a permanent one ends in reclaim; an expired quote re-quotes (§5.6). Wallets SHOULD track their unreceipted entries, open reclaim when the window opens, and execute refunds unattended after the contest delay (§11.1) — refunds can only reach the recorded pointer, so automation risks nothing. **Reclaim automation is for unreceipted entries only (never delivered): reclaiming a delivered** (receipted) two-leg entry to claw the meed back is not honest recovery — it is the strip the merchant-post obligation (F4.4) closes before such a reclaim can execute.

F4.6 Open items handed forward#


F5 — Channel Messages#

The wire layouts of the channel plane: slice carriage, CHANNEL_OPEN/CHANNEL_AUTH/CHANNEL_ACK, FUNDING_PROOF, checkpoints, the settlement messages, and CLOSE. F5 formalizes what Chapter 5 §5.3/§5.4 and Chapter 6 §6.2–6.4 already fix; it does not change them. Encodings, the envelope, and the slice object are F1's; identity, binding, and the seal are F2's; behavior — when to send, guards, recovery — is F6's. The §5.2 registry includes PayTPv1-ack-req, because §5.4's acknowledgment-retrieval request is a signed object and every signed object type needs its own label.

F5.1 Carriage (formalizes §5.3/§5.4; F2.6 resources)#

Header slices — F5-b (field grammar): each PayTP-Slice field value is <channel> ":" <slice>channel the Base64url-unpadded 8-byte channel identifier (11 characters), slice the Base64url-unpadded canonical slice bytes. Repeated field lines and a comma-combined single line are equivalent (§5.3); senders emit slices in ascending SEQ order as a convention, receivers accept by uniqueness, never order (§5.3). All slices on one request MUST name the same channel — one channel per request (§5.3); a request violating that is rejected whole.

Metering batches — F5-c: POSTed to /batch (F2.6), body framed per F1-j: the first framed object is BATCH_HEAD — a TLV object, single field 0x00 CHANNEL_ID (8 bytes) — followed by framed slices, each verified under that channel's keys. The body is self-identifying; no header names the channel.

Control objects: POSTed to /channel (F2.6), one message per request. F5-a (message discrimination): TLV objects do not name their own type, so the body is type-octet ‖ object bytes: 0x01 CHANNEL_OPEN · 0x02 CHANNEL_ACK · 0x03 CHECKPOINT_REQUEST · 0x04 CHECKPOINT · 0x05 FUNDING_PROOF · 0x06 SETTLEMENT_PROPOSE · 0x07 SETTLEMENT_PROOF · 0x08 SETTLEMENT_CONFIRMED · 0x09 CLOSE · 0x0B PREPAY_DRAW_COMPLETED (F5-o — the merchant→payer prepay interim meed-draw completion notice, F5.6/F6-n; merchant-originated, so it travels as a control-plane response a halted payer obtains on its next control-plane contact, never a payer-initiated /channel POST — no new request message). The /ack resource (F2.6) uses the same type-octet form with the one message it carries, 0x0A ACK_REQUEST — retrieval lives on /ack only, never /channel. Responses carrying a message use the same form. The octet is routing, not security: an altered octet mis-parses into a different registry and the signature under the wrong domain label fails (F1.3) — nothing rides on it.

Signature slots — F5-k (role-fixed, never initiator-fixed): in every channel object below that both parties may sign — the checkpoint and the settlement proposal — type 0x70 is the payer key's signature and type 0x71 is the merchant key's, whichever party initiated. Who proposes varies per exchange; who is payer never does — so one agreement has exactly one bilateral byte form, and its hash references (F5-f, F5-h) are unambiguous. Single-signer objects state their signer; the mode tells a verifier which slot must be present.

F5.2 CHANNEL_OPEN and CHANNEL_AUTH (formalizes §5.4)#

CHANNEL_OPEN is the unsigned envelope (§5.4 — "its signature is the CHANNEL_AUTH it carries"): 0x00 AUTH (value: the complete CHANNEL_AUTH bytes) · 0x01 SEAL (80 bytes, F2-f). The CHANNEL_AUTH registry, every field REQUIRED unless marked, §5.4's list in order:

TypeFieldValue
0x00PAYER_KEYMerchant-scoped payer public key (32).
0x01CHANNEL_ID64-bit random, non-zero (§5.4), fixed 8 bytes.
0x02MERCHANT_KEYThe merchant's Ed25519 identity key (32).
0x03DENOMChannel denomination: asset identifier, UTF-8. **CAIP-19-scoped for a CAIP rail, or adapter-scoped (F9.1's x- form) where the channel's DENOM rail has no CAIP namespace — a custodial ledger, an instant bank rail, Lightning (§6.2/§11.1): the metering/net/funding rail is the one the whitepaper's rail-agnosticism reaches, so its asset id uses that rail's vocabulary, matching its settlement pointer's form (F9.1). The baseline** side is separately CAIP (BASELINE_ASSET, below).
0x04MODE1 byte: 0x00 prepay, 0x01 postpay.
0x05LIMIT_LL_prepay or L_credit per mode, µ-units of DENOM, unsigned minimal.
0x06LIMIT_EThe evidence bound E, µ-units, unsigned minimal.
0x07TH_VALUESettlement value threshold, µ-units, unsigned minimal. **0 disables the value trigger** (time-only settlement, F6.5); a non-zero value SHOULD sit above one settlement round-trip (F8.3).
0x08TH_TIMESettlement time threshold, seconds, unsigned minimal. **0 disables the time trigger** (value-only settlement, F6.5); a non-zero value SHOULD sit above one settlement round-trip (F8.3).
0x09REFUND_PTRThe payer's refund pointer (F9 grammar). REQUIRED in prepay — deposits pay out here (§6.4); absent in postpay, where no protocol flow ever pays the payer (F5-d: presence is mode-determined, so no two encodings of one situation exist).
0x0ABASELINE_NETThe baseline rail's network identifier, CAIP-2 (§5.4).
0x0BRATE_SOURCEConversion-rate source (F9 registry grammar). Present exactly when **DENOM ≠ BASELINE_ASSET** — a conversion is needed to settle the meed (accrued in DENOM) to the instance (in BASELINE_ASSET), whatever rail the net leg uses (the net leg pays the merchant in DENOM and needs no conversion; only the meed converts). This is the establishment half of F5.6's CONVERSION presence rule and F8.4b's countersign-time check — they MUST agree, or a cross-currency channel settling on the baseline rail would need a rate its establishment terms never named and its meed would strand. Absent exactly when DENOM = BASELINE_ASSET.
0x0CRATE_DEVPermitted deviation, basis points, unsigned minimal. Present exactly with RATE_SOURCE (DENOM ≠ BASELINE_ASSET).
0x0DSCHEMAMEED_SCHEMA_ID, unsigned minimal.
0x0EVECTORThe canonical meed-vector list (F4-b) — exact schema cardinality, resolved destinations.
0x0FREGISTRY_VRole-registry version the vector was built against, unsigned minimal.
0x10HSH(s) commitment (32, F2.5).
0x11(reserved)RESERVED-UNUSED: formerly CONN_BINDING, the 32-byte TLS-exporter value — deleted with the transport-independent channel-binding change. The type number is retired, not reused, and 0x12+ are not renumbered (no TLV parser drift); a v0.1 CHANNEL_AUTH MUST NOT carry 0x11, and a receiver treats its presence as a malformed object.
0x12PREDECESSOROPTIONAL chaining reference: prior CHANNEL_ID (8) ‖ final checkpoint reference (32, F5.5) — 40 bytes.
0x13TIMESTAMPUnix seconds, unsigned minimal.
0x14BASELINE_ASSETThe baseline settlement asset the channel's meed converts to and its instance holds (UTF-8, CAIP-19 — always a CAIP asset on a contract-capable CAIP rail, because the meed instance is an on-chain contract [F4.1, §11.1's "contract support"]; the baseline never takes the adapter form, even when DENOM does). REQUIRED — every channel accrues meed that settles on the baseline, so the instance's asset must be fixed for the channel's life, not chosen per round. On a baseline-denominated channel BASELINE_ASSET = DENOM (and DENOM is then itself CAIP). This closes the redirection where a debtor could name a different baseline asset at settlement (the instance address, F4.1, derives from it).
0x15CONTRACTThe contract-kit version the channel's meed instance runs, unsigned minimal — REQUIRED, completing the F4.1 instance derivation inputs at establishment so the instance address is fixed at channel open, exactly as a Tier 0 split address is fixed by its quote.
0x16FIN_MEEDRequired finality level for the meed leg on the baseline rail (adapter token, UTF-8, §11.1). REQUIRED — every channel settles meed to its instance on the baseline, so the finality the creditor requires before a meed leg counts as settled (F6-f/F8.1) is a channel-life establishment term, not a per-round choice a debtor could weaken. Fixing it here — beside BASELINE_ASSET/BASELINE_NET, whose rail it names — is what gives a deterministic baseline round (which carries no CONVERSION, F5.6) a defined settlement finality at all.
0x17FIN_DENOMRequired finality level for **every DENOM-rail value transfer** — the postpay net leg to the merchant, the prepay deposit return to the payer, and any FUNDING_PROOF'd transfer — on the DENOM rail (adapter token, UTF-8). REQUIRED in both modes: every channel moves value on its DENOM rail (funding in either mode; a net leg in postpay; a deposit return in prepay), and the finality a party requires before crediting funding or confirming a settlement/refund leg (F6.4/F6-f) is a channel-life term, not a per-transfer or per-round choice a debtor could weaken. FIN_MEED governs the baseline rail, FIN_DENOM the DENOM rail; on a baseline-denominated channel the rails coincide but the two levels are still named independently (they are the two adapters' own tokens, never compared across rails — F8.1).
0x70SIGEd25519 by PAYER_KEY under PayTPv1-chan-auth.

Merchant processing order is §5.4's, verbatim: parse payer key → artifact covers the certificate the client verified for the establishing connection (F2.2 — worded to cover both direct TLS termination and an origin-authorized TLS terminator that fronts the origin; the artifact names the terminator's cert and the origin's ENC_KEY, and the origin completes the channel by unsealing alone, §5.4/§12.2) → verify SIG → unseal and validate against HS → acknowledge. **The former "compute ConnBinding and match 0x11" step is deleted** (there is no exporter value to compute or match). Rejections (§5.4): a CHANNEL_ID reused while live or within the retention window of a terminated channel (the replay-suppression rule below), TIMESTAMP outside the acceptance window (F8), a secret arriving any way but sealed. A retransmitted CHANNEL_OPEN identical to one already acknowledged is answered with the same CHANNEL_ACK, never rejected, and never re-initializes the channel (§5.4).

**F5-o — channel-open MEED_VECTOR validation (formalizes §5.4).** Before acknowledging a CHANNEL_OPEN, the merchant MUST validate its 0x0E VECTOR, and both payer-side layers MUST validate it before committing — so a malformed or non-conformant vector is a channel that never exists — and this validation happens once per channel, never per slice (§5.4). The checks:

(The Tier 0 analogue — a PayTP-aware client validating a merchant-authored quote vector by these same rules before paying — is F3.2/§5.6.)

F5-m — replay-suppression. With no connection-bound key, the durable channel-id record is what stops a captured CHANNEL_OPEN from being replayed onto a new connection (which the TLS exporter formerly barred structurally). The merchant MUST retain an accepted channel's identifier — and enough state to recognize it, e.g. its CHANNEL_AUTH hash — at least through the TIMESTAMP acceptance window (F8) and any advertised channel-retention window, and MUST reject a CHANNEL_OPEN reusing a retained identifier rather than initialize a fresh channel. An identical retransmission returns the stored CHANNEL_ACK; a terminated channel is never re-initialized under its old identifier. This is one durable decision per channel identifier, the same discipline as the consumed-nonce and chaining-reference records (§5.4/§7.4).

F5.3 CHANNEL_ACK and its retrieval (formalizes §5.4)#

CHANNEL_ACK: 0x00 AUTH_HASH (32) · 0x01 SETTLE_PTR (the merchant's settlement pointer, F9 grammar) · 0x70 SIG (merchant key, PayTPv1-chan-ack). F5-e (an encoding refinement): AUTH_HASH = SHA-256(COVERED(CHANNEL_AUTH)). §5.4 describes the ACK's covered bytes as "CHANNEL_AUTH's canonical bytes together with the merchant's settlement pointer"; this construction binds the identical values through a collision-resistant hash inside a uniform F1.3 envelope — equal in binding strength, one verifier code path. The semantic §5.4 fixes — the pointer sits inside the signature; relaying software cannot substitute where settlements pay — hold identically. The channel exists when the payer holds a valid CHANNEL_ACK (§5.4).

Retrieval (§5.4): ACK_REQUEST0x00 CHANNEL_ID (8) · 0x01 TIMESTAMP (Unix seconds, unsigned minimal) · 0x70 SIG (that channel's payer key, PayTPv1-ack-req, §5.2) — POSTed to /ack on any connection. The merchant answers a valid request (signature by that channel's payer key, timestamp within the F8 acceptance window) with the channel's CHANNEL_ACK; nobody else learns a channel's terms from its identifier (§5.4). The freshness window bounds replay to parties that already saw both request and answer.

F5.4 FUNDING_PROOF (formalizes §5.4)#

0x00 CHANNEL_ID (8) · 0x01 AUTH_HASH (32, as F5.3 — a proof can never be presented against a different channel, §5.4) · 0x02 RAIL (CAIP-2, or an adapter rail id per F9.1 — funding rides the DENOM rail, which may be a custodial/instant-bank/Lightning adapter, §6.2/§11.1) · 0x03 TX_REF (the rail transaction reference, UTF-8, bound as the adapter declares, §11.1) · 0x04 AMOUNT (µ-units of DENOM, unsigned minimal) · 0x70 SIG (payer key, PayTPv1-funding). A rail transaction is creditable to at most one channel, once; the merchant records consumed references under the one-decision discipline (§5.4).

**F5-n (the funding transfer binds to its channel on the rail).** The 0x01 AUTH_HASH TLV names the channel inside the proof, but a signed name is not self-securing: a payer can sign a well-formed FUNDING_PROOF for its own channel whose TX_REF points at a victim's rail transfer. So the funding transfer itself MUST bind to the channel it funds on the rail, one of two ways at the merchant's choice per channel: (a) its **immutable, sender-chosen memo carries the 32-byte AUTH_HASH** (SHA-256(COVERED(CHANNEL_AUTH)), F5.3 — the same value the proof's 0x01 carries), or (b) it pays a **settlement pointer the merchant issued uniquely to that channel** (a distinct CHANNEL_ACK.SETTLE_PTR per channel, so the transfer's to alone identifies the channel). Without this, where a merchant shares one settlement pointer across channels, one channel claims another's deposit (gift-theft); and per-channel proof keying without an on-rail bind instead lets one payer credit a single transfer under two of its own channels (double-credit). A rail whose finalized records expose neither an immutable sender-chosen memo (a recipient-supplied or post-hoc-mutable memo does not count) nor a usable per-channel pointer MUST NOT carry channel funding (an adapter capability, §11.1) — the bind is the funding path's precondition, not optional hardening. The merchant's crediting procedure that consumes this bind — resolve the channel first, then check against its stored hash — is F6.4 (F6-d).

F5.5 CHECKPOINT and CHECKPOINT_REQUEST (formalizes §5.4/§6.3)#

CHECKPOINT — the §6.3 canonical statement:

TypeFieldValue
0x00CHANNEL_ID8 bytes.
0x01BALANCEB, µ-units, signed minimal (F1-b) — the parties' live flow-control estimate for window enforcement during OPEN (§6.1). It is not authoritative for what has been paid: the settle/close reconciliation reads the rail, not a possibly-stale B (F6-f).
0x02CUM_TOTALCumulative accepted slice value, µ-units, unsigned minimal — monotone (never decreases; the checkpoint ordering of F6.3 depends on it). This is the authoritative metered principal: what the channel accepted, from which the rail-paid principal subtracts (F6-f).
0x03ACCRUALSCount-prefixed list, ascending role, one item per vector role: role (1) ‖ len (LEB128) ‖ numerator (unsigned minimal) — the cumulative accrued exact numerators of §10.2 (µ-units × basis points), monotone. This is the authoritative metered meed: what accrued, from which the rail-settled meed subtracts (F6-f). F5-j (per-role tracking): §6.3/§10.2 speak of totals per recipient; the checkpoint tracks the finer per-role grain because roles are the vector's units while two roles can share one destination (the fallback shape, F3.2) — a recipient's total is the sum of its roles' numerators, always derivable, never ambiguous; settlement and flooring are per recipient (F7). Per-role is the unique canonical form; per-recipient would make the fallback's shared-destination sum order-ambiguous.
0x04LAST_SEQHighest accepted sequence number, fixed 8 bytes.
0x05RANGESCount-prefixed list of accepted ranges since the previous checkpoint: lo (8) ‖ hi (8), inclusive, ascending, non-overlapping, non-adjacent (adjacent ranges MUST merge — one canonical form).
0x06TRANSCRIPTThe transcript head (32, below).
0x07EVENTSCount-prefixed list of references recorded since the previous checkpoint: kind (1: 0x01 funding, 0x02 settlement round, 0x03 predecessor import) ‖ len (LEB128) ‖ ref (funding: the rail TX_REF bytes; settlement: the countersigned proposal's hash, F5.6; predecessor: the imported checkpoint reference); items sorted ascending by kind, then ref bytes. A best-effort audit trail — not the authoritative paid record (F6-f; the rail is): a settlement re-anchor carries no new slice, so a concurrent slice-checkpoint of higher CUM_TOTAL supersedes it and the re-anchor's EVENTS entry drops from the operative chain. That loses nothing — the settlement is on the rail and credited by its proof at reconciliation — so EVENTS completeness is not relied on; a party that wants a fuller local trail re-presents a superseded reference in its next proposal.
0x08TIMESTAMPUnix seconds, unsigned minimal (§6.3).
0x09PREV_REFThe predecessor checkpoint's reference (32, F5-f), making the channel's checkpoints a chain (§6.3): all-zero for a channel's first own checkpoint with no import; the imported checkpoint's reference for a chained successor's first; otherwise the prior bilateral checkpoint's reference.
0x70SIG_PAYERThe payer key's signature, PayTPv1-ckpt (F5-k).
0x71SIG_MERCHANTThe merchant key's signature, PayTPv1-ckpt, over the same covered bytes (F5-k).

Both signatures cover the identical COVERED bytes (all fields, both authenticators excluded); the object is bilateral when both are present, and the slots are role-fixed (F5-k), so a given agreement has exactly one bilateral byte form — two valid signatures can never be swapped into a second CKPT_REF for the same content. F5-f (checkpoint reference): the reference other objects carry — chaining, and settlement (the operative checkpoint a meed advance settles against and the net leg's NET_MEMO binds, F6-o/F6-h) — is SHA-256 over the complete canonical bytes of the bilateral checkpoint, both signature TLVs included: it names one countersigned instance, not just its content. F5-g (transcript): head_0 = SHA-256("PayTPv1-transcript" ‖ 0x00 ‖ CHANNEL_ID); head_i = SHA-256(head_{i-1} ‖ slice_i) over each accepted slice's complete canonical bytes (TAG included — the chain records what was accepted as received), in sequence order, exactly the slices the accepted ranges name (§6.3); rejected slices enter no chain.

CHECKPOINT_REQUEST: 0x00 PROPOSED (value: the proposed CHECKPOINT bytes, the initiator's role slot signed, the other absent) · 0x70 SIG (the initiator's key, PayTPv1-ckpt-req) — §5.4's two-label construction verbatim: the inner object is signed under the checkpoint's own label so the countersignature completes one canonical bilateral object; the wrapper is its own signed object. The response is the completed CHECKPOINT, or PAYTP_STATE_MISMATCH presenting the responder's bilateral checkpoint (§6.3; behavior in F6).

F5.6 Settlement messages and CLOSE (formalizes §5.4/§6.4)#

SETTLEMENT_PROPOSE (from the debtor — the payer in postpay, the merchant in prepay; each message signed by its sender, §5.4):

TypeFieldValue
0x00CHANNEL_ID8 bytes.
0x01CKPT_REFThe named checkpoint's reference (32, F5-f).
0x02OUTPUTSCount-prefixed list: amt_len ‖ amount (unsigned minimal) ‖ asset_len ‖ asset (UTF-8) ‖ dest_len ‖ dest (UTF-8) — each length a canonical LEB128; **at most one item per (dest, asset) pair (a value movement to one destination in one asset is one output — duplicates are rejected, so the same obligation has exactly one encoding), and an output whose amount evaluates to zero MUST be omitted** (an output is a value movement; there is no zero-value output) — so a deterministic round whose merchant-net is already fully covered by prior net legs simply omits that destination, giving debtor and creditor one canonical OUTPUTS (no omit-versus-zero disagreement to fork the PROPOSAL_HASH); items sorted ascending by dest bytes, then asset (one canonical form, F1.1 rule 2). Destinations MUST match those bound at establishment (§5.4).
0x03INSTANCE_LEG**REQUIRED in every channel settlement round that makes extinguishment progress — i.e. whose E ≥ 1** (F7.3; §6.4: a paid channel meed settles as this aggregate leg advancing the per-channel meed watermark — baseline included — so which rounds settled is rail-discoverable; there is no direct-output channel shape). A round with E = 0 — nothing accrued, P = 0, **or the sub-extinguishment trap where P ≥ 1 but E floors to 0 (F7.3) — carries no** INSTANCE_LEG: it executes no payment and its numerators carry to the next round (F7.1/F7.3). Keying the leg on E ≥ 1 rather than P ≥ 1 is what prevents the infinite loop where a P = 1 / E = 0 round would pay forever without reducing the debt; there is likewise no zero-value aggregate leg to post (rails reject zero-value transfers), so a channel is never stranded on dust or a zero-progress round. Fields in canonical ascending type order (F1.1): 0x00 AMOUNT (the round's own-cumulative meed watermark target target_P the leg advances funded_p to, baseline minimum units, unsigned minimal — the F7.2 result on (Σ ACCRUALS_r(operative) − Σ imported_settled_r), F6-o, stated explicitly so the proposal commits to the cumulative position: a dispute reads target_P off the signed object without replaying any transcript. The leg's on-chain move is the delta ΔP = target_P − funded_p, but the proposal commits the absolute target_P) · 0x01 CREDITED (below) · 0x02 EXTINGUISHED (count-prefixed list, ascending role: role (1) ‖ len (LEB128) ‖ E_r (unsigned minimal) — the per-role numerators this round extinguishes, F7.3; Σ E_r = E. This lives in the signed proposal, where it is authoritative and un-poisonable — an off-baseline round's creditor countersigns it, a deterministic baseline round's is recomputable from the checkpoint — and is what F6-f reconciliation reads; the on-chain watermark advance need not carry it, F4.2). CREDITED (the 0x01 field) is a count-prefixed list of this round's prior finalized legs — populated only across the round's own retries (F6.5), never the channel's whole settlement history, so a proposal's size is bounded by the two-leg round shape and does not grow with channel age — each self-identifyingkind (1: 0x01 meed, 0x02 creditor principal) ‖ rail_len (LEB128) ‖ rail (CAIP-2, or an adapter rail id per F9.1 — a meed leg's rail is always the baseline CAIP rail; a creditor-principal/net leg's rail is the DENOM rail, which may be an adapter) ‖ ref_len (LEB128) ‖ ref (UTF-8) ‖ fin_len (LEB128) ‖ finality (UTF-8 adapter token), sorted ascending by kind then ref bytes — so a credited leg names its kind, rail, on-chain reference, and finality; crediting is verified against that on-chain transfer, F6-f, not inferred from a bare reference. The instance's asset and contract are not here: they are established in CHANNEL_AUTH (BASELINE_ASSET, CONTRACT), so the instance address is fixed for the channel's life (F4.1) and no round can redirect it. AMOUNT is the round's singular figure: the own-cumulative target_P is fixed once per (CHANNEL_ID, CKPT_REF) at the first countersigned proposal (floor per F7.2 on that checkpoint's Σ ACCRUALS(operative) − Σ imported_settled at the observed rate) and never re-derived — the creditor's durable one-decision record per (CHANNEL_ID, CKPT_REF) refuses to countersign a second, different proposal for the same round (F6.5), so target_P/rate/observation are singular, not merely "frozen at whichever first," and still singular per round because ACCRUALS(operative) and imported_settled are fixed at the named checkpoint.
0x04CONVERSIONOPTIONAL — present exactly when **a conversion is needed, i.e. DENOM ≠ BASELINE_ASSET** (the meed accrues in DENOM but settles to the instance in BASELINE_ASSET, so it converts whenever they differ — regardless of which rail the net leg settles on; a cross-currency channel settling its net on the baseline rail still converts its meed): 0x00 RATE (the F3-c decimal grammar, UTF-8, positive — baseline minimum units per one µ-unit of the channel denomination, the channel grain of F7-b) · 0x01 RATE_TIME (observation time, Unix seconds) · 0x02 RATE_EXP (expiry, Unix seconds) · 0x03 RATE_GRACE (seconds, duration). The required finality levels are not here: they are channel-life establishment terms in CHANNEL_AUTH (FIN_MEED/FIN_DENOM, F5.2), so a deterministic baseline round that carries no CONVERSION still has a defined settlement finality and no round — original or retry — can weaken it. CONVERSION is purely the rate agreement. Rate and time MUST sit inside the RATE_SOURCE/RATE_DEV the establishment terms name (§6.4). When DENOM = BASELINE_ASSET the conversion is unity and CONVERSION is absent; the deterministic no-countersignature baseline-atomic round (F5-h) is exactly the DENOM = BASELINE_ASSET and net-on-baseline case — any DENOM ≠ BASELINE_ASSET round carries CONVERSION and is countersigned (rate agreement), even with both legs on the baseline rail.
0x70SIG_PAYER / 0x71 SIG_MERCHANTRole-fixed slots (F5-k), label PayTPv1-settle-propose. A both-signed round (DENOM ≠ BASELINE_ASSET or net-off-baseline, F5-h): the debtor signs its own role slot and leaves the other absent; the counterparty's acceptance completes the object with the second signature over the identical covered bytes (§5.4), and nothing executes before the completed object exists (§6.4). A single-signed deterministic round (DENOM = BASELINE_ASSET, net-on-baseline): only the debtor's role slot is present, the other stays absent, and the debtor executes directly (the outputs are checkpoint-determined, so the creditor needs no pre-agreement — it verifies against the checkpoint after).

F5-h (proposal hash): the round's identifier in later messages is SHA-256 over the proposal's complete canonical bytes. Which signatures those bytes carry depends on whether the round needs agreement — a rate, or an off-baseline net leg — not on whether it has an aggregate leg (every meed-paying round has one and a P = 0 dust round has none, F5.6/§6.4, so aggregate-leg presence is never the trigger either way): a round is both-signed (countersigned before anything executes — rate agreement + the F6.5 one-decision record) iff DENOM ≠ BASELINE_ASSET or its net leg settles off the baseline rail, and its PROPOSAL_HASH is over the both-signed object; a round is single-signed (PROPOSAL_HASH over the debtor's proposal) iff it is deterministicDENOM = BASELINE_ASSET (unity rate) and net-on-baseline, so P, EXTINGUISHED, and the net outputs are all fixed by the named checkpoint and the established vector, leaving nothing to negotiate and no two-replica ambiguity. This matches F6.5's exchange rule exactly. Both are well-defined; a SETTLEMENT_PROOF/SETTLEMENT_CONFIRMED names the hash of whichever object its round produced. The aggregate meed leg the round executes advances the per-channel meed watermark (seed_instance, CHANNEL_ID) to the round's own-cumulative target_P (F6-o), recorded by the instance (§6.4).

F5-p (v0.1 conformance profile — baseline-only). The off-baseline machinery — a channel whose DENOM ≠ BASELINE_ASSET (carrying RATE_SOURCE/RATE_DEV, F5.2), its CONVERSION rate agreement (F5.6), and the both-signed round it forces (F5-h) — is a defined but v0.1-deferred protocol capability. A v0.1 conformant implementation MAY restrict to baseline-denominated channels (DENOM = BASELINE_ASSET, so every round is the deterministic single-signed baseline-atomic form, F5-h) and **reject an off-baseline CHANNEL_AUTH at establishment** (the fail-closed posture); the reference implementation does exactly this — it refuses DENOM ≠ BASELINE_ASSET at open and on converted settlement, and the conversion path is not built in v0.1 (F8: "off-baseline rounds are not built in v0.1 … vacuous today"). This is an implementation-profile scope, not a protocol change: the conversion rules (F5.2/F5.6/F7.3/F8) stay normative for the version that implements them, and a build that does support off-baseline is conformant too. A profile that claims off-baseline support MUST implement the full conversion arithmetic (P/E/E_r at the observed rate, F7.3), both-signed off-baseline proposal handling (F5-h), and its adversarial rate/time/finality tests before enabling it; a v0.1 baseline-only build MUST NOT silently accept an off-baseline channel it cannot settle.

SETTLEMENT_PROOF: 0x00 CHANNEL_ID · 0x01 PROPOSAL_HASH (32) · 0x02 TX_REFS (count-prefixed list: leg (1: 0x01 meed, 0x02 creditor output) ‖ ref_len (LEB128) ‖ ref (UTF-8) ‖ fin_len (LEB128) ‖ finality (UTF-8, adapter token); items sorted ascending by leg, then ref bytes; each named transfer's own finalized rail record carries its round bind, which the creditor verifies before crediting the leg — the meed leg its advanced_channel_meed distribution fact (funded_p ≥ target_P on this (seed_instance, CHANNEL_ID), F6-o/F6-m), the creditor-output/net leg its NET_MEMO (F6-h)) · signed by the debtor in its role slot, PayTPv1-settle-proof.

SETTLEMENT_CONFIRMED: 0x00 CHANNEL_ID · 0x01 PROPOSAL_HASH · signed by the creditor in its role slot, PayTPv1-settle-confirm — sent only after receipt at its own pointer where the round pays it, and after verifying the required meed proof; partial proofs complete nothing (§5.4).

**F5-o (PREPAY_DRAW_COMPLETED — the prepay interim-draw completion notice): the merchant→payer message the merchant emits after executing a prepay interim meed draw (F6-n), and the signal a halted conformant wallet resumes on (§6.4, the prepay meed halt). A prepay interim round is the merchant's — the meed debtor's (F6.5) — so the notice is merchant-single-signed under its own** domain tag PayTPv1-prepay-draw, never a creditor-signed SETTLEMENT_CONFIRMED (PayTPv1-settle-confirm, whose direction is wrong here). Fields in canonical ascending type order (F1.1): 0x00 CHANNEL_ID (8) · 0x01 CKPT_REF (32, F5-f — the operative checkpoint the draw settled against) · 0x02 AMOUNT (the own-cumulative meed watermark target target_P the draw advanced funded_p to, baseline minimum units, unsigned minimal — the F7.2 result on (Σ ACCRUALS − Σ imported_settled), F6-o) · 0x03 EXTINGUISHED (count-prefixed list, ascending role: role (1) ‖ len (LEB128) ‖ E_r (unsigned minimal), Σ E_r = E, F7.3 — the per-role numerators this draw extinguished, exactly as a proposal's EXTINGUISHED, F5.6) · 0x04 CLAIM_RECORD (32 — the deterministic round identifier claim_record_id(seed_instance, CHANNEL_ID, CKPT_REF, target_P), F4.2, computed over the own-cumulative target_P; the wallet re-derives and matches it as a notice-integrity check, but credits value from the advance fact below, not this identifier) · 0x05 RAIL (the baseline CAIP-2 rail id, F9.1) · 0x06 TX_REF (the meed advance transfer reference, UTF-8) · 0x07 FINALITY (the finality the leg reached, UTF-8 adapter token — at least the channel-established FIN_MEED, F5.2) · 0x70 SIG (merchant key, PayTPv1-prepay-draw). The notice is liveness evidence, not settlement authority (§6.4): the wallet verifies the signature and resumes streaming at once — but only on a notice drawing the round's full owed carve at the own-cumulative altitude — the wallet computes the same own-cumulative target_P = floor((Σ ACCRUALS − Σ imported_settled) / 10 000) from its co-signed ACCRUALS and resumes only when 0x02 equals that cumulative target_P, never re-flooring per role (the own-cumulative altitude — a wallet that re-floored per round would trap its own float, and the cumulative watermark avoids the per-role floor-desync), and only when the operative still owes a positive incremental carve. A notice for a smaller target_P — even one the merchant truthfully advances — does not resume the halt, or a merchant under-drawing each round would strip the accrued carve unboundedly, defeating §6.4's "bounded to one round" (the interim-draw analogue of the F6.5 understated-round reject). It then credits the round only from the rail — it independently verifies the rail's advanced_channel_meed fact shows this channel's watermark reached funded_p ≥ target_P on this (seed_instance, CHANNEL_ID) (the distributing advance kind, F6-o/F6-m — never a plain transfer to the instance and never a state read) to the required finality before crediting the round and permitting the next. A signed notice for an advance the merchant never funded resumes the stream once but credits nothing, and the next round's halt does not clear (F6.5) — so the meed a withholding merchant can strip stays bounded to the one already-accrued round (§6.4). A wallet MUST verify the rail facts before crediting each round, never deferring to close, else a merchant could fake the final round's notice and short the recipients for that session (a bounded but real edge-incentive leak).

CLOSE: 0x00 CHANNEL_ID · 0x01 CKPT_REF (the final bilateral checkpoint) · 0x02 CHAIN_INTENT (1 byte: 0x01 = the payer intends to chain, 0x00 = it does not) · 0x70 SIG (sender's key, PayTPv1-close). F5-l (chain intent is the payer's word only): chain intent is meaningful solely on a payer-signed CLOSE (§6.4's "a payer that intends to chain says so in its CLOSE"). A merchant-signed CLOSE MUST set CHAIN_INTENT = 0x00, and a receiver MUST ignore 0x01 on a CLOSE not signed by the channel's payer key — the deposit-return-versus-successor choice (§6.4) turns on the payer's intent, and only the payer's signature can express it, so a merchant cannot forge a chain intent to defer a deposit return. The signer is identified by which key verifies SIG against the channel's CHANNEL_AUTH parties.

F5.7 Starting sequence (F5-i)#

The first slice of every channel carries SEQ = 1; the pre-checkpoint acceptance floor is 0. Nothing about the start is negotiable, so CHANNEL_AUTH carries no field for it — this discharges F1-e's hand-off with the simplest rule that keeps "above the checkpoint floor" uniform from birth.

F5.8 Open items handed forward#


F6 — The Channel State Machine#

Channel behavior: states and guards, the balance arithmetic, slice acceptance, the checkpoint exchange, settlement rounds, chaining, and failure. F6 formalizes what Chapter 5 §5.4/§5.7 and Chapter 6 already fix; it does not change them. Wire layouts are F5's; constants and clocks are F8's; fee arithmetic is F7's.

F6.1 States (formalizes §5.7)#

NEGOTIATING → OPEN ⇄ PAUSED_EVIDENCE / PAUSED_WINDOW → SETTLING → CLOSED (§5.7). Pauses re-enter OPEN as bounds are hit and released; SETTLING and CLOSED are one-way.

F6-a (the implicit transition — an explicit protocol rule): the establishing connection's close IS a transition — the channel enters SETTLING from whatever state it was in. This is a state-machine RULE, not a cryptographic consequence (§5.5): the channel-binding salt is now the public relationship digest BindSalt (F1.6), not a connection-bound key, so nothing about the keys forces a channel to end with its connection — the protocol mandates it. A channel does not outlive the connection that carried its CHANNEL_OPEN; after that connection closes, only the control plane continues (checkpoints, settlement, chaining, on any connection). There is no zombie state: every channel whose connection died is in SETTLING until its obligations resolve by settlement — or, where the payer had closed with explicit chain intent, by an accepted successor — then CLOSED. An implicit close carries no chain intent: the payer declares intent in an **explicit payer-signed CLOSE (CHAIN_INTENT = 0x01, F5-l)** and then presents the chain reference in the successor's CHANNEL_OPEN, both required (F6.6 clause (a)); §6.4's one-durable-choice rule governs regardless. So a channel whose connection merely dropped, with no chain-intent close, is not chainable: letting a channel survive a bare reconnect is explicitly out of v0.1 scope — v0.1 keeps the one-connection-per-channel rule, and continuation across a reconnect is achieved instead by the explicit chain-intent close plus a fresh successor (§6.2).

F6.2 Balance, window, and slice acceptance (formalizes §6.1/§5.3)#

Both parties maintain B as the flow-control estimate (not the authoritative settled position, which is F6-f's reconciliation): an accepted slice adds its amount; a confirmed funding transfer subtracts — **in postpay, only the portion credited toward the outstanding merchant-net (F6.4), so B never falls below 0: the excess of a non-conformant over-transfer is forfeit and moves B no further** (the same max(0, …) clamp F6-f applies to merchant-net, applied to the estimate); **a postpay settlement round decreases B by the gross DENOM value it settles — the merchant-net leg plus the meed settled this round, the latter being the cumulative-delta of the settled carve floor(Σ E_after / 10 000) − floor(Σ E_before / 10 000)** (Σ E = extinguished numerator across completed rounds, F7.3). It MUST be this difference-of-cumulative-floors, not a per-round floor(E_this_round / 10 000): floor is non-distributive, so two rounds each extinguishing E = 5 000 decrease B by floor(10 000/10 000) − floor(5 000/10 000) = 1 in total, which a per-round floor would compute as 0 + 0 = 0 — and since the re-anchor checkpoint requires both parties to sign an **identical B** (F6.3), a per-round reading would fork the countersignature. B tracks this integer DENOM settled-carve, never the baseline amount P (converting P back to DENOM would be fractional); a prepay interim round executes meed only and leaves B unmoved (§6.1, §6.4). Invariant: −L_prepay ≤ B ≤ +L_credit, with the mode restricting to [−L_prepay, 0] (prepay) or [0, +L_credit] (postpay) — the postpay lower bound 0 is enforced by the funding clamp just stated, never breached by an over-transfer. Enforcement is single-ended (§6.1): the merchant MUST reject any slice that would push B above its mode's upper bound; the payer alone decides funding.

**F6-g (initial balance — a fresh channel opens at B = 0).** An unchained channel initializes B = 0 in both modes; a chained successor instead opens at the reconciled imported position (F6.6/F6-e — the rail-computed opening, not the predecessor's possibly-stale checkpoint B), rather than the unchained default of 0 — and that reconciled position may itself legitimately be 0 (a fully-settled or fully-consumed predecessor imports zero owed), which is not the same thing as the fresh-init constant. That one init value is not symmetric in effect, because 0 is the postpay lower bound but the prepay upper bound: a fresh postpay channel opens with its full L_credit of headroom above 0 (consume now, settle in arrears), while a fresh prepay channel opens at its upper bound, so **no slice is acceptable until a confirmed FUNDING_PROOF drives B negative** (a confirmed deposit subtracts, F6.2; consumption then pushes B back up toward 0). This is the whitepaper's "the payer deposits first; slices consume the deposit" and "on confirmation the window opens" (§6.1). Initializing prepay B at −L_prepay instead would pre-credit the whole float and let a payer consume up to L_prepay before funding anything — free service, and a direct contradiction of "in prepay that bound is zero, so a deposit can never be overspent" and of the payer's max(−B, 0) ≤ L_prepay unconsumed-deposit exposure, which is 0 before any deposit lands. L_prepay is the deposit limit, never the opening balance — the deposit is whatever the payer funds, up to L_prepay. Symmetrically at the upper edge: a prepay window exhausted back to 0 re-opens only by funding — an interim settlement round executes meed only and leaves B unmoved (F6.2/F6.5), so it cannot release a prepay PAYTP_WINDOW_EXCEEDED pause — whereas a postpay window re-opens on either funding or a settlement round that moves B down (F6.1's "released by funding or a completed settlement round" is the postpay reading).

F6-b (canonical acceptance order) — one check order, authenticate-before-state, so multi-fault slices draw deterministic errors and no unauthenticated sender learns channel state: (1) carriage names a channel this endpoint holds open — else ordinary HTTP rejection, no PayTP error (an unknown channel's terms are nobody's business, §5.4); (2) parse: the slice is F1's closed object with SEQ ≤ 2^63 — else reject generically; (3) TAG verifies under subkey(SEQ) in constant time — else reject generically, without accounting and without any state-derived error: carriage is connection-agnostic, so anyone can address bytes at a channel, and only MAC-holders may draw state answers; (4) SEQ admissible: above the checkpoint floor and not yet accounted — else PAYTP_SEQ_INVALID (replay or at-or-below floor; reordering is never an error, §5.3); (5) bounds: the amount would not push B past the mode's bound — else PAYTP_WINDOW_EXCEEDED — and would not push unevidenced accepted value above E — else PAYTP_EVIDENCE_REQUIRED (reaching exactly E is accepted and pauses the channel pending checkpoint; §6.3's rule is exceed, never reach). Only a slice passing all five is accepted: B and the cumulative totals move, the accrual numerators advance (F7), and the slice joins the accepted set its next checkpoint's ranges will name. Atomicity across one carriage unit: all slices arriving in one metering batch, or on one request's header fields, validate against a tentative state and commit together — any failure rejects the whole unit with nothing accounted (F1-j's whole-body rule; a partial batch is itself a divergence surface). **"Nothing accounted" governs the accountingB, the cumulative totals, and the accrual numerators all roll back — but a PAYTP_WINDOW_EXCEEDED breach is a control-state consequence that persists regardless: the batch's demand reached the mode's ceiling (guard (5)), so the channel firmly pauses** (F6.1's window pause) even though the batch metered nothing. Otherwise a payer could wrap slices in a batch to probe the ceiling, draw the reject with the accounting rolled back, and retry a smaller amount without ever funding or settling — evading the pause the single-slice path enforces. The pause releases only on confirmed funding or a B-moving settlement round (F6-g/F6.1), never by the rejected batch's own rollback. A rejected response only guides the wallet; the checkpoint, not the response, declares a slice dropped (§5.3).

Creditors SHOULD track aggregate exposure per wallet key and asset across channels — an endpoint risk policy, not a wire requirement, and per-merchant key stability is unverifiable on the wire, so postpay credit stays an identity-and-relationship decision (§6.1).

PAYTP_DENOMINATION_MISMATCH guards the round trip where a slice, funding, or settlement asset differs from the channel's DENOM (§5.7).

F6.3 The checkpoint exchange (formalizes §6.3)#

Cadence: the merchant MUST NOT let unevidenced accepted value exceed E; approaching it, the merchant initiates and MAY keep accepting slices within the remaining headroom while the exchange completes — E governs throughout. The payer MAY request a checkpoint at any time. Setting E to one payment yields a receipt per purchase (§6.3).

Exchange: a CHECKPOINT_REQUEST carries the initiator's proposed state already signed (F5.5); the responder MUST, within CKPT_TIMEOUT (F8), either countersign — completing the bilateral object — or answer PAYTP_STATE_MISMATCH presenting the bilateral checkpoint it holds. F6-c (countersigning condition): the responder countersigns iff it accepted every slice the proposed ranges name and every proposed field — balance, cumulative total, accrual numerators, last sequence, transcript head, event references, predecessor reference — recomputes to identical values from its own books evaluated historically, over exactly the named slices and named events, never against its live state: a responder that has accepted newer slices since the proposal was cut still countersigns the older true snapshot (§6.3). Anything that fails the historical recomputation is a mismatch answer, which fails the one proposal, never the channel (§6.3). A payer request that guesses the accepted set wrong costs a round trip, never the merchant's unevidenced value (§6.3).

Concurrency, the chain, and supersession (§6.3): every checkpoint names its predecessor (PREV_REF, F5.5), so a channel's checkpoints form a chain and "the final bilateral checkpoint" is well-defined — the chain tip. Supersession is ordered by **CUM_TOTAL** (monotone metering): the checkpoint with more accepted value supersedes. It is safe to order by metering alone precisely because payment is rail-authoritative (F6-f): a checkpoint carries no settled/paid figure that a crossing could discard — funding, principal legs, and meed legs are credited by their on-chain proofs regardless of which sibling wins, so a slice-heavier checkpoint superseding a settlement re-anchor loses nothing (the settlement is on the rail, and the operative checkpoint's higher CUM_TOTAL/ACCRUALS reconcile against that same rail record, F6-f). A responder countersigns any valid proposed state even with a higher one of its own in flight — an older snapshot is still true, and staleness is never PAYTP_STATE_MISMATCH. The no-fork rule and its tiebreaker: a proposal naming a PREV_REF and a state the responder has already countersigned is answered with the existing bilateral checkpoint, never signed twice. Crossing initiations can nonetheless complete two bilateral checkpoints at one position with **equal CUM_TOTAL — each side countersigned the other's proposal before its own came back; banning that would invite deadlock, so it resolves deterministically: of two bilateral checkpoints with the same PREV_REF and equal CUM_TOTAL, the one with the lexicographically greater CKPT_REF (byte comparison of the 32-byte references) is operative**. The chain tip is therefore always well-defined, including at an immediate close: a CLOSE naming the superseded twin is answered with the operative one. An event (funding, a settlement round) present only in the superseded twin is not lost — it is on the rail (F6-f) and is credited by its own proof at reconciliation; a party MAY also re-present its checkpoint reference in the next proposal for the audit trail. A countersignature lost in transit costs a retransmission, never the state.

Recovery (§6.3): after crash, disconnection, or mismatch, the last bilateral checkpoint is the anchor — settle from it or chain from it. A proposal bearing one signature is auxiliary evidence, never a checkpoint. A peer that neither countersigns nor answers mismatch within CKPT_TIMEOUT forfeits continued service (PAYTP_CHECKPOINT_TIMEOUT), and the channel settles or closes from the last bilateral checkpoint.

F6.4 Funding (formalizes §6.2)#

F6-d (funding crediting is resolve-then-check). Because a shared settlement pointer makes an on-rail transfer non-channel-specific, the merchant MUST credit a FUNDING_PROOF only after this ordered procedure and MUST record its reference consumed only if every step passes: (1) resolve CHANNEL_ID to an accepted channel and recover that channel's own stored (or recomputed) CHANNEL_AUTH hash; (2) verify the proof's SIG under that channel's payer key and that the proof's 0x01 AUTH_HASH equals the stored hash; (3) canonicalize TX_REF to the single credited transfer event the rail recognizes — an adapter that admits two spellings of one transfer (T and T#0) would double-credit it (F5.4/§11.1); (4) confirm the canonical rail transfer pays the channel's settlement pointer in DENOM for the named AMOUNT, reaches FIN_DENOM (F5.2), and **carries the F5-n on-rail bind — its immutable memo equals the stored AUTH_HASH, or its destination is the pointer the merchant issued uniquely to this channel — checking the memo against the channel's stored** hash, never against the proof's self-declared 0x01 field (that comparison re-admits the gift-theft, since a proof signed for the attacker's own channel can carry any AUTH_HASH value); (5) confirm the canonical (rail, TX_REF) is unconsumed, then atomically record it consumed globally — across all of the merchant's channels — and credit. Any failed check rejects without consuming: a missing or wrong bind leaves an already-executed transfer uncreditable and recoverable only off-protocol — a payer error, never a theft. The on-rail bind and the global one-decision are each load-bearing and neither suffices alone — the bind closes cross-channel gift-theft, the global-once record closes same-channel replay and cross-channel double-credit.

On a valid FUNDING_PROOF (F5.4) the merchant checks (by the F6-d procedure): the rail record shows the transfer bound to this channel (F5-n) at its settlement pointer with the named amount and reference, **reaching the channel-established FIN_DENOM finality** (F5.2) — "confirmed" is exactly this, and pinning it at establishment is what makes it deterministic: both parties agree which funding is creditable in the F6-f reconciliation, and no reorg-weak transfer can re-open a window and buy service before it could reverse; the reference is unconsumed — a rail transaction credits at most one channel, once, under the one-decision record (§5.4). Credit lands at the next checkpoint, at settlement, at close, or in the successor's first checkpoint — the chain reference links a proof bound to its predecessor — and a crash never erases rail-confirmed funding (§6.2). Confirmed funding moves B and re-opens the window (§6.4). **Postpay funding credits up to the merchant-net debt and floors there:** a FUNDING_PROOF proves an already-executed, irreversible rail transfer, so the merchant never rejects it — rejecting money that has already moved would strand it and could wedge a window-paused channel. Instead the merchant credits it toward the reconciled outstanding merchant-net(CUM_TOTAL − meed_carve) − Σ(prior credited funding) − Σ(net legs) (F6-f) — clearing that to 0 and re-opening the window, and carries no excess into a negative position: outstanding merchant-net **floors at 0, because postpay has no payer-refund flow (F5.2 — "no protocol flow ever pays the payer"). The reconciliation records the credited amount, not the raw transfer (closing a path-dependence fork):** each FUNDING_PROOF's recorded contribution is credited = min(raw amount, outstanding merchant-net at its confirmation); any excess over the then-debt is forfeit and never recorded in Σ funding. So both the live B (F6.2) and the authoritative F6-f/F6.6 reconciliation subtract the same Σ(credited funding) — a bounded quantity the total ever owed — and can never disagree. (Had Σ funding been the raw cumulative, B clamping the excess away path-dependently while F6-f retained it path-independently would fork: F6-f would keep offsetting future CUM_TOTAL growth to 0 while B climbed to L_credit, and a settlement carrying OUTPUTS = 0 would leave B stuck — a permanent window deadlock. Recording credited-not-raw removes that fork.) The bound is on **merchant-net, not B**: funding pays down merchant-net specifically (it lands at the merchant's pointer), whereas B is the gross flow-control estimate that still carries the separately-owed meed, so a funding that leaves B ≥ 0 can still overshoot merchant-net by up to the outstanding meed carve (e.g. gross 100, carve 20, merchant-net 80: a 95 funding overshoots merchant-net by 15). A conformant payer funds against the bilateral checkpoint's reconciled merchant-net, never its own unreconciled slice count, so an overshoot arises only from a non-conformant over-transfer (or a dropped-slice view gap) — and that excess is the payer's own forfeit, credited to the merchant (postpay never pays the payer), never stranded and never a deadlock: the creditable portion always clears the debt and re-opens the window. (A payer wanting to pre-fund future consumption uses prepay mode, whose [−L_prepay, 0] range and refund pointer exist for exactly that.)

F6.5 Settlement rounds (formalizes §6.4)#

F6-f (metering in checkpoints, settlement in countersigned rounds). The two durable records a channel keeps are already the whitepaper's (§6.3/§6.4): the bilateral checkpoint for metering, and, for each completed settlement round, its countersigned settlement proposal together with the round's rail-finality proofs (§6.4: "the rail reference against the countersigned proposal is the debtor's proof no less than the recipients'"). Both are bilateral, signed, bounded (one proposal per round, as checkpoints are one per exchange), and self-contained — a proposal carries its CKPT_REF, AMOUNT, rate, per-role EXTINGUISHED (E_r), and OUTPUTS (F5.6). This is the authoritative settled record, and it is un-poisonable: an off-baseline round's E_r is signed by both parties (the creditor countersigns, so a debtor cannot inflate it), and a deterministic baseline-atomic round's E_r/outputs are recomputable by both from the named checkpoint (so a wrong one is rejected on recompute). The rail moves the money and proves finality — every round that makes extinguishment progress (E ≥ 1, F7.3) advances the per-channel watermark (seed_instance, CHANNEL_ID) to target_P, exactly-once by absolute position (F4.2/F6-o), so which rounds finalized is rail-discoverable (an E = 0 round — including the P ≥ 1/E = 0 trap — advances nothing, F4.2/F7.3) — but the rail is not the authoritative numerator log: E_r lives in the signed proposal, never in unverifiable on-chain calldata.

The checkpoint records metering onlyCUM_TOTAL (gross accepted value) and ACCRUALS (accrued meed numerators), both monotone — authoritative for what was metered, never for what was paid; it carries no settled field (a settled field on two independently-advancing axes desyncs under a checkpoint crossing). At settlement and close each party reconciles metered against the completed rounds, gross split into merchant-net and meed so neither double-counts. For a chained channel, CUM_TOTAL/ACCRUALS are whole-chain cumulative and settled/net-legs/funding include the imported cumulative openings (F6.6); for a first-generation channel the openings are zero, so the lines below read directly:

Net legs and funding are keyed (CHANNEL_ID, rail tx ref) and each creditable to at most one channel once — §5.4's funding rule, extended to settlement's net legs: a party records a consumed net-leg reference under the one-decision discipline, so one rail transaction to its pointer credits one channel, never two. This credit-once bookkeeping alone is not sufficient: the net-leg transfer itself MUST also bind to its round on the rail (F6-h) — carrying a (CHANNEL_ID, CKPT_REF) memo, or paying a per-channel settlement pointer — or a debtor whose own round is countersigned could name a victim's fresh transfer to the shared settlement pointer as its own net leg, clearing a real debt with another's money (the net-leg hijack). Because the operative checkpoint carries the highest (monotone) metered totals and the settled record is the held signed proposals + rail finality, no checkpoint crossing, supersession, or lost re-anchor can strand or double-count a completed payment — a superseded settlement re-anchor loses nothing, the round's evidence being its proposal and its on-chain watermark advance, neither in any checkpoint. Recovery (§6.3): last bilateral checkpoint (metering) + the retained countersigned proposals (settlement) + the rail (finality); a party that has lost its proposals queries the rail before re-settling. The channel's meed watermark is **rail-discoverable by (seed_instance, CHANNEL_ID)** (F4.2/F6-o); funded_p is monotone, so the debtor reads the cumulative already-funded position and advances only the residual ΔP = target_P − funded_p, never re-paying (a re-advance to a target_P ≤ funded_p is a rail no-op); the net leg stays credited-once by (CHANNEL_ID, rail tx ref). So the blind-re-settlement hazard the per-round P-committed key once carried simplifies away: the watermark's absolute position, not a recomputed per-round P, is the recovery basis, and even a debtor that lost its terms cannot double-pay by re-advancing (it still recovers the round's per-role E_r from its retained proposal or the counterparty, below, but the value is already pinned by funded_p). For an off-baseline round, the funded watermark position alone does not reconstruct the rate or the per-role E_r that the close/chain reconciliation needs (F7.3); those live in the round's countersigned settlement proposal, which is bilateralboth parties signed and retain it (F6-f) — so a party that lost its copy recovers it from the counterparty. Failing even that, the rail's watermark still proves the cumulative funded position funded_p, so the loss is bounded to the per-role split (never the round total, and never a double-pay): the party settles conservatively, crediting the round up to the finalized funded_p and treating the un-recovered per-role E_r as the last-resort ambiguity the F10 vectors and §6.4's evidence trail address, not a value leak. BALANCE is the live flow-control estimate for window enforcement while OPEN (§6.1); the settle/close reconciliation above is authoritative and reads the rail, never a possibly-stale B. Self-containment (§6.3) is therefore checkpoint (metering) + rail (payment), both durable — not the ephemeral slice transcript; this is the same honest posture as §6.4's "no settlement rail enforces PayTP receipts and this spec claims none does," read from the settlement side: the rail is where value moves, so the rail is where "what was paid" is authoritative. A chained successor imports the predecessor's metered totals and settles imported obligations against the same rail record (F6.6), so imported debt is never replayed, erased, or double-counted.

**F6-h (the settlement net leg binds to its round on the rail — closes the net-leg hijack).** F6-f keys a net leg (CHANNEL_ID, rail tx ref) and credits it once, but — exactly as F5-n showed for a FUNDING_PROOF — a signed SETTLEMENT_PROOF naming a net leg is not self-securing: its 0x02 TX_REF can point at a victim's rail transfer to the shared settlement pointer. A debtor whose round the creditor has countersigned could name another channel's fresh net transfer T as its own leg; its round CONFIRMS, T is consumed globally under the credit-once rule, and T's true channel's later proof for T is refused — the debtor cleared a real debt with another party's money. So the net-leg transfer itself MUST bind to the round it settles on the rail, one of two ways at the merchant's choice per channel (the F5-n discipline): (a) its **immutable, sender-chosen memo carries NET_MEMO = SHA-256("PayTPv1-net" ‖ 0x00 ‖ CHANNEL_ID ‖ CKPT_REF)** — the round's (CHANNEL_ID, CKPT_REF), which the creditor recomputes and checks exactly as it checks the meed leg against its advanced_channel_meed distribution fact (F6-o/F6-m); or (b) it pays a **settlement pointer the merchant issued uniquely to that channel** (a distinct SETTLE_PTR per channel, so the transfer's to alone identifies the channel). A rail whose finalized records expose neither an immutable sender-chosen memo (a recipient-supplied or post-hoc-mutable memo does not count) nor a usable per-channel pointer MUST NOT carry a channel's net leg (the same adapter-capability precondition F5-n sets for funding, §11.1). The creditor rejects any 0x02 leg whose finalized rail record does not carry the bind. This makes the net leg name its round on the rail — symmetric with the meed leg, which advances the per-channel watermark (seed_instance, CHANNEL_ID) and whose distribution the advanced_channel_meed fact proves (F4.2/F6-o/F5-h) — so F6-f's credit-once bookkeeping rests on a cryptographic round bind, never merchant discipline alone. NET_MEMO binds the round, not the amount: the leg's amount is already matched against the round's recomputed OUTPUTS (F5.6) and CKPT_REF is unique per round, so (CHANNEL_ID, CKPT_REF) alone ties a transfer to exactly one settleable position.

**F6-m (the meed leg's rail record must attest its watermark advance — not merely carry the key — closing the non-distributing-leg forge). F6-f credits a round's meed only once the advance** of the per-channel watermark (seed_instance, CHANNEL_ID) reached funded_p ≥ target_P at the required finality (above); the advance is the distinct on-chain kind (F4.2/F6-o) that *distributes ΔP among the establishment-bound meed destinations over the cumulative target on arrival* — the on-chain record captures the monotone division and its §10.2 residue, and the rail adapter source-debits the round's source and delivers each role's delta, exposing the fact only after that distribution ran (the two-layer custody, F6-o). The identifiers it binds — the channel (seed_instance, CHANNEL_ID) and the round's target_P — are rail-public the moment a round is proposed (F4.2) — so, exactly as a bare TX_REF does not self-secure a net leg (F6-h), a memo bearing those identifiers does not self-secure the meed leg: a settling debtor could pay a plain transfer to the instance address stamped with them, present it as the 0x01 leg, and — on a memo/identifier match alone — complete the round while the recipients receive nothing (the debtor discharges its meed for free; the enablers' governed carve is silently pocketed, the §10.2/F7.3 conservation break). The creditor MUST therefore verify the leg's finalized rail record exposes the **advanced_channel_meed distribution fact** — the F6-o kind whose per-role distribution executed — never a transfer that merely carries the identifiers, and never a state read of the record's standing position: the memo/identifier names the round, the advance kind proves the distribution. This is the meed-side member of the rail-fact discipline F5-n sets for funding and F6-h for the net leg (bind to a rail fact, never a caller-declared field), the settlement realization of §6.4's "the rail reference against the round's proposal is the debtor's proof no less than the recipients'", and the enforcement of F4.2's "the kind exists to make [a settling debtor completing the round while keeping the recipients' money] unwritable". On the baseline SVM rail the advance is the kit's advance_channel_meed instruction (which records the cumulative division, its rail adapter source-debiting and delivering per role); a bare SPL TransferChecked to the instance PDA advances no watermark and distributes nothing, so it can never satisfy the leg. A rail whose finalized records cannot distinguish the watermark-advance kind from a plain transfer to the instance address MUST NOT carry a channel's meed leg (the same adapter-capability precondition F5-n/F6-h set, §11.1).

Triggers — unsettled value is the reconciled metered − rail-paid (F6-f), and it is settleable only when a round could discharge it: a net leg due, or meed that **extinguishes E ≥ 1** (F7.3 — meed that would pay P but extinguish E = 0, or sub-P dust with no net leg, is unsettleable, compels no round, and carries; F7.3's rule is that a round is compelled only by settleable value). Both threshold triggers gate on settleability: a round MUST begin when settleable unsettled value reaches TH_value, or when now − last_settle ≥ TH_time with settleable value present; also when the window exhausts and the payer elects settlement over funding (a postpay reopen — that round moves B; a prepay payer reopens an exhausted window by funding, an interim round being meed-only and leaving B unmoved, F6-g), or at channel close — unless a successor chains and imports instead (§6.4). Gating both thresholds on settleable forecloses the deadlock a bare value trigger would open: a conformant prepay payer halts at a due TH_value round (§6.4 prepay meed halt), so a value trigger that fired on a position the debtor cannot discharge would strand the payer waiting for a round that can never run. A threshold of **0 disables that trigger** (TH_value = 0 → time-only settlement; TH_time = 0 → value-only; F5.2); the window/evidence bound and close remain the backstops, so disabling a trigger defers settlement, never blocks it (close still reconciles unsettleable sub-P dust to the merchant, F7.3/§10.2). Thresholds are ceilings, not schedules: the debtor MAY propose earlier at will. The round is the debtor's to start (payer in postpay, merchant in prepay); against a debtor that does not, the creditor holds the standing remedies — pause at the window or evidence bound, and close from the last bilateral checkpoint (§6.4). Each deadline binds the party that acts on it, on its own clock within the F8 skew allowance; a rail-enforced deadline runs on the rail's clock (§6.4).

The exchange (§6.4, layouts F5.6): SETTLEMENT_PROPOSE from the debtor against a named checkpoint. A round that carries a conversion (DENOM ≠ BASELINE_ASSET) or settles its net off the baseline is countersigned before anything executes — its terms (rate, observation time) MUST sit inside the establishment-named source and deviation, and a proposal naming any destination not bound at establishment MUST be rejected; a deterministic round (DENOM = BASELINE_ASSET, unity rate, P and net outputs fixed by the checkpoint and the established vector) needs no countersignature (§6.4's three-message vs four-message distinction; PROPOSAL_HASH per F5-h). One frozen proposal per round (the durable one-decision rule, closing the two-replica fork on off-baseline rounds): for a given (CHANNEL_ID, CKPT_REF) the creditor records the round's terms durably — the economic and risk content: AMOUNT, EXTINGUISHED, rate, observation time, RATE_EXP, RATE_GRACE, and outputs — exactly once across whatever serves its traffic, the same discipline as the consumed-nonce and chaining-reference records (§5.4/§5.6). It MUST refuse to countersign a second proposal whose terms differ, but MUST countersign a retry carrying identical terms — a retry differs only in CREDITED (which grows to name the legs already finalized, F5.6); every economic and risk term above is byte-identical across a retry, and finality is not a proposal field at all — it is established once in CHANNEL_AUTH (FIN_MEED/FIN_DENOM, F5.2), so no retry can weaken the finality the creditor requires or extend its rate-honor window. So a debtor cannot get two different AMOUNTs countersigned for one round against two creditor replicas (the two-replica fork), yet the ordinary retry-after-partial-completion is not blocked (the one-decision key is the terms, not the whole proposal object). A deterministic round needs no such record: its AMOUNT, EXTINGUISHED, and net outputs are a deterministic floor from the named checkpoint, so every replica computes the one same values. Execution: meed first — the aggregate outstanding meed, converted once at the round's rate (F7), **advancing the channel's per-channel watermark (seed_instance, CHANNEL_ID) to the round's own-cumulative target_P (F4.2/F6-o, the aggregate leg — never loose outputs** — for every round that makes extinguishment progress [E ≥ 1], so every such round is rail-discoverable; an E = 0 round — dust or the P ≥ 1/E = 0 trap — advances nothing, F4.2/F7.3); the debtor starts the creditor's net output only after the meed leg has reached its own established FIN_MEED on the baseline rail (F5.2) — the ordering gate is "meed finalized to its required level first," each leg judged against its own rail's level (the net leg against FIN_DENOM), never a cross-rail comparison of one adapter's finality token against another's, which do not compare (F8.1) (§6.4). SETTLEMENT_PROOF carries the rail references and finality; SETTLEMENT_CONFIRMED comes only after the creditor's own output arrived at its pointer and the required meed proof verified — partial proofs complete nothing (§5.4). Completion is recorded in a bilateral re-anchor checkpoint that records the round in EVENTS and carries the metered totals unchanged (a round accepts no new slice; CUM_TOTAL/ACCRUALS do not move — the round's effect is on the rail, F6-f, not in a checkpoint counter). The round's finalized legs are credited by their on-chain proofs (F6-f) whether or not this re-anchor survives supersession.

F6-l (at most one in-flight round — an implementation MAY serialize): F6-f's rail-authoritative crediting tolerates overlapping rounds — a superseded round's finalized legs are credited by their own on-chain proofs ((CHANNEL_ID, rail tx ref) / the per-channel advance fact), never stranded — but an implementation MAY instead enforce the stricter sequential discipline the exchange already describes: at most one settlement round in flight per channel. It then rejects a new SETTLEMENT_PROPOSE on a different CKPT_REF while an earlier round on the channel is still unconfirmed, admitting only that round's retry (same (CHANNEL_ID, CKPT_REF), identical terms, F6.5) until it completes or lapses (SETTLE_TIMEOUT, all-or-close below). A conformant debtor settles sequentially regardless (propose → execute → confirm → next), so this rejects only a non-conformant overlap; it is a valid stricter posture (like an implementation that defers off-baseline settlement), never looser — it forecloses rather than reconciles the two overlapping-round races (two rounds each folding one accrual's E_r toward the settled > accrued brick; a slow-rail round confirming after its checkpoint was already re-settled and over-collecting a conformant payer), at the cost of pipelined settlement. Under it the single in-flight round always confirms against an unmoved settled position, so its recomputed E_r and its proposed E_r coincide, and the chain-close quiescence bar (F6-i) reduces to "no unconfirmed round stands." An implementation that instead admits overlap MUST provide F6-f's crediting in full (every finalized leg credited by its own rail reference, the meed by its per-channel advance fact independently of the net leg) so no such race strands or double-charges. Under the watermark (F6-o), a pending advance MAY remain unresolved — a close (F6-i) may advance the same channel watermark to a higher absolute target_P regardless of which checkpoint each named, and the monotone funded_p subsumes the pending advance idempotently rather than double-pays; serialization here bounds pipelining, not exactly-once (which the watermark's absolute position guarantees on its own).

F6-l-async (finality-confirmed, restart-durable reconciliation — the async-rail realization of F6-f). F6-f is rail-authoritative but was stated against a rail where submit is settlement. On a real rail (F8.1) a submitted transfer is not yet final and a not-yet-irreversible one can reorg away, so an implementation MUST separate the two: a fold (settled_r, net legs, credited funding), a clear (a pending prepay draw), a consume (a funding/net-leg reference), a credit (the window B), or a refund-done mark happens only when the rail confirms the backing transfer reached the channel-established finality level. That level MUST be irreversible on a reorg-capable rail: FIN_MEED/FIN_DENOM (F5.2) name it, and a merely "accepted" but reversible level (Solana confirmed) has no un-fold path and would short recipients on a post-fold reorg — so fold/clear/consume/credit/refund at an irreversible level (Solana finalized) is a requirement, and a channel pinning a reversible level for these is non-conformant on a reorg-capable rail. A submitted-but-not-final operation is a pending decision, retained until conclusively resolved: finalized → commit the fold/clear; dropped/reorged → it moved nothing, safe to re-issue (the idempotent primitive re-issues it: a watermark advance by its on-chain absolute position, F6-o, exactly-once; a keyed release under the async-durability caveat at the end of this paragraph). Every one-decision record and every pending decision survives a process restart: a restarted party re-derives the same decision from durable state and never replays — never re-consumes a funding reference, re-advances a settled watermark to double-pay, or re-refunds a reconciled close. The keyed release is the refund's exactly-once primitive, and it RESERVES before it submits: a prepay close refund is keyed (CHANNEL_ID, refund-basis CKPT_REF), **reserved in the durable one-decision store before submitting to the rail (persisting the canonical ref) and marked settled only on confirmed finality; a retry after an outage re-derives the pending reserve from the durable store and re-submits the same keyed release, which the rail dedups — so a failed/ambiguous release is retried rather than blindly re-released (the §6.4 standing-obligation the durable keyed release discharges). What is certified here is the synchronous-rail core: reserve-before-submit + fold-at-irreversible, where the release resolves in the same step it is submitted. Full exactly-once across an async drop/reorg/restart is NOT yet realized — the party's durable reserve alone does not prevent a restart double-release — and additionally requires two pieces, both the tracked async-durability layer, not this milestone: (i) the rail's keyed-release idempotency must itself be durable/on-chain, because an in-memory dedup is lost on a restart, so a re-submit after both party and rail restart would no longer be recognized as a duplicate; and (ii) a refund poll-then-settle worker that marks the refund settled only on confirmed finality** (never at submit), re-submitting a dropped release. This formalizes an implementation robustness the whitepaper §6.4 already implies ("a crash never erases rail-confirmed funding"; recovery reads the rail). The synchronous-rail core — a durable one-decision store plus a synchronous release_keyed — is what v0.1 realizes; the durable-rail idempotency and the poll-then-settle worker (i)/(ii) are async-durability work outside v0.1 scope.

All-or-close and retry (§6.4): if proofs and confirmation do not complete within SETTLE_TIMEOUT, no re-anchor is signed, the channel closes (PAYTP_SETTLE_TIMEOUT), and whatever remains unpaid is the reconciled metered − rail-paid (F6-f), evidenced by the last checkpoint and the rail. A failing round MAY be re-proposed within SETTLE_TIMEOUT. A retry carries the round's identical terms — same AMOUNT, rate, observation time, RATE_EXP, RATE_GRACE, outputs, and EXTINGUISHED, and the same channel-established finality (FIN_MEED/FIN_DENOM, which are not proposal fields, F5.2) — with a possibly-grown CREDITED naming the legs already finalized; because CREDITED is inside the proposal (F5.6), the bytes differ, so the retry is signed afresh and produces its own PROPOSAL_HASH — a both-signed round is re-countersigned (the creditor signs iff the retry's terms match its one-decision record), a single-signed deterministic round is re-signed by the debtor alone. Neither re-runs the F8.4b rate-freshness check (the rate was agreed once; re-checking a now-hours-old RATE_TIME would deadlock the retry). So a round is re-signed but never re-priced: the terms are singular across every retry, only CREDITED grows. Its CREDITED names the legs already finalized (each self-identifying — leg kind, rail, reference, finality — F5.6); a finalized leg is credited by its on-chain proof, never paid twice, never re-executed — the meed leg advances the per-channel watermark exactly-once by absolute position (a re-advance to a target_P ≤ funded_p distributes nothing, F4.2/F6-o), so a retry executes only the still-unfinalized legs. The terms stay singular by the creditor's one-decision record (F6.5) — a retry carries a byte-identical target_P, rate, and EXTINGUISHED — and the watermark's idempotency-by-position is the backstop: even a re-advance at the singular target_P moves only the residual funded_p → target_P and can never double-pay, so a finalized meed leg exactly satisfies the round without the deadlock a re-priceable per-round record would have risked. If the remaining legs cannot complete, all-or-close closes with the finalized legs credited (F6-f) and the rest standing as the reconciled obligation.

Direction and close (§6.4), with the exact figures each side computes (F6-f):

Returning the deposit and accepting a successor are one durable choice per final checkpoint (§5.4/§6.4): chain intent in CLOSE is not a waiver — until a successor is accepted the payer may demand the return at any time, and past the merchant's advertised holding period an unclaimed deposit returns unprompted (§6.4).

F6-n (the prepay interim meed draw — closing the long-lived-prepay halt). F6.5's prepay direction executes meed-only interim rounds (B unmoved), and the prepay meed halt (below) has a conformant wallet stop at a due-but-uncompleted round — but a merchant that drew meed only at close would strand a long-lived prepay stream at its first TH_value boundary (recoverable only by close + re-chain), defeating the persistent-metering value the mode exists for. So the merchant — the prepay meed debtor (F6.5) — runs an interim meed draw on a live (non-terminal) channel when the reconciled position is settleable (E ≥ 1 at TH_value/TH_time, the Triggers rule): a deterministic (DENOM = BASELINE_ASSET, unity-rate) meed-only round **advancing the channel's per-channel watermark to the own-cumulative target_P = floor((Σ ACCRUALS_r(operative checkpoint) − Σ imported_settled_r) / 10 000)** — the same F7.3 recompute the postpay creditor runs — distributing the delta ΔP = target_P − funded_p from the deposit (the distributing kind, F6-m), folding E_r into the settled record on rail-finality (F6-f, credited independently of any net leg, idempotent by absolute position, F4.2/F6-o). Four rules make it sound:

On completion the merchant emits PREPAY_DRAW_COMPLETED (F5-o), the signal the halted wallet resumes on — and re-servable idempotently: because the wallet resumes only on the notice, a lost delivery would strand the halted payer, so a retry of a completed round re-serves the identical signed notice, reconstructed from the round's retained facts (its target_P, E_r, and advance reference) + the deterministic round identifier claim_record_id(seed_instance, CHANNEL_ID, CKPT_REF, target_P) (F4.2) — never re-drawing (the debtor-side analogue of the postpay SETTLEMENT_CONFIRMED re-emit, F6.5). No dedicated re-anchor exchange is needed to resume — the settled record is rail-authoritative (F6-f), and the round is recorded in EVENTS at the next ordinary checkpoint (best-effort, F5.5). B does not move and the prepay window re-opens only by funding (F6-g); an interim round pauses nothing (F6.1).

The prepay meed halt (§6.4): a conformant wallet stops sending slices once a meed round due by TH_value, or by TH_time with settleable unsettled value, has not completed — a round comes due only on settleable value (the Triggers rule above), so the wallet never stalls waiting for a round the merchant cannot run. It **resumes on the merchant's PREPAY_DRAW_COMPLETED notice (F5-o) for that round — a liveness signal it verifies and acts on at once — but credits the round only from the rail** (F6-m/F6-f), verifying the advance reached funded_p ≥ target_P on this (seed_instance, CHANNEL_ID) before crediting and before permitting the next round; a signed notice for an unfunded advance resumes the stream once and credits nothing, leaving the next halt uncleared, so the strippable meed stays bounded to the one already-accrued round (§6.4). The halt itself remains the payer's standing right to decide how much to stream — no new error. Bounded and conformance-dependent exactly as §6.4/§6.5 state it.

**F6-o (the per-channel meed watermark and its advance instruction — the chain-enforced exactly-once meed). A channel's meed is settled not as a sequence of per-round claim-records but by advancing a single per-channel cumulative watermark** on the instance — the ChannelMeed record keyed (seed_instance, CHANNEL_ID) (F4.2), holding the cumulative funded aggregate funded_p (baseline minimum units, monotone), the per-destination cumulative paid_d, and a §10.2 residue. **advance_channel_meed(CHANNEL_ID, target_P)** computes ΔP = target_P − funded_p; if ΔP ≤ 0 it distributes nothing (idempotent by absolute position — the record already stands at or beyond target_P); otherwise it distributes over the cumulative target, aggregating by destination first — for each meed destination d, bp_d = Σ_r bp_r over the roles naming d, and paid_d ← floor(target_P · bp_d / Σ bp), non-decreasing in target_P so each destination's cumulative paid only grows — carries the sub-unit remainder target_P − Σ_d paid_d as the §10.2 residue, and commits funded_p ← target_P. **The per-destination flooring is exactly F7-d/F7.3's — the same by-destination aggregation the Tier 0 MeedInstance division runs (bp_d = Σ bp_r over roles naming d, floored once per destination): roles sharing a destination floor once on the combined bp_d, never independently. Per-role flooring would strand up to one sub-unit per shared destination per advance, persistently underpaying a chronically-shared fallback destination (e.g. unasserted 0x10/0x12 joining 0x13 at a Development Fund).** The product target_P · bp_d is computed in the F7 exact arithmetic (target_P < 2¹²⁸, F7.2). The record is seed/channel/asset-bound, prefund-tolerant, and has no close/re-init, so funded_p only ever grows — the on-chain exactly-once guarantee. A model change **deploys under a fresh CONTRACT (F5.2), which derives a fresh seed_instance and hence a fresh ChannelMeed PDA** (F4.1) — that is the isolation mechanism, not the CHANMEED_VERSION field, which is only a forward-compat marker recorded in the account (the PDA seed (seed_instance, CHANNEL_ID) omits it and no instruction checks it).

Custody (the v0.1 channel-meed profile boundary). The design is on-chain custody: a channel's meed instance holds the value and divides it by code among the destinations fixed at establishment, exactly as the Tier 0 split address does — and the Tier 0 split is already code-enforced today (the permissionless distribute, F4-d), so "code pays" is literally true for the baseline split now. For the channel meed watermark, the v0.1 profile realizes this in two layers, deferring on-chain custody to the rail adapter the same way F5-p defers off-baseline settlement: the on-chain record captures the monotone division only (funded_p/paid_d/residue) and does not itself source-transfer, and the rail adapter is the custody layer — it source-debits the round's source (a prepay draw's deposit at SETTLE_PTR, or a postpay payer's leg) and credits the per-destination recipient deltas, then exposes the advanced_channel_meed fact only after that apply (mutate record → debit → credit → set fact, on finalization). So the v0.1 profile fixes the on-chain record semantics and the adapter's custody-and-fact semantics separately; the channel instance's code does not yet itself move ΔP. Full on-chain custody for the channel meed — the instance code holding and dividing the value directly (the F7-d instance-side model), matching the Tier 0 split — is required for production; it is a v0.1-deferred completeness boundary (a sibling deferral to the async-durability realization above, F6-l-async), and it may change the recipients' on-chain collection path — a pushed per-destination credit here versus the F7-d withdraw-claimable_d model (push versus pull, not a change of division: both floor once per destination) — so it is not claimed byte-identical to v0.1. What holds in both realizations is the guarantee the creditor checks: **advance_channel_meed sets the advanced_channel_meed distribution fact only in the same atomic on-chain operation that source-debits the round's source and credits the per-destination deltas (the ordering above, all-or-nothing) — so a fundless or failed invocation debits nothing, credits nothing, and therefore sets no fact and advances no** funded_p (there is no bare-bump-then-fact path, and none that poisons the watermark altitude on a failed debit) — and F6-m requires the creditor to verify that distribution fact — proof the recipients were paid — before crediting the round (never a bare watermark bump, never a plain transfer, never a state read; a rail whose finalized records cannot distinguish the distributing advance from a bare bump MUST NOT carry a channel's meed leg, F6-m). So under a conformant rail no round completes without the recipients being paid; the residual the production milestone closes is that v0.1 leans on the rail adapter to hold this atomic debit-credit-then-fact, which full instance-custody makes unconditional at the instance itself (as the Tier 0 split already is, F4-d).

The rail fact. A finalized advance exposes advanced_channel_meed { CHANNEL_ID, seed_instance, funded_p (the post-advance cumulative), delta ΔP, asset }, set only by this instruction after the source-debit + distribution ran — the per-channel form of the F6-m distribution fact. A plain transfer to the instance address, even one copying the record's identifiers, sets it absent (it funds no record and distributes nothing); the fact is never a state read ("the record stands at ≥ target_P") but a witnessed distribution event. A creditor/wallet credits the round against this fact — the advance reached funded_p ≥ target_P for this (seed_instance, CHANNEL_ID) — never a memo (the F6-m closure, per-channel). A rail whose finalized records cannot distinguish the advance from a plain transfer MUST NOT carry a channel's meed leg (the F5-n/F6-h/F6-m adapter-capability precondition, §11.1).

The round's target is own-cumulative. A round settling meed advances to target_P = floor((Σ ACCRUALS_r(operative checkpoint) − Σ imported_settled_r) / 10 000) — the channel's own cumulative meed owed, excluding a chained predecessor's already-settled imported_settled_r (0 unchained). ΔP = target_P − funded_p is exactly the F6.2 difference-of-cumulative-floors the settlement already computes, so the on-chain draw amount is the existing settled-carve delta — no new arithmetic, and the settled_r(E_r)/B-move/merchant-net zone is untouched (the watermark carries only the aggregate distribution; the authoritative per-role E_r still lives in the round's signed proposal, F6-f). Because interim and close both advance the same monotone funded_p, a close advance to target_P_final ≥ target_P_interim moves only the residual whatever checkpoint each names — the drop-then-redraw double-draw is closed by construction, on the rail, not by bookkeeping.

Async reconciliation (F8.1). The advance's value moves at the rail's finalization, and a not-yet-irreversible advance can reorg away (reverting the distribution and the watermark exactly, conserving). The creditor/wallet therefore folds the round (settled_r/credited_r) only once the advance reaches the channel-established FIN_MEED — which on a reorg-capable rail MUST be an irreversible level (F6-l-async) — never on submit; a pending advance is retained until resolved (finalized → fold; dropped/reorged → moved nothing, safe to re-advance to the same target_P); and the fold is a durable one-decision (F6-l-async) that survives a restart. This is the settlement-side of §6.4's rail-authoritative recovery, made robust on a rail where submit ≠ settlement.

F6.6 Chaining (formalizes §6.2/§5.4)#

Validation, both parties (§5.4): accept a predecessor reference only if (a) the predecessor received a **payer-signed CLOSE carrying explicit chain intent** (CHAIN_INTENT = 0x01, F5-l) and is now **CLOSED, or in SETTLING with its obligations not otherwise discharged — because accepting the chain reference is itself the act that moves such a SETTLING predecessor to CLOSED (F6.1). An implicit close carries no chain intent and is NOT chainable in v0.1:** a channel whose connection merely dropped (no CLOSE, F6-a), or one closed with CHAIN_INTENT = 0x00, cannot be chained from — the payer that means to continue **declares it in its CLOSE** (F5-l, §6.4 "a payer that intends to chain says so in its CLOSE") before the successor's CHANNEL_OPEN presents the reference (both are required). This does not weaken §6.2's "a tab continues across reconnects": the CLOSE is a control-plane message the payer MAY send on any connection — including one it opens after an ungraceful drop — so continuation is achieved by chain-intent-closing the dropped predecessor and opening a fresh successor. What is out of v0.1 scope (F6-a) is resuming the same channel across a reconnect (reusing its id/session with no successor) — the deferred reconnect work. A predecessor still OPEN cannot be chained from, and one whose closing settlement already began or whose deposit already paid out cannot either (that is condition (d)); (b) the reference names its final bilateral checkpoint; (c) parties, denomination, mode, baseline asset, and baseline network are identical (below); **F6-j: the settlement thresholds TH_value/TH_time are identical too, and the successor inherits — never restarts at birth — the predecessor's settlement clock, so an imported already-due obligation comes due in the successor exactly as it would have in the predecessor (a successor opening with slacker thresholds, or a clock reset to its own birth, would defer an obligation already due — contradicting the Import paragraph's "a deferred round comes due in the successor exactly as it would have" and §6.4's "chaining never resets its clock"). The merchant's chain-terms fingerprint therefore covers the thresholds; equality** is the fail-closed v1 rule — a strictly tighter successor would be safe (it only settles sooner) but is also rejected, keeping the fingerprint a simple identity. And — where the predecessor's final checkpoint carries outstanding accruals the successor imports — **the whole meed-instance identity is too: schema, MEED_VECTOR (shares and destinations), and CONTRACT version, and the settlement-governing terms RATE_SOURCE, RATE_DEV, FIN_MEED, and FIN_DENOM** (the Import paragraph: imported accruals must be able to settle to the same instance on the same chain under the same rate-and-finality discipline they accrued under, or they are re-divided, misrouted, residue-fragmented, stranded — or settled at a weaker finality or a different rate source than the accrual's own establishment terms agreed); and (d) neither party has already accepted a successor for that checkpoint or paid it out at close. One durable decision per final checkpoint, exactly once across whatever serves that party's traffic; consumed references are retained for as long as a reference of that age would be accepted, and pruning is safe only together with refusing all references that old (§5.4). Failure: PAYTP_CHAIN_REJECTED; recovery is settling the predecessor from its final checkpoint and opening fresh (§6.2). Of two successors racing for one checkpoint, the first accepted wins and the other starts fresh (§6.2).

F6-i (chain-close quiescence — the close-side dual of the import): the imported openings a chain_intent close rolls forward (clause (a)) are taken from the predecessor's completed rounds (F6-f opening_settled_r/opening_net_legs), so the close is sound only from a settlement-quiescent channel — one with no interim settlement round still able to complete, i.e. no unresolved credit decision (an advance whose E_r is not yet folded into opening_settled_r). A pending advance MAY otherwise remain unresolved (F6-l/F6-o) — the meed leg advances the predecessor's per-channel watermark (seed_instance, CHANNEL_ID) to an absolute position, while the postpay net leg keeps its (CHANNEL_ID, CKPT_REF) memo-bind (F6-h) — but a round completing after the snapshot would leave its E_r unfolded (finalized on the rail, uncredited into opening_settled_r) while the successor imported the same obligation as still-outstanding — the payer pays it twice, once through the predecessor's late advance and once through the successor's. A merchant MUST therefore reject a chain_intent close while any interim round can still complete (PAYTP_CHAIN_REJECTED); the debtor completes it or lets it lapse — a round the ledger has already superseded (a later completed round or funding moved the position past it), or one past SETTLE_TIMEOUT (F6.5 all-or-close), can no longer complete and does not block — then chain-closes. A non-chain close is unaffected: it reconciles the pending round's on-rail outcome on this channel (F6-f), stranding nothing. This settlement-quiescence bar is scoped to the chaining dispositions — it forbids a new settlement round only while the channel may still hand its position to a successor (a chain_intent close whose successor has not yet imported, or one that already has). A plain (reconciling) close settles on its own books and therefore still admits — indeed F6.5 ("a round MUST begin … at channel close") requires — the channel's final settlement round: the postpay net-plus-meed round the payer runs, or the prepay close that draws the outstanding meed carve to the instance (the merchant is the prepay meed debtor, F6.5). An implementation that bars settlement for every closed channel rather than only a chaining one would strand the postpay final round and never draw the prepay carve — the merchant over-collecting the enablers' meed, the exact conservation break §10.2/F7.3 forbid. ("Still able to complete" is exactly the settlement plane's own staleness test — a round whose economics were verified against a ledger position later moved past cannot fold — so an implementation MAY block on that predicate alone and treat the SETTLE_TIMEOUT lapse as the coarser backstop, holding a chain-close until an abandoned round is superseded: stricter than this rule on the liveness side, never looser on the safety side.)

F6-k (checkpoint-before-chain — the named final checkpoint MUST be the final metered position): clause (b)'s "final bilateral checkpoint" is exactly the position the successor imports (the Import paragraph: it opens at the predecessor's final cumulative values), so a chain_intent close is honored only when the channel's live metering equals that named checkpoint — no slice accepted-but-not-yet-checkpointed standing beyond it. Uncheckpointed value is the merchant's E-bounded risk (§6.3), evidenced in no bilateral checkpoint; importing the checkpoint while live metering exceeds it drops that value from the successor's opening — a prepay successor would re-credit float the payer already consumed (the payer re-spends the deposit), a postpay successor would import less obligation than accrued (the merchant loses the debt) — and because a chain re-imports at every hop, the drop **amplifies per hop, defeating the E bound** (an unbounded bleed the single-channel E cap never sanctioned). A merchant MUST therefore reject a chain_intent close while live metering exceeds the named final checkpoint (PAYTP_CHAIN_REJECTED); the parties checkpoint the outstanding slices first — making them the new final bilateral checkpoint (on any connection, F6.1) — and chain from that. A birth/stillborn predecessor (no operative checkpoint) chains only at CUM_TOTAL = 0 (F6-e), where live metering trivially equals the synthetic checkpoint, so the funded-but-unmetered float case is unaffected. A plain (non-chain) close is not bound by this rule: it reconciles against the named checkpoint and the merchant bears any uncheckpointed ≤ E once (F6-f prepay close = Σ funding − CUM_TOTAL(final checkpoint)), with no per-hop amplification to bound — refunding against live instead would let a merchant, holding the symmetric slice key, forge slices to inflate the deduction and short the deposit, so the checkpoint basis is a payer protection, not merely a convenience.

Mode fit (part of (c)): chaining requires the successor's mode to equal the predecessor's, because the imported reconciled outstanding (F6-f — the rail-computed position, not a stale checkpoint B) must be valid in the successor's window and its refund semantics: a prepay predecessor closing with an unconsumed deposit the merchant owes back imports a payer-side balance that only a prepay successor's [−L_prepay, 0] range and REQUIRED refund pointer can carry (F5.2) — importing it into a postpay successor (range [0, +L_credit], no refund pointer, "no protocol flow ever pays the payer") would strand the deposit. The successor's **opening B is set from the reconciled imported position** (so window enforcement bounds the imported exposure from birth), not copied from the predecessor's possibly-stale B. A successor whose mode, or whose limits, cannot admit the reconciled imported position MUST reject the reference (PAYTP_CHAIN_REJECTED); the parties settle the predecessor and open fresh.

Import — the running chain cumulatives (§6.2/§6.4): the successor carries the predecessor's cumulative running totals forward and keeps accumulating them, so every reconciliation computes the meed carve once, on the whole-chain cumulative accrued — the only way to conserve value across a boundary, because floor(A) + floor(B) ≤ floor(A+B): splitting the carve into a per-channel floor drops a sub-unit whenever fractional meed crosses a hop. The imported openings, all cumulative over the chain so far and computed deterministically from the predecessor's final checkpoint + completed rounds + funding (which chaining references and both parties hold; F6-f/§6.2):

Reconciliation (F6-f) then runs on the cumulatives: outstanding meed per role = ACCRUALS_r − (opening_settled_r + Σ E_r(own completed)); outstanding merchant-net (postpay) = max(0, (CUM_TOTAL − floor(Σ_r ACCRUALS_r / 10 000)) − (opening_net_legs + Σ(own net legs)) − (opening_funding + Σ(own funding))) — the **same max(0, …) floor F6-f applies (F6.4's over-transfer forfeit), so a chained successor never imports a negative merchant-net** that its mode-window check (clause (c)) would then wrongly reject; the carve taken once on the cumulative ACCRUALS; unconsumed deposit (prepay) = (opening_funding + Σ(own funding)) − CUM_TOTAL. Cumulative funding therefore lands in exactly one line, the mode's principal obligation — paying down merchant-net in postpay, returnable as deposit in prepay — so a chained channel credits every funded transfer once and never double-counts or strands it (the mode is fixed across the chain, F6.6 (c)). Because the carve is computed once on the running cumulative and settled is tracked from the held proposals (never a per-CHANNEL_ID rail query), this is exact, conserves value across any chain depth, never re-charges a settled round, and never strands a deposit. Imported value counts toward the successor's thresholds from birth, a deferred round comes due in the successor exactly as it would have in the predecessor, and chaining never extinguishes an obligation or resets its clock, meed accruals included. **Because imported accruals still owe the predecessor's recipients their exact shares, a successor importing outstanding accruals MUST route them to the predecessor's same meed instance — which means all of the instance's derivation inputs identical: schema, MEED_VECTOR (shares and destinations), BASELINE_ASSET, and CONTRACT version (F4.1 — the address is the derivation) and settle them under the same rate-and-finality discipline — RATE_SOURCE, RATE_DEV, FIN_MEED, FIN_DENOM — per clause (c)** (these are not address inputs, so they govern how the imported meed settles rather than where; importing under a weaker finality or a different rate source would settle the accrual on terms it never agreed). Changing shares would re-divide imported meeds, changing a destination would misroute them, and — the subtler one — **changing the contract version changes the instance address, so imported accruals would land in a fresh instance with a fresh residue accumulator**, fragmenting the sub-unit residue F7-d carries in the instance's running V (two rounds of one unit each in one instance pay out floor(2 × bp_d/bp_total); split across two instances each pays floor(1 × …) = 0 and the recipient loses the unit). The registry version MAY advance while accruals import **only where the pinned RATE_SOURCE's resolved mapping is unchanged** — the registry carries the id → source series map (F9.3), and an off-baseline round's rate is checked against that resolved source (F5.2/F8.4b), so if version v maps fx-main → A and v+1 maps fx-main → B, importing outstanding accruals under v+1 would settle them against a source their establishment never agreed. A successor importing outstanding accruals therefore validates the resolved RATE_SOURCE mapping is byte-equal at the version it holds versus establishment (the same discipline as the destination-unchanged check, F9-a/F9.4); a changed rate-source resolution forces settle-first. (A registry advance that leaves the pinned id's resolution byte-equal is safe — it changes neither where nor how the accruals settle.) A relationship changing any instance-address input **settles the predecessor's outstanding accruals first** — so no outstanding accrual is re-divided or misrouted — and imports only the net principal. Honest bound: settle-first drains the channel's outstanding accruals, not the old instance's internal sub-unit V residue (< 1 payout unit per destination, left by past settled rounds — F7-d's "permanently where nothing follows" dust); that residue does stay in the old instance when the instance address changes, so an instance change strands up to that sub-unit per destination. It is bounded (per change, per destination, sub-payout-unit) and would need an on-chain instance-sweep mechanism to reclaim — out of v0.1 scope: v0.1 accepts the bounded sub-unit strand on a governance-driven instance change, exactly as it forgives every other sub-unit dust.

The per-channel meed watermark's bounded per-hop dust (F6-o). The settlement reconciliation above still computes the meed carve **once on the whole-chain cumulative ACCRUALS** (F6.2/F6-f) — the shared settled_r/E_r/merchant-net zone is unchanged, and the sentence above (the meed carve "computed once, on the whole-chain cumulative accrued — the only way to conserve value across a boundary") stands. But the on-chain distribution to the enablers advances a per-channel watermark funded_p = floor((own cumulative accrued − imported_settled) / 10 000) (F6-o), which floors per channel, not once on the whole chain. Across a chain boundary the two need not coincide to the µ-unit: Σ_channels funded_p can fall short of floor(Σ whole-chain accrued / 10 000) by at most 1 baseline µ-unit per hop, in aggregate (floor(A) + floor(B) ≤ floor(A+B) on the aggregate cumulative; the shortfall is {0, 1} total per hop — not per destination — and 0 for a first-generation channel, which has imported no already-settled meed). This aggregate cross-hop shortfall is distinct from the per-channel instance's own per-destination sub-unit residue (target_P − Σ_d paid_d, each destination floored paid_d = floor(target_P · bp_d / Σ bp) on the aggregated bp_d = Σ_r bp_r, F6-o/F7-d): that per-destination residue (< 1 per destination) is held in the instance as the §10.2 residue and tops up as later advances raise target_P — a separate strand from this cross-hop aggregate dust. That shortfall is not a conservation break: it is §10.2 sub-unit dust — the enablers receive the correct per-channel watermark (each payable unit exactly once, never twice), the merchant absorbs the ≤1µ/hop (a bounded merchant shortfall / payer discount), and value conserves (deposit = Σ recipient credits + residue + refund). The v0.1 resolution is reconcile-only (the whole-chain carve is deliberately not realigned to the per-channel floor — the ≤1µ/hop is < 0.00001% of any economically-sensible settlement, not worth touching the fragile shared arithmetic): the strand is forgiven exactly as the governance-driven instance-change strand above (bounded — aggregate, per hop, sub-unit; reclaimable only by an out-of-scope on-chain sweep). This sub-unit MUST NOT be a silent, unattributed gap in the settled-then-chained-successor case: a conforming implementation MUST surface it as an explicit, attributed reconciliation figure, never absorb it silently — the merchant-side line item reconciliation_dust(cid) = floor(Σ accrued / 10 000) − floor(Σ imported_settled / 10 000) − target_P ∈ {0, 1} aggregate per hop, so the merchant's books tie out and the sub-unit is an attributed figure, not a silent leak. The keying by the **signed CHANNEL_ID** (never a lineage or a forgeable root) is what makes each channel's watermark independent and un-collidable (the per-lineage design that avoided the per-hop floor died three ways — escrow-strand, forgeable root, floor-desync).

Stillborn channels (§5.4): a channel that ends before signing any bilateral checkpoint of its own resolves to the state its mutually signed terms adopted — for a chained successor, the imported checkpoint — and presents that state, under its own channel identifier, as the final checkpoint a further successor names. F6-e (the synthetic checkpoint's bytes): both parties construct it deterministically, with no signatures — its authority is the CHANNEL_AUTH/CHANNEL_ACK pair, which both signed and which committed to the import: CHANNEL_ID = the stillborn channel's; CUM_TOTAL/ACCRUALS = zero for an unchained stillborn, or the predecessor's final cumulative values for a chained one, and BALANCE = the reconciled imported position by an explicit deterministic formula (it is not load-bearing for settlement — the reconciliation recomputes that — but it **is hashed into PREV_REF, so both parties MUST compute the identical integer or the chain forks): zero for an unchained stillborn; for a chained postpay** stillborn, BALANCE is the **gross unsettled position, by the single canonical formula BALANCE = CUM_TOTAL − Σ(credited funding) − Σ(net legs) − floor(Σ E / 10 000)** — where floor(Σ E / 10 000) is the DENOM value of settled meed (not the accrued carve). Equivalently = outstanding_merchant_net + (floor(Σ ACCRUALS / 10 000) − floor(Σ E / 10 000)), the merchant-net plus the outstanding-meed DENOM value written as the difference of the two floorsnot floor((Σ ACCRUALS − Σ E)/10 000), which is a different integer (floor is non-distributive over subtraction: with Σ ACCRUALS = 40000, Σ E = 33333, the difference-of-floors is 4 − 3 = 1 while the floor-of-difference is floor(6667/10000) = 0). Implementations MUST use the CUM_TOTAL − Σ(credited funding) − Σ(net legs) − floor(Σ E / 10 000) form to get one canonical integer; for a chained prepay stillborn, BALANCE = −(unconsumed deposit) = −(Σ funding − CUM_TOTAL) (F6-f). No implementation infers a different figure (a bare "the reconciled imported position" would leave the sum ambiguous — merchant-net alone, or gross, or merchant-net + meed — and two conforming builders could hash different BALANCE bytes) — consistent with the cumulative-import model (F6.6): a stillborn accepts no slices, so its cumulative CUM_TOTAL/ACCRUALS (metering) equal its predecessor's, and a further successor imports that same metered cumulative. **A stillborn can nonetheless be funded** — a FUNDING_PROOF needs no checkpoint (§5.4/§6.4) — so its cumulative **funding is its predecessor's opening_funding plus the stillborn's own accepted funding**, and a further successor imports that (not the predecessor's unchanged); opening_settled/opening_net_legs do pass through unchanged (a stillborn signs no settlement round, which needs a CKPT_REF). So no metered value, settled round, or deposit is double-counted or forgotten as the chain passes through a stillborn — including one that was funded before its connection dropped; LAST_SEQ = 0; RANGES empty; TRANSCRIPT = the stillborn channel's head_0 (F5-g); EVENTS = the single import event naming the imported checkpoint, or empty; TIMESTAMP = the CHANNEL_AUTH's; PREV_REF = the imported checkpoint's reference, or all-zero. Its reference is SHA-256 over these canonical bytes with no authenticator TLVs present — never colliding with a real checkpoint reference, whose hashed bytes always contain both signature TLVs (F5-f). A party validating a chain reference against a stillborn predecessor checks the CHANNEL_AUTH/CHANNEL_ACK pair and recomputes this construction. Consumed references are keyed by (channel identifier, checkpoint), so nothing strands and nothing double-consumes (§5.4). **v0.1 deferral — onward-chaining through a nonzero stillborn:** the unchained stillborn (CUM_TOTAL/ACCRUALS = 0) is implemented; a chained stillborn that imported a nonzero cumulative position and must present it onward — the CUM_TOTAL/ACCRUALS = predecessor's-final-values case above — is defined here but is a v0.1-deferred completeness case (the nonzero-import onward-chain of F6.6, defined but outside the v0.1 profile). A v0.1 implementation MAY reject an onward chain from a nonzero-imported stillborn — not wiring a nonzero PREV_REF through a stillborn; the deferral is safe, foreclosing only a rare multi-hop-through-a-stillborn liveness path, never a value case (the parties settle the stillborn's imported obligation and open fresh).

F6.7 Failure and uncooperative close (formalizes §6.4)#

Past TIMEOUT_close (F8), or against a peer that refuses to checkpoint or settle: service already stopped at the window edge or evidence bound, whichever came first; the survivor holds the bilateral checkpoints and CHANNEL_AUTH — evidence of what was authorized and acknowledged — as the basis for recovery through contract, guarantor, or legal process. No settlement rail enforces PayTP receipts on-chain, and this specification claims none does (§6.4, verbatim).

F6.8 Error mapping (formalizes §5.7)#

PAYTP_VERSION_UNSUPPORTED — negotiation, before any state. PAYTP_SEQ_INVALID — F6.2 guard (4). PAYTP_WINDOW_EXCEEDED / PAYTP_EVIDENCE_REQUIRED — F6.2 guard (5), entering the pauses. PAYTP_DENOMINATION_MISMATCH — F6.2. PAYTP_CHECKPOINT_TIMEOUT / PAYTP_STATE_MISMATCH — F6.3. PAYTP_CHAIN_REJECTED — F6.6. PAYTP_SETTLE_TIMEOUT — F6.5's all-or-close. The Tier 0 codes are F3.6's/F4's. The registry is §5.7's, closed for v0.1.

F6.9 Open items handed forward#


F7 — Fee Arithmetic#

The meed numbers: accrual, conversion, division, rounding, extinguishment, and the canonical remainder attribution §10.2 defers to this specification. F7 formalizes Chapter 10 §10.2 (with Chapter 6 §6.4's settlement shapes); it does not change them. All arithmetic below is exact integer or exact rational arithmetic — no floating point anywhere, so every implementation computes bit-identical results (F10 vectors enforce it).

F7.1 Accrual (formalizes §10.2)#

Slice amounts (AMT_µ) and Tier 0 amounts are gross. Per accepted value, each vector role r accrues the exact integer numerator accrued_r += amount_µ × bp_r — µ-units × basis points, no division, no rounding, ever, during accrual (§10.2). Meed accrues outside the channel balance B, so the checkpoint carries the cumulative accrued per-role numerators, ACCRUALS (F5.5), monotone. The outstanding numerator a round converts is the accrued minus what the completed rounds have already settled, N_r = accrued_r(operative checkpoint) − Σ E_r(completed rounds) — the settled side is read from each completed round's countersigned/deterministic proposal (F6-f), a round counting as completed only once the advance fact shows the channel's watermark reached funded_p ≥ target_P on the rail (F6-f/F6-o); this is the "unpaid remainders stay in the accumulators and carry" of §10.2, with the carry recovered as accrued-minus-settled without any checkpoint field a crossing could desync and without inverting an ephemeral rate. A recipient's outstanding total is the sum of its roles' N_r. Within one channel every slice accrues under the same vector, so accrued proportions are exactly bp_r : bp_total at all times.

Bounds (F7-a): numerators are arbitrary-precision by encoding (F1.1 minimal integers); implementations MUST compute exactly for values up to 2^128 − 1, and a checkpoint naming any numerator beyond that is rejected — a channel MUST close and chain long before (the bound exceeds any plausible channel by many orders of magnitude; it exists so two implementations never differ by overflow behavior). **The meed vector's length is bounded too — MAX_ROLES = 64: a vector or checkpoint naming more than 64 priced roles is rejected**. This is not a "short vector" expectation (schema 0x01 prices 4 roles, F9-e; any real schema far fewer) but a hard arithmetic-domain boundary, so that the round total N = Σ_r N_r (F7.2) — a sum of at most 64 per-role numerators each < 2¹²⁸ — is itself bounded N < 64 · 2¹²⁸ = 2¹³⁴, and no fixed-width implementation can be pushed to overflow by a maliciously long vector (F3.2's "one entry per priced role" already bounds a conformant vector; this is the defense against a malformed one). The reference implementation enforces it (MAX_ROLES = 64); pinning the exact value is what keeps two implementations agreeing on the reject boundary (a 65-role vector is rejected by both).

F7.2 Division at settlement (formalizes §10.2)#

Division happens only at settlement, in one of two shapes:

The Tier 0 baseline split (§5.6, not a channel round): the full payment arrives at the split address and its code pays each recipient floor(unpaid_numerator_recipient / 10 000) µ-units — the recipient's numerator being the sum of its roles' — rounded down to the rail's minimum unit (§10.2). What each output extinguishes is paid_amount × 10 000 from that recipient's numerators, drawn from its roles in ascending role-id order; the remainder stays and carries.

The aggregate leg (every channel settlement round that makes extinguishment progress, i.e. whose E ≥ 1 (F7.3), on any rail including the baseline — §6.4/§10.2, no direct-output channel shape; an E = 0 round — nothing accrued, P = 0, or the P ≥ 1/E = 0 sub-extinguishment trap — carries no aggregate leg, F7.3): the debtor divides nothing. It sums the round's outstanding numerators N = Σ N_r (the checkpoint's cumulative accrued minus what completed rounds settled, both whole-chain cumulative for a chained channel, F7.1/F6.6), converts once at the round's rate (unity when DENOM = BASELINE_ASSET), rounds down to the baseline rail's minimum unit, and pays that one amount P, advancing the channel's per-channel meed watermark toward its own-cumulative target (§10.2, F6-o). **Do not equate the round's P with the watermark's cumulative position: the on-chain meed leg commits the own-cumulative target target_P as its INSTANCE_LEG.AMOUNT** (F5.6), a cumulative figure, while the P computed here is the round's payable and the leg's on-chain move is ΔP = target_P − funded_p; P (extinguished-based, on N = accrued − Σ E) and ΔP (accrued-based) can differ by the ≤1µ aggregate reconciliation_dust at a chain boundary (F6.6), so the three are not interchangeable. **P is computed once, at the round's first proposal** (countersigned for a both-signed round, single-signed for a deterministic DENOM = BASELINE_ASSET round, F5-h), on that checkpoint's outstanding N at the rate observed then; a retry of the same round reuses the identical P (F6.5) — the terms are singular per round, so P is a property of the round, not re-derived against a moved rate:

P = floor( N × p / (q × 10 000) )

Domain (closing an overflow divergence): the round total N = Σ_r N_r is a sum of at most MAX_ROLES = 64 per-role numerators each < 2¹²⁸ (F7-a), so N < 2¹³⁴not 2¹²⁸, which is the per-role cap; the round total is wider by the vector-length factor. The product N × p can therefore reach ≈ 2¹⁹⁸ (p near 2⁶⁴, F3-g), and the per-role attribution E × N_r (F7.3) reaches ≈ 2²⁶² — both exceeding a 256-bit register. Implementations MUST compute these in exact arithmetic wide enough for this MAX_ROLES-bounded domain — exact arbitrary-precision, or a fixed width sized for it (the reference implementation uses 256-bit values with a 512-bit intermediate for the attribution product) — never a fixed 128-bit register, nor one sized only for a single 2¹²⁸ numerator — and the result **P MUST satisfy P < 2¹²⁸** to fit the 16-byte AMT domain (F4.2) — the domain the round's committed INSTANCE_LEG.AMOUNT = target_P and the surviving claim_record_id(…, target_P) notice identifier (F5-o) each occupy, and the u128 watermark funded_p/target_P fill (F6-o); a round whose P ≥ 2¹²⁸ is invalid and rejected, a magnitude a channel settles and closes long before (F7-a). This is why the input bounds alone (F3-g) do not suffice — the reject on the output domain is what keeps a 128-bit and a bignum implementation from computing different P (one wrapping, one not) and thereby a different INSTANCE_LEG.AMOUNT and claim_record_id (the notice identifier over target_P, F5-o).

F7-b (rate and unit semantics): the rate is the exact rational p/q its F3-c decimal grammar denotes, in baseline minimum units per one unit of the context's accounting grain — and the grain differs by tier, deliberately: Tier 0 amounts are the offer asset's minimum units (x402's own amount vocabulary), so a quote's rate is per minimum unit of the offer's asset (F3-c); a channel meters in µ-units (10⁻⁶) of DENOM (§5.3), so a CONVERSION.RATE is per µ-unit of the channel denomination (F5.6 states this beside the field). The rate applies **whenever DENOM ≠ BASELINE_ASSET (a conversion is genuinely needed), and is unity (p/q = 1) only when DENOM = BASELINE_ASSET** — not merely when the round settles on the baseline rail (a cross-currency channel settling net-on-baseline still converts its meed; F5.6's CONVERSION presence keys on the denomination, not the rail). The two grains never meet in one computation, so no scale factor is needed: the formula is exactly P = floor(N × p / (q × 10 000)), with N in the context's own grain × basis points and no additional unit divisor. Tier 0's per-payment leg uses the same formula with the quote's rate and the purchase's numerators; its sub-unit dust is extinguished in the payer's favor for that payment — no carry, no ledger, nothing owed later. This is the Tier 0 case of §10.2's "rounding never mints or owes" invariant — §10.2 spells out the channel disposition (dust out of the merchant's net) and defers the Tier 0 disposition here as a HOW-detail (favor the payer; channels carry instead, F7.3); both sit under the one whitepaper invariant.

F7.3 Extinguishment and the canonical attribution (the §10.2 deferral, F7-c)#

An aggregate leg extinguishes the numerators it converts, less the total's sub-unit remainder, which stays in the accumulators (§10.2). Canonically:

  1. The extinguished total is E = floor( P × q × 10 000 / p ) — exactly the numerator quantity the payment P covers, never more: §10.2's channel rule is that the sub-unit remainder stays and carries, so extinguishment rounds down (a ceil here would silently strip the recipients' carried fractions round after round — the payer-favor rule is Tier 0's, not the channel's). E ≤ N holds by construction (P was floored from N); a proposal whose numbers do not satisfy it is inconsistent and MUST be rejected, never repaired. The remainder R = N − E stays. **The aggregate leg is carried iff it makes extinguishment progress, E ≥ 1 — not merely P ≥ 1** (closing an infinite-loop trap). A round with E = 0 carries no aggregate leg (INSTANCE_LEG absent, F5.6), executes no payment, and its whole numerator carries to the next round (F7.1). E = 0 arises three ways: N = 0; P = 0 (N × p < q × 10 000); **and, critically, the sub-extinguishment case where P ≥ 1 but E = floor(P × q × 10 000 / p) = 0** — reachable when p > q × 10 000 (the baseline unit is worth far less than a DENOM µ-unit), e.g. N = 1, p = 15 000, q = 1 gives P = floor(1.5) = 1 yet E = floor(10 000/15 000) = 0. Were the leg keyed on P ≥ 1, that round would pay 1 baseline unit, extinguish 0, leave N = 1 unchanged, and be compelled again forever — an infinite payment loop bleeding the debtor. Keying on E ≥ 1 makes such a round carry no leg: the un-extinguishable sub-unit meed carries until enough accrues that a round reaches E ≥ 1, or is forgiven as dust at close (F7.3/§10.2). A proposal carrying an INSTANCE_LEG with AMOUNT = 0, or one whose E = 0, is invalid. So a settlement round is compelled only by settleable value — a net leg due, or meed that extinguishes E ≥ 1 (F6.5's trigger); dust below that carries and never forces a zero-progress or zero-value on-chain post.
  2. Per role (evaluated only when N > 0): E_r = floor( E × N_r / N ), then the shortfall E − Σ E_r is assigned one numerator unit at a time to roles in **ascending role-id order, skipping any role already at its cap E_r = N_r** — a unit never pushes an E_r above its own N_r (so a role with N_r = 0 receives none, and no role is ever over-extinguished). This keeps E_r ≤ N_r for every role, so the next round's outstanding N_r = accrued_r − Σ E_r(completed rounds) can never go negative. The assignment always terminates with the full shortfall placed: aggregate spare capacity is Σ (N_r − E_r) = N − Σ E_r ≥ E − Σ E_r = the shortfall (because N ≥ E), so the positive-N_r roles can always absorb it. These E_r are recorded in the round's countersigned/deterministic proposal (F5.6's EXTINGUISHED), which is the authoritative settled record (F6-f/F4.2); the next round's N_r drops accordingly, so the residues remain and carry (§10.2) without any checkpoint counter that a crossing could desync and without any unverifiable on-chain number.
  3. A finalized aggregate leg is credited against exactly the obligations its named checkpoint carries and is never paid twice across re-proposals or close (§6.4, F5-h/F5.6); crediting re-runs no arithmetic — the countersigned proposal's numbers are the numbers.

Instance-side division (formalizes §10.2/§5.6): the instance divides among the establishment-bound meed destinations alone, pro-rata by their shares — destination d's share is bp_d = Σ bp_r over the roles naming d. F7-d (the exact update rule): the instance tracks, per division configuration, the running received total V (every amount arrived for these destinations) and per-destination paid totals paid_d; destination d may withdraw claimable_d = floor( V × bp_d / bp_total ) − paid_d at any time. This makes the §10.2 residue behavior a theorem rather than bookkeeping: per-recipient sub-unit residue sits in V's undistributed remainder until later legs top it up, monotone and exact, and it is never a debt on the channel's books (§10.2). Sub-unit dust always stays where §10.2 assigns it: a **channel's sub-P conversion residue** (accrued meed numerator that never floored up to a payable P = 1) reverts to the merchant at close — realized as the F6-f close-reconciliation credit floor(Σ ACCRUALS/10 000) − floor(Σ E/10 000), an exact DENOM integer, not an instance payout (the channel meed instance has no merchant share, F4.3, so the reversion is on the settlement books); an instance's per-division residue stays in the split/meed instance until a later leg tops it up, or permanently where nothing follows (F7-d's running V); and Tier 0 per-payment sub-unit dust stays with the payer (§10.2).

F7.4 Completeness rules (formalizes §10.2)#

A payment is complete only when its meed execution is: Tier 0 delivery gates on the quoted finality of every required leg (F4.4), and a conforming channel settlement is never acknowledged complete without its meed outputs (§10.2, §7.6 — the conformance-scoped claim, not a cryptographic one). Settlement pays meed outputs only to the destinations fixed at establishment (§10.2); the split's merchant share is simply another configured share, and the merchant never holds meed money on a baseline purchase (§10.2).

F7.5 Open items handed forward#


F8 — Timeouts and Clocks#

Every timeout constant, acceptance window, skew allowance, clock authority, and finality-time rule the earlier sections name. F8 formalizes the constants Chapter 5/6 name and the clock rules §5.6/§6.4 state; it does not change them. The whitepaper names CKPT_TIMEOUT, SETTLE_TIMEOUT, and TIMEOUT_close without fixing values, and CHANNEL_AUTH (§5.4) deliberately carries no field for them — so they are protocol constants a builder cannot pick alone; the values below fix them.

F8.1 Clock authority (formalizes §5.6/§6.4)#

Three clocks, each authoritative for what it alone can see:

  1. Endpoint clocks. Each deadline binds the party that acts on it, on its own clock, within the skew allowance (§6.4). Endpoints SHOULD keep wall clocks within ordinary NTP discipline; the protocol never requires better than SKEW (F8.2).
  2. The rail clock. Where a deadline is rail-enforced, the rail's clock governs (§6.4): the entry machine's T_open/T_lapse/T_exec (F4.3) live entirely on the rail's clock, and the contest-delay margin before delivering against an entry under reclaim is measured there (§5.6). F8-a (no conversion, one time base): recorded deadlines are Unix-second values, computed by pure arithmetic from the quote (T_open = exp + grace, T_lapse = T_open + reclaim) with no chain-state input, and the instance compares them against the rail's declared on-chain time source — the adapter names it (a block timestamp, a cluster clock: every §11.2-qualifying rail exposes Unix-denominated time on-chain) together with its documented drift bound. Nothing depends on observed chain state, so the funding wallet and the merchant computing from the same quote land on identical deadlines by arithmetic alone (F4.3), or the entry is rejected.
  3. Adapter-declared finality time. A rail does not reliably show when a transfer was started, so the adapter's stated timestamp semantics decide when a leg "reached the quoted finality" (§5.6): the adapter declares, per finality level, which rail timestamp constitutes reaching it. The honor rule then reads: a leg is honored iff its declared finality time t_fin ≤ exp + grace (§5.6), whichever leg it is.

Finality levels are adapter-declared identifiers with declared meanings including any residual reversal risk (§11.1); each adapter MUST declare a total order over its own levels, giving "finality at least as strong as" (§6.4) an objective test. Levels never compare across adapters — a quote or proposal names each rail's level in that rail's own vocabulary (F3.2, F5.6).

F8.2 The skew allowance (F8-b)#

One constant everywhere a wall-clock comparison crosses parties: **SKEW = 300 seconds.** Uses: the merchant's CHANNEL_AUTH timestamp acceptance (§5.4 — accept iff |now − TIMESTAMP| ≤ SKEW + LATENCY, with **LATENCY = 300 seconds** of delivery allowance, so the window is ±600 s total); the ACK_REQUEST timestamp (F5.3, same window); artifact validity (F2.2 — current iff NOT_BEFORE − SKEW ≤ now ≤ NOT_AFTER + SKEW); Tier 0 expiry checks at the merchant (§5.6's "clock-skew allowance" — a quote is expired only when now > exp + SKEW, before the separate grace/honor arithmetic). Rationale: 300 s tolerates the worst honest clocks in the wild (unsynced consumer machines drift minutes, not hours) while keeping every replay window narrow; a single constant kills a family of subtle cross-implementation disagreements.

F8.3 Protocol timeout constants (F8-c/d/e)#

ConstantProposed v0.1 valueNamed byStartsRationale
CKPT_TIMEOUT30 seconds§6.3When a CHECKPOINT_REQUEST is deliveredA countersignature is one verify-and-sign over state the responder already holds; 30 s absorbs GC pauses and mobile radio wake-ups without letting E sit exposed. The initiator MAY retry within it; expiry is PAYTP_CHECKPOINT_TIMEOUT (F6.3).
SETTLE_TIMEOUT24 hours§6.4At the round's PROPOSAL_HASH object (F5-h): the both-signed proposal for a round that needs agreement (DENOM ≠ BASELINE_ASSET or net-off-baseline), or the debtor's single-signed proposal for a deterministic DENOM = BASELINE_ASSET net-on-baseline round (F5-h defines the hash for each; the whitepaper's three- vs four-message distinction, §6.4)The round must fit rail congestion, finality, and retries on whichever baseline the open selection lands on (§11.2) — a universal constant must cover the worst candidate, and the cost of generosity is small: an incomplete round's obligations already stand in signed checkpoints, and all-or-close still resolves within a day. Re-proposal is allowed within it (§6.4).
TIMEOUT_close72 hours§6.4From the last completed protocol exchange with the peerUnreachability past three days is abandonment, not weather; the survivor's remedies (§6.4) need a definite boundary, and nothing in the design rewards waiting longer — service already stopped at the window or evidence bound.

These are constants, not negotiable terms: §5.4's CHANNEL_AUTH carries no field for them, and the whitepaper defines no negotiability for them. TH_value/TH_time are per-channel negotiated terms (§5.4) and both SHOULD be sized above one settlement round-trip (§6.4); E likewise, above one checkpoint round-trip against the stream's rate (§6.3) — sizing guidance the whitepaper already states, restated here once.

F8.4 Tier 0 window arithmetic (formalizes §5.6; the entry machine's inputs)#

All quote durations are seconds (F3.2); the quote's exp is absolute. The derived boundaries, in order: expiry exp (merchant clock, SKEW-tolerant) → honor boundary exp + grace (a leg whose declared finality time is inside it MUST be honored; the pinned conversion rate lives and dies with the quote, §5.6) → reclaim opens at T_open = exp + grace (Unix seconds, evaluated on the rail's declared time source, F8-a) → reclaim closes at T_lapse = T_open + reclaim → an opened reclaim executes strictly after T_exec = opening + contest (F4.3). The retry window (retry) bounds the consumed-nonce record's retention beside the entry windows (§5.6): retention ends at max(exp + retry, T_lapse + contest), all in one time base. F8-f (margin): before delivering against an entry under reclaim, the merchant confirms remaining contest delay of at least twice the adapter's declared inclusion latency — a documented per-adapter constant: the adapter's stated p99 submission-to-acceptance time under its declared congestion assumptions (§5.6's "margin for the posting to land", made testable).

F8.4b Channel-round windows (formalizes §6.4)#

A channel round's CONVERSION terms (F5.6) get the same treatment: a leg whose declared finality time is within RATE_EXP + RATE_GRACE is honored under the same rule Tier 0 applies (§6.4, verbatim). **The honor-window forfeiture of a late off-baseline round — the retired "forfeited-late-P, recovered on a fresh CKPT_REF" path — is retracted under the per-channel watermark** (F6-f): a late meed advance simply raises the absolute funded_p, so the design cannot keep an unqualified monotone watermark, no un-fold path, and a late-rate forfeiture all at once; the off-baseline late-rate penalty is a deferred redesign, not a v0.1 rule, and is vacuous today — off-baseline rounds are not built in v0.1, and a deterministic baseline round (DENOM = BASELINE_ASSET, F5-h) carries no rate and no honor window at all. The rate-freshness and required-finality-level tests below stand; only the late-round forfeiture is retracted. The counterparty runs the rate-freshness check only at the round's first countersignature: the proposal's RATE sits within the establishment-named RATE_SOURCE/RATE_DEV at the named RATE_TIME, and RATE_TIME is within SKEW + LATENCY of the countersigning party's clock at that moment — no debtor proposes yesterday's rate (§6.4's establishment-pinned source and deviation; the observation-time rule). A retry is still countersigned afresh (its CREDITED grew, so the bytes changed — F6.5), but the creditor verifies only that the retry's terms match the round's one-decision record and skips the freshness check — the freshness gate is on agreeing a rate, not on re-signing an already-agreed one, so a retry hours later inside SETTLE_TIMEOUT is never rejected as stale. Which finality level each leg must reach is the channel-established FIN_MEED/FIN_DENOM (F5.2), never a per-round field — so a deterministic baseline round, which carries no CONVERSION (F5.6), still has a defined required finality, and neither a debtor's proposal nor a retry can weaken it; the honor rule of F8.1 (finality time within the window) and this required-level test are the two independent finality gates a settled leg must pass. The per-channel meed watermark carries no windows at all (F4.2/F6-o): a channel leg advances its per-channel instance record (seed_instance, CHANNEL_ID) at once and has no reclaim to gate, so none of T_open/T_lapse/T_exec exist for it — the advance call's shape selects the kind, and window arithmetic here applies only to Tier 0 purchase entries. last_settle, for the TH_time trigger (§6.4), advances on the acting party's **own clock and its own finality observation — never on a counterparty-proposed re-anchor checkpoint TIMESTAMP. Before any settlement round exists it initializes from CHANNEL_AUTH.TIMESTAMP** (channel open), so TH_time is well-defined and identical for both parties from birth, rather than left "unset and never time-triggering" on a low-volume channel that never reaches TH_value. That open timestamp is bounded — the merchant accepts CHANNEL_AUTH only within the F8.2 acceptance window, so a payer cannot push it beyond SKEW + LATENCY — so it is safe to init from (a bounded, SKEW-limited influence, not the unbounded hazard below), it is the same value both parties hold, and either can re-derive it after a restart from the signed CHANNEL_AUTH it retains. last_settle then **advances on the party's own observation that a settlement round completed** — SETTLEMENT_CONFIRMED for a postpay round (which the creditor issues only after its net output arrived and the required meed proof verified, F6.5), or the PREPAY_DRAW_COMPLETED the wallet credits only on the rail's advanced_channel_meed fact at the full own-cumulative target_P (F5-o) for the prepay halt — **stamped with the party's own clock at that observation, never the checkpoint's TIMESTAMP field.** Because completion already requires the round's meed leg wherever meed is due (F6.5/F5-o rejects an under-draw or a net-only settlement of a position with payable meed), a party cannot advance its own clock by settling net alone while payable meed stands, and an E = 0 round (no meed leg due, F7.3) completes on its net leg and advances the clock without stalling — the existing completion semantics carry both, needing no separate clock rule. This is the fix. F6-c's countersigning conditions never validate a checkpoint's TIMESTAMP (the responder recomputes balance, cumulative total, accrual numerators, sequence, transcript head, and references — never the clock), so a hostile counterparty could propose a re-anchor checkpoint carrying a far-future TIMESTAMP, the acting party would still countersign it, and a party that anchored TH_time on that value would have its halt deferred without bound — defeating §6.4's prepay meed halt, whose whole purpose is to bound what a withholding merchant can strip to a single round (F5-o enforces that bound). Anchoring on the party's own clock and its own finality observation closes that; the bounded open-init timestamp is the only counterparty-touched value and is SKEW-limited, never the unbounded hazard. On recovery a party reads its durable last_settle (it is durable channel state); if that is lost it re-derives only a value it can **prove is not later than its true last_settle — the rail finality of its last completed meed advance (of this channel or its chained predecessors), reduced by any positive adapter drift and** the SKEW allowance (F8.1/F8.2) so it cannot exceed even a conformantly-slow party's own-clock stamp, or, for a channel with no meed settlement yet, the bounded first-generation CHANNEL_AUTH.TIMESTAMP (the chain origin's, never a later successor's — so a chained channel preserves the clock across hops, F6-j) — never the counterparty checkpoint field, and never funding finality (which can post-date open). So recovery only ever makes TH_time fire sooner, never defers it, and a first-generation channel always has its bounded open timestamp to fall back on (no recovery deadlock). A chained successor inherits the settlement clock — it never restarts at birth (F6-j; §6.4 "chaining never resets its clock"), the same party carrying its value forward because the successor imports the predecessor's still-unsettled meed obligation (§6.2/F6.6); resetting at each hop would let a withholding merchant force a reconnect just before every TH_time and defer without bound. The TH_time trigger is evaluated against the acting party's own wall clock within SKEW, and fires only with settleable value present (F6.5 Triggers). The prepay deposit's advertised holding period (§6.4) is deliberately not a protocol constant: it is the merchant's published commercial term, off-wire, and the payer's any-time demand right is what the protocol enforces.

F8.5 Quote and window consistency (formalizes §5.4/§5.6)#

Validated with the vector before paying (§5.4): grace, retry, reclaim, contest are each ≥ 0; a two-leg quote MUST leave both legs' declared finality achievable inside exp + grace at quote time (the wallet's pre-flight, §5.6); and a quote whose reclaim window would close before the instance's execution gate opens is invalid (§5.4) — in F8 terms this reduces to reclaim > 0 and contest > 0, and here is why that suffices: opening is allowed anywhere in [T_open, T_lapse], and execution — strictly after opening + contest — has no upper deadline, so with both durations positive the gate is always reachable from any valid opening; the §5.4 failure mode (a window closing before the gate opens) cannot be constructed under F4.3's machine. Merchants MAY lengthen exp while the baseline is degraded, weighing the pinned rate's longer exposure (§11.2).

F8.6 Open items handed forward#


F9 — Registry Snapshot, Pointers, and Identifiers#

The role-registry snapshot's format and lifecycle, the destination-pointer grammar every vector and settlement pointer uses, and the identifier grammars (registry recipients, rate sources). F9 formalizes what Chapter 10 §10.1/§10.5, Chapter 5 §5.4, and Chapter 11 §11.5 already fix; it does not change them.

F9.1 Destination pointers (F9-a)#

A destination pointer names where money lands: MEED_VECTOR destinations, the refund pointer, the settlement pointer. It is exactly one of two disjoint forms, distinguished by its first colon-delimited token:

Constraints on both: UTF-8 per F1-g (no controls, no NUL), no whitespace, total length ≤ 512 bytes. A pointer matching neither form is rejected. Pointer equality is byte equality after F1-g validation — nothing is case-folded or normalized (F1's validation-never-transformation rule) — which is what "the registry version may advance where the destinations are unchanged" compares (§5.4, F6.6). Operational hazard: some rails carry semantic-free casing (an EIP-55 mixed-case checksum address), so a registry and a wallet that render the same account in different valid casings will byte-mismatch — forcing a settle-first on chaining, or a quote rejection. Refusing normalization is nonetheless correct (normalizing signed bytes is exactly the malleability F1-g forbids); the discipline is that a registry, a merchant's quote, and a wallet MUST render each destination in one agreed canonical casing, and the reference implementation pins that casing per rail adapter. A pointer's rail MUST be one the naming context can pay: a vector destination is payable on the baseline rail; a settlement pointer, on the channel's rail. The two forms map onto PayTP's two-tier rail model: the baseline rail is always CAIP (the meed instance is an on-chain contract, F4.1/F5.2), so every meed destination — MEED_VECTOR entries, the Tier 0 split, the channel instance — uses the CAIP-10 form; the adapter form serves the channel's DENOM-rail pointers (the merchant's settlement pointer, the payer's refund pointer) when that metering/net/funding rail is a custodial, instant-bank, or Lightning adapter (§6.2/§11.1). So the adapter form is not dead scaffolding — it is exactly the wire vocabulary a non-CAIP channel rail needs, and the rail-identifier fields that name such a rail (DENOM, RAIL, CREDITED's net-leg rail) admit the same two forms (F5.2/F5.4/F5.6).

F9.2 Registry and rate-source identifiers (F9-b)#

Registry recipient identifiers (the OS assertion, F3.3) and rate-source identifiers (RATE_SOURCE, F5.2; rateSource, F3.2) share one grammar: lowercase ASCII, ^[a-z0-9]([a-z0-9\-\.]{0,62}[a-z0-9])?$ (1–64 bytes, no leading/trailing separator). Identifier equality is byte equality. Rate-source identifiers name a publicly retrievable price series — a Foundation-published source list accompanies the registry distribution so both parties resolve an identifier to the same series (a snapshot-carried list, F9.3, keeping "named public source" [§5.6/§6.4] checkable rather than aspirational).

F9.3 The snapshot object (formalizes §10.1/§10.5)#

The Foundation publishes the role registry as a signed TLV snapshot (F1.1). Registry (all REQUIRED unless marked):

TypeFieldValue
0x00VERSIONUnsigned minimal, strictly increasing across publications; the number signed vectors name (§10.5).
0x01KIND1 byte: 0x00 rotation, 0x01 revocation — updates state which kind they are (§10.5).
0x02ISSUEDUnix seconds, unsigned minimal.
0x03WINDOW_FLOORThe oldest version validators still accept — the governance-defined acceptance window travels in the snapshot (§10.5), so no out-of-band rule exists to disagree about.
0x04OS_RECIPIENTSCount-prefixed list, ascending by identifier bytes: id_len (LEB128) ‖ id (F9-b) ‖ dest_len (LEB128) ‖ dest (F9-a, baseline-payable) — the approved OS recipients with canonical destinations (§10.1).
0x05REVOKEDCount-prefixed ascending list of version numbers (each a LEB128 integer, as OS_RECIPIENTS/RATE_SOURCES lengths are) withdrawn for compromise (present when KIND = 0x01, else absent): a revoked version leaves the window the moment a validator learns of it (§10.5).
0x06RATE_SOURCESCount-prefixed list, ascending by identifier: id_len (LEB128) ‖ id (F9-b) ‖ uri_len (LEB128) ‖ uri (UTF-8, F1-g) — the published source list of F9.2.
0x70SIGEd25519 by the Foundation registry key under the domain label PayTPv1-registry.

F9-c (the label and the trust anchor): PayTPv1-registry is part of the §5.2 label registry (mirrored in F1.3) — the snapshot is a governance document distributed out of band rather than an endpoint message, but it is a PayTP-defined signed object, so it belongs under the one label discipline that keeps no two object types sharing a domain label. The Foundation registry key is pinned in implementation releases (exactly as the PSL snapshot, F2-c, and the meed schema's release-bound destination addresses — the Development Fund and the independent open-source fund, F9-e/§10.1/§10.5; the schema's role ids and basis points are pinned in F9-e itself, not release-bound); rotating it is a software release; compromising it is the emergency-release case, mirroring §10.5's charter-level custody posture for the fund key. Distribution endpoints are implementation configuration, not wire protocol; a snapshot verifies the same wherever it came from.

F9.4 Validation and the fallback algorithm (formalizes §5.4/§5.6/§10.1)#

Given a schema, the payer's asserted roles (F3.3), and a snapshot at the vector's named version:

  1. Version acceptance: the named version is accepted iff WINDOW_FLOOR ≤ version ≤ VERSION under the newest snapshot the validator holds, and the version is not in any known REVOKED list (§10.5, §11.5 — a validator rejects a version it knows revoked; staleness is a conformance failure, not a protocol ambiguity). Implementations SHOULD refresh on revocation notices (§10.5).
  2. OS resolution: an asserted recipient identifier that is registry-listed at that version resolves to its canonical destination; an unlisted assertion, or no assertion, resolves to the independent open-source fund's schema-pinned destination (§10.1) — a destination outside the PayTP Foundation's control and distinct from the Development Fund, so that no registry decision changes the Foundation's own income (§10.5, the neutrality mechanism); the fallback keeps the 100 bp total invariant. Which case applies is the wallet's assertion, cross-checked by the interaction layer and auditable under governance; the merchant validates destination correctness only — listed-or-independent-fund (§5.4, §10.1).
  3. Unasserted payer-side roles (0x10/0x12) route their shares to the Development Fund the same way (§5.6) — distinct from the OS role's independent-fund fallback in step 2; no absence reduces the total (§10.1).
  4. Chaining: a successor validates that the predecessor vector's resolved destinations are unchanged at whatever version it now holds (byte equality, F9-a); a changed destination forces settle-first (§5.4, F6.6). Registry rotation therefore never strands a channel; revocation reaches new channels immediately and live channels at their next establishment — destinations are immutable per channel (§10.5), so shedding a revoked destination means closing and reopening, which is cheap.

F9-d (historical retention): because a signed vector may name any version within the current window (step 1), and destination resolution is as defined at that named version (step 2), a validator MUST retain every snapshot from WINDOW_FLOOR to the newest it holds — not only the tip. Resolving an in-window vector against the tip's recipient list rather than the named version's would misroute an OS share whose destination rotated inside the window. Snapshot handling — cached, versioned, validated against the acceptance window — is core-library duty (§11.1); the registry's gatekeeping character, appeals, and the charter rules around it are governance, deliberately outside this spec (§10.5).

F9.5 Open items handed forward#

`

MEED_SCHEMA_ID = 0x01

0x10 Interaction Layer 50 bp base (payer-side; unasserted → Development Fund)

0x11 Operating System 10 bp base (registry-adjudicated dest; unlisted/absent → independent OS fund, F9.4 step 2)

0x12 Wallet 30 bp base (payer-side; unasserted → Development Fund)

0x13 Development Fund 10 bp base (fixed seat → Development Fund)

`

The four base roles sum to exactly 100 bp; the protocol's hard cap is 150 bp, the range above 100 (the half-open (100, 150]) reserved exclusively for opt-in service roles (0x14 dispute resolution proposed, §10.5) — a base-only vector sums to exactly 100 and carries no service role. A conformant vector carries exactly one entry per priced role (F3.2 / F4-b), each in ascending role-id order, and its bp sum lies in [100, 150] (100 base-only, up to 150 with services).

What is not a spec value is the set of concrete destination addresses the pinned roles resolve to: the Development Fund address (the 0x13 seat, and the fallback for unasserted payer-side 0x10/0x12) and the independent open-source fund address (the fallback for an absent/unlisted 0x11, F9.4 step 2 — outside the Foundation's control, distinct from the Development Fund). These two addresses are release-pinned trust anchors — part of an enumerated ship-together constant set with the Foundation registry key (F9-c), the PSL snapshot (F2-c), and the UTS #46 / Unicode table edition (F2, governing registrable-domain computation and thus payer-key scope) — each byte-identical across every implementation, none derivable by any implementer, chosen once and agreed by all; a conformance profile names the exact edition/version of each. F1–F10 plus this constant set yields byte-identical ADDRESS_INPUTS (F4.1) and thus byte-identical split/instance addresses for the same quote; F1–F10 alone cannot, because a not-yet-deployed fund address is no more a spec value than the registry key is. F10 pins the table's canonical encoding and the derivation path (so the mapping is checkable) and pins the concrete destination bytes as a vector once the release constants exist; until then the addresses are named, their shape fixed, their value release-bound. This is an inherent trust-anchor boundary, not a closable F1–F10 gap — every protocol with a governance-distributed constant has one (a CA root certificate, a chain genesis block, a PSL edition). For the schema table the boundary is now scoped to the destinations only (the role/bp structure above is pinned here); the broader constant set closes the rest: address interop closes when the named destination set is fixed, and identity interop when the registry key (F9-c), the PSL snapshot (F2-c), and the UTS #46 / Unicode edition (F2) are — both at the reference implementation's first release, which the F10.4 freeze rule already gates (nothing freezes until the F10 corpus, carrying the then-final constants, passes end-to-end).


F10 — Conformance Vectors#

The canonical test-vector corpus: its format, the required coverage derived from F1–F9, the canonicalization discipline that makes a vector authoritative, and the hand-derivable seed set. F10 defines the corpus the reference implementation's conformance suite executes (§11.1); nothing here changes F1–F9 — a vector that disagrees with the sections is a defect in one of them, found exactly as intended.

F10.1 Corpus format (F10-a)#

One vector = one JSON object in a per-section file (f1-encoding.json, f7-arithmetic.json, …): {"id": "<section>-<class>-<nnn>", "title": …, "inputs": {…}, "expect": {…}}. All binary values are lowercase hex strings; all integers are F1-c decimal strings; expect is either {"bytes": …} / {"value": …} for constructive vectors or {"verdict": "accept" | "reject"} for decision vectors (rejects name no error code unless the section pins one — error-code assertions exist only where F3.6/F6.8 fixed the code). Vector files are data for every implementation's test harness, never code.

F10.2 The canonicalization discipline (F10-b)#

A vector is canonical only when two independently written implementations produce byte-identical results for it. The seed set below is canonical by hand derivation (pure arithmetic and SHA-256, reproducible from the sections' text alone); every vector class involving Ed25519, Poly1305, or HPKE is generation-required: the reference implementation generates candidates from pinned inputs (deterministic signing, fixed test keys published with the corpus), a second implementation confirms, and only then does the corpus admit them. A generation-required class is listed here as an obligation with its pinned inputs, so the corpus's shape is fixed now even where its bytes wait for code.

F10.3 Required coverage, per section#

Profile scope (F5-p). The vectors below that exercise off-baseline conversion — a DENOM ≠ BASELINE_ASSET round, its CONVERSION/RATE/RATE_TIME handling, the both-signed off-baseline PROPOSAL_HASH, an off-baseline creditor one-decision reject, and the fractional-off-baseline chain-hop conservation case — belong to the off-baseline capability profile, defined but v0.1-deferred (F5-p). A v0.1 baseline-only conformance run (the reference implementation's, which rejects DENOM ≠ BASELINE_ASSET at establishment) executes the baseline subset (DENOM = BASELINE_ASSET, unity rate, single-signed rounds) and is not required to pass the off-baseline vectors; a profile that enables off-baseline MUST pass them. Every other class below — baseline value-conservation, chaining, the per-channel watermark, arithmetic, encoding, entry machine, timeouts, registry — is required of every profile.

F10.4 Freeze rule#

Nothing in F1–F9 freezes until this corpus passes end-to-end against the reference implementation and a second independent decoder (§11.1): the vectors and running code are the test. A vector failure reopens its section for correction.

F10.5 Conformance obligations beyond the vectors (certification-level)#

The F10.3 vectors are PayTP's machine-checkable, wire-level conformance — every byte and arithmetic rule of F1–F9, decided by two independent implementations producing identical results (F10.2). The whitepaper additionally imposes a small set of conformance MUSTs that have no wire form, named here so they are neither silently dropped nor mistaken for wire rules:

These are masterless (§10.5): no wire rule, settlement rule, or protocol gate enforces them — they are certification-level obligations, not protocol-enforced invariants (certification rides the Foundation charter, §10.5, which is not wire protocol and cannot become a protocol gate). This specification therefore names them but does not carry them as F1–F9 rules or F10 vectors; their testable/attestable form — which sub-rules a conformance suite can check mechanically versus which are attestation-only — is classified per obligation in F10.6 below (mostly attestation-only), with the concrete test fixtures/vectors deferred to the conformance suite (F10.4). What auditability does exist rests on the already-formalized signed MEED_VECTOR/roles — a party can prove what it accrued (§7.6/§10.3) — not on these behavioral rules.

F10.6 Testable form of the F10.5 obligations (the conformance-criteria classification)#

Each F10.5 obligation is machine-checkable (a conformance test decides it — the directional assertion is given) or attestation-only (a certifier reviews it; no test decides it). This classification is design-level and stable; the concrete test fixtures and vectors are pinned when the conformance suite is built (F10.4), and the machine-checkable behaviors additionally require the implementation's spending-policy engine (§11.1) and a path-selection surface (§10.3) — a test has nothing to run against until then. The assertions below fix what a test decides, not its byte-level inputs.

So exactly one obligation (spending-policy) is cleanly testable, two are testable under an explicit policy/cost fixture, three reduce to an interface-presence check plus attestation, and one is pure attestation. Only the concrete vectors — and the implementation engine they run against — remain.