Skip to content

Gentx validation

Every gentx submitted to join a launch is validated server-side before it is stored — a bad gentx is rejected at submission (400) with a precise, per-invariant reason, and never persisted. coordd runs the shared gentxvalidate library from seedward-libs (the same implementation the CLI and the browser use), so the rules never drift between client and server.

What is checked (RunAll)

coordd runs the full invariant set (server-grade), not the browser's advisory subset:

Invariant Checks
well_formed exactly one MsgCreateValidator, decodable structure
bond_denom the self-delegation is in the launch's bond denom
self_delegation ≥ the launch's floor (see below)
commission_consistency / commission_bounds rate ≤ max-rate ≤ 1; within the launch's commission bounds
moniker non-empty, ≤ 70 bytes, valid UTF-8, no control chars
operator_address derives from the signing account under the launch's bech32 prefix
consensus_pubkey present and well-formed
signature_direct / signature_amino_json the gentx signature verifies (the heavy check the browser omits)

Derived identity

On a pass, validation also derives the consensus pubkey and the operator (validator) address from the gentx's signer — coordd trusts the derived validator identity, not anything self-declared in the request. This is the cold operator identity, distinct from the hot submitter that signed the submission.

Self-delegation floor

The self-delegation floor is applied by launch type — enforced for MAINNET, INCENTIVIZED_TESTNET, and PERMISSIONED launches; a plain testnet may set none.

Failure response

A failed gentx returns 400 with a structured body listing each failed invariant:

{
  "error": {
    "code": "gentx_invalid",
    "message": "gentx validation failed: signature_direct",
    "invariants": [
      {
        "invariant": "signature_direct",
        "ok": false,
        "reason": "…"
      }
    ]
  }
}

The web renders this inline so a validator sees exactly which checks failed before resubmitting.