Agent Skills: Alchemy Performance Tuning

|

UncategorizedID: jeremylongshore/claude-code-plugins-plus-skills/alchemy-performance-tuning

Install this agent skill to your local

pnpm dlx add-skill https://github.com/jeremylongshore/claude-code-plugins-plus-skills/tree/HEAD/plugins/saas-packs/alchemy-pack/skills/alchemy-performance-tuning

Skill Files

Browse the full folder contents for alchemy-performance-tuning.

Download Skill

Loading file tree…

plugins/saas-packs/alchemy-pack/skills/alchemy-performance-tuning/SKILL.md

Skill Metadata

Name
alchemy-performance-tuning
Description
|

Alchemy Performance Tuning

Performance Targets

| Operation | Target Latency | CU Cost | |-----------|---------------|---------| | getBlockNumber | < 50ms | 10 | | getBalance | < 100ms | 19 | | getTokenBalances | < 200ms | 50 | | getNftsForOwner | < 300ms | 50 | | getAssetTransfers | < 500ms | 150 | | Multi-chain portfolio | < 2s | ~400 |

Instructions

Step 1: Response Caching with TTL

// src/performance/cache.ts
import { Alchemy, Network } from 'alchemy-sdk';

class BlockchainCache {
  private store = new Map<string, { data: any; expiry: number }>();

  // Different TTLs for different data freshness needs
  private TTL: Record<string, number> = {
    blockNumber: 12000,     // 12s (~1 block)
    balance: 30000,         // 30s
    tokenBalances: 60000,   // 60s
    nftOwnership: 300000,   // 5 min (NFTs transfer less frequently)
    contractMetadata: 3600000, // 1 hour (rarely changes)
    tokenMetadata: 86400000,   // 24 hours (almost never changes)
  };

  async cached<T>(category: string, key: string, fetcher: () => Promise<T>): Promise<T> {
    const cacheKey = `${category}:${key}`;
    const entry = this.store.get(cacheKey);
    if (entry && entry.expiry > Date.now()) return entry.data;

    const data = await fetcher();
    this.store.set(cacheKey, { data, expiry: Date.now() + (this.TTL[category] || 30000) });
    return data;
  }

  invalidate(category: string): void {
    for (const key of this.store.keys()) {
      if (key.startsWith(`${category}:`)) this.store.delete(key);
    }
  }
}

const cache = new BlockchainCache();
export { cache };

Step 2: Parallel Multi-Chain Fetching

// src/performance/parallel-fetch.ts
import { Alchemy, Network } from 'alchemy-sdk';
import { cache } from './cache';

const CHAINS = [
  { name: 'ethereum', network: Network.ETH_MAINNET },
  { name: 'polygon', network: Network.MATIC_MAINNET },
  { name: 'arbitrum', network: Network.ARB_MAINNET },
  { name: 'base', network: Network.BASE_MAINNET },
];

async function multiChainBalance(address: string) {
  const results = await Promise.allSettled(
    CHAINS.map(chain =>
      cache.cached('balance', `${chain.name}:${address}`, async () => {
        const client = new Alchemy({ apiKey: process.env.ALCHEMY_API_KEY, network: chain.network });
        const bal = await client.core.getBalance(address);
        return { chain: chain.name, balance: (parseInt(bal.toString()) / 1e18).toFixed(6) };
      })
    )
  );

  return results
    .filter((r): r is PromiseFulfilledResult<any> => r.status === 'fulfilled')
    .map(r => r.value);
}

Step 3: Batch NFT Metadata (Reduce CU)

// src/performance/batch-nft.ts
import { Alchemy, Network } from 'alchemy-sdk';

const alchemy = new Alchemy({ apiKey: process.env.ALCHEMY_API_KEY, network: Network.ETH_MAINNET });

// SLOW: Individual calls = 50 CU each
// async function slowGetMetadata(tokens) {
//   return Promise.all(tokens.map(t => alchemy.nft.getNftMetadata(t.contract, t.tokenId)));
// }

// FAST: Batch call = 50 CU total for up to 100 tokens
async function fastGetMetadata(tokens: Array<{ contractAddress: string; tokenId: string }>) {
  return alchemy.nft.getNftMetadataBatch(tokens);
}

Step 4: WebSocket for Real-Time Data

// src/performance/realtime.ts
import { Alchemy, AlchemySubscription, Network } from 'alchemy-sdk';

const alchemy = new Alchemy({ apiKey: process.env.ALCHEMY_API_KEY, network: Network.ETH_MAINNET });

// Use WebSocket subscriptions instead of polling
function watchAddress(address: string, onActivity: (tx: any) => void) {
  alchemy.ws.on(
    {
      method: AlchemySubscription.PENDING_TRANSACTIONS,
      toAddress: address,
    },
    (tx) => onActivity(tx)
  );
}

// Auto-reconnect on disconnect
alchemy.ws.on('close', () => {
  console.log('WebSocket disconnected — reconnecting in 5s');
  setTimeout(() => alchemy.ws.connect(), 5000);
});

Output

  • TTL-based response cache matching data freshness requirements
  • Parallel multi-chain fetching (4 chains in < 2s)
  • Batch NFT metadata (100x CU reduction)
  • WebSocket subscriptions replacing polling

Resources

Next Steps

For cost optimization, see alchemy-cost-tuning.