Discrepancy in Total Staked Calculation: StakingRegistry vs. Stake Dashboard

Hi Aztec team and community,

I’m currently building an explorer and indexer for the Aztec network, specifically focusing on on-chain metrics like Total Value Staked, APR, and provider-side analytics.

While indexing the staking data, I’ve encountered a significant discrepancy between my computed totals and the figures displayed on stake.aztec.network. I’ve previously shared some of these points in Discord and Telegram, but I’d like to consolidate them here to get a clearer technical picture.

Current Implementation & Observations

To calculate the total staked amount, I am using the following approach:

Contract: StakingRegistry at 0x35b22e09ee0390539439e24f06da43d83f90e298.

Logic: I iterate through all current providers, scan StakedWithProvider logs for each, and sum the stake.

Assumption: Each successful delegation corresponds to a 200,000 AZTEC stake slot.

The “Other” Category

On the official dashboard stake.aztec.network, there is a row labeled “Other”, which seems to account for a large portion of difference between StakingRegistry Providers calculation and data from staking dashboard. As I understood these are sequencers registered directly (self-staked) rather than through the standard staking provider flow.

Questions:

  1. Source of Truth: What is the recommended on-chain strategy to compute the actual total stake? Does the dashboard pull data from additional contracts or specific events beyond StakedWithProvider in the StakingRegistry?

  2. Handling “Others”: Are there plans to normalize these direct/self-staked sequencers by attributing them to real provider entities or enriching their metadata?

  3. Roadmap: Should indexer developers implement custom logic to separately aggregate these “direct” sequencers now, or is there an upcoming change/fix that will map these into the standard provider structure?

  4. Documentation: Is there a spec or a public tracking issue regarding the “Others” category and how these direct registrations are handled in the long term?

This information is crucial for us to ensure our indexer provides accurate data to the users. Any guidance or links to relevant technical documentation would be greatly appreciated.

Thanks!

1 Like

Hi @m1amgn

  1. Source of Truth: What is the recommended on-chain strategy to compute the actual total stake? Does the dashboard pull data from additional contracts or specific events beyond StakedWithProvider in the StakingRegistry?

The source of truth for the total amount of staked will always be the onchain GSE contract found at 0xa92ecFD0E70c9cd5E5cd76c50Af0F7Da93567a4f

In particular you can query the totalSupply() to figure out the total amount of stake deposited in the system. Etherscan link here.

  1. Handling “Others”: Are there plans to normalize these direct/self-staked sequencers by attributing them to real provider entities or enriching their metadata?

Not at the moment since sequencer registration is permissionless. However, sequencers can self-declare their own metadata on platforms like dashtec.xyz

Questions 3 and 4 were not very clear to me, but if you provide more information I will answer again.

1 Like

Hi @amin,

thank you for your reply.

Can you clarify the following discrepancy for me:

The source of truth for the total amount of staked will always be the onchain GSE contract found at 0xa92ecFD0E70c9cd5E5cd76c50Af0F7Da93567a4f

In particular you can query the totalSupply() to figure out the total amount of stake deposited in the system. Etherscan link here.

According to that smart-contract function total supply of tokens in GSE contract is 357 938 000 AZTEC.

According to https://stake.aztec.network/ total amount of staked tokens is 889 800 000 AZTEC.

The difference is 531 862 000 AZTEC.

So there is some misunderstanding, because if the source of truth can be only GSE contract, that amount doesn’t correlate with amount on official Aztec staking dashboard. Even if we’ll substract amount of “Other” “self-registered sequencers” there won’t be the amount corresponding to GSE total supply.

Questions 3 and 4 were not very clear to me, but if you provide more information I will answer again.

Those questions about fixing that issue of “self-registered” sequencers and line “Other” on Aztec staking dashboard, because fetching and collecting providers staking data is simple job, but trying to find all “self-registered” sequencers is the complex challenge. And I know that Aztec developer team knows about that issue and was planning to fix that by attributing “self-registered” sequencers to real providers. So I was interested in is there a plan of fixing that issue.

@m1amgn

The 889.8m includes all the sequencers who are still in the queue. Their stake has not yet been deposited to the GSE contract. This is good feedback though because it would be helpful to show the total stake deposited vs stake in transit.

Note that this number does not discriminate between self-sequencer and delegated-sequencer registration.

1 Like

Hi,@amin,

