Skip to content

feat(deployments): generate the subgraph manifest from the deployment record - #252

Merged
truthixify merged 1 commit into
wraith-protocol:developfrom
izzetemredemir:fix/233-subgraph-from-manifest
Oct 17, 2026
Merged

truthixify merged 1 commit into
wraith-protocol:developfrom
izzetemredemir:fix/233-subgraph-from-manifest

Conversation

@izzetemredemir

Copy link
Copy Markdown
Contributor

Closes #233

Summary

evm/subgraph/subgraph.yaml still had 0x000000000000000000000000000000000000dead as the address of WraithNames, WraithSender and WraithWithdrawer (lines 57, 81 and 109 on develop), and both checks accepted it: the manifest consumer skipped placeholders for contracts that are not in the manifest (consumers.ts:72), and validate-config.js only reads <network>/instant-config.json. On develop, npm run check passes with all three placeholders in place.

This PR replaces the hand-maintained manifest with a template and a generator in scripts/deployment-manifest:

  • evm/subgraph/subgraph.yaml is renamed to subgraph.template.yaml and loses network, source.address and source.startBlock on every data source (and the three TODO comments). It gains a header comment saying how to generate the manifest; nothing else changes.
  • npm run subgraph -- --network <slug> (in scripts/deployment-manifest), or npm run manifest -- --network <slug> (in evm/subgraph), reads deployments/evm/<slug>.json with the same parsing and validation build and check use, maps each data source to its catalogue contract by source.abi, and writes evm/subgraph/subgraph.yaml with network, source.address and source.startBlock filled in. The generated file is git-ignored.
  • npm run deploy and npm run deploy-local in evm/subgraph now run npm run manifest -- --check before graph deploy.

Fails closed

The generator writes nothing and exits 1 if any of these hold, and lists every problem of every contract in one run:

  • the record does not exist (the message lists the EVM networks that do have one), or fails the schema, ID, file-name or ABI-path checks that check applies;
  • a data source's contract is not in the record;
  • its contract has no start block (deployment.height), or start block 0 (the placeholder value validate-config.js already rejects);
  • its contract has the placeholder address 0x…dead;
  • the template sets network, address or startBlock itself, a data source's source.abi is not one of the five EVM contracts in catalogue.ts, or the template has a templates: section (dynamic data sources would also need a network, which the generator does not set yet, so it refuses instead of emitting a manifest without one).

There is no fallback to a placeholder.

--check fails unless subgraph.yaml exists and is byte-for-byte what the generator writes now for the network the file names. So npm run deploy stops if the manifest was never generated, was edited by hand, or was generated from a record or template that has changed since. In a fresh checkout there is no subgraph.yaml at all, so a bare graph deploy also fails; once a manifest has been generated, a bare graph deploy skips the check, and the subgraph README says to use the npm scripts.

horizen-testnet until #231

deployments/evm/horizen-testnet.json records only ERC5564Announcer and ERC6538Registry, so today:

$ npm run manifest -- --network horizen-testnet
Cannot generate evm/subgraph/subgraph.yaml for horizen-testnet:
  ✗ WraithNames: not recorded in deployments/evm/horizen-testnet.json
  ✗ WraithSender: not recorded in deployments/evm/horizen-testnet.json
  ✗ WraithWithdrawer: not recorded in deployments/evm/horizen-testnet.json

Once #231 records the three contracts (npm run record -- evm ...), the same command writes a complete manifest with no other change. The Goldsky instant-subgraph path (horizen-testnet/instant-config.json, two contracts) is unchanged and still checked by validate-config.js and the instant-config consumer.

Design

Own template instead of graph-cli's networks.json + --network. I read graph-cli 0.96.0 (dist/command-helpers/network.js). graph build/deploy --network rewrites subgraph.yaml in place (re-serialised, comments dropped) and only checks that each data source name has an entry in networks.json; an entry without address or startBlock is accepted and copied as is. We would still need a generator to write networks.json from the record and validate it, and the committed subgraph.yaml would change on every deploy. The deployment-manifest package already owns the records, their validation and the consumer pattern, and already depends on yaml, so the template is rendered there with the yaml Document API. The output keeps the template's layout and comments and is prettier-clean.

