Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Blockchain RPC error handling, gas estimation, multi-chain config, and transaction management. Use when interacting with smart contracts, estimating gas, or managing transactions. Triggers on: RPC, contract call, gas, multicall, nonce, transaction, revert.
.claude/skills/aiskillstore-pitfalls-blockchain/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-16 | ✗→✓ | ▲ Improved | 9% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 51% | 0% |
| case-12 | ✓→✓ | = Same ✓ | 19% | 0% |
| case-21 | ✓→✓ | = Same ✓ | 31% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 4% | 0% |
Common pitfalls and correct patterns for blockchain interactions.
Check all contract calls are wrapped in try/catch.
Ensure gas is estimated with buffer before sending.
Confirm multicall uses allowFailure: true.
typescript// ✅ Wrap ALL contract calls async function getQuote(tokenIn: Address, tokenOut: Address) { try { const quote = await quoter.quoteExactInput(...); return quote; } catch (error) { // Low-liquidity tokens WILL fail - this is expected console.warn(`Quote failed for ${tokenIn}->${tokenOut}:`, error.message); return null; // Continue processing other tokens } } // ✅ Validate before calling contracts if (!isAddress(tokenAddress)) { throw new Error('Invalid token address'); } // ✅ Handle "execution reverted" gracefully if (error.message.includes('execution reverted')) { // Pool doesn't exist or insufficient liquidity return null; } // ✅ Multicall with individual error handling const results = await multicall({ contracts: tokens.map(t => ({ ... })), allowFailure: true, // CRITICAL }); results.forEach((result, i) => { if (result.status === 'success') { // Use result.result } else { // Log and skip this token } });
typescript// ✅ Always estimate gas before sending const gasEstimate = await contract.estimateGas.swap(...args); // ✅ Add 10-20% buffer to gas estimates const gasLimit = gasEstimate.mul(120).div(100); // 20% buffer // ✅ EIP-1559 gas pricing const feeData = await provider.getFeeData(); const tx = { maxFeePerGas: feeData.maxFeePerGas, maxPriorityFeePerGas: feeData.maxPriorityFeePerGas, gasLimit, }; // ✅ Simulate before execution try { await contract.callStatic.swap(...args); // Dry run const tx = await contract.swap(...args); // Real execution } catch (e) { // Would revert - don't send } // ✅ Handle gas price spikes if (feeData.maxFeePerGas > MAX_ACCEPTABLE_GAS) { throw new Error('Gas too high, waiting...'); }
typescript// ✅ Chain-specific configuration const CHAIN_CONFIG: Record<ChainId, ChainConfig> = { ethereum: { chainId: 1, rpcUrl: process.env.ETHEREUM_RPC_URL, blockTime: 12, confirmations: 2, nativeToken: 'ETH', }, polygon: { chainId: 137, rpcUrl: process.env.POLYGON_RPC_URL, blockTime: 2, confirmations: 5, // More confirmations for faster chains nativeToken: 'MATIC', }, };
typescript// ✅ Wait for confirmations const receipt = await tx.wait(2); // 2 confirmations // ✅ Nonce management class NonceManager { private pending = new Map<Address, number>(); async getNextNonce(address: Address, provider: Provider): Promise<number> { const onChain = await provider.getTransactionCount(address, 'pending'); const local = this.pending.get(address) ?? onChain; const next = Math.max(onChain, local); this.pending.set(address, next + 1); return next; } }
typescript// ✅ Exponential backoff async function fetchWithRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> { for (let attempt = 0; attempt < maxRetries; attempt++) { try { return await fn(); } catch (error) { if (error.status === 429) { // Rate limited const delay = Math.pow(2, attempt) * 1000; await sleep(delay); continue; } throw error; } } throw new Error('Max retries exceeded'); } // ✅ Fallback RPC endpoints const RPC_ENDPOINTS = [ 'https://eth-mainnet.alchemyapi.io/v2/KEY', 'https://mainnet.infura.io/v3/KEY', 'https://rpc.ankr.com/eth', ];
allowFailure: true| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-03 | pass→pass | 12,204 | 10,368 | -15% | 1 | 1 | 0% | 2,255 | 3,413 | +51% | 0 | 0 | — |
case-12 | pass→pass | 23,385 | 20,847 | -11% | 1 | 1 | 0% | 3,751 | 4,457 | +19% | 0 | 0 | — |
case-21 | pass→pass | 21,439 | 19,000 | -11% | 1 | 1 | 0% | 3,043 | 3,989 | +31% | 0 | 0 | — |
case-01 | pass→pass | 25,133 | 24,366 | -3% | 1 | 1 | 0% | 5,255 | 5,464 | +4% | 0 | 0 | — |
case-02 | pass→pass | 12,638 | 12,807 | +1% | 1 | 1 | 0% | 2,501 | 3,766 | +51% | 0 | 0 | — |
case-04 | pass→pass | 13,003 | 13,650 | +5% | 1 | 1 | 0% | 2,652 | 2,838 | +7% | 0 | 0 | — |
case-05 | pass→pass | 20,797 | 13,245 | -36% | 1 | 1 | 0% | 2,761 | 3,584 | +30% | 0 | 0 | — |
case-06 | pass→pass | 21,726 | 19,836 | -9% | 1 | 1 | 0% | 3,559 | 4,393 | +23% | 0 | 0 | — |
case-07 | pass→pass | 21,134 | 14,196 | -33% | 1 | 1 | 0% | 3,196 | 3,014 | -6% | 0 | 0 | — |
case-08 | pass→pass | 20,777 | 20,092 | -3% | 1 | 1 | 0% | 3,012 | 3,970 | +32% | 0 | 0 | — |
case-09 | pass→pass | 15,079 | 9,305 | -38% | 1 | 1 | 0% | 2,833 | 3,339 | +18% | 0 | 0 | — |
case-10 | pass→pass | 19,972 | 11,788 | -41% | 1 | 1 | 0% | 2,793 | 3,480 | +25% | 0 | 0 | — |
case-11 | fail→fail | 23,245 | 22,608 | -3% | 1 | 1 | 0% | 2,900 | 4,584 | +58% | 0 | 0 | — |
case-13 | pass→pass | 18,502 | 20,712 | +12% | 1 | 1 | 0% | 3,504 | 4,510 | +29% | 0 | 0 | — |
case-14 | pass→pass | 16,923 | 12,168 | -28% | 1 | 1 | 0% | 2,475 | 2,657 | +7% | 0 | 0 | — |
case-15 | pass→pass | 8,026 | 4,712 | -41% | 1 | 1 | 0% | 1,185 | 2,133 | +80% | 0 | 0 | — |
case-16 | fail→pass | 15,834 | 10,160 | -36% | 1 | 1 | 0% | 2,796 | 3,061 | +9% | 0 | 0 | — |
case-17 | pass→pass | 14,201 | 7,281 | -49% | 1 | 1 | 0% | 2,369 | 2,675 | +13% | 0 | 0 | — |
case-18 | pass→pass | 15,564 | 12,028 | -23% | 1 | 1 | 0% | 2,225 | 2,702 | +21% | 0 | 0 | — |
case-19 | pass→pass | 21,475 | 20,447 | -5% | 1 | 1 | 0% | 3,487 | 4,544 | +30% | 0 | 0 | — |
case-20 | pass→pass | 13,962 | 20,100 | +44% | 1 | 1 | 0% | 2,747 | 3,951 | +44% | 0 | 0 | — |
case-22 | pass→pass | 12,341 | 11,539 | -6% | 1 | 1 | 0% | 1,611 | 2,416 | +50% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +5 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.