Skip to content

Resolver

FidemarkResolver is a custom EAS SchemaResolver registered with both Fidemark schemas. EAS calls it on every attestation and revocation; the resolver decides whether to accept.

  • contentHash != bytes32(0): empty hashes are rejected.
  • All required string fields must be non-empty.
  • String fields are length-bounded: proofMethod ≤ 64 bytes, contentType ≤ 128 bytes, modelId and provider (AI) ≤ 128 bytes.
  • The attestation’s schema UID must be one of the two Fidemark schemas. Unknown schemas revert.
  • When the resolver is paused (pause() called by owner), all new attestations revert with EnforcedPause. Verifying existing attestations is unaffected.
  • creator == attestation.attester: you can’t attest authorship on behalf of a different wallet. EAS’s delegated attestation flow still works because EAS sets attester to the original signer when relayed.
  • createdAt != 0.
  • createdAt <= block.timestamp + 1 day: protects against far-future timestamps while tolerating client clock skew.
  • proofMethod must be on the resolver’s allowlist. wallet-signed is bootstrapped at deploy time; the owner can add more (e.g. ens-verified).
  • modelId non-empty.
  • provider non-empty.
  • promptHash may be zero: not every agent flow has a discrete prompt.

onRevoke accepts every revocation and emits a Revoked event. EAS already enforces that only the original attester can revoke a revocable attestation, so the resolver doesn’t need to re-check. Revocation is permitted even when the resolver is paused (revocation only ever removes a claim; pause blocks adding new ones).

The resolver uses OpenZeppelin’s Ownable2Step (two-step ownership transfers). Owner-only functions:

FunctionPurpose
setSchemas(humanUID, aiUID)Bind the schema UIDs to the resolver. Callable once. Reverts if humanUID == aiUID.
addProofMethod(string method)Add a value to the proofMethod allowlist (≤ 64 bytes).
removeProofMethod(string method)Remove a value from the allowlist. Cannot remove wallet-signed (the bootstrap method) so an owner-key compromise cannot brick L0.
pause() / unpause()Emergency switch. While paused, onAttest reverts; revocations still work.
transferOwnership(newOwner) / acceptOwnership()Two-step ownership transfer. Bad-address transfers do not brick admin.

There is no upgrade path: the resolver is non-upgradeable by design. EAS schema bindings are immutable in the registry, and silently changing validation rules under existing attestations would break their trust guarantee.

If new validation logic is needed (e.g. verifying a TEE attestation signature), Fidemark ships a new resolver version paired with a new schema: old attestations stay verifiable forever, new attestations get the new rules.

The same admin pattern applies to FidemarkMultiResolver and FidemarkPoPResolver:

  • Two-step ownership.
  • pause() / unpause() on the attest path.
  • Bootstrap proofMethod (multi-party and pop-verified-worldid respectively) cannot be removed.

The PoP resolver additionally exposes:

FunctionPurpose
proposeWorldIdVerifier(addr)Stage a swap of the World ID verifier address. Subject to a 24-hour timelock.
finalizeWorldIdVerifier()Apply the previously-proposed verifier swap once the timelock has elapsed.
cancelWorldIdVerifierProposal()Cancel a pending proposal.
setWorldIdAppId(string) / lockAppId()Update or permanently freeze the Worldcoin app id.
setWorldIdGroupId(uint256) / lockGroupId()Update or permanently freeze the verification level (1 = Orb, 0 = Phone).

In production deployments the appId and groupId are locked immediately after the resolver is bound to the production Worldcoin app, so they cannot drift even with a compromised owner key.

EventWhen
HumanAttestation(uid, creator, contentHash, proofMethod)A Human Proof attestation passed validation.
AIAttestation(uid, attester, contentHash, modelId, provider)An AI Proof attestation passed validation.
MultiAttestation(uid, contentHash, submitter, attesterCount)A multi-party attestation passed validation (multi resolver).
PoPAttestation(uid, creator, contentHash, nullifierHash, proofMethod)A PoP attestation passed validation (PoP resolver).
Revoked(uid, attester)An attestation was revoked.
SchemasSet(humanUID, aiUID) / SchemaSet(uid)A resolver was bound to its schema(s).
ProofMethodAdded(method) / ProofMethodRemoved(method)The allowlist changed.
Paused(account) / Unpaused(account)The resolver was paused or unpaused.
OwnershipTransferStarted(previousOwner, newOwner) / OwnershipTransferred(...)Two-step ownership flow events.
WorldIdVerifierProposed(verifier, effectiveAt) / WorldIdVerifierFinalized(verifier) / WorldIdVerifierProposalCancelled()PoP timelock-gated verifier swap events.
WorldIdAppIdLocked() / WorldIdGroupIdLocked()PoP one-shot freeze events.

These events are stable indexer integration points.