Sashité for Developers
  1. Sashité for Developers
  2. Nostr
  3. NIPs
  4. Rematch Offer

NIP-XX

Rematch Offer

draft optional

This NIP defines a Nostr event kind by which a player of a concluded session offers to play its opponent again — a rematch — under the same terms with the seats swapped. Two mutually addressed offers let the session’s arbiter found the rematch, so there is no directed challenger / acceptor asymmetry and no possibility of a crossed-challenge dead-end.

Abstract

Defines kind: 3430, a regular event by which a player of a concluded Game Session (kind 3422) offers a rematch to that session’s opponent. The offer references the concluded session and an Adjudication (kind 3425) of it, designates the same arbiter (and mirrors its timing mode), and names the opponent. That second reference is the offer’s structural proof that the session is over — a proof of conclusion, not of outcome: any conforming Adjudication of the session serves, canonical or not, and the session’s outcome remains the canonical one’s alone (§Tags; kind 3425 §Idempotence and finality). It carries no terms of its own: a rematch reuses the concluded session’s game, per-player variants, and time control, with the seats swapped. When both players of the concluded session have published mutually addressed offers, the concluded session’s arbiter founds a single new Game Session for the rematch (kind 3422 §Rematch founding). A lone offer is a standing proposal with no effect until the opponent’s matching offer joins it; an offer that is never matched lapses without effect once its accept_until passes.

Motivation

The directed founding path (kinds 3420/3421) is asymmetric — one challenger, one acceptor. If both players of a finished game tried to re-challenge each other at once, each would sign a Direct Challenge to the other and neither would be the acceptor: the crossed challenges would found two sessions, or none — a race the directed path does not resolve. A rematch, however, is naturally symmetric: two known players, already paired by the session that just ended, each simply expressing “again”.

This NIP models that symmetry the way the matchmaking pool does — as two independent offers bound by a single third party — with two adaptations. The binder is the concluded session’s own arbiter (which already founds the Game Session on every path) rather than the matchmaker; and the pair is fixed in advance (the concluded session’s two players) rather than drawn from a pool, so no Pairing (kind 3419) is needed to select it. The result is a single “rematch” affordance offered to both players, with the rematch beginning once both have used it, and no crossed-challenge dead-end.

This NIP carries only the structural aspects of the offer. The terms of the rematch — game, variants, time control — are inherited from the concluded session and are not restated here (§Inherited terms); the arbiter, which founded the original session, already holds them.

Specification

Event kind

kind: 3430

Rematch Offer events are regular events per NIP-01: immutable once signed and broadcast.

Like the Open Challenge (kind 3418) and the Direct Challenge (kind 3420), a Rematch Offer is a founding designation: it is referenced by event id and is neither timed nor subject to race resolution (it defines no slot in the sense of Canonical Timing §Meta-resolution). Its effect is realized only when the arbiter founds the rematch Game Session from a matched pair of offers (§Rematch founding).

Operating mode

A Rematch Offer MUST mirror the operating mode of the Game Session it rematches: the same arbiter, and the same timing designation — the same timestamper in attested mode, or the same timing_relay set in self-timed mode (kind 3420 §Operating mode; Canonical Timing §Timing modes and mode selection). The rematch session inherits this designation; an offer that designates a different arbiter, or whose timing designation differs from the concluded session’s, is non-conforming. (This mirrors the way an Accepted Challenge mirrors its Direct Challenge, kind 3421 §Operating mode.)

The Rematch Offer itself — a founding designation — is not attested and not timed, exactly as the Direct Challenge (kind 3420) is not. The timing designation it carries is the one the arbiter applies to the rematch session’s timed events (Game Session, Plies, Adjudication).

Tags

Reference tags

Tag Cardinality Value Description
e rematch_of exactly one event id, optional relay hint, marker the concluded Game Session (kind 3422) being rematched
e concluded_by exactly one event id, optional relay hint, marker an Adjudication (kind 3425) that concluded that session

The relay hint (third element) is OPTIONAL but SHOULD be present.

