5 minutes
GraphTally Guide
Learn about The Graph’s new payment system, GraphTally (previously Timeline Aggregation Protocol). This system provides fast, efficient microtransactions with minimized trust.
Overview
GraphTally is a drop-in replacement to the Scalar payment system currently in place. It provides the following key features:
- Efficiently handles micropayments.
- Adds a layer of consolidations to onchain transactions and costs.
- Allows Indexers control of receipts and payments, guaranteeing payment for queries.
- Enables decentralized, trustless gateways and improves indexer service performance for multiple senders.
How It Works
GraphTally allows a sender to make multiple payments to a receiver through Receipts, which are then aggregated into a single payment called a Receipt Aggregate Voucher (RAV). This aggregated payment can be verified on the blockchain, reducing the number of transactions and simplifying the payment process.
For each query, the gateway sends a signed receipt that is stored in your database. The indexer-tap-agent
aggregates these receipts into RAVs through periodic requests. You can update a RAV by sending it with newer receipts, which generates a new RAV with an increased value.
RAV Details
- RAVs represent money waiting to be sent to the blockchain.
- The system continuously aggregates receipts to ensure that the total value of non-aggregated receipts does not exceed the configured
max_amount_willing_to_lose_grt
. - Each RAV can be redeemed once in the contracts, which is why they are sent after the allocation is closed.
Redeeming RAVs
The redemption process is fully automated when running both indexer-tap-agent
and indexer-agent
:
- An Indexer closes an allocation.
- After the
recently-closed-allocation-buffer
period,indexer-tap-agent
takes all pending receipts for that allocation and requests aggregation into a final RAV, marking it aslast
. indexer-agent
takes all the last RAVs and sends redeem requests to the blockchain, updating theredeem_at
value.- During the
finality-time
period,indexer-agent
monitors for blockchain reorganizations:- If the transaction was reverted, the RAV is resent to the blockchain.
- If not reverted, it gets marked as
final
.
Blockchain Addresses
Contracts
Contract | Arbitrum Mainnet (42161) | Arbitrum Sepolia (421614) |
---|---|---|
TAP Verifier | 0x33f9E93266ce0E108fc85DdE2f71dab555A0F05a | 0xfC24cE7a4428A6B89B52645243662A02BA734ECF |
AllocationIDTracker | 0x5B2F33d7Ca6Ec88f5586f2528f58c20843D9FE7c | 0xAaC28a10d707bbc6e02029f1bfDAEB5084b2aD11 |
Escrow | 0x8f477709eF277d4A880801D01A140a9CF88bA0d3 | 0x1e4dC4f9F95E102635D8F7ED71c5CdbFa20e2d02 |
Gateway
Component | Edge and Node Mainnet (Arbitrum Mainnet) | Edge and Node Testnet (Arbitrum Sepolia) |
---|---|---|
Sender | 0xDDE4cfFd3D9052A9cb618fC05a1Cd02be1f2F467 | 0xC3dDf37906724732FfD748057FEBe23379b0710D |
Signers | 0xfF4B7A5EfD00Ff2EC3518D4F250A27e4c29A2211 | 0xFb142dE83E261e43a81e9ACEADd1c66A0DB121FE |
Aggregator | https://tap-aggregator.network.thegraph.com | https://tap-aggregator.testnet.thegraph.com |
Prerequisites
In addition to typical indexer requirements, you’ll need a tap-escrow-subgraph
endpoint to query escrow information. You can use The Graph Network to query or self-host on your graph-node
:
- Graph TAP Arbitrum Sepolia Subgraph (for The Graph testnet)
- Graph TAP Arbitrum One Subgraph (for The Graph mainnet)
Note: indexer-agent
does not currently handle the indexing of this Subgraph like it does for the Network Subgraph deployment. You must index it manually.
Migration Guide
Software Requirements
Required Versions
- indexer-agent: Latest version supporting TAP
- indexer-service-rs: Latest release
- indexer-tap-agent: Latest release
Docker Images
1# Indexer Service2docker pull ghcr.io/graphprotocol/indexer-service-rs:latest34# TAP Agent5docker pull ghcr.io/graphprotocol/indexer-tap-agent:latest
Migration Steps
1. Update Indexer Agent
- Continue using your existing
indexer-agent
- Add the
--tap-subgraph-endpoint
argument to enable TAP functionality and RAV redemption - Example:
--tap-subgraph-endpoint https://api.thegraph.com/subgraphs/name/graphprotocol/tap-mainnet
2. Replace Indexer Service
- Fully replace your TypeScript indexer-service with
indexer-service-rs
- The new service is stateless and can be scaled horizontally
- Use the same database as your existing setup
3. Deploy TAP Agent
- Run exactly one instance of
indexer-tap-agent
- This component manages receipt aggregation and RAV creation
- It must have access to the same database as other indexer components
4. Configuration
Both indexer-service-rs
and indexer-tap-agent
share a TOML configuration file. Create a configuration file and pass it with --config /path/to/config.toml
.
Minimal Configuration Example
1# Essential configuration for indexer-rs components2# All values below must be updated to match your setup34[indexer]5indexer_address = "0x1111111111111111111111111111111111111111"6operator_mnemonic = "your twelve word mnemonic phrase here ..."78[database]9# Use the same database as your indexer-agent10postgres_url = "postgresql://user:password@localhost:5432/indexer_db"1112[graph_node]13# Your graph-node endpoints14query_url = "http://graph-node:8000"15status_url = "http://graph-node:8000/graphql"1617[subgraphs.network]18# The Graph Network Subgraph (use query_url OR deployment_id, not both)19query_url = "https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-arbitrum"20# deployment_id = "QmUVskWrz1ZiQZ76AtyhcfFDEH1ELnRpoyEhVL8p6NFTbR"2122[subgraphs.escrow]23# TAP Escrow Subgraph (use query_url OR deployment_id, not both)24query_url = "https://api.thegraph.com/subgraphs/name/graphprotocol/tap-arbitrum-one"25# deployment_id = "QmPcbDomKwfsmVBNbvncU8gdWTvUiH9zVFYxDMc5ohpjvU"2627[blockchain]28# For Arbitrum mainnet29chain_id = 4216130receipts_verifier_address = "0x33f9E93266ce0E108fc85DdE2f71dab555A0F05a"3132# For Arbitrum Sepolia testnet, use:33# chain_id = 42161434# receipts_verifier_address = "0xfC24cE7a4428A6B89B52645243662A02BA734ECF"3536[tap]37# Maximum GRT amount to risk before requiring aggregation38# Use string format to prevent rounding errors39max_amount_willing_to_lose_grt = "0.1"4041[tap.sender_aggregator_endpoints]42# Gateway endpoints for RAV aggregation43# Mainnet44"0xDDE4cfFd3D9052A9cb618fC05a1Cd02be1f2F467" = "https://tap-aggregator.network.thegraph.com"4546# For testnet, use:47# "0xC3dDf37906724732FfD748057FEBe23379b0710D" = "https://tap-aggregator.testnet.thegraph.com"
Environment Variable Overrides
You can override any configuration value using environment variables:
1# Pattern: [PREFIX]__[SECTION]__[KEY]2# PREFIX can be INDEXER_SERVICE or TAP_AGENT34# Examples:5export INDEXER_SERVICE__DATABASE__POSTGRES_URL="postgresql://..."6export TAP_AGENT__TAP__MAX_AMOUNT_WILLING_TO_LOSE_GRT="0.5"7export INDEXER_SERVICE__BLOCKCHAIN__RECEIPTS_VERIFIER_ADDRESS="0x..."
Advanced Configuration
For all configuration options, see:
Logging
Set the log level using the RUST_LOG
environment variable:
1# Recommended for production2export RUST_LOG=indexer_service=info,indexer_tap_agent=info34# For debugging5export RUST_LOG=indexer_service=debug,indexer_tap_agent=debug67# TAP-specific debugging8export RUST_LOG=indexer_tap_agent=debug,info
Monitoring
Metrics
All components expose Prometheus metrics on port 7300:
http://indexer-service:7300/metrics
http://tap-agent:7300/metrics
Key metrics to monitor:
- Receipt Processing: Track receipt validation, aggregation rates, and failures
- RAV Creation: Monitor RAV request success/failure rates
- Unaggregated Fees: Ensure fees stay below
max_amount_willing_to_lose_grt
- Sender Balances: Track escrow account balances and obligations
Grafana Dashboard
Import the official Grafana dashboard for comprehensive monitoring of:
- TAP receipt flow and aggregation status
- RAV creation and redemption lifecycle
- System performance and error rates
- Database query performance
Troubleshooting
Common issues and solutions:
-
RAV requests failing:
- Check aggregator endpoint connectivity
- Verify sender configuration in
tap.sender_aggregator_endpoints
- Review debug logs for specific error messages
-
Receipts not aggregating:
- Ensure
tap-agent
is running (only one instance) - Check database connectivity
- Verify
max_amount_willing_to_lose_grt
is not too high
- Ensure
-
High unaggregated fees:
- Lower
max_amount_willing_to_lose_grt
to trigger more frequent aggregation - Check if specific senders are having aggregation issues
- Monitor the Grafana dashboard for aggregation patterns
- Lower
Deployment Options
Docker Compose
Example compose configuration for both services:
1version: '3.8'23services:4 indexer-service:5 image: ghcr.io/graphprotocol/indexer-service-rs:latest6 ports:7 - '7600:7600' # Service port8 - '7300:7300' # Metrics port9 volumes:10 - ./config.toml:/config.toml11 command: ['--config', '/config.toml']12 environment:13 - RUST_LOG=indexer_service=info14 restart: unless-stopped1516 tap-agent:17 image: ghcr.io/graphprotocol/indexer-tap-agent:latest18 ports:19 - '7301:7300' # Metrics port (different host port)20 volumes:21 - ./config.toml:/config.toml22 command: ['--config', '/config.toml']23 environment:24 - RUST_LOG=indexer_tap_agent=info25 restart: unless-stopped
Kubernetes
For Kubernetes deployments, see the Graph Launchpad charts which include:
- Helm charts for both services
- ConfigMap templates for configuration
- Service and ingress definitions
- Prometheus ServiceMonitor resources
Best Practices
-
Database Performance:
- Ensure your PostgreSQL instance has adequate resources
- Monitor query performance through metrics
- Regular maintenance of receipt tables
-
High Availability:
- Run multiple
indexer-service-rs
instances behind a load balancer - Keep
tap-agent
as a single instance with proper monitoring - Use database connection pooling
- Run multiple
-
Security:
- Store operator mnemonic securely (use environment variables)
- Restrict database access to indexer components only
- Monitor for unusual receipt patterns
-
Capacity Planning:
- Monitor receipt growth rate
- Plan database storage accordingly
- Set appropriate
max_amount_willing_to_lose_grt
based on query volume
Additional Resources
- indexer-rs Repository
- TAP Core Documentation
- The Graph Discord - Get help in the #indexers channel
- Support - Report issues or get help