Skip to content

feat(evm): parity uplift — subgraph mappings, Foundry invariants, slither CI, gas gate - #180

Merged
truthixify merged 4 commits into
wraith-protocol:developfrom
gbengaeben:feat/evm-parity-uplift
Aug 31, 2026
Merged

feat(evm): parity uplift — subgraph mappings, Foundry invariants, slither CI, gas gate#180
truthixify merged 4 commits into
wraith-protocol:developfrom
gbengaeben:feat/evm-parity-uplift

Conversation

@gbengaeben

Copy link
Copy Markdown
Contributor

Summary

Closes #157 — brings the EVM side up to parity with the Stellar stack.

What's included

Subgraph (evm/subgraph/)

  • Proper subgraph.yaml replacing the instant-config-only setup, with dataSources for all five contracts.
  • AssemblyScript mappings under evm/subgraph/mappings/: event handlers for ERC5564Announcer, ERC6538Registry, and WraithNames; call handlers for WraithSender and WraithWithdrawer.
  • New GraphQL schema (Announcement, StealthMetaAddress, Name, Send, Withdrawal).
  • graph codegen && graph build pass against the real contract ABIs. Names/Sender/Withdrawer addresses are placeholders (marked TODO) until those contracts are deployed.

Foundry invariant tests (evm/foundry/)

  • foundry.toml with 256 runs per invariant.
  • Suites under test/invariant/:
    • sender balance conservation (no retained ETH/tokens, ERC-20 conservation across the pool),
    • withdrawer atomicity (ETH + ERC-20 conservation),
    • name-registration monotonicity (unambiguous forward resolution, exact reverse inverse, no stale bindings after update).
  • Gas snapshot committed at evm/foundry/.gas-snapshot; CI runs forge snapshot --check --tolerance 5 so any PR increasing gas >5% fails.

Slither (evm/slither.config.json, CI)

  • Curated detector set; slither . --config-file slither.config.json --fail-medium returns zero High / Medium.
  • Targeted slither-disable-next-line comments where a finding is an intentional pattern (exact zero-balance guard, destructured tryRecover tuple).

CI (.github/workflows/ci.yml)

  • Installs Foundry, runs the invariant suite, enforces the gas snapshot gate, runs Slither (SARIF upload), and builds the subgraph.

Docs — new evm/README.md covering the four new local commands (forge invariants, gas snapshot, slither, subgraph codegen/build).

Verification (all local)

  • npx hardhat test — 44 passing
  • forge test --match-path 'test/invariant/*' — 3 suites, 256 runs each, passing
  • forge snapshot --no-match-path 'test/invariant/*' --check --tolerance 5 — passing
  • slither . --config-file slither.config.json --fail-medium — 0 High / 0 Medium
  • graph codegen && graph build — success

…ther CI, gas gate

Brings the EVM stack to parity with Stellar:
- Full subgraph with AssemblyScript mappings and a subgraph.yaml for all five
  contracts (event handlers for Announcer/Registry/Names, call handlers for
  Sender/Withdrawer); graph codegen && graph build pass against the real ABIs.
- Foundry invariant suite under evm/foundry covering sender balance
  conservation, withdrawer atomicity, and name-registration monotonicity
  (256 runs per invariant), plus a committed gas snapshot with a +5% CI diff gate.
- Slither config + CI step enforcing zero High/Medium findings; adds targeted
  slither-disable comments for intentional patterns and initializes one local.
- evm/README.md documenting the four new local commands.

Closes wraith-protocol#157
@drips-wave

drips-wave Bot commented Aug 29, 2026

Copy link
Copy Markdown

@gbengaeben Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@github-advanced-security

Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

Bumps the resolved @types/node entry so `npm ci` in the CI subgraph step no
longer fails out-of-sync validation.

@truthixify truthixify left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gbengaeben the work here is good and I want to be clear about that before the one thing I am asking you to change.

