Skip to content

Methodology

What a finding means, and what it does not.

RagnaLens reads public state from Robinhood Chain and evaluates it with a fixed set of rules. This page explains each step in plain language so you can decide how much weight to give a report.

1. One block, recorded first

A scan starts by asking the provider for the latest block and recording its number and hash. Every chain read that follows is pinned to that block. Where the node supports it, reads reference the block hash and require it to be canonical; otherwise reads use the block number and the hash is fetched again at the end to confirm it did not change. If it changed, the scan restarts once and is otherwise marked incomplete.

The block timestamp is chain state and is part of the record. The time the scan ran on our clock is stored separately and never influences a finding.

2. Observations, each with a status

An observation is one question asked of the chain or of an explorer, together with the answer and a status:

  • ok — data came back.
  • empty — the call succeeded and returned nothing (for example, no bytecode).
  • reverted — the contract rejected the call. This is a real on-chain answer, usually meaning the function does not exist.
  • unsupported, timeout, rate limited, error, historical state unavailable — the provider could not answer. These are failures of the reading, not facts about the contract, and they make the affected rules Unknown.

Explorer answers (source verification) are recorded with their own retrieval time. They are not pinned to the block and are treated as supplementary evidence.

3. Rules and their four answers

Each rule looks only at the recorded observations and answers one of:

  • Pass — the check completed and found nothing to flag. It is the absence of one specific signal, not a statement that the contract is safe.
  • Flag — the check completed and found something worth your attention, with a severity. A flag is a fact to read, not an accusation.
  • Unknown — the observation the rule needed could not be established. Unknown never counts as a pass and never counts as a flag.
  • Not applicable — the rule does not apply (for example, token rules on an address with no bytecode).

The overall summary says “Flags detected” when any completed check flagged, “Incomplete” when any applicable check is unknown, both when both are true, and “No flags in completed checks” only when every applicable check completed without a flag. There is no score.

4. The rules in version 1.0.0

RuleWhat it checks
RL-001 · Address syntaxThe target is a syntactically valid 20-byte EVM address. It is normalized and, when mixed-case, its checksum must match.
RL-002 · Runtime bytecodeReads the code at the target for the recorded block. No code means the address is not a contract at that block; it says nothing about intent.
RL-003 · Native balanceRecords the native currency balance at the recorded block. Informational only.
RL-004 · Token interfaceAttempts name, symbol, decimals and totalSupply, plus ERC-165 interface declarations. A responding call is evidence of an interface, not proof of standard compliance.
RL-005 · Proxy patternReads the standardized EIP-1967, EIP-1822 and legacy OpenZeppelin proxy slots and checks for the EIP-1167 minimal proxy runtime. Unrecognized patterns are not ruled out.
RL-006 · Ownership getterAttempts owner() and getOwner(). A set owner is a privileged party; a zero owner does not prove every privileged role is gone; a failed call proves nothing about administration.
RL-007 · Pause capabilityReads paused() and looks for pause()/unpause() selectors. A pausable contract can have its transfers halted by a privileged role.
RL-008 · Privileged selectorsScans the runtime bytecode (and the resolved implementation, for proxies) for known privileged function selectors such as mint, blacklist and upgradeTo. Heuristic: selectors can be missed or misread.
RL-009 · Source verificationAsks Sourcify whether verified source exists for the target. The answer is recorded with its own retrieval time and is not pinned to the block.

5. What is deliberately not claimed

  • No address is labelled “safe”. A pass on every rule means only that these particular checks found nothing.
  • No bytecode at an address is not evidence of a wallet, a scam, or anything else beyond “no contract code at that block”.
  • A failed owner() call does not prove there is no administrator; a zero owner does not prove every privileged role is gone.
  • Unrecognized proxy patterns are not detected; a pass on the proxy rule does not prove immutability.
  • Selector scanning is heuristic. Constants can look like selectors and unusual dispatchers can hide them.
  • Holder distribution, liquidity, transaction history and audit status are not evaluated because no supported source for them is wired in. They are listed as unsupported, not inferred.

6. Replaying a report

Exported reports contain the recorded observations. Importing one validates its structure, recomputes the evidence id from the recorded inputs, and re-runs the rules locally under the report’s own rule-set version when this build supports it. If the recomputed id differs, the inputs were changed after export. The evidence id proves the report matches its inputs; it does not prove the provider told the truth.

7. Explanations and AI

Every explanation on a report is produced by fixed templates from the rule engine. No language model chooses or alters a verdict. If an optional AI explanation is added in the future it will be clearly separated from the rule engine and unable to change its output.

Technical documentation →