Skip to Content
ReferenceSDKMainnet Follow

Mainnet Follow

Pin contract state to the live chain your Stagenet forks. A followed account or slot always reads the current mainnet value — even after transactions on your Stagenet have written to it.

Use this to stop market state from freezing and drifting on a long-lived Stagenet:

  • Keep DEX pool prices live, so aggregator quotes (computed against mainnet) keep matching what your fork executes.
  • Keep a market maker’s inventory live, so RFQ fills don’t start reverting after heavy testing.
  • Keep oracle data fresh.

Your own wallets, deployments, and balances keep persisting normally. For the full mechanics, see Mainnet Follow.

How it works

Following is a standing mode, not a one-shot copy:

  • Reads of a followed key always return the live mainnet value.
  • Writes still work normally within a transaction (and block) — protocols that write-then-read their own state behave correctly — but are discarded at block seal. The next block reads mainnet again.
  • The follow registry survives Stagenet restarts.

followAccount / unfollowAccount

Follow everything on a contract: every storage slot, plus the account record (ETH balance, nonce) and its code. Use for contracts holding only market state — AMM pools, settlement contracts, oracles.

import createStagenet from "contract.dev"; const stagenet = createStagenet(); // reads contract.dev.js // A Uniswap pool your routes trade through: price/reserves stay live forever. await stagenet.followAccount("0xc9034c3E7F58003E6ae0C8438e7c8f4598d5ACAA"); // Later: await stagenet.unfollowAccount("0xc9034c3E7F58003E6ae0C8438e7c8f4598d5ACAA");
ParameterTypeDescription
addressstring0x-prefixed contract address

Returns { address, followed, residueCleared }residueCleared is the number of previously-persisted local slots that were removed (any locally-persisted account record or code is cleared as well). Unfollowing clears local history too, so the contract behaves as never-touched.

Don’t followAccount a token: balanceOf holds user balances alongside market inventory, and following the whole contract would stop your balances from persisting. Use followTokenBalance instead.

followTokenBalance / unfollowTokenBalance

Follow one holder’s balance on a token — the slot is discovered automatically (works with proxies and non-standard layouts). Other balances on the token are untouched.

// Keep an RFQ market maker's USDC inventory live: const res = await stagenet.followTokenBalance( "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC "0x67336CeC42645F55059efF241CB02eA5cC52FF86", // the maker ); console.log(res.slot); // the discovered balanceOf slot
ParameterTypeDescription
tokenstringERC20 contract address
holderstringThe holder whose balance should track mainnet

Returns { token, holder, slot, residueCleared }.

followSlots / unfollowSlots

Follow specific storage slots when you know the keys (allowances, custom mappings, packed words). Mapping entries take the full 32-byte hex key; declared slots can be plain decimal.

await stagenet.followSlots("0xA0b8…eB48", [ "0x6e91f60197c982353033e86512311820683e018e0f39963c5d00c2c490bc45d3", ]); // Declared slots by number — e.g. a V3 pool's slot0 and fee-growth accumulators: await stagenet.followSlots("0xc903…ACAA", [0, 1, 4]);
ParameterTypeDescription
addressstringContract address
slots(string | number | bigint)[]0x-prefixed 32-byte slot keys, or decimal slot numbers (10 is slot ten, not 0x10)

Returns { address, followedSlots, residueCleared }.

getFollowed

Everything currently followed on the Stagenet.

const followed = await stagenet.getFollowed(); // { accounts: ["0xc903…"], slots: { "0xa0b8…": ["0x6e91…"] } }
Last updated on