Track and analyze proof submissions, slashing events, and validator exits on the Aztec Testnet rollup contract deployed on Sepolia.
This tool indexes events emitted by the Aztec rollup contract to provide statistics on:
- Prover activity: Which provers are submitting epoch proofs and how many
- Slashing events: Which attesters have been slashed and for how much
- Exit tracking: Which attesters have initiated withdrawals and their finalization status
The Aztec rollup contract emits an L2ProofVerified event every time an epoch proof is successfully verified:
event L2ProofVerified(uint256 indexed blockNumber, address indexed proverId);This event is emitted in the submitEpochRootProof function in EpochProofLib.sol (line 124) after:
- Attestations are verified
- The epoch proof is validated
- The proven chain tip is advanced
- Rewards are distributed
The contract also emits a Slashed event when an attester is penalized:
event Slashed(address indexed attester, uint256 amount);This event is emitted in the slash function when:
- An attester is penalized for misbehavior
- The slash amount is deducted from their stake or exit balance
The contract emits withdrawal events when attesters exit the network:
event WithdrawInitiated(address indexed attester, address indexed recipient, uint256 amount);
event WithdrawFinalized(address indexed attester, address indexed recipient, uint256 amount);When an attester initiates a withdrawal, there is a 14-day delay before they can finalize it. The exit mode tracks:
- How many attesters have pending exits
- Which exits can be finalized (14 days elapsed)
- Which exits are still in the waiting period
- A timeline visualization of pending exits
- Node.js (v18 or higher)
- A Sepolia RPC endpoint (from Infura, Alchemy, or another provider)
- The Aztec Testnet rollup contract address on Sepolia
- Clone or navigate to this directory:
cd aztec-prover-stats- Install dependencies:
npm install- Create a
.envfile based on.env.example:
cp .env.example .env- Edit
.envand add your configuration:
SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/YOUR_API_KEY
ROLLUP_CONTRACT_ADDRESS=0xYourAztecRollupContractAddressOptional: Set block range to limit scanning:
START_BLOCK=5000000
END_BLOCK=5100000Run the indexer to scan the blockchain and collect prover statistics:
npm startThis will:
- Connect to Sepolia via your RPC endpoint
- Scan for
L2ProofVerifiedevents in the specified block range - Display statistics in the console
- Save detailed data to
data/prover-stats-{timestamp}.json
To view the most recent prover statistics without re-scanning:
npm run statsThis displays:
- Total number of proofs submitted
- Number of unique provers
- Proof count and percentage per prover
- Visual distribution chart
- Recent block numbers for each prover
Run the indexer in slash mode to scan for slashing events:
npm run slash
# or
npm start slashThis will:
- Connect to Sepolia via your RPC endpoint
- Scan for
Slashedevents in the specified block range - Display slash statistics in the console
- Save detailed data to
data/slash-stats-{timestamp}.json
To view the most recent slash statistics without re-scanning:
npm run slash-stats
# or
npm run stats slashThis displays:
- Total number of slashes
- Total amount slashed (in ETH)
- Number of unique attesters slashed
- Slash count and amount per attester
- Visual distribution chart
Run the indexer in exit mode to scan for withdrawal events:
npm run exit
# or
npm start exitThis will:
- Connect to Sepolia via your RPC endpoint
- Scan for
WithdrawInitiatedandWithdrawFinalizedevents - Fetch block timestamps to calculate finalization eligibility
- Display exit statistics in the console
- Save detailed data to
data/exit-stats-{timestamp}.json
To view the most recent exit statistics without re-scanning:
npm run exit-stats
# or
npm run stats exitThis displays:
- Total withdrawals initiated vs finalized
- Pending exits breakdown (can finalize vs cannot finalize yet)
- Timeline of pending exits with days remaining
- Progress visualization for each pending exit
================================================================================
PROVER STATISTICS
================================================================================
Total proofs submitted: 156
Unique provers: 3
Proofs by Prover:
--------------------------------------------------------------------------------
0x1234...5678: 89 proofs (57.05%)
0xabcd...ef00: 45 proofs (28.85%)
0x9876...5432: 22 proofs (14.10%)
Distribution Chart:
--------------------------------------------------------------------------------
0x1234...5678 ██████████████████████████████████████████████████ 89
0xabcd...ef00 █████████████████████████ 45
0x9876...5432 ████████████ 22
Detailed prover data is saved to data/prover-stats-{timestamp}.json:
{
"scannedAt": "2025-10-13T12:34:56.789Z",
"blockRange": {
"from": 5000000,
"to": 5100000
},
"summary": {
"totalProofs": 156,
"uniqueProvers": 3
},
"provers": [
{
"address": "0x1234...5678",
"proofCount": 89,
"blocks": [
{
"blockNumber": "123",
"txHash": "0xabc...",
"ethBlockNumber": 5012345
}
]
}
]
}Detailed slash data is saved to data/slash-stats-{timestamp}.json:
{
"scannedAt": "2025-10-13T12:34:56.789Z",
"blockRange": {
"from": 5000000,
"to": 5100000
},
"summary": {
"totalSlashes": 5,
"totalAmountSlashed": "50000000000000000000",
"uniqueAttesters": 2
},
"attesters": [
{
"address": "0x1234...5678",
"slashCount": 3,
"totalAmountSlashed": "30000000000000000000",
"slashes": [
{
"amount": "10000000000000000000",
"txHash": "0xabc...",
"ethBlockNumber": 5012345
}
]
}
]
}Detailed exit data is saved to data/exit-stats-{timestamp}.json:
{
"scannedAt": "2025-10-13T12:34:56.789Z",
"currentTimestamp": 1697199296,
"blockRange": {
"from": 5000000,
"to": 5100000
},
"summary": {
"totalInitiated": 10,
"totalFinalized": 7,
"totalPending": 3,
"pendingCanFinalize": 1,
"pendingCannotFinalize": 2,
"uniqueAttesters": 8
},
"pendingExits": [
{
"attester": "0x1234...5678",
"recipient": "0xabcd...ef00",
"amount": "100000000000000000000",
"txHash": "0xabc...",
"ethBlockNumber": 5012345,
"timestamp": 1696000000,
"exitableAt": 1697209600,
"canFinalize": false
}
],
"attesters": [
{
"address": "0x1234...5678",
"initiatedCount": 2,
"finalizedCount": 1,
"totalInitiatedAmount": "200000000000000000000",
"totalFinalizedAmount": "100000000000000000000",
"initiated": [...],
"finalized": [...]
}
]
}The indexer queries events in chunks (default: 10,000 blocks) to avoid RPC provider limits. You can adjust CHUNK_SIZE in src/index.js if needed.
Both event parameters (blockNumber and proverId) are indexed, making queries very efficient. The indexer can filter and retrieve events quickly even across large block ranges.
If you encounter rate limit errors, consider:
- Using a paid RPC provider with higher limits
- Reducing the
CHUNK_SIZEvalue - Adding delays between chunk queries
- Scanning smaller block ranges
aztec-prover-stats/
├── src/
│ ├── abi.js # Contract ABI with all tracked events
│ ├── index.js # Main indexer script (supports slash, exit modes)
│ └── getStats.js # Statistics viewer (supports slash, exit modes)
├── data/ # Generated JSON files (prover-stats-*, slash-stats-*, exit-stats-*)
├── .env # Configuration (not committed)
├── .env.example # Configuration template
├── .gitignore
├── package.json
└── README.md
The L2ProofVerified event is emitted in:
- File:
l1-contracts/src/core/libraries/rollup/EpochProofLib.sol - Function:
submitEpochRootProof() - Line: 124
blockNumber(uint256, indexed): The L2 block number that was provenproverId(address, indexed): The Ethereum address of the prover who submitted the proof
attester(address, indexed): The Ethereum address of the attester who was slashedamount(uint256): The amount of tokens slashed (in wei)
WithdrawInitiated:
attester(address, indexed): The attester initiating the withdrawalrecipient(address, indexed): The address that will receive the fundsamount(uint256): The amount being withdrawn (in wei)
WithdrawFinalized:
attester(address, indexed): The attester whose withdrawal is being finalizedrecipient(address, indexed): The address receiving the fundsamount(uint256): The amount withdrawn (in wei)
Tracking prover activity helps:
- Monitor network decentralization
- Identify active provers
- Analyze proof submission patterns
- Verify prover participation in the network
- Calculate prover market share
Tracking slashing events helps:
- Monitor validator/attester behavior and compliance
- Identify problematic attesters
- Analyze slashing patterns and severity
- Assess network security and stake distribution
- Track total penalties across the network
Tracking exit events helps:
- Monitor validator churn and network stability
- Identify attesters leaving the network
- Track the 14-day exit queue and pending finalizations
- Plan for network capacity changes
- Detect unusual exit patterns that might indicate issues
Make sure you've created a .env file with the correct contract address.
- Check your RPC endpoint is working
- Verify you haven't exceeded rate limits
- Try reducing the block range or chunk size
Run the indexer first with npm start to generate data files.
Run the indexer in slash mode first with npm run slash to generate slash data files.
Run the indexer in exit mode first with npm run exit to generate exit data files.
MIT