Skip to content

fix(curation): count curator fees in the network signal total - #336

Open
MoonBoi9001 wants to merge 7 commits into
masterfrom
mb9/count-curator-query-fees-in-network-signal-total
Open

MoonBoi9001 wants to merge 7 commits into
masterfrom
mb9/count-curator-query-fees-in-network-signal-total

Conversation

@MoonBoi9001

@MoonBoi9001 MoonBoi9001 commented Sep 28, 2026 •

Copy link
Copy Markdown
Member

Motivation

When an indexer collects query fees, a cut goes into that deployment's curation pool. That adds GRT to the pool without creating new shares, so every curator's shares become worth more. The subgraph was adding that GRT to the deployment's own signalledTokens but not to the network-wide totalTokensSignalled, so the network total fell further behind with every fee paid.


This PR counts curator query fees in totalTokensSignalled and its auto-migrating and direct split. A deployment grafted from an earlier version adds the fees it missed back to the total once and, on Arbitrum, re-splits it by the current value of the GNS contract's shares. Those fees raised each deployment's signal but not the network total, which had fallen behind by 1,801,315 GRT on Arbitrum by 2026-09-25.

Curator fees paid into a curation pool raised each deployment's signal but not totalTokensSignalled,
so the total fell behind by every fee ever paid: 1,801,315 GRT on Arbitrum by 2026-09-25.
The fee test only had a pool with no GNS signal. This one gives the GNS contract a quarter of a
pool and checks it takes a quarter of the fees as auto-migrating signal.
A deployment grafted from a version that left curator query fees out of totalTokensSignalled
inherits a total short by exactly the fees paid so far, so add them back once and record it.
Lint flagged these imports as unused in files this branch already touches.
Network signal is split into GRT curated through the GNS contract and GRT curated directly.
Adding past fees to the total alone left the 2 parts 1,801,315 GRT short of it on Arbitrum, so
the GNS part is reset to what its shares are worth and direct gets the rest. L1 is unchanged.
The one-time step that adds back past curator fees walks every pool the GNS contract curates.
Saving straight away stops each later handler in the same block from repeating that walk.
Removes 3 commented-out helper functions, shortens 2 comments that ran long, and wraps 2 test
lines that were wider than the formatter's 100-character limit.
Comment on lines +693 to +696
let graphNetwork = GraphNetwork.load('1')!
countPastCurationFeesInSignal(graphNetwork)
return graphNetwork
}

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.

I'd rather keep this as it was, instead of adding a graft specific calculation.
As mentioned via Slack, grafting long term is an antipattern, so we can (and should) always assume we are indexing the data from scratch :)

// Versions that left curation fees out of totalTokensSignalled fell short by exactly the fees paid,
// and a graft inherits that, so add them back once and re-split the total by the value of the GNS
// contract's shares. Not on L1, which subtracts signal sent to L2 twice, so this would not match.
function countPastCurationFeesInSignal(graphNetwork: GraphNetwork): void {

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.

Remove this

graphNetwork.save()
}

function splitSignalByGnsShareValue(graphNetwork: GraphNetwork): void {

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.

Remove this

graphNetwork.totalTokensSignalled = BigInt.fromI32(0)
graphNetwork.totalTokensSignalledAutoMigrate = BigDecimal.fromString('0')
graphNetwork.totalTokensSignalledDirectly = BigDecimal.fromString('0')
graphNetwork.curationFeesInSignalTotal = true

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.

Remove this


graphNetwork.save()
}
countPastCurationFeesInSignal(graphNetwork)

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.

Remove this

graphNetwork: GraphNetwork,
deployment: SubgraphDeployment,
fees: BigInt,
): void {

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.

I don't exactly remember if this is still an issue with graph node, but at some point in order for graph-node to properly update your entities when modifying them in a separate function, you had to return the "new" updated entity, and reassign them to your variable. I'm like 95% sure this doesn't happen anymore, but potentially worth checking. I'll explain in the next line.

Comment thread src/mappings/staking.ts
graphNetwork.totalCuratorQueryFees = graphNetwork.totalCuratorQueryFees.plus(
event.params.curationFees,
)
addCurationFeesToNetworkSignal(graphNetwork, deployment, event.params.curationFees)

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.

As mentioned above, at some point, you used to need to do this:
graphNetwork = addCurationFeesToNetworkSignal(graphNetwork, deployment, event.params.curationFees)
Or graph node would not properly save the modifications done in the addCurationFeesToNetworkSignal function.

Unsure if that's still a thing, but worth mentioning.

Comment thread src/mappings/staking.ts
graphNetwork.totalCuratorQueryFees = graphNetwork.totalCuratorQueryFees.plus(
event.params.curationFees,
)
addCurationFeesToNetworkSignal(graphNetwork, deployment, event.params.curationFees)

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.

Same as the last comment

graphNetwork.totalCuratorQueryFees = graphNetwork.totalCuratorQueryFees.plus(
event.params.tokensCurators,
)
addCurationFeesToNetworkSignal(graphNetwork, deployment, event.params.tokensCurators)

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.

Same as the last comment

Comment thread schema.graphql
Comment on lines +109 to +110
"Whether totalTokensSignalled, and on Arbitrum its auto-migrating and direct parts, include every curator query fee paid into curation pools. Unset only on a deployment grafted from a version that left them out, until its next update adds them"
curationFeesInSignalTotal: Boolean

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.

Not needed anymore

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.

2 participants