Attestation, it answers one question: did enough selected Molpha nodes sign this exact payload under the stated registry version? It does not store feeds or consumed updates. Your contract owns source and threshold policy, replay protection, and value decoding.
Source: molpha/starknet-verifier · Cairo / Scarb 2.18+ · snforge 0.61+. Addresses: Deployments.
Depend on the verifier
Your contract only needs the interface types and the generated dispatcher. Add the repository as a Scarb git dependency; the package is namedverifier. Pin the chivchyn tag, the release that matches the deployed verifier.
Scarb.toml
Verify an attestation in Cairo
verify never panics on a rejected attestation. It returns (false, code), so you must check the bool before using the payload.
- Check the
bool. A bad signature, a stale timestamp and a malformed field all return(false, code). - Pin
source_idand enforce a minimumsignatures_required(>=, not==).source_iddoes not commit the threshold, so a higher threshold is always acceptable. - Pass a non-zero
max_age. With0, a correctly signed attestation keeps verifying for as long as its registry version is accepted. - Prevent replay.
verifyis a view call, so the same attestation verifies any number of times. - Treat
valueas an opaqueu256until you decode it for your source.
sourceId derivation is on Feeds.
Build the arguments off-chain
The SDK maps a gatewayAttestation onto the Cairo structs, with no starknet.js runtime dependency.
args.attestation uses the Cairo member names, so an ABI-aware client can pass it directly. parseStarknetVerifyResult also accepts a decoded (bool, u8) tuple, and throws if the two halves disagree, which means the call did not reach a Molpha verifier with this interface. See the SDK reference.
Reference
Structs
Defined inverifier/src/interface.cairo. Field order is the order of the signed message; see Attestations for the message itself.
verify is 13 felts. Each u256 is two felts, low 128 bits first:
bool and the u8 code. Calldata that does not deserialize (for example a signatures_required felt above 255) fails before verify runs instead of returning a code.
verify
max_age is in seconds and is compared against timestamp / 1000 and the block timestamp. Checks run in this order and stop at the first failure:
1
Structural guards
R_MALFORMED if signatures_required == 0, signers_bitmap == 0, signature is 0 or >= Q, commitment is 0 or wider than 160 bits, or fewer bits are set than signatures_required.2
Freshness (only when max_age != 0)
R_MALFORMED if timestamp / 1000 is after the block timestamp; R_STALE if it is more than max_age seconds old.3
Registry version
R_BAD_REGISTRY_VERSION if the version was never published; R_NOT_YET_ACTIVE if the payload predates its activation; R_VERSION_EXPIRED if it is past the grace window below.4
Signer selection
R_BAD_QUORUM if the bitmap is not within the derived selection set, or the version has no nodes.5
Aggregate signature
R_BAD_AGGREGATE if the signers’ keys sum to the point at infinity; R_BAD_SIGNATURE if the Schnorr check fails. Otherwise (true, R_OK).s·G − e·P with commitment, the same check the EVM verifier does with ecrecover.
Result codes
Codes are defined inverifier/src/verify_codes.cairo and are identical to the EVM verifier’s: see EVM result codes. The same payload produces the same code on every chain, and codes 1 and 6 are reserved and never returned.
Registry versions
Every registry change publishes a new immutable version whose activation time is the block timestamp of that transaction. A version accepts payloads whosetimestamp / 1000 lies in [activates_at(v), activates_at(v + 1) + 60]; the latest version has no upper bound. The 60 s grace is checked against the payload timestamp, not the wall clock. Pass the exact registry_version the nodes signed under. Details: Registry versions.
Reads and admin functions
The protocol admin manages the node set with
add_node (compressed key plus proof-of-possession), remove_node (address plus 0-based index witness), set_redundancy_buffer and transfer_protocol_admin. Each registry change publishes a new version, so attestations signed under an earlier version keep verifying against it within its window. Nodes register per deployment, with a proof-of-possession bound to the verifier’s contract address.
Gas
Measured withverifier/tests/benchmarks.cairo (snforge 0.61, scarb run bench); re-run for your configuration.
Cost is not linear in signer count, because selection switches algorithms depending on group size relative to the node count. Registry changes copy the previous key set forward, so their cost grows with registry size.
Parity with EVM
The Cairo verifier is a port of the EVM verifier: same structs, same signed message (nochainId), same selection, same result codes and the same 60 s grace. One gateway payload verifies unmodified on Starknet and every supported EVM chain; the repository’s parity.cairo and e2e.cairo tests check this against EVM golden vectors. Bit i of the bitmap refers to the same node as index i on the EVM verifier.
Next steps
Consumer checklist
Freshness, replay and threshold rules for every chain.
Deployments
Verifier addresses and network status.
Smart contract quickstart
Fetch an attestation and verify it end to end.