Integration Guide
Getting Started
This guide provides comprehensive instructions for integrating Shards into your decentralized applications, protocols, and services. Whether you're building a DeFi protocol, an AI-powered trading bot, or a data analytics platform, this guide will help you leverage Shards' oracle aggregation capabilities effectively.
Prerequisites
Technical Requirements
Programming Knowledge: Familiarity with JavaScript/TypeScript, Python, or Rust
Solana Basics: Understanding of Solana accounts, transactions, and programs
API Experience: Basic knowledge of REST APIs and WebSocket connections
Development Environment: Node.js 16+ or Python 3.8+
Account Setup
Register for API Access
curl -X POST https://api.shards.tv/v1/auth/register \ -H "Content-Type: application/json" \ -d '{ "email": "[email protected]", "organization": "Your Organization", "use_case": "DeFi Protocol Integration" }'
Generate API Key
curl -X POST https://api.shards.tv/v1/auth/api-key \ -H "Authorization: Bearer YOUR_AUTH_TOKEN" \ -d '{ "name": "Production Key", "permissions": ["read", "stream"], "rate_limit_tier": "pro" }'
Installation
JavaScript/TypeScript
npm install @shards/sdk
# or
yarn add @shards/sdk
# or
pnpm add @shards/sdk
Python
pip install shards-sdk
# or
poetry add shards-sdk
Rust
[dependencies]
shards-sdk = "0.2.0"
tokio = { version = "1", features = ["full"] }
Basic Integration
Initialize Client
TypeScript
import { ShardsClient, Network, OracleSource } from '@shards/sdk';
const client = new ShardsClient({
apiKey: process.env.SHARDS_API_KEY,
network: Network.Mainnet,
options: {
timeout: 5000,
retryAttempts: 3,
cacheEnabled: true
}
});
// Verify connection
const status = await client.getStatus();
console.log('Shards API Status:', status);
Python
import os
from shards import ShardsClient, Network
from shards.config import ClientConfig
config = ClientConfig(
api_key=os.environ['SHARDS_API_KEY'],
network=Network.MAINNET,
timeout=5,
retry_attempts=3,
cache_enabled=True
)
client = ShardsClient(config)
# Verify connection
status = client.get_status()
print(f"Shards API Status: {status}")
Fetching Oracle Data
Simple Price Query
// Get current price with aggregation
const solPrice = await client.oracle.getPrice('SOL');
console.log(`SOL Price: $${solPrice.price}`);
console.log(`Confidence: ±${solPrice.confidence}`);
console.log(`Last Updated: ${new Date(solPrice.timestamp * 1000)}`);
// Get price from specific oracle
const pythPrice = await client.oracle.getPrice('SOL', {
source: OracleSource.Pyth,
includeMetadata: true
});
Batch Price Queries
// Efficient batch request
const symbols = ['SOL', 'BTC', 'ETH', 'USDC', 'RAY'];
const prices = await client.oracle.getBatchPrices(symbols);
prices.forEach(({ symbol, price, confidence }) => {
console.log(`${symbol}: $${price} (±${confidence})`);
});
Real-time Data Streaming
WebSocket Subscription
// Create streaming client
const stream = client.createStream();
// Subscribe to price updates
stream.subscribe({
channels: ['oracle.price'],
symbols: ['SOL', 'BTC'],
callback: (update) => {
console.log(`${update.symbol} Price Update: $${update.price}`);
console.log(`Change: ${update.change24h}%`);
},
errorHandler: (error) => {
console.error('Stream error:', error);
}
});
// Start streaming
await stream.connect();
// Graceful shutdown
process.on('SIGINT', async () => {
await stream.disconnect();
process.exit(0);
});
Advanced Integration Patterns
DeFi Protocol Integration
Lending Protocol Example
import { PublicKey, Connection } from '@solana/web3.js';
import { ShardsClient, PriceData } from '@shards/sdk';
class LendingProtocolOracle {
private shards: ShardsClient;
private priceCache: Map<string, PriceData>;
private updateInterval: NodeJS.Timer;
constructor(apiKey: string) {
this.shards = new ShardsClient({ apiKey });
this.priceCache = new Map();
this.initializePriceUpdates();
}
private initializePriceUpdates() {
// Update prices every 5 seconds
this.updateInterval = setInterval(async () => {
await this.refreshPrices();
}, 5000);
// Subscribe to real-time updates
this.shards.stream.subscribe({
channels: ['oracle.price'],
symbols: this.getSupportedAssets(),
callback: (update) => {
this.priceCache.set(update.symbol, update);
this.checkLiquidations(update);
}
});
}
async getCollateralValue(
asset: string,
amount: number
): Promise<number> {
const price = await this.getPrice(asset);
const collateralFactor = this.getCollateralFactor(asset);
return amount * price.price * collateralFactor;
}
async checkLiquidations(priceUpdate: PriceData) {
// Get all positions for this asset
const positions = await this.getPositionsForAsset(priceUpdate.symbol);
for (const position of positions) {
const healthFactor = await this.calculateHealthFactor(
position,
priceUpdate
);
if (healthFactor < 1.0) {
await this.triggerLiquidation(position);
}
}
}
async calculateHealthFactor(
position: LoanPosition,
priceData: PriceData
): Promise<number> {
const collateralValue = position.collateralAmount * priceData.price;
const borrowValue = await this.getBorrowValue(position);
// Include confidence interval for conservative calculation
const adjustedCollateral = collateralValue *
(1 - priceData.confidence / priceData.price);
return adjustedCollateral / borrowValue;
}
}
AI/LLM Trading Bot Integration
class AITradingBot {
private shards: ShardsClient;
private llm: LLMInterface;
constructor(shardsKey: string, llmKey: string) {
this.shards = new ShardsClient({ apiKey: shardsKey });
this.llm = new LLMInterface(llmKey);
}
async analyzeMarket(query: string): Promise<TradingSignal> {
// Use Shards' LLM interface for natural language queries
const marketData = await this.shards.llm.query(query);
// Get detailed technical analysis
const analysis = await this.performTechnicalAnalysis(
marketData.data
);
// Generate trading signal
return this.generateSignal(analysis);
}
async executeNaturalLanguageStrategy(instruction: string) {
// Example: "Buy SOL when it drops 5% from daily high"
const interpretation = await this.shards.llm.interpret(instruction);
// Set up monitoring
this.shards.stream.subscribe({
channels: ['oracle.price'],
symbols: [interpretation.asset],
callback: async (update) => {
if (this.meetsCondition(update, interpretation.condition)) {
await this.executeTrade(interpretation.action);
}
}
});
}
async getMarketContext(symbol: string): Promise<MarketContext> {
// Parallel data fetching for comprehensive analysis
const [
currentPrice,
historicalData,
volatility,
correlations
] = await Promise.all([
this.shards.oracle.getPrice(symbol),
this.shards.oracle.getHistory(symbol, '7d', '1h'),
this.calculateVolatility(symbol),
this.getCorrelations(symbol)
]);
return {
price: currentPrice,
trend: this.analyzeTrend(historicalData),
volatility,
correlations,
sentiment: await this.getSentiment(symbol)
};
}
}
Cross-Chain Oracle Aggregation
class CrossChainAggregator {
private shards: ShardsClient;
private externalOracles: Map<string, OracleInterface>;
async getUniversalPrice(
asset: string,
chains: string[]
): Promise<UniversalPrice> {
// Get Solana oracle data from Shards
const solanaPrice = await this.shards.oracle.getPrice(asset, {
source: 'aggregated',
includeAllSources: true
});
// Aggregate with other chains if needed
const crossChainPrices = await Promise.all(
chains.map(chain => this.getChainPrice(chain, asset))
);
return this.calculateUniversalPrice(
solanaPrice,
crossChainPrices
);
}
private calculateUniversalPrice(
solanaData: PriceData,
otherChains: ChainPrice[]
): UniversalPrice {
// Weight by liquidity and update frequency
const weights = this.calculateWeights(solanaData, otherChains);
let weightedPrice = 0;
let totalWeight = 0;
// Include Solana price
weightedPrice += solanaData.price * weights.solana;
totalWeight += weights.solana;
// Include other chain prices
otherChains.forEach((chainPrice, i) => {
weightedPrice += chainPrice.price * weights.chains[i];
totalWeight += weights.chains[i];
});
return {
price: weightedPrice / totalWeight,
sources: [solanaData, ...otherChains],
confidence: this.calculateAggregateConfidence(
solanaData,
otherChains
),
timestamp: Date.now()
};
}
}
Error Handling & Resilience
Retry Logic Implementation
class ResilientShardsClient {
private client: ShardsClient;
private fallbackCache: Map<string, CachedPrice>;
async getPriceWithFallback(
symbol: string,
maxRetries: number = 3
): Promise<PriceData> {
let lastError: Error;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const price = await this.client.oracle.getPrice(symbol);
// Update cache on success
this.fallbackCache.set(symbol, {
data: price,
timestamp: Date.now()
});
return price;
} catch (error) {
lastError = error;
// Exponential backoff
const delay = Math.min(1000 * Math.pow(2, attempt), 10000);
await this.sleep(delay);
// Check if we should use cache
if (attempt === maxRetries - 1) {
return this.getCachedPrice(symbol);
}
}
}
throw new Error(
`Failed to get price after ${maxRetries} attempts: ${lastError}`
);
}
private getCachedPrice(symbol: string): PriceData {
const cached = this.fallbackCache.get(symbol);
if (!cached) {
throw new Error(`No cached price available for ${symbol}`);
}
const age = Date.now() - cached.timestamp;
const maxAge = 60000; // 1 minute
if (age > maxAge) {
console.warn(`Using stale cached price for ${symbol} (${age}ms old)`);
}
return {
...cached.data,
cached: true,
cacheAge: age
};
}
}
Circuit Breaker Pattern
class CircuitBreaker {
private failures: number = 0;
private lastFailTime: number = 0;
private state: 'CLOSED' | 'OPEN' | 'HALF_OPEN' = 'CLOSED';
async execute<T>(
operation: () => Promise<T>,
fallback?: () => T
): Promise<T> {
if (this.state === 'OPEN') {
if (Date.now() - this.lastFailTime > 60000) {
this.state = 'HALF_OPEN';
} else if (fallback) {
return fallback();
} else {
throw new Error('Circuit breaker is OPEN');
}
}
try {
const result = await operation();
this.onSuccess();
return result;
} catch (error) {
this.onFailure();
if (fallback) {
return fallback();
}
throw error;
}
}
private onSuccess() {
this.failures = 0;
this.state = 'CLOSED';
}
private onFailure() {
this.failures++;
this.lastFailTime = Date.now();
if (this.failures >= 5) {
this.state = 'OPEN';
console.error('Circuit breaker opened due to repeated failures');
}
}
}
Performance Optimization
Caching Strategy
class OptimizedShardsClient {
private cache: LRUCache<string, CacheEntry>;
private batchQueue: Map<string, Promise<PriceData>>;
constructor(client: ShardsClient, cacheSize: number = 1000) {
this.cache = new LRUCache({ max: cacheSize });
this.batchQueue = new Map();
}
async getPrice(
symbol: string,
maxAge: number = 1000
): Promise<PriceData> {
// Check cache first
const cached = this.cache.get(symbol);
if (cached && Date.now() - cached.timestamp < maxAge) {
return cached.data;
}
// Check if request is already in flight
if (this.batchQueue.has(symbol)) {
return this.batchQueue.get(symbol);
}
// Create new request
const request = this.fetchPrice(symbol);
this.batchQueue.set(symbol, request);
try {
const price = await request;
this.cache.set(symbol, {
data: price,
timestamp: Date.now()
});
return price;
} finally {
this.batchQueue.delete(symbol);
}
}
async getPricesBatch(symbols: string[]): Promise<Map<string, PriceData>> {
const results = new Map();
const toFetch = [];
// Check cache for each symbol
for (const symbol of symbols) {
const cached = this.cache.get(symbol);
if (cached && Date.now() - cached.timestamp < 1000) {
results.set(symbol, cached.data);
} else {
toFetch.push(symbol);
}
}
// Batch fetch missing prices
if (toFetch.length > 0) {
const prices = await this.client.oracle.getBatchPrices(toFetch);
prices.forEach(price => {
results.set(price.symbol, price);
this.cache.set(price.symbol, {
data: price,
timestamp: Date.now()
});
});
}
return results;
}
}
Testing & Development
Mock Client for Testing
import { MockShardsClient } from '@shards/sdk/testing';
describe('Trading Bot Integration', () => {
let mockClient: MockShardsClient;
let tradingBot: TradingBot;
beforeEach(() => {
mockClient = new MockShardsClient();
tradingBot = new TradingBot(mockClient);
});
test('should execute trade on price threshold', async () => {
// Set up mock price data
mockClient.setPriceData('SOL', {
price: 100,
confidence: 0.1,
timestamp: Date.now()
});
// Simulate price update
mockClient.emitPriceUpdate('SOL', {
price: 95,
confidence: 0.1,
timestamp: Date.now()
});
// Verify trade execution
const trades = await tradingBot.getExecutedTrades();
expect(trades).toHaveLength(1);
expect(trades[0].action).toBe('BUY');
});
});
Development Environment Setup
# Clone example repository
git clone https://github.com/shards-protocol/examples
cd examples
# Install dependencies
npm install
# Set up environment variables
cp .env.example .env
# Edit .env with your API key
# Run development server
npm run dev
# Run tests
npm test
# Build for production
npm run build
Best Practices
1. API Key Security
Never commit API keys to version control
Use environment variables for key storage
Implement key rotation policies
Use different keys for development/production
2. Rate Limit Management
Implement request queuing
Use caching to reduce API calls
Monitor rate limit headers
Implement exponential backoff
3. Data Validation
Always validate oracle data before use
Check confidence intervals
Verify data freshness
Implement sanity checks for price movements
4. Monitoring & Alerting
Log all oracle data requests
Monitor latency and error rates
Set up alerts for data anomalies
Track API usage and costs
Troubleshooting
Common Issues
Connection Timeouts
Check network connectivity
Verify API endpoint status
Increase timeout settings
Implement retry logic
Stale Data
Check oracle update frequencies
Verify timestamp freshness
Subscribe to real-time updates
Implement cache invalidation
Rate Limiting
Monitor request patterns
Implement request batching
Use WebSocket for real-time data
Upgrade API tier if needed
Support & Resources
Documentation: https://docs.shards.io
API Status: https://status.shards.io
Discord Community: https://discord.gg/shards
GitHub Examples: https://github.com/shards-protocol/examples
Support Email: [email protected]
Last updated