Stripping out vendored code and lockfiles, you authored 31 files and about 1820 lines, and all of it is the right shape:

  • three real invariant suites (sender balance conservation, withdrawer atomicity, name registration monotonicity) rather than unit tests wearing an invariant label
  • five AssemblyScript mappings with networks.json indirection, which is what I asked for given WraithNames, WraithSender and WraithWithdrawer have no deployed addresses
  • slither wired at fail-on: medium with SARIF upload, and the suppressions done as per-site slither-disable-next-line with a written justification each, in ERC6538Registry.sol and WraithWithdrawer.sol. I had suggested config-level suppressions; per-site with a reason is better for incorrect-equality because the justification travels with the code. Good call.
  • excluding the invariant suites from the gas snapshot because they carry run-to-run reverts: counters, with a comment explaining why. That is a subtle failure mode to have anticipated.
  • symlinking lib/openzeppelin to evm/node_modules/@openzeppelin instead of installing OZ twice. Neat, and correctly ordered after npm ci in the job.

The change I need: forge-std is vendored, not linked.

evm/foundry/lib/forge-std/ is committed as 68 files and 30266 lines of third-party source, which is 94 percent of this PR. There is no .gitmodules, so it is a plain tree rather than a pinned reference. That lands permanently in every clone, every git grep, and every future diff, and there is no recorded version to audit or bump.

It is also inconsistent with what you did for the other two libs, which are symlinks, so I suspect this was accidental rather than deliberate.

Either fix is fine:

# option A, pinned submodule (my preference, it records a version)
git rm -r --cached evm/foundry/lib/forge-std
rm -rf evm/foundry/lib/forge-std
cd evm/foundry && forge install foundry-rs/forge-std
# then add `submodules: recursive` to the checkout step in the evm job
# option B, install in CI
echo "evm/foundry/lib/forge-std/" >> .gitignore
git rm -r --cached evm/foundry/lib/forge-std
# and run `forge install` before `forge test` in the evm job

A prefers reproducibility, B is less friction for contributors. Your call, just not the current state.

Two smaller notes, neither blocking:

  • evm/subgraph/package-lock.json at 5998 lines is fine to keep, since the subgraph job runs npm ci and evm/ is already npm rather than pnpm. Just confirming that was deliberate and not a stray npm install.
  • The openzeppelin symlink silently depends on npm ci having run in evm/ first. It holds in CI because of step ordering, but someone running forge test in a fresh clone will get a confusing failure. Worth one line in evm/README.md.

Replace the 68-file vendored forge-std tree (~30K lines, unpinned) with a
git submodule pinned to v1.16.2, matching the previously vendored version.
This records a reviewable and bumpable version, keeps third-party source out
of every clone and future diff, and is consistent with the symlinks already
used for the openzeppelin and wraith-contracts libraries.

Enable recursive submodule checkout in the evm CI job so forge resolves
forge-std on a fresh clone. Document in the evm README that forge-std is a
submodule and that the openzeppelin symlink requires `npm ci` beforehand.
The forge-std submodule's auxiliary files (CI yaml, CONTRIBUTING.md, JSON
fixtures) follow upstream formatting and do not match this repo's prettier
config, failing the evm job's `prettier --check` step. Skip the whole
foundry/lib directory the same way node_modules already is; dependency code
is not formatted to this project's rules. Project-owned sources under
evm/contracts are still checked.
@truthixify
truthixify merged commit 2d28131 into wraith-protocol:develop Aug 31, 2026
14 checks passed
@truthixify

Copy link
Copy Markdown
Contributor

Merged @gbengaeben. forge-std is now a pinned submodule at v1.16.2 with .gitmodules and submodules: recursive in the checkout, so the PR went from 38k lines to 8k and there is a version to audit. Everything I praised the first time still stands: three real invariant suites, the networks.json indirection, per-site slither suppressions with written justifications, and excluding the invariant suites from the gas snapshot because of their run-to-run revert counters. Good turnaround.

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.

EVM parity uplift: subgraph mappings + slither CI + Foundry invariant tests

3 participants