My first set of multi-chain fee tracking contributions: 4 chains using Blockscout API, submitted in rapid succession.
- Type: Chain-level fees
- Pattern:
blockscoutFeeAdapter2(centralized config) - Submitted: January 2-3, 2026
- Chains: NEO X Mainnet, Bitkub (KUB), Vana, Shibarium
All 4 PRs merged, January 3, 2026
Success rate: 4/4 (100%)
Reviewer: noateden
1. Background story
a. Rapid succession strategy
After completing individual protocol adapters (AquaBank, HunnySwap), I shifted to chain-level fees. I noticed many new chains use Blockscout explorers with the same API structure.
The approach:
- Research chains with Blockscout explorers
- Implement one chain at a time
- Submit PR immediately after testing
- Move to next chain while previous PR is in review
- Result: 4 PRs submitted within hours
This wasn’t a planned “batch”. I was researching and implementing simultaneously, submitting each as I completed it.
b. Why this worked
Pattern recognition:
- DefiLlama has
blockscoutFeeAdapter2helper - Same implementation pattern across chains
- Only need to add config, not write logic
- Quick to verify and test (~10 min per chain)
Research flow:
Search for new chains that use Blockscout as their block explorer.
Look up the chain’s native token on CoinGecko to get the correct token ID for pricing.
Add the chain configuration with explorer URL and CoinGecko token ID to the centralized config file.
If the chain doesn’t exist, add it to the chains enum.
Create the minimal adapter file that uses blockscoutFeeAdapter2 with the chain config.
Run local tests to verify data fetching works, then submit the pull request.
Don’t wait idle. Start researching the next chain while the PR is under review.
2. The chains
a. NEO X Mainnet
Implementation:
File: fees/neo-x-mainnet.ts (6 lines)
import { blockscoutFeeAdapter2 } from "../helpers/blockscoutFees";
import { CHAIN } from "../helpers/chains";
export default blockscoutFeeAdapter2(CHAIN.NEO_X_MAINNET); Chain config added to helpers/blockscoutFees.ts:
[CHAIN.NEO_X_MAINNET]: {
CGToken: "gas",
explorer: "https://xexplorer.neo.org/"
}, Chain enum added to helpers/chains.ts:
NEO_X_MAINNET = "neo_x_mainnet", Test results:
> [email protected] test
> ts-node --transpile-only cli/testAdapter.ts fees neo-x-mainnet.ts
🦙 Running NEO-X-MAINNET.TS adapter 🦙
---------------------------------------------------
Start Date: Fri, 02 Jan 2026 00:00:00 GMT
End Date: Sat, 03 Jan 2026 00:00:00 GMT
---------------------------------------------------
NEO_X_MAINNET 👇
Daily fees: 3.00
End timestamp: 1767312000 (2026-01-02T00:00:00.000Z) Issues: None, clean merge
Key notes:
- NEO X uses “gas” as native token (CoinGecko ID)
- Blockscout explorer
- Ultra-clean 4-line implementation
b. Bitkub Chain (KUB)
PR: #5485
Status: Merged (after clarification)
Merged: January 3, 2026
Issue: Chain identifier confusion
Implementation:
File: fees/kub.ts (4 lines)
import { blockscoutFeeAdapter2 } from "../helpers/blockscoutFees";
import { CHAIN } from "../helpers/chains";
export default blockscoutFeeAdapter2(CHAIN.KUB); Chain config added to helpers/blockscoutFees.ts:
[CHAIN.KUB]: {
CGToken: 'bitkub-coin',
explorer: 'https://www.kubscan.com/'
}, Chain enum added to helpers/chains.ts:
KUB = "kub", The issue:
Reviewer noateden questioned:
“is this chain
kuborbitkub? they are two difference chains.”
The problem:
- DefiLlama has two different chains:
kubandbitkub - Bitkub Chain rebranded to KUB Chain
- But in DefiLlama system, both identifiers exist
My response:
I provided evidence of the rebranding:
“Bitkub Chain is now KUB Chain due to rebranding”
Reference: https://support.bitkub.com/hc/en-us/articles/9687614585113-Bitkub-Chain-is-now-KUB-Chain
Resolution:
- Used
CHAIN.KUBidentifier - CoinGecko token:
bitkub-coin - Explorer: kubscan.com (not bkcscan.com)
- Maintained backward compatibility
Test results:
> [email protected] test
> ts-node --transpile-only cli/testAdapter.ts fees kub.ts
🦙 Running KUB.TS adapter 🦙
---------------------------------------------------
Start Date: Fri, 02 Jan 2026 00:00:00 GMT
End Date: Sat, 03 Jan 2026 00:00:00 GMT
---------------------------------------------------
error fetching block Error: Last block for kub is 6366 minutes behind
[... RPC provider warnings ...]
KUB 👇
Daily fees: 230.00
End timestamp: 1767312000 (2026-01-02T00:00:00.000Z) Despite RPC warnings, fee data was successfully fetched from Blockscout API.
Key Learning:
When chains rebrand:
Search DefiLlama’s codebase to see if the old chain identifier is still being used.
Determine whether to use the old identifier, new identifier, or if both are maintained separately.
Include official documentation or announcements about the rebranding to support your decision.
c. Vana
Implementation:
File: fees/vana.ts (4 lines)
import { blockscoutFeeAdapter2 } from "../helpers/blockscoutFees";
import { CHAIN } from "../helpers/chains";
export default blockscoutFeeAdapter2(CHAIN.VANA); Chain config added to helpers/blockscoutFees.ts:
[CHAIN.VANA]: {
CGToken: 'vana',
explorer: 'https://vanascan.io/'
}, Test results:
> [email protected] test
> ts-node --transpile-only cli/testAdapter.ts fees vana.ts
🦙 Running VANA.TS adapter 🦙
---------------------------------------------------
Start Date: Fri, 02 Jan 2026 00:00:00 GMT
End Date: Sat, 03 Jan 2026 00:00:00 GMT
---------------------------------------------------
VANA 👇
Daily fees: 9.00
End timestamp: 1767312000 (2026-01-02T00:00:00.000Z) Issues: None, clean merge
Key notes:
- Vana uses vanascan.io (Blockscout)
- Standard Ethereum-compatible chain
- CoinGecko token ID:
vana - Referenced live chain: https://defillama.com/chain/vana
d. Shibarium
Implementation:
File: fees/shibarium.ts (4 lines)
import { blockscoutFeeAdapter2 } from "../helpers/blockscoutFees";
import { CHAIN } from "../helpers/chains";
export default blockscoutFeeAdapter2(CHAIN.SHIBARIUM); Chain config added to helpers/blockscoutFees.ts:
[CHAIN.SHIBARIUM]: {
CGToken: 'bone-shibaswap',
explorer: 'https://shibariumscan.io/'
}, Test Results:
> [email protected] test
> ts-node --transpile-only cli/testAdapter.ts fees shibarium.ts
🦙 Running SHIBARIUM.TS adapter 🦙
---------------------------------------------------
Start Date: Fri, 02 Jan 2026 00:00:00 GMT
End Date: Sat, 03 Jan 2026 00:00:00 GMT
---------------------------------------------------
SHIBARIUM 👇
Daily fees: 4.00
End timestamp: 1767312000 (2026-01-02T00:00:00.000Z) Issues: None, clean merge
Key notes:
- Shibarium is Shiba Inu’s L2 chain
- Uses shibariumscan.io (Blockscout)
- CoinGecko token ID:
bone-shibaswap(BONE token) - Standard implementation
3. The common pattern
a. blockscoutFeeAdapter2 structure
All 4 chains use the same ultra-clean pattern:
Step 1: Create adapter file (4 lines!)
// fees/{chain}.ts
import { blockscoutFeeAdapter2 } from "../helpers/blockscoutFees";
import { CHAIN } from "../helpers/chains";
export default blockscoutFeeAdapter2(CHAIN.{CHAIN_NAME}); Step 2: Add config to helpers/blockscoutFees.ts
[CHAIN.{CHAIN_NAME}]: {
CGToken: '{coingecko-id}',
explorer: 'https://{explorer-url}/'
}, Step 3: Add chain enum to helpers/chains.ts
{CHAIN_NAME} = "{chain_name}", That’s it! 3 steps, minimal code.
b. How blockscoutFeeAdapter2 works
Centralized configuration approach:
- Explorer URLs stored in one place (
helpers/blockscoutFees.ts) - CoinGecko token mappings centralized
- Adapter files are ultra-clean (4 lines!)
How it works internally:
The adapter reads the chain’s explorer URL and CoinGecko token ID from the centralized config.
Builds the Blockscout API endpoint: {explorer}/api?module=stats&action=totalfees&date={date}
Makes a request to the Blockscout JSON API to get the day’s total fees.
Divides the raw wei value by 1e18 to get the actual token amount.
Fetches the token price from CoinGecko and calculates the USD value.
Returns the final metrics in the standardized format.
The API endpoint:
https://{explorer}/api?module=stats&action=totalfees&date=2026-01-05 Returns JSON like:
{
"message": "OK",
"result": "3311212584000000000",
"status": "1"
} The result is total fees in wei (smallest unit).
c. Why I chose this pattern
Simple and fast:
- Only 4 lines per adapter
- Just add chain config once
- No need to look up API URLs every time
- Quick to verify and test
Why Blockscout specifically:
- Many new chains use Blockscout explorers
- All have the same API endpoint structure
- Easy to identify (Blockscout branding in footer)
- Reliable fee data already aggregated via API
The workflow is quick:
Search for chains using Blockscout explorers. Time: ~2 minutes
Look up the native token on CoinGecko. Time: ~1 minute
Add chain config and create the 4-line adapter file. Time: ~5 minutes
Run the test suite to verify data fetching. Time: ~2 minutes
Push changes and create pull request. Time: ~1 minute
Total: ~10 minutes per chain. That’s why I could do 4 chains in a few hours.
d. When to use this pattern
Perfect for:
- Chain has Blockscout explorer
- Explorer has
/api?module=stats&action=totalfeesendpoint - Standard fee tracking (no custom logic needed)
- Chain already on CoinGecko with known ID
How to identify Blockscout chains:
Navigate to the blockchain explorer website.
Scroll to the bottom and look for “Powered by Blockscout” or similar branding.
Try accessing: {explorer}/api?module=stats&action=totalfees&date={today}
If JSON returns with a result field containing fee data → use blockscoutFeeAdapter2
Example Blockscout URLs:
- xexplorer.neo.org (NEO X)
- kubscan.com (KUB)
- vanascan.io (Vana)
- shibariumscan.io (Shibarium)
4. Submission results
a. Timeline
January 2-3, 2026:
- Researching chains with Blockscout
- Implemented first chain → submitted PR #5480 (NEO X)
- While waiting, researched next chain
- Implemented second chain → submitted PR #5485 (KUB)
- Continued pattern for remaining 2 chains
- All submitted within hours of each other
llamabutlerran automated tests on each
January 3, 2026:
- Reviewer
noatedenchecked all 4 PRs - Raised question on Bitkub chain identifier
- I clarified with documentation
- All 4 PRs merged same day
b. Efficiency metrics
| Metric | Result |
|---|---|
| PRs submitted | 4 |
| Time window | Several hours (sequential) |
| PRs merged | 4/4 (100%) |
| Issues found | 1 (Bitkub identifier clarification) |
| Time to merge | ~1 day |
| Lines of code per adapter | 4-6 lines |
| Total lines added | ~24 lines for 4 chains |
Key insight: Rapid succession works when:
- Pattern is proven (
blockscoutFeeAdapter2) - Implementation is ultra-simple (~10 min each)
- Can research and code simultaneously
- Submit as you go, don’t wait
5. Comparison with previous contributions
a. Individual vs rapid succession
Previous (Individual):
- AquaBank: Custom wallet tracking, 3 commits
- HunnySwap: DEX fees, folder issue, refactored
- OpenTrade: Multi-chain vaults, 3 issues fixed
- One at a time, wait for merge before next
Chain Fees Set 1 (Rapid Succession):
- 4 chains, same pattern
- Research → Implement → Submit → Repeat
- Don’t wait for merge, keep moving
- Ultra-clean code (4 lines per adapter)
- All merged same day
b. Evolution
Individual complex protocols (slow, many iterations)
↓
Recognizing patterns
↓
Rapid succession (research + implement simultaneously) This shows:
- Pattern recognition (blockscoutFeeAdapter2)
- Efficient workflow (don’t wait for reviews)
- Understanding of what’s “safe to submit rapidly”
6. Key learnings
a. When to submit rapidly
Good for rapid succession:
- Same implementation pattern
- Ultra-low complexity (~4 lines per adapter)
- Independent changes (no conflicts)
- Proven helper (already used successfully)
Don’t submit rapidly:
- Different patterns per PR
- Complex implementations
- Untested approaches
- High risk of issues
The workflow:
- Research chain A → Implement → Test → Submit PR
- While PR in review, research chain B
- Implement chain B → Test → Submit PR
- Repeat, don’t wait for merges
- Respond to questions as they come
b. Chain identifier verification
Key lesson from Bitkub:
Always verify:
- Does chain exist in
helpers/chains.ts? - Are there multiple similar identifiers? (kub vs bitkub)
- Has chain rebranded recently?
- Which identifier does DefiLlama use?
- What’s the correct CoinGecko token ID?
How to check:
# Search existing chains
grep -r "CHAIN.KUB" helpers/chains.ts
grep -r "CHAIN.BITKUB" helpers/chains.ts
# Check live data
https://defillama.com/chain/{chain-name}
# Verify CoinGecko ID
https://www.coingecko.com/en/coins/{token-id} c. Documentation matters
When reviewer questions your choice:
- Provide official documentation
- Link to rebranding announcements
- Reference existing usage in codebase
- Don’t just assert without evidence
My Bitkub response was effective because:
- Quoted official support article
- Explained rebranding clearly
- Showed why
KUBwas correct choice
d. CoinGecko token IDs
Key mappings learned:
| Chain | Native Token | CoinGecko ID |
|---|---|---|
| NEO X | GAS | gas |
| KUB | KUB | bitkub-coin |
| Vana | VANA | vana |
| Shibarium | BONE | bone-shibaswap |
How to find CoinGecko ID:
- Go to https://www.coingecko.com
- Search for chain’s native token
- Check URL:
/en/coins/{this-is-the-id} - Use that ID in config
7. Technical details
a. The blockscoutFeeAdapter2 helper
Internal structure (simplified):
export function blockscoutFeeAdapter2(chain: CHAIN) {
const config = chainConfigMap[chain];
return {
fetch: async (options) => {
const dateString = options.dateString; // e.g., "2026-01-05"
const url = `${config.explorer}api?module=stats&action=totalfees&date=${dateString}`;
const response = await httpGet(url);
const feesInWei = response.result; // e.g., "3311212584000000000"
const feesInTokens = feesInWei / 1e18; // Convert from wei
const tokenPrice = await getCoinGeckoPrice(config.CGToken, dateString);
const usdValue = feesInTokens * tokenPrice;
return {
dailyFees: usdValue,
dailyRevenue: usdValue,
};
}
};
} The chainConfigMap:
const chainConfigMap: Record<CHAIN, ChainConfig> = {
[CHAIN.NEO_X_MAINNET]: {
CGToken: "gas",
explorer: "https://xexplorer.neo.org/"
},
[CHAIN.KUB]: {
CGToken: 'bitkub-coin',
explorer: 'https://www.kubscan.com/'
},
// ... more chains
}; b. Adding new chains, step by step
1. Find chain with Blockscout:
- Visit explorer
- Look for Blockscout branding
- Test API endpoint:
/api?module=stats&action=totalfees&date={date}
2. Get CoinGecko token ID:
- Search token on CoinGecko
- Note the ID from URL
3. Add chain enum:
// helpers/chains.ts
export enum CHAIN {
// ... existing
YOUR_CHAIN = "your_chain",
} 4. Add config:
// helpers/blockscoutFees.ts
[CHAIN.YOUR_CHAIN]: {
CGToken: 'your-coingecko-id',
explorer: 'https://your-explorer.com/'
}, 5. Create adapter:
// fees/your-chain.ts
import { blockscoutFeeAdapter2 } from "../helpers/blockscoutFees";
import { CHAIN } from "../helpers/chains";
export default blockscoutFeeAdapter2(CHAIN.YOUR_CHAIN); 6. Test locally:
pnpm test fees your-chain 7. Submit PR!
8. Statistics
a. Rapid succession performance
Submission efficiency:
- 4 adapters written and submitted within hours
- Average ~10 minutes per adapter (research + implement)
- 100% merge rate
- 1 clarification needed (25% question rate)
Code efficiency:
- ~4-6 lines per adapter file
- ~1 line per chain config
- ~1 line per chain enum
- Total: ~24 lines for 4 chains
- Reused pattern:
blockscoutFeeAdapter2
Workflow efficiency:
- Research while waiting for reviews
- Submit as you complete (don’t batch)
- Parallel research + sequential submission
b. Chain coverage added
After this set, DefiLlama now tracks fees for:
- NEO X Mainnet (gas token)
- KUB Chain (bitkub-coin)
- Vana (vana token)
- Shibarium (bone-shibaswap)
All now visible on DefiLlama’s chain dashboards!
9. Resources
a. PRs
b. Chain explorers
c. Documentation
10. Key takeaways
a. What worked well
- Pattern recognition. Identified
blockscoutFeeAdapter2helper - Ultra-clean code. 4 lines per adapter
- Rapid succession. Submitted in hours, all merged same day
- Centralized config. Explorer URLs and tokens in one place
- Quick clarification. Responded to Bitkub question with docs
b. What I learned
- blockscoutFeeAdapter2 pattern. Cleaner than etherscanFeeAdapter
- Chain identifiers matter. Check for rebranding and duplicates
- CoinGecko ID verification. Critical for USD conversion
- Rapid succession works. When pattern is proven and simple
c. Process improvements
Before rapid submissions:
- Verify chain identifier doesn’t conflict
- Check for rebranding history
- Get correct CoinGecko token ID
- Test API endpoint manually
- Run local test before submitting
d. The pattern
Identify Blockscout chains
↓
Research chain A → Add config → Create adapter → Test → Submit
↓
Research chain B (while A in review) → Add config → Create adapter → Test → Submit
↓
Research chain C (while A,B in review) → Add config → Create adapter → Test → Submit
↓
Respond quickly to questions
↓
All merged efficiently Not batch. A continuous flow of research → implement → submit.
11. Comparison with previous contributions
This is my first rapid succession submission. Previously:
- All contributions were individual
- Each PR had unique implementation
- Waited for merge before next contribution
Chain Fees Set 1:
- 4 PRs submitted within hours (one after another)
- Same ultra-clean pattern across all
- Don’t wait. Submit and move to next
- 100% success rate
Key difference: Moving from “wait for review” to “continuous flow of research + submit.”
This shows growth from:
- Contributor → executing individual tasks, waiting for feedback
- Pattern recognizer → identifying reusable approaches (blockscoutFeeAdapter2)
- Efficient contributor → continuous research & submission flow
First multi-chain rapid submission: 100% success
All 4 chain fee adapters merged in one day with minimal review needed. This demonstrates:
- Pattern recognition ability (blockscoutFeeAdapter2)
- Efficient workflow (research while waiting)
- Ultra-clean code (4 lines per adapter)
- Quick response to clarifications
From individual protocols (wait for merge) to rapid succession (research + submit continuously). This is what efficient contribution workflow looks like!