Skip to main content
This page is for Cairo developers who consume Molpha attestations on Starknet. It covers how to depend on the verifier, how to call it from your contract, how to build the arguments off-chain, and the contract reference. The Starknet verifier is a stateless view contract. Given an 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 named verifier. Pin the chivchyn tag, the release that matches the deployed verifier.
Scarb.toml
To build and test the contracts locally:

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.
Around every call:
  • Check the bool. A bad signature, a stale timestamp and a malformed field all return (false, code).
  • Pin source_id and enforce a minimum signatures_required (>=, not ==). source_id does not commit the threshold, so a higher threshold is always acceptable.
  • Pass a non-zero max_age. With 0, a correctly signed attestation keeps verifying for as long as its registry version is accepted.
  • Prevent replay. verify is a view call, so the same attestation verifies any number of times.
  • Treat value as an opaque u256 until you decode it for your source.
The full list, shared by every chain, is the consumer checklist. sourceId derivation is on Feeds.

Build the arguments off-chain

The SDK maps a gateway Attestation 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 in verifier/src/interface.cairo. Field order is the order of the signed message; see Attestations for the message itself.
Serialized calldata for verify is 13 felts. Each u256 is two felts, low 128 bits first:
The call returns two felts: the 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).
Selection and the Schnorr check are described in Cryptography. On Starknet the final curve check uses native secp256k1 syscalls and compares the Ethereum-style address of s·G − e·P with commitment, the same check the EVM verifier does with ecrecover.

Result codes

Codes are defined in verifier/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 whose timestamp / 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 with verifier/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 (no chainId), 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.