Thank you for the clarification! That explains the discrepancy perfectly: Total Stake (Dashboard) = GSE Total Supply + Stake in Queue/Transit + Other.

To make our explorer accurate and aligned with the official dashboard, I have a few follow-up technical questions regarding the “Queue” and “Other” sequencers:

1. Tracking the “Queue” On-Chain

Since the GSE totalSupply() only reflects activated stake, what is the recommended way to track the “in-transit” stake?

  • Which contract/function should I query to see the current queue of sequencers waiting for activation?

  • Are there specific events that I should listen to for “Pending” stake that hasn’t hit the GSE yet?

2. Comprehensive Indexing of “Other”

Since sequencer registration is permissionless and “Other” won’t be normalized into providers, I need to ensure my explorer doesn’t miss them.

  • If a sequencer registers directly (bypassing the standard provider logic), they won’t trigger a StakedWithProvider event in the StakingRegistry.

  • Which “canonical” event should I use as the primary trigger to catch every registration, regardless of whether it’s through a provider or a self-stake?

3. Calculating the Delta

To match the 889.8m figure exactly, should I be looking for a specific state variable in the contracts that tracks “Total Committed Stake,” or is the dashboard manually aggregating InitialDeposit events minus Exited events?

This detail is vital for us to build a reliable “Source of Truth” for the community via our explorer. Thanks again for your help!

Cant say the answer is clear from the above. We are trying to build an explorer, but have some numbers in the economy that dont come together. Would love to get some answers @amin @zac-williamson @koenmtb1

When a sequencer first joins the rollup queue, the following event is emitted by the Rollup contract.

emit IStakingCore.ValidatorQueued(_attester, _withdrawer);

For each sequencer that makes it past the queue and into the active set (i.e. their stake is deposited in the GSE) the following event is emitted from the Rollup contract.

emit IStakingCore.Deposit(
          args.attester, args.withdrawer, args.publicKeyInG1, args.publicKeyInG2, args.proofOfPossession, amount
        );

Note that every sequencer registration emits the previous Deposit event regardless of whether it was delegated stake or a direct registration.

You can find the full code here aztec-packages/l1-contracts/src/core/libraries/rollup/StakingLib.sol at next · AztecProtocol/aztec-packages · GitHub

The dashboard is summing up the current active attesters + those in the queue - finalized exits. Sequencers who have initialized an exit (voluntarily or via a forced slashing exit) are still counted as part of the 889.8m figure until their exit is finalized.

2 Likes

Hi @amin ,

Thank you for the detailed clarifications! Based on your answers and our review of StakingLib.sol,
we’ve designed our indexer approach. Could you please confirm this is correct?

Our understanding:

  1. ValidatorQueued - tokens are already locked in the Rollup contract (via safeTransferFrom before the event). Sequencer is in queue, stake is NOT yet in GSE.
  2. Deposit - tokens are transferred from Rollup to GSE. Sequencer becomes active.
  3. Dashboard counts from ValidatorQueued - as you mentioned, the 889.8m includes sequencers still in queue whose stake hasn’t been deposited to GSE yet.

Our calculation:

Active Sequencers = unique(ValidatorQueued attesters) - unique(WithdrawFinalized attesters)
Total Staked = count(Active Sequencers) × 200,000 AZTEC

For separating delegated vs self-staked:

  • Has ValidatorQueued and StakedWithProvider event → delegated and can be matched to Providers
  • Only ValidatorQueued (no StakedWithProvider) → self-staked

Questions:

  1. Is this approach correct for matching dashboard’s Total Staked?
  2. Is 200,000 AZTEC always the stake amount?
  3. Any edge cases to handle (re-registration after exit, partial withdrawals)?

Thanks!

1 Like

@m1amgn

Yes correct and the tokens eventually end up in the Governance contract, deposited by the GSE.

Correct.

The dashboard doesn’t not filter for unique attesters. Eventually when those duplicate attesters are flushed from the queue, the deposit fails and a DepositFailed event is emitted.

Yes or you can query the Staker contracts themselves for this event:

emit Staked(address(this), _attester, rollup);

ofcourse to do so you’d need to keep track of all Staker contracts that were deployed but either approach should work.

Yes correct, this is defined at the GSE level so even rollup upgrades don’t change the activation threshold unless you also deploy a new GSE which would be a world of pain for sequencers.

2 Likes