PATINA docs

SEED rules

Six checks, applied in block order, in this order. A transaction that fails any of them records an invalid event and creates nothing.

What you will know after this page
  • The six checks in the order an indexer applies them, and the reason code a failure at each one records.
  • That the 144 block wait is measured from the block that created the commit output, and that exactly 144 passes.
  • Which carrier minimum applies to your reveal: 100000 sats for a founding claim, 10000 sats otherwise.
  • Why a commit confirmed exactly at h_close is already outside the founding window.
  • What a failed reveal actually costs: the fees and the claim, never the coins.

The six checks

Work down the list and stop at the first failure. That is why the reason code on an invalid event tells you how far your transaction got before the protocol declined it.

  1. The marker decodes as SEED with a well formed payload

    Single minimal push, magic, version 0x01, op 0x01, and exactly 18 payload bytes laid out as salt(16) | flags(1) | carrier_vout(1). Every bit of flags is reserved and must be zero.

    Failure: SEED_BAD_GRAMMAR.

  2. carrier_vout is in range and is not an OP_RETURN

    The index must name an output that exists in this transaction, and that output must not be a data output.

    Failure: SEED_CARRIER_OUT_OF_RANGE or SEED_CARRIER_IS_OPRETURN.

  3. Exactly one input reveals a qualifying commit leaf

    The input must be a Taproot script path spend whose revealed leaf is exactly either the reduced-data form or the permanent legacy form:

    <claimant_xonly(32)> OP_CHECKSIG PUSH32(commitment) OP_DROP
    <claimant_xonly(32)> OP_CHECKSIG OP_0 OP_IF PUSH32(commitment) OP_ENDIF

    The commitment in the leaf must equal SHA256("PTNA/commit" || claimant_xonly || salt), using the claimant key from the leaf and the salt from the SEED payload.

    Failure: SEED_NO_COMMIT_INPUT when no input reveals such a leaf and equally when two or more inputs qualify, or SEED_COMMITMENT_MISMATCH when a leaf is present but the recomputed commitment differs.

  4. The commit output is old enough

    reveal_height - commit_output_height >= 144

    commit_output_height is the height of the block that created the commit output, not the height it was spent. The comparison is inclusive: exactly 144 passes.

    Failure: SEED_COMMIT_TOO_YOUNG.

  5. Founding status is decided

    founding = (h_open <= commit_output_height < h_close)
            and (reveal_height <= h_close + 4032)

    This is not a pass or fail check. It sets a flag on the artifact, and it selects which minimum the last check applies. That is why it is decided before the carrier value is looked at.

  6. The carrier value clears the minimum

    At least 100000 sats if the artifact is founding, otherwise at least 10000 sats. An artifact that missed the window is still created, as long as it clears the open minimum.

    Failure: SEED_CARRIER_BELOW_MIN.

Order matters

Two implementations that apply the same checks in a different order can emit different reason codes for the same transaction. The state they produce is identical, because a failure at any step creates nothing, but the recorded reason will differ and that shows up as a state root mismatch when invalid events are part of the snapshot.

Apply them in the order above. When you disagree with another implementation about a reason code, that is a real disagreement worth reporting. See Report a disagreement.

Founding, in detail

What the founding cohort is, and what it does not entitle anyone to, is on the public Firstlight Seals page. Here it is arithmetic on two heights.

The window is defined by two heights in the deployment record: h_open and h_close, with h_close = h_open + 4032. The grace period runs a further 4032 blocks after that.

The first two rows below are the requirements. The rows under them exist to kill an assumption: there is no rank inside the window, no bonus for a larger carrier, and no effect from the fee. The last row says what a late reveal leaves you holding.

What decides founding status, and what does not.
FactEffect on founding
Commit output confirmed at or after h_open and before h_closeRequired
Reveal confirmed at or before h_close + 4032Required
How early inside the window the commit landedNone. There is no rank.
How large the carrier is above 100000 satsNone
The fee paidNone
Reveal confirmed after the grace periodNot founding. Still an artifact if it clears 10000 sats.
Boundary arithmetic

h_open is inclusive and h_close is exclusive. A commit output confirmed exactly at h_close is outside the window. If you are committing near the edge, assume you are one block off and commit earlier.

Worked example

Take a deployment with h_open = 880000, so h_close = 884032 and the grace period ends at 888064.

Five reveals against the same window.
Commit heightReveal heightAgeResult
879999880200201Artifact created, founding: false. The commit was one block early.
880000880144144Artifact created, founding: true. The age check passes at exactly 144.
880000880143143Nothing created. SEED_COMMIT_TOO_YOUNG.
8840318880644033Artifact created, founding: true. Last commit height and last reveal height that both qualify.
8840318880654034Artifact created, founding: false. One block past the grace period.

What a failure costs

  • The commit output is spent, because the reveal was a valid Bitcoin transaction whatever the protocol thought of it.
  • The coins are in the outputs your reveal created, and they are still yours.
  • The fees are gone.
  • The claim is gone. Retrying means a new salt, a new commit, and a new 144 block wait.

Every failure is visible through GET /patina/invalid-events with its reason code, so you never have to guess which check you missed.

The two transactions and the wait between them are walked through, in order, on the public mint page.

Bundling

One transaction contains one marker, and a SEED marker names one carrier. So one transaction creates at most one artifact. Creating several artifacts means several reveals, each spending its own aged commit.

Several artifacts can end up sharing a carrier later, through successor routing. That is a bundle, and it is described on State machine.