chore: update submodule references and documentation
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled

- Marked submodules ai-mcp-pmm-controller, explorer-monorepo, and smom-dbis-138 as dirty to reflect recent changes.
- Updated documentation to clarify operator script usage, including dotenv loading and task execution instructions.
- Enhanced the README and various index files to provide clearer navigation and task completion guidance.

Made-with: Cursor
This commit is contained in:
defiQUG
2026-03-04 02:03:08 -08:00
parent 70eadb7bf0
commit e4c9dda0fd
246 changed files with 17774 additions and 93 deletions

View File

@@ -1 +1 @@
{"name":"DBIS Chain 138 Token List","version":{"major":1,"minor":5,"patch":0},"timestamp":"2026-02-28T00:00:00.000Z","keywords":["dbis","chain138","defi oracle meta"],"logoURI":"https://ipfs.io/ipfs/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong","tokens":[{"chainId":138,"address":"0x3304b747E565a97ec8AC220b0B6A1f6ffDB837e6","name":"ETH/USD Price Feed","symbol":"ETH-USD","decimals":8,"logoURI":"https://ipfs.io/ipfs/QmPZuycjyJEe2otREuQ5HirvPJ8X6Yc6MBtwz1VhdD79pY","tags":["oracle","pricefeed"]},{"chainId":138,"address":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","name":"Wrapped Ether","symbol":"WETH","decimals":18,"logoURI":"https://ipfs.io/ipfs/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong","tags":["defi","wrapped"]},{"chainId":138,"address":"0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9F","name":"Wrapped Ether v10","symbol":"WETH10","decimals":18,"logoURI":"https://ipfs.io/ipfs/QmanDFPHxnbKd6SSNzzXHf9GbpL9dLXSphxDZSPPYE6ds4","tags":["defi","wrapped"]},{"chainId":138,"address":"0xb7721dD53A8c629d9f1Ba31a5819AFe250002b03","name":"Chainlink Token","symbol":"LINK","decimals":18,"logoURI":"https://ipfs.io/ipfs/QmenWcmfNGfssz4HXvrRV912eZDiKqLTt6z2brRYuTGz9A","tags":["defi","oracle","ccip"]},{"chainId":138,"address":"0x93E66202A11B1772E55407B32B44e5Cd8eda7f22","name":"Compliant Tether USD","symbol":"cUSDT","decimals":6,"logoURI":"https://ipfs.io/ipfs/QmRfhPs9DcyFPpGjKwF6CCoVDWUHSxkQR34n9NK7JSbPCP","tags":["stablecoin","defi","compliant"]},{"chainId":138,"address":"0xf22258f57794CC8E06237084b353Ab30fFfa640b","name":"Compliant USD Coin","symbol":"cUSDC","decimals":6,"logoURI":"https://ipfs.io/ipfs/QmNPq4D5JXzurmi9jAhogVMzhAQRk1PZ1r9H3qQUV9gjDm","tags":["stablecoin","defi","compliant"]},{"chainId":138,"address":"0x8085961F9cF02b4d800A3c6d386D31da4B34266a","name":"Euro Coin (Compliant)","symbol":"cEURC","decimals":6,"logoURI":"https://ipfs.io/ipfs/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong","tags":["stablecoin","defi","compliant"]}],"tags":{"defi":{"name":"DeFi","description":"Decentralized Finance tokens"},"wrapped":{"name":"Wrapped","description":"Wrapped tokens representing native assets"},"oracle":{"name":"Oracle","description":"Oracle price feed tokens"},"pricefeed":{"name":"Price Feed","description":"Price feed oracle contracts"},"stablecoin":{"name":"Stablecoin","description":"Stable value tokens pegged to fiat currencies"},"compliant":{"name":"Compliant","description":"Regulatory compliant tokens with compliance features"},"ccip":{"name":"CCIP","description":"Cross Chain Interoperability Protocol tokens"}}}
{"name":"DBIS Chain 138 Token List","version":{"major":1,"minor":6,"patch":0},"timestamp":"2026-02-28T00:00:00.000Z","keywords":["dbis","chain138","defi oracle meta"],"logoURI":"https://ipfs.io/ipfs/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong","tokens":[{"chainId":138,"address":"0x3304b747E565a97ec8AC220b0B6A1f6ffDB837e6","name":"ETH/USD Price Feed","symbol":"ETH-USD","decimals":8,"logoURI":"https://ipfs.io/ipfs/QmPZuycjyJEe2otREuQ5HirvPJ8X6Yc6MBtwz1VhdD79pY","tags":["oracle","pricefeed"]},{"chainId":138,"address":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","name":"Wrapped Ether","symbol":"WETH","decimals":18,"logoURI":"https://ipfs.io/ipfs/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong","tags":["defi","wrapped"]},{"chainId":138,"address":"0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9F","name":"Wrapped Ether v10","symbol":"WETH10","decimals":18,"logoURI":"https://ipfs.io/ipfs/QmanDFPHxnbKd6SSNzzXHf9GbpL9dLXSphxDZSPPYE6ds4","tags":["defi","wrapped"]},{"chainId":138,"address":"0xb7721dD53A8c629d9f1Ba31a5819AFe250002b03","name":"Chainlink Token","symbol":"LINK","decimals":18,"logoURI":"https://ipfs.io/ipfs/QmenWcmfNGfssz4HXvrRV912eZDiKqLTt6z2brRYuTGz9A","tags":["defi","oracle","ccip"]},{"chainId":138,"address":"0x93E66202A11B1772E55407B32B44e5Cd8eda7f22","name":"Compliant Tether USD","symbol":"cUSDT","decimals":6,"logoURI":"https://ipfs.io/ipfs/QmRfhPs9DcyFPpGjKwF6CCoVDWUHSxkQR34n9NK7JSbPCP","tags":["stablecoin","defi","compliant"]},{"chainId":138,"address":"0xf22258f57794CC8E06237084b353Ab30fFfa640b","name":"Compliant USD Coin","symbol":"cUSDC","decimals":6,"logoURI":"https://ipfs.io/ipfs/QmNPq4D5JXzurmi9jAhogVMzhAQRk1PZ1r9H3qQUV9gjDm","tags":["stablecoin","defi","compliant"]},{"chainId":138,"address":"0x8085961F9cF02b4d800A3c6d386D31da4B34266a","name":"Euro Coin (Compliant)","symbol":"cEURC","decimals":6,"logoURI":"https://ipfs.io/ipfs/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong","tags":["stablecoin","defi","compliant"]},{"chainId":138,"address":"0xdf4b71c61E5912712C1Bdd451416B9aC26949d72","name":"Tether EUR (Compliant)","symbol":"cEURT","decimals":6,"logoURI":"https://ipfs.io/ipfs/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong","tags":["stablecoin","defi","compliant"]},{"chainId":138,"address":"0x003960f16D9d34F2e98d62723B6721Fb92074aD2","name":"Pound Sterling (Compliant)","symbol":"cGBPC","decimals":6,"logoURI":"https://ipfs.io/ipfs/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong","tags":["stablecoin","defi","compliant"]},{"chainId":138,"address":"0x350f54e4D23795f86A9c03988c7135357CCaD97c","name":"Tether GBP (Compliant)","symbol":"cGBPT","decimals":6,"logoURI":"https://ipfs.io/ipfs/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong","tags":["stablecoin","defi","compliant"]},{"chainId":138,"address":"0xD51482e567c03899eecE3CAe8a058161FD56069D","name":"Australian Dollar (Compliant)","symbol":"cAUDC","decimals":6,"logoURI":"https://ipfs.io/ipfs/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong","tags":["stablecoin","defi","compliant"]},{"chainId":138,"address":"0xEe269e1226a334182aace90056EE4ee5Cc8A6770","name":"Japanese Yen (Compliant)","symbol":"cJPYC","decimals":6,"logoURI":"https://ipfs.io/ipfs/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong","tags":["stablecoin","defi","compliant"]},{"chainId":138,"address":"0x873990849DDa5117d7C644f0aF24370797C03885","name":"Swiss Franc (Compliant)","symbol":"cCHFC","decimals":6,"logoURI":"https://ipfs.io/ipfs/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong","tags":["stablecoin","defi","compliant"]},{"chainId":138,"address":"0x54dBd40cF05e15906A2C21f600937e96787f5679","name":"Canadian Dollar (Compliant)","symbol":"cCADC","decimals":6,"logoURI":"https://ipfs.io/ipfs/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong","tags":["stablecoin","defi","compliant"]},{"chainId":138,"address":"0x290E52a8819A4fbD0714E517225429aA2B70EC6b","name":"Gold (Compliant)","symbol":"cXAUC","decimals":6,"logoURI":"https://ipfs.io/ipfs/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong","tags":["defi","compliant"]},{"chainId":138,"address":"0x94e408E26c6FD8F4ee00b54dF19082FDA07dC96E","name":"Tether XAU (Compliant)","symbol":"cXAUT","decimals":6,"logoURI":"https://ipfs.io/ipfs/Qma3FKtLce9MjgJgWbtyCxBiPjJ6xi8jGWUSKNS5Jc2ong","tags":["defi","compliant"]}],"tags":{"defi":{"name":"DeFi","description":"Decentralized Finance tokens"},"wrapped":{"name":"Wrapped","description":"Wrapped tokens representing native assets"},"oracle":{"name":"Oracle","description":"Oracle price feed tokens"},"pricefeed":{"name":"Price Feed","description":"Price feed oracle contracts"},"stablecoin":{"name":"Stablecoin","description":"Stable value tokens pegged to fiat currencies"},"compliant":{"name":"Compliant","description":"Regulatory compliant tokens with compliance features"},"ccip":{"name":"CCIP","description":"Cross Chain Interoperability Protocol tokens"}}}

View File

@@ -0,0 +1,170 @@
#!/usr/bin/env node
/**
* Full diff: Blockscout /api/v2/tokens vs curated token list (Chain 138).
*
* Outputs:
* - missing_in_blockscout: in tokenlist but not in Blockscout response
* - missing_in_tokenlist: in Blockscout but not in tokenlist
* - metadata_mismatches: same address, different name/symbol/decimals (or null/0)
* - source-of-truth recommendation per field
*
* Usage:
* node diff-blockscout-vs-tokenlist.js
* node diff-blockscout-vs-tokenlist.js --url "https://explorer.d-bis.org/api/v2/tokens"
* node diff-blockscout-vs-tokenlist.js --file /path/to/blockscout-tokens.json
*
* Curated list: token-lists/lists/dbis-138.tokenlist.json (Chain 138 tokens).
* ETH-USD (oracle) is not an ERC-20 supply token; it is expected to be missing from Blockscout.
*/
import { readFileSync } from 'fs';
import { dirname, resolve } from 'path';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const CHAIN_ID = 138;
const TOKENLIST_PATH = resolve(__dirname, '../lists/dbis-138.tokenlist.json');
function normAddr(addr) {
return (addr || '').toLowerCase();
}
function parseArgs() {
const args = process.argv.slice(2);
let url = null;
let file = null;
for (let i = 0; i < args.length; i++) {
if (args[i] === '--url' && args[i + 1]) {
url = args[i + 1];
i++;
} else if (args[i] === '--file' && args[i + 1]) {
file = args[i + 1];
i++;
}
}
return { url, file };
}
async function fetchAllBlockscoutTokens(baseUrl) {
const items = [];
let next = null;
const base = baseUrl.replace(/\?.*$/, '');
while (true) {
const qs = next ? new URLSearchParams({ page_size: 100, ...next }) : new URLSearchParams({ page: 1, page_size: 100 });
const res = await fetch(`${base}?${qs}`);
if (!res.ok) throw new Error(`Blockscout ${res.status}`);
const data = await res.json();
const list = data.items ?? data.data ?? (Array.isArray(data) ? data : []);
items.push(...list);
next = data.next_page_params ?? null;
if (!next) break;
}
return items;
}
function loadTokenList() {
const raw = readFileSync(TOKENLIST_PATH, 'utf8');
const data = JSON.parse(raw);
const tokens = (data.tokens || []).filter((t) => t.chainId === CHAIN_ID);
return tokens.map((t) => ({
address: normAddr(t.address),
name: t.name ?? null,
symbol: t.symbol ?? null,
decimals: t.decimals != null ? Number(t.decimals) : null,
logoURI: t.logoURI ?? null,
}));
}
function loadBlockscoutFromFile(path) {
const raw = readFileSync(path, 'utf8');
const data = JSON.parse(raw);
const list = data.items ?? data.data ?? (Array.isArray(data) ? data : []);
return list.map((t) => ({
address: normAddr(t.address ?? t.hash),
name: t.name ?? null,
symbol: t.symbol ?? null,
decimals: t.decimals != null && t.decimals !== '' ? Number(t.decimals) : null,
}));
}
function runDiff(tokenlist, blockscout) {
const byAddr = (arr) => Object.fromEntries(arr.map((t) => [t.address, t]));
const listMap = byAddr(tokenlist);
const scoutMap = byAddr(blockscout);
const missing_in_blockscout = tokenlist
.filter((t) => !scoutMap[t.address])
.map((t) => ({ address: t.address, symbol: t.symbol, name: t.name, note: t.symbol === 'ETH-USD' ? 'Oracle; not ERC-20 supply token' : null }));
const missing_in_tokenlist = blockscout
.filter((t) => !listMap[t.address])
.map((t) => ({ address: t.address, symbol: t.symbol, name: t.name, decimals: t.decimals }));
const metadata_mismatches = [];
for (const addr of Object.keys(listMap)) {
const list = listMap[addr];
const scout = scoutMap[addr];
if (!scout) continue;
const mismatches = [];
if (list.name !== scout.name && (scout.name != null || list.name != null)) mismatches.push({ field: 'name', tokenlist: list.name, blockscout: scout.name });
if (list.symbol !== scout.symbol && (scout.symbol != null || list.symbol != null)) mismatches.push({ field: 'symbol', tokenlist: list.symbol, blockscout: scout.symbol });
if (list.decimals !== scout.decimals && (scout.decimals != null || list.decimals != null)) mismatches.push({ field: 'decimals', tokenlist: list.decimals, blockscout: scout.decimals });
if (mismatches.length) metadata_mismatches.push({ address: addr, symbol: list.symbol ?? scout.symbol, mismatches });
}
return { missing_in_blockscout, missing_in_tokenlist, metadata_mismatches };
}
function sourceOfTruthRecommendation(diff) {
return {
address: 'Token list (dbis-138.tokenlist.json) and CONTRACT_ADDRESSES_REFERENCE; Blockscout is on-chain index.',
symbol: 'Token list; use Explorer UI override only when Blockscout returns null (e.g. WETH9).',
name: 'Token list; same as symbol.',
decimals: 'Token list; use override when Blockscout returns 0 or null.',
logo: 'Token list logoURI.',
};
}
function main() {
const { url, file } = parseArgs();
const baseUrl = url || 'https://explorer.d-bis.org/api/v2/tokens';
(async () => {
let blockscout;
if (file) {
blockscout = loadBlockscoutFromFile(file);
console.error(`Loaded ${blockscout.length} tokens from file: ${file}`);
} else {
try {
blockscout = await fetchAllBlockscoutTokens(baseUrl);
console.error(`Fetched ${blockscout.length} tokens from ${baseUrl}`);
} catch (e) {
console.error('Fetch failed:', e.message);
console.error('Use --file path/to/blockscout-tokens.json with a saved snapshot.');
process.exit(1);
}
}
const tokenlist = loadTokenList();
console.error(`Loaded ${tokenlist.length} Chain ${CHAIN_ID} tokens from ${TOKENLIST_PATH}`);
const diff = runDiff(tokenlist, blockscout);
const recommendation = sourceOfTruthRecommendation(diff);
const out = {
chainId: CHAIN_ID,
tokenlist_path: TOKENLIST_PATH,
blockscout_source: file || baseUrl,
missing_in_blockscout: diff.missing_in_blockscout,
missing_in_tokenlist: diff.missing_in_tokenlist,
metadata_mismatches: diff.metadata_mismatches,
source_of_truth: recommendation,
};
console.log(JSON.stringify(out, null, 2));
})().catch((e) => {
console.error(e);
process.exit(1);
});
}
main();