Advanced Usage Guide
Complex Integration Patterns
Real-time Market Making
Track pool state changes and price movements in real-time:
import { createClient, gql } from '@apollo/client';
const POOL_STATE = gql`
query GetPoolState($poolId: ID!, $lastTimestamp: Int!) {
pandaPool(id: $poolId) {
price
pandaReserve
baseReserve
swaps(
where: { timestamp_gt: $lastTimestamp }
orderBy: timestamp
orderDirection: desc
first: 1
) {
timestamp
amountPandaIn
amountPandaOut
averagePrice
}
}
}
`;
class MarketMaker {
private lastPoll: number = 0;
private readonly POLL_INTERVAL = 1000; // 1 second
async monitorPool(poolId: string) {
while (true) {
const { data } = await client.query({
query: POOL_STATE,
variables: {
poolId,
lastTimestamp: this.lastPoll
},
fetchPolicy: 'network-only' // Bypass cache
});
this.updateStrategy(data.pandaPool);
this.lastPoll = Math.floor(Date.now() / 1000);
await new Promise(resolve => setTimeout(resolve, this.POLL_INTERVAL));
}
}
private updateStrategy(poolData: any) {
// Implement your market making strategy
}
}
Historical Analysis Engine
Efficiently process historical data for analytics:
const HISTORICAL_DATA = gql`
query GetHistoricalData($startTime: Int!, $endTime: Int!) {
priceSnapshots(
where: {
timestamp_gte: $startTime,
timestamp_lte: $endTime,
timeframe: HOUR
}
orderBy: timestamp
orderDirection: asc
) {
timestamp
open
high
low
close
volume
}
}
`;
class AnalysisEngine {
async analyzeTimeframe(startTime: number, endTime: number) {
const batchSize = 1000;
let currentStart = startTime;
const results = [];
while (currentStart < endTime) {
const batchEnd = Math.min(currentStart + batchSize * 3600, endTime);
const { data } = await client.query({
query: HISTORICAL_DATA,
variables: {
startTime: currentStart,
endTime: batchEnd
}
});
results.push(...data.priceSnapshots);
currentStart = batchEnd + 1;
}
return this.processResults(results);
}
private processResults(snapshots: any[]) {
// Implement your analysis logic
}
}
Performance Optimization
Caching Strategies
Implement efficient caching for frequently accessed data:
class SubgraphCache {
private cache: Map<string, {
data: any,
timestamp: number
}> = new Map();
private readonly TTL = 60 * 1000; // 1 minute
async getCachedData(key: string, fetchFn: () => Promise<any>) {
const cached = this.cache.get(key);
if (cached && Date.now() - cached.timestamp < this.TTL) {
return cached.data;
}
const data = await fetchFn();
this.cache.set(key, {
data,
timestamp: Date.now()
});
return data;
}
invalidateCache(key?: string) {
if (key) {
this.cache.delete(key);
} else {
this.cache.clear();
}
}
}
Batch Processing
Efficiently handle multiple queries:
class BatchProcessor {
private queue: Set<string> = new Set();
private processing = false;
private readonly BATCH_SIZE = 100;
async queuePool(poolId: string) {
this.queue.add(poolId);
if (!this.processing) {
await this.processBatch();
}
}
private async processBatch() {
this.processing = true;
while (this.queue.size > 0) {
const batch = Array.from(this.queue).slice(0, this.BATCH_SIZE);
batch.forEach(id => this.queue.delete(id));
const { data } = await client.query({
query: POOL_DATA,
variables: { poolIds: batch }
});
await this.handleBatchResults(data);
}
this.processing = false;
}
}
Error Handling & Recovery
Robust Query Handler
Handle network issues and retry failed queries:
class RobustQueryHandler {
private readonly MAX_RETRIES = 3;
private readonly BACKOFF_BASE = 1000; // 1 second
async executeQuery(query: any, variables: any) {
for (let attempt = 0; attempt < this.MAX_RETRIES; attempt++) {
try {
return await client.query({ query, variables });
} catch (error) {
if (!this.shouldRetry(error) || attempt === this.MAX_RETRIES - 1) {
throw error;
}
await this.sleep(this.getBackoffTime(attempt));
}
}
}
private shouldRetry(error: any): boolean {
// Implement retry logic based on error type
return error.message.includes('network')
|| error.message.includes('timeout');
}
private getBackoffTime(attempt: number): number {
return this.BACKOFF_BASE * Math.pow(2, attempt);
}
private sleep(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
Edge Cases
Handling Network Upgrades
class NetworkUpgradeHandler {
private lastKnownBlock: number = 0;
async checkNetworkContinuity() {
const { data } = await client.query({
query: gql`
{
_meta {
block {
number
}
}
}
`
});
const currentBlock = data._meta.block.number;
if (this.lastKnownBlock > 0) {
const gap = currentBlock - this.lastKnownBlock;
if (gap > 100) { // Potential network upgrade
await this.handleNetworkUpgrade(this.lastKnownBlock, currentBlock);
}
}
this.lastKnownBlock = currentBlock;
}
private async handleNetworkUpgrade(lastBlock: number, currentBlock: number) {
// Implement upgrade handling logic
}
}
Best Practices & Tips
1. Query Optimization
// Efficient field selection
const OPTIMIZED_QUERY = gql`
query GetPoolData($poolId: ID!) {
pandaPool(id: $poolId) {
price # Only request needed fields
volumeUSD
# Avoid requesting unnecessary relationships
}
}
`;
2. Rate Limiting
class RateLimiter {
private timestamps: number[] = [];
private readonly WINDOW_MS = 1000; // 1 second
private readonly MAX_REQUESTS = 10;
async executeWithRateLimit(fn: () => Promise<any>) {
this.timestamps = this.timestamps.filter(
ts => Date.now() - ts < this.WINDOW_MS
);
if (this.timestamps.length >= this.MAX_REQUESTS) {
const oldestTimestamp = this.timestamps[0];
const waitTime = this.WINDOW_MS - (Date.now() - oldestTimestamp);
await new Promise(resolve => setTimeout(resolve, waitTime));
}
this.timestamps.push(Date.now());
return fn();
}
}
Monitoring & Debugging
Performance Monitoring
class QueryMonitor {
private metrics: {
[key: string]: {
count: number;
totalTime: number;
errors: number;
}
} = {};
async trackQuery(name: string, query: Promise<any>) {
const start = Date.now();
try {
const result = await query;
this.recordSuccess(name, Date.now() - start);
return result;
} catch (error) {
this.recordError(name);
throw error;
}
}
getMetrics() {
return Object.entries(this.metrics).map(([name, data]) => ({
name,
averageTime: data.totalTime / data.count,
errorRate: data.errors / data.count,
totalCalls: data.count
}));
}
}
Next Steps
Explore our WebSocket API for real-time updates
Check our GitHub for example implementations
Join our Developer Discord for advanced support
Last updated