Docs · Concepts

The eight checks

Rule set one. What each check asks, how it decides, what counts as evidence, and the direction it errs in when it cannot decide.

Rule set one is eight questions about the shape of the code: what it can do to supply, to balances, to transfers, to itself. Each is decided by a program, the same way every time, and each answer carries a sentence naming the function and the path that decided it.

One rule governs all eight: when a check cannot decide, it fails and says why. A seal that guesses in the developer's favour is worth nothing to a holder, and a false fail costs the developer a fix and a resubmission, which is cheap.

How the checks read the code

Seven of the eight read the compiled artifact: the abstract syntax tree the compiler produces, plus the opcodes of the runtime. Reading the AST rather than the source text means every reference is by the compiler's declaration id, so a variable named _balances in one contract is not confused with one in another, and a function call resolves to the function it actually calls.

From the AST the checks build two things.

Entries. Every external or public function of the sealed contract and its inherited bases, the constructor excluded. These are what anyone can call.

The call graph. For each function, the set of functions it calls. Reachability from an entry through the graph is what turns "this internal function can mint" into "and here is how a caller gets to it".

The eighth check does not read code at all. It runs it, on a fork.

The list

Id Check Passes when
01 No hidden mint No path from an entry point creates supply after the constructor.
02 No owner drain Balances move only from the caller, or with an allowance.
03 Tax under the cap Any tax is fixed, or its setters are bounded at or under ten percent.
04 No blacklist No per-address switch decides whether a transfer reverts.
05 No pause on transfer No switch can stop transfers after they are open.
06 Not upgradeable The runtime contains no DELEGATECALL.
07 Sell path clears Tokens go into a fresh address and back out, on a fork.
08 No self-destruct The runtime contains no SELFDESTRUCT.

The three answers

Each check returns one of three values.

  • pass: the check decided, and the answer is no.
  • fail: the check decided, and the answer is yes, or the check could not decide.
  • not run: the check does not apply. Today only check 07 returns this, when the contract is not deployed or nobody holds it yet.

A seal with fewer than eight passes is still written and still public. The badge shows the count. A developer who disagrees with a fail can read the evidence, fix or argue, and resubmit at a new commit.

What the list is not

The list is short on purpose. A check has to be decidable by a machine, the same way every time, or it cannot be proven, and a check that is proven is worth more than ten that are promised. Rule set one does not look at liquidity, supply distribution, the honesty of the deployer, reentrancy in arbitrary calls, oracle manipulation, or anything that depends on state rather than code. Limits is the list of what it does not see.

Rule set two will add checks the same way: published first, then in the registry, never silently. A seal always records the rule set it was made under.