Skip to main content
The MetalAssertions genesis contract at 0x000000000000000000000000000000000000018c records claims backed by a bond under a domain’s published rules. A permitted challenger can dispute a claim during the domain’s challenge window. Once the window ends, anyone can call settle(id) to settle an unchallenged assertion. Verified oracle claims are checked and settled when submitted. Each domain sets one of three challenge classes: When a bond is forfeited, half goes to the winner as claimable balance, rounded down. The remainder is recorded as burned and held permanently by the assertions contract.

Before you start

Prepare the bond token and its spending approval using the token and spending approval instructions. Fund the signing account’s balance in the gas token using Estimate and record fees, then verify execution and finality for each transaction.

Domains

Domains are fixed at genesis. domainIdOf(name) computes the domain ID as keccak256(name), and domain(id) returns its configuration: requiredBond(domainId, declaredValue) returns the minimum bond: max(bondFloor, floor(declaredValue * bondBps / 10000)). A challenge posts the assertion’s recorded bond, which can exceed that minimum.

Claims

An objective claim identifies a subject whose value can be checked onchain and records the asserter’s proposed value:
claimHashOf(kind, subjectA, subjectB, value) computes it on chain. rulesHash identifies the rules under which the assertion is made. The assertion ID is keccak256(abi.encode(domainId, asserter, claimHash, rulesHash, block.number)), allowing one assertion with those same fields per block. Submit a new assertion if the claim or rules change.

Asserting and settling

  • assertClaim(domainId, claimHash, rulesHash, declaredValue, bond) pulls bond of the domain’s token from the caller (approve first) and returns the assertion id, also emitted in Asserted.
  • settle(id) settles an assertion once its window elapsed. Anyone may call it.
  • withdraw(token) pays out everything claimable to the caller.
Settled and Voided are final states. Consumers check status when using an assertion, and later disputes require a new assertion.

Verified oracle claims

Use assertOracleClaim(domainId, itemId, height, value, rulesHash) for oracle claims (kind 1). It reads 0xFD.at(itemId, height) in the same call and reverts with Unreadable if that write is unavailable, WrongValue if the value differs, or Flagged if any flag is set. A successful call records the assertion as Settled with verified = true, a zero bond and declared value, and expiresAt set to the current block time. It emits Asserted followed by Settled. The claim hash and assertion ID use the same formulas as assertClaim. The verified assertion remains after the oracle’s history ring overwrites the original write. Save its item ID, height, and value so a consumer can recompute the claim hash and compare it with the verified record. The domain’s asserter allowlist and suspensions apply across all three challenge classes. Check verified == true when relying on immediate oracle verification. A claim submitted through assertClaim is checked only if challenged.

Objective challenges

challenge(id, proof) takes proof = abi.encode(kind, subjectA, subjectB, value, actual, siblings): the claim’s preimage, the value the challenger says the subject has, and for a Merkle claim the sibling path from actual to the root. siblings is empty for an oracle claim.
  • Contradiction. The assertion is voided, the asserter’s bond is forfeited (half burned, half to the challenger, whose own bond is returned), and the asserter is suspended in the domain.
  • Failed proof. An invalid path or proof of the claimed value forfeits the challenger’s bond, with half burned and half claimable by the asserter. The assertion remains open to further challenges until its window ends.
  • Unreadable oracle claim. If a claim submitted through assertClaim names an unavailable oracle write, a challenge voids it and returns both bonds in full as claimable balances. The challenger must still post its bond, and the asserter remains permitted in the domain. If unchallenged, the assertion can settle after the window ends.
Use assertOracleClaim to verify an oracle value while the write is available. The history ring keeps one write per height % 64, so an item written every block loses its earlier write after 64 blocks. A bonded claim through assertClaim then becomes voidable before its challenge window may have ended.

Evidence challenges

In an evidence domain a challenge is a question for the validators:
  • challengeEvidence(id, evidenceURI) posts a bond equal to the asserter’s, names the evidence, marks the assertion Challenged, and lists it in pendingEvidence().
  • Validators that answer evidence questions add the verdict item verdictItemOf(id) to the oracle catalog through a catalog/1 statement, and attest the verdict there. The item’s name, verdictNameOf(id), is v/ followed by the first 14 bytes of id in hex. The row leaves the catalog once the challenge closes.
  • resolveEvidence(id) applies an undisputed verdict written after the challenge. If none is available after one challenge window, anyone can resolve it as TOO_EARLY.
One challenge per assertion runs at a time. tooEarly in assertion(id) counts TOO_EARLY resolutions, including those caused by a missing verdict. The third such resolution (MAX_TOO_EARLY) voids the assertion and returns both bonds.

Subjective challenges

In a domain that names an arbiter, that address decides challenges.
  • challengeSubjective(id) posts a bond equal to the asserter’s and marks the assertion Challenged. A challenge from the arbiter reverts with ArbiterCannotChallenge.
  • resolveSubjective(id, verdict) lets the arbiter apply a verdict from the table above. After one challenge window, anyone else can call it to resolve the challenge as TOO_EARLY, regardless of the supplied verdict.
A challenge of the wrong class reverts with WrongChallengeClass: challenge outside an objective domain, challengeEvidence outside an evidence domain, and challengeSubjective outside a subjective domain.

Interface

Reads: Events: Asserted, Settled, Voided, ChallengeFailed, Withdrawn, EvidenceChallenged, EvidenceResolved, SubjectiveChallenged, SubjectiveResolved. Errors: UnknownDomain, WrongChallengeClass, NotChallenged, NoVerdict, NotArbiter, ArbiterCannotChallenge, BadVerdict, NotAsserter, NotChallenger, Suspended, BondTooSmall, TransferFailed, AlreadyAsserted, NotAsserted, WindowActive, WindowElapsed, BadClaim, Unreadable, WrongValue, Flagged, NothingToWithdraw.