AIOUM subgraph
Mirrored from
subgraph/README.mdin the repository — edit that file, not this page.
A Graph Protocol subgraph for AIOUM discovery & analytics. It indexes services, payment sessions, staking/delegation, reputation and identities into queryable GraphQL entities.
What it indexes
| Contract | Events | Entities touched |
|---|---|---|
ServiceRegistry | ServiceRegistered, ServiceUpdated | Node, Service |
PaymentManager | SessionOpened, SessionSettled, SessionReclaimed, SessionDisputed | Node, Service, Session |
StakingManager | Staked, Delegated, RewardNotified, Slashed | Node, Delegation |
ReputationRegistry | SettlementRecorded, FeedbackSubmitted | Reputation, Feedback |
IdentityRegistry | Registered | Identity |
DisputeManager, the arbitrators | DisputeRaised, DisputeResolved, votes, commits, reveals | Dispute, DisputeVote, DisputeCommit |
EndpointRegistry | EndpointSet, EndpointCleared | Endpoint (a node's address and certificate pin) |
OperatorSigners | SignerSet, SignerCleared | Signer |
ReviewManager | ReviewRequested, ReviewFinalized | PaidReview |
AIOUMToken | Transfer | TokenHolder, TokenTransfer, TokenStats |
Entities: Node, Service, Session, Delegation, Feedback, Reputation, Identity, Dispute,
Endpoint, Signer, PaidReview, TokenHolder, TokenTransfer, TokenStats, with Protocol and the
per-asset stats as the totals. With these, a front-end runs from an RPC and this subgraph alone: the app
reads them when NEXT_PUBLIC_SUBGRAPH_URL names a graph-node that serves this subgraph (dapp/lib/subgraph.ts).
All mapping handlers are idempotent (load-or-create), so reprocessing a block (e.g. after a reorg) never double-counts, and entities referenced before their own "create" event (e.g. a settle before an indexed open) are materialised as stubs.
ABIs
abis/*.json contain only the .abi arrays extracted from the Foundry build
artifacts in ../out/<Contract>.sol/<Contract>.json. To regenerate them after a
contract change:
cd .. # repo root (AIOUM)
for c in ServiceRegistry PaymentManager StakingManager ReputationRegistry IdentityRegistry; do
jq '.abi' "out/$c.sol/$c.json" > "subgraph/abis/$c.json"
done
Base Sepolia
networks.json carries the Base Sepolia deploy of 2026-10-12 (offchain/deployments.84532.json, every
contract from block 48,020,971; no arbitrator contract is deployed there, so those two stay at zero). The
public RPCs for Base Sepolia prune old history and refuse block 0, which graph-node asks for to identify the
chain: give it the deploy block instead with GRAPH_ETHEREUM_GENESIS_BLOCK_NUMBER=48020971, and keep
GRAPH_ETHEREUM_MAX_BLOCK_RANGE_SIZE within what the RPC allows (publicnode: 1000).
npm run codegen && graph build --network base-sepolia
GRAPH_ETHEREUM="base-sepolia:https://base-sepolia-rpc.publicnode.com" GRAPH_MAX_BLOCK_RANGE=1000 GRAPH_GENESIS_BLOCK=48020971 docker compose up -d
npm run create-local
graph deploy --node http://localhost:8020/ --ipfs http://localhost:5001 --network base-sepolia --version-label v0.1.0 aioum/aioum-v2
# then: curl -s localhost:8000/subgraphs/name/aioum/aioum-v2 -d '{"query":"{ protocol(id:\"protocol\") { totalServices settledSessions } }"}'
Any host with Docker runs an indexer the same way: the compose file above, or two containers on their own (Postgres 16 made with
POSTGRES_INITDB_ARGS="-E UTF8 --locale=C", and graph-node started by its image's own script with postgres_host,
postgres_port, postgres_user, postgres_pass, postgres_db, node_id, ipfs=https://api.thegraph.com/ipfs/ and
ethereum=base-sepolia:<rpc>, plus the two GRAPH_ETHEREUM_* settings). An indexer is one of any number: the app takes a
comma-separated list of them in NEXT_PUBLIC_SUBGRAPH_URL and asks the next when one does not answer.
To The Graph's network instead: graph auth <deploy key> then graph deploy --studio aioum-base-sepolia --network base-sepolia;
the query URL it prints goes into the app as NEXT_PUBLIC_SUBGRAPH_URL.
Networks
subgraph.yaml carries network: mainnet as the manifest's network key; the contract
addresses for each target live in networks.json, one key per network. The checked-in
entries hold the zero address with startBlock: 0 until you fill them in for your
deployment.
Before deploying, set the deployed addresses in networks.json (see
../offchain/deployments.json) and the startBlock at which the contracts were deployed,
then re-apply them to the manifest:
graph build --network mainnet # injects networks.json[mainnet] into subgraph.yaml
To index your local development network, point graph-node at http://127.0.0.1:8545
(chainId 31337) and set the addresses from ../offchain/deployments.json:
serviceRegistry→ServiceRegistrypayment→PaymentManagerstaking→StakingManagerreputation→ReputationRegistryidentity→IdentityRegistry
(You may rename the network key to e.g. anvil in both networks.json and the
network: field of every dataSource in subgraph.yaml if your graph-node is
configured with that network name.)
Build & deploy
Install the dependencies first:
cd subgraph
npm install # installs @graphprotocol/graph-cli + graph-ts
Then the standard workflow:
npm run codegen # graph codegen — generates ./generated/* from schema + ABIs
npm run build # graph build — compiles AssemblyScript to WASM
codegen must run before build (and before TypeScript/AssemblyScript will
resolve the ../generated/* imports in src/mappings.ts).
Deploy to a local graph-node
npm run create-local # registers the subgraph name on a local graph-node
npm run deploy-local # graph deploy --node http://localhost:8020/ --ipfs http://localhost:5001
Deploy to a hosted/Studio endpoint
npm run deploy # graph deploy --network mainnet aioum/aioum-v2
Adjust the subgraph slug (aioum/aioum-v2), --node, --ipfs and auth (graph auth)
for your target. See https://thegraph.com/docs for the current Studio flow.
Example queries
# Active services with their node, cheapest first
{
services(where: { active: true }, orderBy: pricePerCall, orderDirection: asc) {
serviceId
category
pricePerCall
node { operator totalStaked totalDelegated active }
}
}
# A node's sessions and settlement split
{
node(id: "0x...") {
operator
totalStaked
sessions {
sessionId
status
deposited
gross
operatorNet
protocolFee
delegatorShare
refund
}
}
}
# Operator reputation roll-up
{
reputations(orderBy: totalVolume, orderDirection: desc) {
client
operator
settlementCount
totalVolume
feedbackCount
scoreSum
}
}