Skip to content

feat(protocol-core): add on-chain deployment verification script - #35

Merged
henrypalacios merged 1 commit into
mainfrom
feat/protocol-core-verify-onchain
Sep 8, 2026
Merged

feat(protocol-core): add on-chain deployment verification script#35
henrypalacios merged 1 commit into
mainfrom
feat/protocol-core-verify-onchain

Conversation

@henrypalacios

@henrypalacios henrypalacios commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add pnpm verify:onchain: a maintainer tool that reads every address the registry records and checks it against live chain state.
  • Report each chain as checked, void or skipped, so an endpoint that could not answer never produces a failing address.
  • Ignore *.no-commit* at the repo root.

Why

ChainConfig carries contract deployments and multicall addresses, all hand-transcribed. Confirming a backfill or a redeploy meant ad hoc terminal calls that left no reusable record and no consistent verdict. This gives that check a home.

It runs on demand against the registry itself, so it stays correct as chains are added — one entry in the endpoint table per chain, and the address list comes from whatever the registry declares at run time.

Three outcomes, not two

An endpoint that is dead, rate-limited or pointed at the wrong network answers identically for every address it is asked about. A two-outcome model would turn that into a page of false failures.

So every batch carries that chain's wrapped native token as a control, read before the address sweep and again after it. If either read fails, the batch is discarded and the next endpoint candidate is tried; when candidates run out, the chain reports void:

type BatchResult =
  | { status: 'checked'; endpointTier: EndpointTier; findings: Finding[] }
  | { status: 'void';    endpointTier: EndpointTier; reason: string }
  | { status: 'skipped'; reason: string }

The void variant has no findings field, so a result from an unusable endpoint does not typecheck as a finding. skipped stays distinct from void: never attempted and attempted-but-unusable call for different fixes. Only a negative finding inside a completed batch fails the run; an all-void run exits 0.

What each field is checked for

Field Check
quoter, positionManager eth_call factory(), compared against the chain's recorded factory
factory, poolDeployer, swapRouter, multicall eth_getCode returns non-empty
wrappedNative control — gates the batch, never reported as a finding

Role checks have three outcomes: role-ok when the returned factory matches the recorded one; role-sibling when it matches the recorded pool deployer instead, which is the same deployment answering differently and does not fail; role-mismatch otherwise. eth_call answers in lowercase and the registry stores EIP-55 checksummed values, so both sides are lowercased before comparing.

Contract code size is printed as a column for comparison within a run.

Changes

File Change
scripts/verify-onchain.ts The verification tool
package.json verify:onchain script entry
.gitignore Ignore *.no-commit*

Nothing under src/ changes, and no dependency is added — the script uses the global fetch already available on the engine range the package supports.

Not wired into CI or prepublishOnly: it needs network access and an optional RPC credential read from the environment. Without that credential it falls back to each chain's public endpoint and prints which tier it used, so it runs unattended either way. It never prints an endpoint URL that carries a credential.

Isolation follows the validate-addresses.ts precedent: files lists only dist, the bundler entry and the declaration build cover src only, while the package tsconfig and lint config still cover scripts/.

Size

431 added lines. The tool is one work unit — a result model, an RPC layer, the per-field checks and the reporter — and any split would leave a half that cannot run. Roughly a quarter of the file is type declarations and comments.

Test plan

scripts/ sits outside the vitest test.include and coverage.include globs, both scoped to src/**, so this script has no automated test. It was exercised by the runs below.

  • pnpm verify:onchain — 3 checked, 0 void, 0 negative findings, exit 0. Role checks returned role-ok on all four quoters and position managers, confirming the case-insensitive compare against real checksummed values.
  • VOID drill, unreachable host — one chain pointed at a non-resolving endpoint reports VOID ... eth_getCode: fetch failed, no findings, run exits 0.
  • VOID drill, live endpoint for the wrong chain — one chain pointed at another chain's healthy RPC reports VOID ... control reported no code, no findings, run exits 0. Without the control gate this case would have produced false absent-address results.
  • npm pack --dry-run — 8 files: README.md, six dist/*, package.json. No scripts/ entry.
  • pnpm test — 13 files, 229 tests pass, no type errors
  • pnpm lint — clean
  • pnpm typecheck — clean
  • pnpm build — CJS, ESM and declaration builds succeed
  • pnpm validate:addresses — 54 addresses validated across 9 chains

Add `pnpm verify:onchain`, a maintainer tool that reads the deployment addresses the registry records and checks each one against live chain state. Every chain reports checked, void or skipped.

The addresses are hand-transcribed, and confirming a backfill or a redeploy meant ad hoc terminal calls that left no reusable record and no consistent verdict. This gives that check a home, driven by whatever the registry declares at run time.

An endpoint that is unreachable, rate-limited or pointed at the wrong network answers identically for every address it is asked about. Each batch therefore carries the chain's wrapped native token as a control across both transports it uses, and a batch whose control does not answer reports void and carries no findings. A role question the endpoint leaves unanswered is recorded as unknown rather than as a mismatch, so an endpoint condition never becomes a claim about an address. A run that verified nothing exits with its own status, distinct from both a clean run and a run that found a problem.

The decisions this rests on — address decoding, role classification, batch projection and exit status — live in src/verification with unit tests. The transport and orchestration stay in scripts/, outside the published package.
@henrypalacios
henrypalacios force-pushed the feat/protocol-core-verify-onchain branch from 9809a27 to 6486c48 Compare September 8, 2026 22:58
@henrypalacios
henrypalacios merged commit 53c6718 into main Sep 8, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant