Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 154 additions & 0 deletions .github/workflows/manual-subgraph-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
name: Subgraph manual deploy
Comment thread
coderabbitai[bot] marked this conversation as resolved.
on:
workflow_dispatch:
inputs:
metadata-ref:
description: >-
rain.metadata ref to take the subgraph SOURCE from. The manifest, schema and mappings are not in this repo; only networks.json is.
required: false
default: main
# Read-only, stated rather than left to the repo default. This job fetches and
# then RUNS another repo's `package.json` install scripts, so the ambient
# `GITHUB_TOKEN` is reachable from code this repo did not review; nothing here
# needs to write anything back.
permissions:
contents: read
# One deploy at a time. `GOLDSKY_SUBGRAPH_NAME` is a single name, so two
# dispatches publish over each other. Never cancelled: a half-finished
# seven-network loop leaves Goldsky holding some networks from one run and some
# from the other, which is worse than waiting.
concurrency:
group: subgraph-manual-deploy
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
env:
GOLDSKY_TOKEN: ${{ secrets.CI_GOLDSKY_TOKEN }}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
GOLDSKY_SUBGRAPH_NAME: metaboard
Comment thread
coderabbitai[bot] marked this conversation as resolved.
steps:
# `persist-credentials: false` on both checkouts: the fetched subgraph
# source's install scripts run in this job, and a git config holding the
# token is one `git config --get` away from them. Nothing here pushes.
- name: Checkout repository
uses: actions/checkout@v6
Comment thread
coderabbitai[bot] marked this conversation as resolved.
with:
fetch-depth: 0
persist-credentials: false
# The subgraph is split on whether a file carries a deployment fact
# (rainlanguage/rain.metadata#149). This repo holds `networks.json` and
# nothing else under `subgraph/`; the manifest, schema, mappings and
# package lock are SOURCE and live in the library half. They are fetched
# rather than duplicated, so there is one copy of each and it is the one
# matchstick runs against.
- name: Checkout the subgraph source
uses: actions/checkout@v6
with:
repository: rainlanguage/rain.metadata
ref: ${{ inputs.metadata-ref }}
path: .subgraph-source
persist-credentials: false
- uses: nixbuild/nix-quick-install-action@v30
with:
nix_conf: |
keep-env-derivations = true
keep-outputs = true
- name: Restore and save Nix store
uses: nix-community/cache-nix-action@v7
with:
primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }}
restore-prefixes-first-match: nix-${{ runner.os }}-
gc-max-store-size-linux: 1G
# Merged INTO `subgraph/` rather than over it: this repo's own
# `networks.json` has to survive, and the library must not be shipping one
# of its own to shadow it. Both are asserted, because a silent shadow
# would deploy whatever table the library happened to carry.
- name: Assemble the subgraph
run: |
set -euo pipefail
if [ -e .subgraph-source/subgraph/networks.json ]; then
echo "::error::rain.metadata ships a networks.json; it would shadow this repo's deploy record"
exit 1
fi
cp -R .subgraph-source/subgraph/. subgraph/
test -f subgraph/networks.json
test -f subgraph/subgraph.yaml
source_sha="$(git -C .subgraph-source rev-parse HEAD)"
echo "subgraph source: rainlanguage/rain.metadata@${source_sha}"
echo "Subgraph source: [rain.metadata@\`${source_sha}\`](https://github.com/rainlanguage/rain.metadata/commit/${source_sha})" >> "$GITHUB_STEP_SUMMARY"
# The manifest reads its ABI out of `out/`, which is a forge build of the
# interface it arrives with as a soldeer dependency, so the dependencies
# have to be on disk and compiled before `graph build` can read anything.
- name: Build the ABI the manifest reads
run: |
nix develop github:rainlanguage/rainix#sol-shell -c forge soldeer install
nix develop github:rainlanguage/rainix#sol-shell -c forge build
# Fail here rather than part way through a seven-network Goldsky loop: the
# manifest's ABI paths are a cross-repo coupling and this is the first
# place they can be resolved. Read out of the manifest with `yq` rather
# than grepped for: `file:` also names the schema and the mapping, and a
# grep that matched one of those would report success having checked a
# path that was never in question.
- name: Check the manifest ABIs resolve
run: |
nix develop --command bash -c '
set -euo pipefail
abis="$(yq -r ".dataSources[].mapping.abis[].file" subgraph/subgraph.yaml)"
test -n "$abis"
while read -r abi; do
echo "manifest ABI: $abi"
test -f "subgraph/$abi"
done <<< "$abis"
'
# `subgraph-deploy` runs `npm ci` and then `graph build --network`, and
# `graph build` does NOT codegen. It compiles `src/metaBoard.ts`, which
# imports `../generated/metaboard0/MetaBoard` and `../generated/schema` —
# generated files, gitignored in the library half, so they never arrive
# with the fetched source. Without this step the AssemblyScript compile
# fails on two unresolved imports for every network in the loop.
#
# `npm ci` here is the same install `subgraph-deploy` repeats. It removes
# `node_modules` and not `generated/`, so the types survive into it.
- name: Generate the subgraph types
run: nix develop --command bash -c 'cd subgraph && npm ci && graph codegen'
- name: Deploy and capture URLs
id: deploy
run: |
set -o pipefail
nix develop --command subgraph-deploy 2>&1 | tee deploy.log
echo
# `subgraph-deploy` skips a network whose version Goldsky already
# holds, and prints no URL for it. A re-dispatch that skips every
# network is a SUCCESSFUL no-op matching nothing, and `grep` answers
# no-match with exit 1 — which `pipefail` plus the runner's `-e` would
# read as a failed deploy. So exit 1 is folded into an empty list, and
# only exit 1: anything above it is `grep` failing rather than not
# matching, and still fails the step.
matched=0
grep -oE 'https://api\.goldsky\.com/api/public/[^[:space:]]+/gn' deploy.log > matched_urls.txt || matched=$?
if [ "$matched" -gt 1 ]; then
exit "$matched"
fi
sort -u matched_urls.txt > deployed_urls.txt
echo "::group::Deployed Goldsky URLs"
cat deployed_urls.txt
echo "::endgroup::"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
# Into the run summary as well as the log: `deployed_urls.txt` lives
# in the runner workspace and is gone with it, and the log is where
# nobody looks for the one fact a deploy produces. The summary already
# names the source commit these URLs were built from, so the two sit
# together and the pair survives the runner.
#
# The empty case is spelled rather than left as an empty list: a
# summary reading "Deployed:" and then nothing looks like a broken
# step rather than the no-op it is.
{
echo
if [ -s deployed_urls.txt ]; then
echo "Deployed:"
echo
sed 's|^|- |' deployed_urls.txt
else
echo "Deployed: nothing. Every network already held this version."
fi
} >> "$GITHUB_STEP_SUMMARY"
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,15 @@ result
dependencies
remappings.txt
.pre-commit-config.yaml
<<<<<<< HEAD

# `subgraph/networks.json` is the only file this repo owns under `subgraph/`.
# The `Subgraph manual deploy` workflow fetches the SOURCE from rain.metadata
# and merges it in here, then `graph build` writes `build/`, `generated/` and
# `node_modules/` beside it and rewrites the manifest in place. All of that is
# transient and none of it is this repo's to commit.
/subgraph/*
!/subgraph/networks.json
=======
target
>>>>>>> origin/main
1 change: 1 addition & 0 deletions .soldeerignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ CLAUDE.md
/remappings.txt
/slither.config.json
/soldeer.lock
/subgraph
/REUSE.toml
/script
/test
31 changes: 27 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ rain.metadata.deploy is the **deploy half** of `rain.metadata`: the concrete
`MetaBoard` (an `IMetaBoardV1_2` that is nothing but one delegation per entry
point into `LibIMetaBoardV1_2`) plus its deployed address + codehash pins. The
`IMeta*` **interfaces and the metaboard logic are NOT here** — they live in
`rain.metadata` and arrive as the `rain-metadata` Soldeer dependency
(`dependencies/rain-metadata-<version>/src/`). The metaboard subgraph is not
here either; it stays in `rain.metadata`, as do the metadata rust crates. The
one crate here reports on Goldsky deploys, and is not metadata logic.
`rain.metadata` and arrive as the `rain-metadata` Soldeer dependency. The
subgraph SOURCE and the metadata rust crates stay in `rain.metadata`. Here: the
subgraph's deployment record — see below — and one crate reporting on Goldsky
deploys, which is not metadata logic.

## Conventions an agent would get wrong

Expand Down Expand Up @@ -42,6 +42,29 @@ one crate here reports on Goldsky deploys, and is not metadata logic.
`src/lib/LibMetaBoardReleased.sol`, `src/lib/LibReleasedSuites.sol`) — do not
hand-edit; `script/Build.sol` regenerates them.

## The subgraph: one file here (#2, recut by rain.metadata#149)

- `subgraph/networks.json` (per-network address + start block) is a deploy
record and the WHOLE of this repo's share. Manifest, schema, mappings and
matchstick suite are SOURCE and stay in `rain.metadata`, which pins the
manifest to the interface it indexes. `Subgraph manual deploy` fetches that
source (`metadata-ref`) and merges it in beside the table, and `graph build`
rewrites the manifest in place — hence `.gitignore` ignores all of `subgraph/`
except the table. Nothing else here runs a subgraph command.
- The table names the **0.1.0** `MetaBoard` (`0x8fD50fF9...`) — this repo's own
frozen release — on all seven deploy networks, each `startBlock` the chain's
verified deploy block (#4). The v1 board (`0xfb8437Ae...`) survives here only
in git history.
- `SubgraphDeployRecord.t.sol`'s release-coverage assertion armed at
`sol-v0.1.0`: every frozen release must be indexed on every indexed network,
or the suite is red.
- The Graph and `LibRainDeploy` spell chains differently (`matic`/`polygon`,
`arbitrum-one`/`arbitrum`). Adding a network to `networks.json` means adding
its mapping in that test in the same change, or it fails closed.
- The Goldsky version is `<address>-<short commit of THIS repo>`, not of the
source, so two dispatches from one commit against different `metadata-ref`s
collide and the second is skipped as already deployed (rainix#354).

## Release / deploy shape

- The on-chain deploy is a human-dispatched `Manual sol artifacts` run
Expand Down
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,36 @@ Consumers that need only the interfaces or the libraries depend on
`rain-metadata`; consumers that need the deployed address/codehash pins depend
on `rain-metadata-deploy`.

## Subgraph

`subgraph/networks.json` is a deployment record in JSON — a per-network table of
the deployed MetaBoard address and start blocks — which is the same class of
fact as `src/generated/<tag>/`, so it belongs with the deploy records rather
than with the interfaces
([#2](https://github.com/rainlanguage/rain.metadata.deploy/issues/2)).

It is the only file this repo holds under `subgraph/`. The manifest, schema,
mappings and matchstick suite are subgraph SOURCE and stay in `rain.metadata`
([rain.metadata#149](https://github.com/rainlanguage/rain.metadata/issues/149)),
whose `subgraph.yaml` is a template carrying no address, start block or real
network name. `graph build --network <x>` fills all three from the table beside
it.

Because the table and the deploy records are in one tree, they are checked
against each other: `test/src/subgraph/SubgraphDeployRecord.t.sol` holds the
network table to `LibMetaBoardReleased` and to the networks this repo broadcasts
to. It is a Solidity test in the ordinary `rainix-sol` lane, so it runs without
docker, node or matchstick.

Deploys are manual. The `Subgraph manual deploy` workflow (`workflow_dispatch`,
with a `metadata-ref` input naming the subgraph source revision) checks out that
source, merges it in beside `networks.json`, builds the ABI the manifest reads,
and publishes to Goldsky under the subgraph name `metaboard`.

The Cynic GraphQL client that _consumes_ this subgraph (`crates/metaboard`,
published as `rain-metaboard-subgraph`) stays in `rain.metadata`: it is keyed by
endpoint URL and has no address or Goldsky coupling.

## Releases

This is a deploy repo: releases are **manual `sol-v*` tags**, not merges.
Expand Down
1 change: 1 addition & 0 deletions REUSE.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ path = [
"flake.nix",
"foundry.toml",
"slither.config.json",
"subgraph/**/",
"REUSE.toml",
"soldeer.lock",
".soldeerignore",
Expand Down
18 changes: 13 additions & 5 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,21 @@ evm_version = "cancun"
bytecode_hash = "none"
cbor_metadata = false