The two references are deliberately both required, and deliberately not interchangeable. rematch_of names the session; concluded_by proves it ended. Carrying the Adjudication makes conclusion a structural property of the offer — a verifier checks it rather than trusting the signer to have waited — and, because the Adjudication mirrors its session’s player and seat tags and is signed by its arbiter, it gives the verifier a second, independently signed witness to the facts constraints 3–5 turn on. (The same redundant-but-constrained double reference is used by kind 3425 itself, which carries both a game_session and a triggered_by reference and requires them to agree.)

The session, not the Adjudication, remains the anchor: the matched-pair rule, the idempotence slot (rematch, G), and the rematch chain are all keyed on G (§Rematch founding). This matters because a session MAY carry several Adjudications, exactly one of them canonical (kind 3425 §Idempotence and finality). Two offers whose concluded_by tags name different Adjudications of the same G still form a matched pair; both are proofs of the same fact. Clients SHOULD reference the canonical Adjudication, but referencing a non-canonical one — one that is signature-valid, conforming, and adjudicates G — does not make the offer non-conforming.

Player tags

Tag Cardinality Value Description
p two or three pubkey, optional relay hint, role marker exactly one opponent (the concluded session’s other player); exactly one arbiter; and, in attested mode, exactly one timestamper
timing_relay zero or more relay URL (wss://…) in self-timed mode, the designated timing relays, mirroring the concluded session’s set verbatim; absent in attested mode

The p tags MUST carry a role marker as the fourth element:

The p tags serve the usual dual purpose: semantic (identifying the participants) and structural (notification routing via #p filters). The relay hint (third element) is OPTIONAL but SHOULD be present.

Lifecycle tags

Tag Cardinality Value Description
accept_until exactly one unix timestamp (seconds) the latest moment at which a rematch Game Session founded on this offer is valid
nonce exactly one nonce + difficulty, per NIP-13 required proof of work

Inherited terms

A Rematch Offer carries no game, variant, time_control, or seat tag. The rematch reuses the concluded session’s terms:

Restating terms is deliberately excluded: it could let the two offers disagree, and the arbiter — which founded the original session — already holds them. A player who wants different terms (a new variant, a new time control) should send a fresh Direct Challenge (kind 3420) instead of a Rematch Offer.

Content

The content field MAY carry a free-form text message from the signer to the opponent (e.g., “Good game — again?”). It is OPTIONAL: an empty string is permitted. The content field is subject to the same constraints as kind 3420 §Content (0 to 255 Unicode code points, valid UTF-8, no C0/C1 control characters except tab and line feed, no bidirectional override or isolate characters) and MUST NOT alter the interpretation of the offer: the semantic meaning is fully carried by the tags. Clients displaying it MUST apply context-appropriate output escaping (§Security considerations).

Rematch founding

A rematch begins when the arbiter of the concluded session holds a matched pair of Rematch Offers and founds a single new Game Session from them. A matched pair is two Rematch Offers O₁ and O₂ such that:

  1. both reference the same concluded Game Session G (via the rematch_of e tag). Each also carries a concluded_by reference to an Adjudication of G; the two need not name the same Adjudication, since a session may have several and each is an equally valid proof that G is over (§Tags);
  2. they are mutually addressed — O₁ is signed by one player of G and names the other as its opponent, and O₂ is signed by that other player and names the first;
  3. both designate G’s arbiter and mirror G’s timing designation (§Operating mode);
  4. the arbiter can still found within both windows — a rematch Game Session whose canonical timing is not later than both offers’ accept_until, i.e. not later than the earlier of the two (kind 3422 §Rematch founding).

On observing a matched pair, the arbiter founds the rematch Game Session (kind 3422): the same game and per-player variants as G, the seats swapped relative to G, the same operating mode, and referencing the two offers via rematch_offer-marked e tags (kind 3422 §Founding reference and §Rematch founding). The rematch session’s slot is (rematch, G), so there is at most one canonical rematch Game Session per concluded session (kind 3422 §Idempotence and race resolution): duplicate offers, or re-offers after a window lapses, cannot spawn a second rematch. A chain of rematches is unbounded — each hop’s slot is keyed on its own immediate predecessor (G → G′ → G″ …).

Both offers are REQUIRED. An offer is a signed statement of consent; the arbiter founds nothing until both players have signed one, so neither player can be drawn into a rematch they did not sign. A single offer standing alone is a proposal only: the opponent’s client SHOULD surface it (“<name> offers a rematch”) and let the opponent complete the pair by publishing their own offer.

Semantic constraints

A conforming Rematch Offer event MUST satisfy all of the following:

  1. The event contains exactly one e tag marked rematch_of, referencing a retrievable, signature-valid, conforming Game Session (kind 3422).
  2. The event contains exactly one e tag marked concluded_by, referencing a retrievable, signature-valid, conforming Adjudication (kind 3425) whose own game_session-marked e tag references the same Game Session as constraint 1. (The session must be over; its outcome is immaterial — the arbiter founds the rematch whichever way the verdict went, and the Adjudication need not be the canonical one, §Tags.)
  3. The event’s pubkey (the signer) is one of the two players of the referenced Game Session.
  4. The event contains exactly one opponent-marked p tag, whose pubkey is the referenced session’s other player (distinct from the signer).
  5. The event contains exactly one arbiter-marked p tag, equal to the referenced session’s arbiter.
  6. The event’s timing designation mirrors the referenced session’s: a timestamper-marked p tag equal to that session’s timestamper (attested mode), or timing_relay tags equal to that session’s set (self-timed mode) — exactly one of the two forms, matching the session’s (§Operating mode).
  7. Exactly one accept_until tag, with a unix-seconds value strictly greater than the event’s created_at.
  8. Exactly one nonce tag is present, carries its committed difficulty as its third element, and the event id satisfies NIP-13 against that committed difficulty — never against a relay’s advertised minimum (an ingestion policy, not conformance).
  9. The event contains no game, variant, time_control, or seat tag (§Inherited terms).

Constraints 1–6 require cross-event validation against the referenced Game Session and Adjudication (and, for the timing mode of constraint 6, that session’s founding chain). Constraints 7–9 are checkable from the event alone (constraint 8 binds the event id to the nonce’s committed difficulty; the relay’s advertised minimum is an ingestion policy, not conformance).

Validation responsibility

Validation of a Rematch Offer against the structural semantic constraints (§Semantic constraints) is the responsibility of the client and the relay. A relay additionally enforces its advertised NIP-13 minimum difficulty at ingestion — a relay policy, distinct from conformance.

Constraints 1–2 require retrieving two events — the concluded Game Session and an Adjudication that concluded it. This is not a burden in practice: a client that just played or watched the game already holds both, and a client discovering an offer cold must fetch the session anyway to resolve the opponent, the arbiter, and the timing mode. The Adjudication is one further e-tag hop from the same author it already trusts to have founded the session.

The matched-pair rule (§Rematch founding) is enforced by the arbiter: it founds a rematch only from two conforming, mutually addressed offers signed by the concluded session’s two players, and only into a Game Session whose canonical timing falls within both offers’ accept_until. Downstream observers and rating verifiers validate the resulting Game Session (kind 3422) as they would any other — including that its two rematch_offer references are themselves conforming (constraints above) — so a rematch session founded from a non-conforming or unmatched pair is structurally invalid and MUST be rejected.

Race conditions

Two offers are two independent founding designations: like two Open Challenges (kind 3418), they are not competitors for a slot and are not race-resolved (Canonical Timing §Meta-resolution applies to slots, and an offer defines none). The single canonical outcome is enforced one level down, at the Game Session: the rematch session’s slot is (rematch, concluded session), so however many offers the two players publish — re-offers after an expiry, accidental duplicates — the arbiter founds at most one canonical rematch Game Session (kind 3422 §Idempotence and race resolution). If both players have published several conforming offers, the arbiter MAY bind any mutually addressed pair; every such pair founds the same slot, so the canonical rematch is unique regardless of which pair the arbiter binds.

The same holds for the concluded_by references. A session may accumulate several Adjudications while exactly one is canonical (kind 3425 §Idempotence and finality), so two players offering a rematch at slightly different moments may well cite different ones. This is not a race and needs no resolution: a concluded_by reference is a proof that G ended, not an identifier of the pair. The pair is identified by G alone, and that both offers name the same G is required by the matched-pair rule (§Rematch founding), not by the concluded_by references.

Examples

The examples below use placeholder pubkeys, relay URLs, event ids, and timestamps for illustration. They assume a concluded Game Session (kind 3422) with id <game_g_id> in which Alice held seat first (variant chess) and Bob held seat second (variant ogi), arbitrated by Carol, in self-timed mode, concluded by an Adjudication (kind 3425) with id <adjudication_g_id> signed by Carol. Each conforming Rematch Offer also carries a nonce tag (NIP-13 proof of work, §Lifecycle tags); it is shown in Example 1 with an illustrative placeholder value and omitted from the other examples for brevity.

Example 1 — A player offers a rematch (self-timed)

Alice offers Bob a rematch of the concluded session, addressed to Bob, designating the same arbiter Carol, with a ten-minute window. No timestamper is present because the concluded session is self-timed:

{
 "kind": 3430,
 "pubkey": "<alice_pubkey>",
 "created_at": 1700010000,
 "tags": [
  ["e", "<game_g_id>", "wss://relay.example.com", "rematch_of"],
  ["e", "<adjudication_g_id>", "wss://relay.example.com", "concluded_by"],
  ["p", "<bob_pubkey>", "wss://relay.example.com", "opponent"],
  ["p", "<carol_pubkey>", "wss://relay.example.com", "arbiter"],
  ["timing_relay", "wss://relay.example.com"],
  ["accept_until", "1700010600"],
  ["nonce", "742513", "20"]
 ],
 "content": "Good game — again?",
 "id": "<offer_alice_id>",
 "sig": "..."
}

The offer restates no terms: the rematch will reuse the concluded session’s game, variants, and time control, with the seats swapped. On its own this offer does nothing but signal Alice’s intent; Bob’s client surfaces it as a standing rematch proposal.

Example 2 — The matched pair, and the rematch the arbiter founds

Bob completes the pair by publishing his own offer, mutually addressed (signed by Bob, naming Alice), referencing the same concluded session and arbiter:

{
 "kind": 3430,
 "pubkey": "<bob_pubkey>",
 "created_at": 1700010060,
 "tags": [
  ["e", "<game_g_id>", "wss://relay.example.com", "rematch_of"],
  ["e", "<adjudication_g_id>", "wss://relay.example.com", "concluded_by"],
  ["p", "<alice_pubkey>", "wss://relay.example.com", "opponent"],
  ["p", "<carol_pubkey>", "wss://relay.example.com", "arbiter"],
  ["timing_relay", "wss://relay.example.com"],
  ["accept_until", "1700010660"]
 ],
 "content": "",
 "id": "<offer_bob_id>",
 "sig": "..."
}

Carol (the concluded session’s arbiter) now holds a matched pair and founds the rematch Game Session — seats swapped (Bob now first, Alice now second), same variants, same game — referencing both offers:

{
 "kind": 3422,
 "pubkey": "<carol_pubkey>",
 "created_at": 1700010100,
 "tags": [
  ["e", "<offer_alice_id>", "wss://relay.example.com", "rematch_offer"],
  ["e", "<offer_bob_id>", "wss://relay.example.com", "rematch_offer"],
  ["timing_relay", "wss://relay.example.com"],
  ["game", "sanki"],
  ["p", "<alice_pubkey>", "wss://relay.example.com", "player"],
  ["p", "<bob_pubkey>", "wss://relay.example.com", "player"],
  ["seat", "<bob_pubkey>", "first"],
  ["seat", "<alice_pubkey>", "second"],
  ["variant", "<alice_pubkey>", "chess"],
  ["variant", "<bob_pubkey>", "ogi"]
 ],
 "content": "<FEEN string for the swapped-seat starting position>",
 "id": "<game_g_prime_id>",
 "sig": "..."
}

Everything downstream of this Game Session is identical to a directed or matchmade session. Had only one offer been published, Carol would found nothing; had Alice and Bob each published several offers, Carol would still found exactly one canonical rematch for the slot (rematch, <game_g_id>) (§Race conditions). A further rematch — of this session — would be offered against <game_g_prime_id> in turn, concluded_by naming that session’s own Adjudication.

Example 3 — Attested mode

This example steps outside the session assumed above: it concerns a different concluded session <game_h_id>, run by the same players and arbiter but in attested mode under timestamper Dave, concluded by an Adjudication <adjudication_h_id>. A distinct session is necessary — the timing designation is a property of the session being replayed, not a choice the offer makes, so an offer citing the self-timed <game_g_id> could not carry a timestamper tag without violating constraint 6. Each offer for <game_h_id> therefore additionally carries that session’s timestamper (mirroring its mode, §Operating mode):

{
 "kind": 3430,
 "pubkey": "<alice_pubkey>",
 "created_at": 1700010000,
 "tags": [
  ["e", "<game_h_id>", "wss://relay.example.com", "rematch_of"],
  ["e", "<adjudication_h_id>", "wss://relay.example.com", "concluded_by"],
  ["p", "<bob_pubkey>", "wss://relay.example.com", "opponent"],
  ["p", "<carol_pubkey>", "wss://relay.example.com", "arbiter"],
  ["p", "<dave_pubkey>", "wss://relay.example.com", "timestamper"],
  ["accept_until", "1700010600"]
 ],
 "content": "",
 "id": "<offer_alice_attested_id>",
 "sig": "..."
}

The rematch Game Session Carol founds is then attested by Dave (the Session Start Attestation, kind 3410), exactly as for a directed or matchmade session in attested mode.

Client guidelines

Clients implementing kind: 3430 SHOULD:

  1. Offer both players a single “rematch” affordance once the session has concluded — that is, once an Adjudication (kind 3425) of it exists, since without one no conforming offer can be built at all (constraint 2). The affordance is symmetric: it is presented to the winner and the loser alike, and neither is treated specially. Note the ordering this imposes. An Adjudication is reactive — it exists only after some player has published an Adjudication Request (kind 3424) — so a client that wants the rematch affordance visible the moment the board reaches a terminal position SHOULD pair it with that request rather than gate on a verdict that nobody has yet asked for. Two shapes are conforming: present the result/rating action (which publishes the 3424) as a distinct step the user takes first, the rematch becoming available once the verdict lands; or fold the request into the rematch action itself, publishing the 3424 and then the 3430 once the Adjudication is observed. The first keeps the two acts legible to the user and is RECOMMENDED; either way, the client MUST NOT publish an offer before it holds the Adjudication it will reference.
  2. On use, publish a Rematch Offer addressed to the opponent, designating the concluded session’s arbiter and mirroring its timing designation, with a short accept_until (§Security considerations).
  3. If a matching offer from the opponent already exists for this session, treat the affordance as completing the pair — publish the user’s own offer — rather than as initiating a fresh proposal. Present a received lone offer as “<name> offers a rematch”.
  4. Watch for the rematch Game Session (kind 3422) referencing the user’s offer and redirect into it, exactly as after any other founding. The wait is the arbiter’s founding latency, the same as for a directed or matchmade session.
  5. Fall back when the arbiter is unresponsive. If the offer’s accept_until passes with no rematch Game Session, offer to send a fresh Direct Challenge (kind 3420) to the same opponent — possibly designating a different arbiter — or surface the arbiter as unavailable. See §Security considerations and kind 3422 §Handling a silent arbiter.
  6. Support withdrawal. A user MAY withdraw a standing offer with a NIP-09 deletion request, or simply let its accept_until lapse. Clients SHOULD stop presenting an offer past its accept_until or that its signer has deleted.
  7. Filter out offers whose accept_until has already elapsed, and respect the user’s NIP-51 mute list (kind 10000) when surfacing a received offer.

Security considerations

References