From alchemy-pack
Optimizes Alchemy API costs using CU monitoring in TypeScript, caching strategies, batching, and plan recommendations for dApps.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin alchemy-packThis skill is limited to using the following tools:
Alchemy pricing is based on Compute Units (CU). Different API methods have different CU costs. Optimize by caching, batching, choosing cheaper methods, and right-sizing your plan.
Implements CU-aware throttling for Alchemy API calls using Bottleneck to avoid 429 errors and optimize concurrent blockchain queries within plan limits.
Integrates Alchemy APIs for EVM JSON-RPC calls, token balances, NFT ownership/metadata, transfers, prices, portfolio data, transaction simulation, webhooks, Solana RPC. Covers base URLs, auth, endpoints, pagination. Requires $ALCHEMY_API_KEY.
Integrates Alchemy APIs into application code (servers, backends, dApps, scripts) via API key. Covers EVM JSON-RPC, Token/NFT/Transfers/Prices/Portfolio APIs, Solana RPC/DAS/gRPC, Sui gRPC, Wallets. Requires $ALCHEMY_API_KEY.
Share bugs, ideas, or general feedback.
Alchemy pricing is based on Compute Units (CU). Different API methods have different CU costs. Optimize by caching, batching, choosing cheaper methods, and right-sizing your plan.
| Plan | CU/sec | Monthly CU | Price | Best For |
|---|---|---|---|---|
| Free | 330 | 300M | $0 | Dev/prototyping |
| Growth | 660 | 1.2B | $49/mo | Small dApps |
| Scale | Custom | Custom | Custom | High-traffic apps |
| Method | CU | Optimization |
|---|---|---|
eth_blockNumber | 10 | Cache 12s (1 block) |
eth_getBalance | 19 | Cache 30s |
eth_call | 26 | Cache based on use case |
getTokenBalances | 50 | Cache 60s; batch addresses |
getNftsForOwner | 50 | Cache 5 min |
getTokenMetadata | 50 | Cache 24h (rarely changes) |
getAssetTransfers | 150 | Cache aggressively; paginate |
getNftMetadataBatch | 50 | Use batch over individual calls |
// src/cost/cu-monitor.ts
const CU_COSTS: Record<string, number> = {
'eth_blockNumber': 10, 'eth_getBalance': 19, 'eth_call': 26,
'getTokenBalances': 50, 'getNftsForOwner': 50, 'getTokenMetadata': 50,
'getAssetTransfers': 150, 'getNftMetadataBatch': 50,
};
class CuMonitor {
private usage: Array<{ method: string; cu: number; timestamp: number }> = [];
record(method: string): void {
this.usage.push({ method, cu: CU_COSTS[method] || 26, timestamp: Date.now() });
}
getHourlyReport(): { totalCu: number; byMethod: Record<string, number> } {
const cutoff = Date.now() - 3600000;
const recent = this.usage.filter(u => u.timestamp > cutoff);
const byMethod: Record<string, number> = {};
let totalCu = 0;
for (const u of recent) {
byMethod[u.method] = (byMethod[u.method] || 0) + u.cu;
totalCu += u.cu;
}
return { totalCu, byMethod };
}
getMonthlyProjection(): { projectedMonthly: number; planRecommendation: string } {
const hourly = this.getHourlyReport();
const projectedMonthly = hourly.totalCu * 24 * 30;
let recommendation = 'Free';
if (projectedMonthly > 300_000_000) recommendation = 'Growth';
if (projectedMonthly > 1_200_000_000) recommendation = 'Scale';
return { projectedMonthly, planRecommendation: recommendation };
}
}
export { CuMonitor };
// src/cost/optimized-client.ts
import { Alchemy, Network } from 'alchemy-sdk';
const cache = new Map<string, { data: any; expiry: number }>();
// Cache token metadata aggressively (rarely changes)
async function getTokenMetadataCached(alchemy: Alchemy, contract: string) {
const key = `metadata:${contract}`;
const cached = cache.get(key);
if (cached && cached.expiry > Date.now()) return cached.data;
const data = await alchemy.core.getTokenMetadata(contract);
cache.set(key, { data, expiry: Date.now() + 86400000 }); // 24h cache
return data;
}
// Use batch instead of individual NFT metadata calls
// 1 batch call (50 CU) vs 100 individual calls (5000 CU)
async function getNftMetadataOptimized(
alchemy: Alchemy,
tokens: Array<{ contractAddress: string; tokenId: string }>
) {
const BATCH_SIZE = 100;
const results = [];
for (let i = 0; i < tokens.length; i += BATCH_SIZE) {
const batch = tokens.slice(i, i + BATCH_SIZE);
const batchResults = await alchemy.nft.getNftMetadataBatch(batch);
results.push(...batchResults);
}
return results;
}
// For staying within Free tier (330 CU/sec, 300M CU/month):
// 1. Cache eth_blockNumber (saves 10 CU per redundant call)
// 2. Cache token metadata (saves 50 CU per redundant call)
// 3. Use getNftMetadataBatch instead of getNftMetadata (100x savings)
// 4. Avoid getAssetTransfers loops (150 CU each — cache results)
// 5. Use WebSockets instead of polling (one connection vs repeated calls)
// 6. Rate-limit user-facing endpoints to prevent CU bursts
For architecture design, see alchemy-reference-architecture.