# `script/Build.sol` writes the generated candidate snapshot and the generated
# libs under `src/`, and reads the release version from this file when
# `cutRelease()` runs. `MetaBoardDeploySnapshotTest`'s inherited frozen-record
# walk reads `src/generated/` too, so tests need the same read access. Nothing
# else in this repo touches the filesystem.
# The filesystem access in this repo. `script/Build.sol` writes the generated
# candidate snapshot and the generated libs under `src/`, and reads the release
# version from this file when `cutRelease()` runs;
# `MetaBoardDeploySnapshotTest`'s inherited frozen-record walk reads
# `src/generated/` too, so tests need the same read access.
# `test/src/subgraph/SubgraphDeployRecord.t.sol` reads the deploy record under
# `./subgraph`. That grant is the directory rather than the one file because
# `.gitignore` already states the boundary — this repo owns `networks.json`
# there and nothing else under it is committed — and read-only, so no Forge
# cheatcode can write into it. That is the whole of what `fs_permissions`
# governs: the deploy workflow drops the fetched subgraph source beside the
# table with its own `cp -R`, which this file has no say over.
fs_permissions = [
{ access = "read", path = "./foundry.toml" },
{ access = "read", path = "./subgraph" },
Comment thread
coderabbitai[bot] marked this conversation as resolved.
{ access = "read-write", path = "./src" },
]
libs = ["dependencies"]
Expand Down
44 changes: 44 additions & 0 deletions subgraph/networks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"matic": {
"metaboard0": {
"address": "0x8fD50fF9Db9835ba1B61394752A26F53D721D2a1",
"startBlock": 92426181
}
},
"arbitrum-one": {
"metaboard0": {
"address": "0x8fD50fF9Db9835ba1B61394752A26F53D721D2a1",
"startBlock": 496974800
}
},
"base": {
"metaboard0": {
"address": "0x8fD50fF9Db9835ba1B61394752A26F53D721D2a1",
"startBlock": 50277465
}
},
"base-sepolia": {
"metaboard0": {
"address": "0x8fD50fF9Db9835ba1B61394752A26F53D721D2a1",
"startBlock": 45787995
}
},
"flare": {
"metaboard0": {
"address": "0x8fD50fF9Db9835ba1B61394752A26F53D721D2a1",
"startBlock": 67943188
}
},
"hyperevm": {
"metaboard0": {
"address": "0x8fD50fF9Db9835ba1B61394752A26F53D721D2a1",
"startBlock": 43806327
}
},
"mainnet": {
"metaboard0": {
"address": "0x8fD50fF9Db9835ba1B61394752A26F53D721D2a1",
"startBlock": 25805918
}
}
}
Loading
Loading