graphprotocol / graphprotocol/contracts

CI does not pin Foundry: forge 1.8 breaks the issuance callback gas canary

Open Beginner friendly
#1,361 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Solidity
Stars
374
Forks
176
Avg merge
1d 15h
Merged PRs (30d)
4

Description

Summary

On a clean checkout of main, pnpm test fails for anyone running Foundry 1.8.x:

packages/issuance/test/unit/agreement-manager/callbackGas.t.sol
  test_AfterCollection_GasWithinBudget_CanceledBySP
  [FAIL: afterCollection (canceled by SP) exceeds 1/10th of callback gas budget: 181458 >= 150000]

Not a contract regression — the bytecode is unchanged. Foundry 1.8 changed warm/cold storage
accounting across calls within a test body, and the canary was relying on the old behaviour.

Bisect

Same commit, same solc_version = '0.8.35' / evm_version = 'cancun', only the forge binary changed:

forge result
v1.4.0 PASS
v1.5.0 PASS
v1.7.0 PASS
v1.8.0 FAIL — 181,458
v1.8.1 FAIL — 181,458

Mechanism

From -vvvv traces of the identical test:

forge 1.7.0 forge 1.8.1
distributeIssuance() 5,424 31,124
afterCollection() 89,772 191,772

setUp() and _offerAgreement() touch the allocator, token account and escrow slots before the
measured call. Under ≤1.7 those stayed warm into afterCollection; under 1.8 they are cold and
pay full EIP-2929 cost. I have not confirmed against the 1.8 changelog whether this was
deliberate, though it looks intentional — the callback is its own transaction in production,
where cold slots are the honest baseline.

Why CI hasn't caught it

.github/actions/setup/action.yml:14 uses foundry-rs/foundry-toolchain@v1 with no version,
which defaults to stable. The cache input doesn't pin it either (cache-key is per-SHA).

Triage note: the green checks on main aren't evidence against this. The latest
build-test.yml run is 2026-08-26T20:03:43Z; forge 1.8.1 was built 2026-08-28. No CI run has
executed against 1.8.x yet because no PR has opened since. The next PR will surface it, as a
mystery failure in a package the author didn't touch.

Suggested fix

- uses: foundry-rs/foundry-toolchain@v1
  with:
    version: v1.7.0

Separately, worth deciding what the canary should measure. Its stated intent is catching RAM code
getting heavier, but under ≤1.7 roughly 60k of its slack came from warm-slot carryover rather than
lean code. Since the production callback runs as its own transaction, 181k is closer to real than
89k — so the true margin against MAX_CALLBACK_GAS is thinner than the suite has reported. Either
re-baseline against cold accounting or warm the slots deliberately in setUp.

Minor, related

README.md:52 lists only git and pnpm as prerequisites. Foundry is required — horizon,
subgraph-service, issuance and testing all shell out to forge, and the first two need it at
compile time via hardhat-foundry. Following the README as written, pnpm build fails with
Error in plugin hardhat-foundry: Couldn't run 'forge', which doesn't name the missing prerequisite.

Environment

forge 1.8.1 (982849d314) / 1.8.0, compared against 1.7.0 / 1.5.0 / 1.4.0 · Node v24.20.0 · pnpm 10.28.0 · WSL2

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with .github/actions/setup/action.yml:14 and inspect how the Foundry toolchain action receives its version and cache settings. Run pnpm test with the current CI toolchain to reproduce the callbackGas.t.sol failure, then verify that CI uses a pinned Forge version and the issuance gas canary passes; the separate cold-accounting and README concerns need maintainer direction.

Written by the indexing model from the issue text.

Assessment

Tech stack
github-actions, solidity
Domain
ci-cd, testing
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.