The generated manifest is not committed. A checked-in subgraph.yaml for horizen-testnet cannot be generated until #231, so it would have to keep the placeholders this issue is about. The template is the only committed manifest, and check (CI) now validates the template instead: every data source names an EVM contract and none sets network, address or startBlock. The old subgraph.yaml consumer is removed.

The template is not named subgraph.yaml. graph-cli defaults to subgraph.yaml, so only a generated, validated manifest ever has that name. codegen and build pass the template path explicitly, and a new evm/subgraph/matchstick.yaml sets manifestPath: ./subgraph.template.yaml for graph test (Matchstick 0.6.0 reads manifestPath in src/config.rs). Matchstick uses the manifest for the schema location, templates and handlers, not for addresses, so the tests do not need a network.

Changes

  • scripts/deployment-manifest/src/subgraph.ts (new): templateErrors, renderSubgraph (template + record, all checks above), generateSubgraph(network) (reads the files), generatedNetwork (for --check).
  • src/cli.ts: new subgraph --network <slug> / subgraph --check command and usage text. package.json: npm run subgraph.
  • src/manifest.ts: the per-file part of loadRecords moves into readRecord(chain, file), so loadRecords and the generator share it. Behaviour of loadRecords is unchanged.
  • src/consumers.ts: the subgraph.yaml consumer is replaced by a subgraph.template.yaml consumer.
  • evm/subgraph: subgraph.yaml renamed to subgraph.template.yaml; .gitignore ignores the generated /subgraph.yaml; package.json gets manifest, codegen/build point at the template, deploy/deploy-local run manifest -- --check first; matchstick.yaml added.
  • evm/scripts/deploy.ts: the closing hint now prints the generate command (relative to evm/, where the script runs) instead of "Update evm/subgraph/subgraph.yaml to match"; the network slug is computed once.
  • .prettierignore: ignores the generated subgraph.yaml, like the other generated subgraph paths.
  • src/manifest.ts readRecord also reports a record that is valid JSON but not an object (for example null) instead of throwing.
  • Docs: deployments/README.md (consumer table, a "Subgraph manifest" section, commands table), evm/subgraph/README.md (a "graph-cli manifest" section, structure, horizen-testnet status), evm/README.md (subgraph and deployment sections).

Tests

scripts/deployment-manifest/test/check.e2e.test.ts, run through the CLI against a temporary copy of the repository, like the existing tests:

  • subgraph > refuses the checked-in horizen-testnet record, naming the three contracts it lacks: exit 1, names WraithNames, WraithSender and WraithWithdrawer, does not mention the Announcer or Registry, writes no file.

  • subgraph > fills network, address and start block from a record with every contract: the horizen-testnet record plus the three missing contracts (made-up addresses and blocks, only inside the temporary copy). Checks each data source's network, source.address and source.startBlock against the record, and that with those three keys removed every data source and the top-level keys equal the template.

  • subgraph > fails when a contract has no start block and ... has start block 0.

  • subgraph > fails when a contract has the placeholder address.

  • subgraph > fails for a network without a deployment record.

  • subgraph > --check passes only while the generated manifest matches the template and record: fails before generation, passes after, fails after a hand edit, and fails once the record loses a contract.

  • check > fails when the subgraph template address drifts and ... contract drifts replace the two subgraph.yaml drift cases: a 0x…dead address written into the template, and a source.abi that is not a catalogue contract.

  • subgraph > --check refuses a manifest whose data sources name more than one network.

  • subgraph > lists every problem of a contract, not only the first (start block 0 and the placeholder address together).

  • subgraph > reports a record that fails validation and writes nothing and ... that is not a JSON object.

  • subgraph > refuses a template with dynamic data source templates.

  • subgraph > refuses a network that is not a slug, ... neither --network nor --check, ... both --network and --check.

Negative check: in a temporary worktree of this branch with scripts/deployment-manifest/src and package.json reset to develop (tests and template from this branch), 18 of the 43 tests fail and the other 25 pass.

Commands

All on macOS, Node 22.23.3. Dependencies installed with npm ci --ignore-scripts.

scripts/deployment-manifest (what the Deployment Manifest workflow runs):

  • npm run typecheck: pass.
  • npm test: 43 passed. Develop has 28; the two subgraph.yaml drift cases are replaced by the two template cases, and 15 tests are new.
  • npm run check: ✓ manifest valid; 3 deployments; 8 consumers agree. On develop the same command also passes, with the three placeholders in subgraph.yaml.
  • Negative check above: 18 failed, 25 passed.

evm (the EVM job; it runs because evm/ changed):

  • npx prettier --check --ignore-path ../.prettierignore .: pass.
  • npm run validate-subgraph: pass (unchanged, instant configs only).
  • evm/subgraph: npm run codegen and npm run build from the template: pass. generated/ is identical to develop's, and build/ differs only in build/subgraph.yaml, which no longer has network, address and startBlock.
  • evm/subgraph: a manifest generated from the five-contract fixture, built with graph build: pass; compared with develop's build, only the three placeholder addresses and start blocks differ.
  • npm run deploy -- <name> --node <url> with nothing generated, and npm run deploy-local with a manifest generated from the fixture but checked against the real horizen-testnet record: both exit 1 at manifest -- --check, before graph deploy.
  • Not run locally: npm test in evm/subgraph (Matchstick downloads and runs its own binary, which I did not do here). Matchstick 0.6.0 reads manifestPath from matchstick.yaml (src/config.rs) and uses the manifest only for the schema path, templates and handler names, none of which change. The EVM job runs it on this PR.
  • Also not run locally: hardhat compile/hardhat test, the Foundry invariant tests and gas snapshot, and Slither. This PR changes no Solidity, test or Foundry file; deploy.ts only changes a log line.

Open questions

  • Start block 0 is rejected, to match validate-config.js. The schema allows 0; say if you want it accepted.
  • Once [Wave 10][Carryover] Complete the EVM deployment manifest contract set #231 lands, CI could run npm run subgraph -- --network <slug> for every EVM record, so a record that misses a contract fails CI instead of at deploy time. I left it out because it would fail on develop today.
  • The generator sets network on data sources only and refuses a template with templates:. There are none today; if dynamic data sources are added, the generator should set their network too.

… record

evm/subgraph/subgraph.yaml still carried 0x...dead placeholder
addresses for WraithNames, WraithSender and WraithWithdrawer, and both
checks let them through: the manifest consumer skipped placeholders for
contracts missing from the manifest, and validate-config.js only reads
the instant configs.

subgraph.yaml becomes subgraph.template.yaml, without network,
addresses or start blocks. `npm run subgraph -- --network <slug>` in
scripts/deployment-manifest (`npm run manifest` in evm/subgraph) fills
them in from deployments/evm/<slug>.json and writes subgraph.yaml,
which is git-ignored. It writes nothing and names every offending
contract if a data source's contract is not recorded, has no start
block or start block 0, or has the placeholder address. `--check`
fails unless an existing subgraph.yaml is exactly what the generator
writes now for its network; `deploy` and `deploy-local` run it before
graph deploy.

codegen, build and test read the template (matchstick.yaml sets
manifestPath), so CI needs no deployment. The manifest check validates
the template instead of subgraph.yaml: every data source must name an
EVM contract and must not set network, address or startBlock.

horizen-testnet records only the Announcer and Registry, so generation
for it fails, naming the other three, until they are recorded.
@drips-wave

drips-wave Bot commented Oct 17, 2026

Copy link
Copy Markdown

@izzetemredemir 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

@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.

Deployment manifest subgraph generation is structured, fail-closed on missing records, and passes 43 focused tests plus typecheck. Approved.

@truthixify
truthixify merged commit 0f20a63 into wraith-protocol:develop Oct 17, 2026
21 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.

[Wave 10][Carryover] Generate deployable subgraph configuration from the deployment manifest

2 participants