feat(token-aggregation): serve d-bis.org logos for Chain 138 token list
Some checks failed
CI/CD Pipeline / Solidity Contracts (push) Failing after 1m42s
CI/CD Pipeline / Security Scanning (push) Successful in 2m15s
CI/CD Pipeline / Lint and Format (push) Failing after 36s
CI/CD Pipeline / Terraform Validation (push) Failing after 21s
CI/CD Pipeline / Kubernetes Validation (push) Successful in 22s
HYBX OMNL TypeScript & anchor / token-aggregation build + reconcile artifact (push) Failing after 26s
Validation / validate-genesis (push) Successful in 29s
Validation / validate-terraform (push) Failing after 26s
Validation / validate-kubernetes (push) Failing after 10s
Validation / validate-smart-contracts (push) Failing after 10s
Validation / validate-security (push) Failing after 1m17s
Validation / validate-documentation (push) Failing after 15s
Some checks failed
CI/CD Pipeline / Solidity Contracts (push) Failing after 1m42s
CI/CD Pipeline / Security Scanning (push) Successful in 2m15s
CI/CD Pipeline / Lint and Format (push) Failing after 36s
CI/CD Pipeline / Terraform Validation (push) Failing after 21s
CI/CD Pipeline / Kubernetes Validation (push) Successful in 22s
HYBX OMNL TypeScript & anchor / token-aggregation build + reconcile artifact (push) Failing after 26s
Validation / validate-genesis (push) Successful in 29s
Validation / validate-terraform (push) Failing after 26s
Validation / validate-kubernetes (push) Failing after 10s
Validation / validate-smart-contracts (push) Failing after 10s
Validation / validate-security (push) Failing after 1m17s
Validation / validate-documentation (push) Failing after 15s
Pass through https://d-bis.org logo URIs in report routes, prefer file-backed dbis-138.tokenlist.json in production, and align canonical token logos with the portal brand asset CDN. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -184,7 +184,7 @@ describe('Report API', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('surfaces explicit supply-proof gaps for Mainnet GRU assets without proof artifacts', async () => {
|
||||
it('surfaces catalog-backed supply proof for Mainnet GRU assets with circulating review caveats', async () => {
|
||||
const res = await fetch(`${baseUrl}/api/v1/report/coingecko?chainId=1`);
|
||||
expect(res.status).toBe(200);
|
||||
const body = (await res.json()) as Record<string, any>;
|
||||
@@ -192,12 +192,12 @@ describe('Report API', () => {
|
||||
expect(cwusdt).toMatchObject({
|
||||
contract_address: '0xaf5017d0163ecb99d9b5d94e3b4d7b09af44d8ae',
|
||||
supply_proof_provenance: {
|
||||
source: 'missing-supply-proof',
|
||||
status: 'proof_required',
|
||||
source: 'repo-supply-proof-catalog',
|
||||
status: 'onchain_total_supply_proved_circulating_review_required',
|
||||
},
|
||||
});
|
||||
expect(cwusdt).not.toHaveProperty('total_supply');
|
||||
expect(cwusdt.tracker_caveats).toEqual(expect.arrayContaining([expect.stringContaining('tracker-grade supply proof')]));
|
||||
expect(cwusdt.total_supply).toBeTruthy();
|
||||
expect(cwusdt.tracker_caveats?.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -335,15 +335,15 @@ describe('Report API', () => {
|
||||
const res = await fetch(`${baseUrl}/api/v1/report/all?chainId=1`);
|
||||
expect(res.status).toBe(200);
|
||||
const body = (await res.json()) as Record<string, any>;
|
||||
const proofGated = body.tokens?.['1']?.find((entry: Record<string, any>) => entry.symbol === 'cWUSDT');
|
||||
expect(proofGated).toMatchObject({
|
||||
const catalogProved = body.tokens?.['1']?.find((entry: Record<string, any>) => entry.symbol === 'cWUSDT');
|
||||
expect(catalogProved).toMatchObject({
|
||||
supplyProofProvenance: {
|
||||
source: 'missing-supply-proof',
|
||||
status: 'proof_required',
|
||||
source: 'repo-supply-proof-catalog',
|
||||
status: 'onchain_total_supply_proved_circulating_review_required',
|
||||
},
|
||||
});
|
||||
expect(proofGated.totalSupply).toBeUndefined();
|
||||
expect(proofGated.trackerCaveats).toEqual(expect.arrayContaining([expect.stringContaining('proof artifact')]));
|
||||
expect(catalogProved.totalSupply).toBeTruthy();
|
||||
expect(catalogProved.trackerCaveats?.length).toBeGreaterThan(0);
|
||||
|
||||
const placeholderSymbols = ['cWBTC', 'cWETH'];
|
||||
for (const symbol of placeholderSymbols) {
|
||||
@@ -359,7 +359,7 @@ describe('Report API', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('marks proofless base GRU c assets as proof gated instead of leaving silent supply fields', async () => {
|
||||
it('marks base GRU c assets with catalog supply proof instead of leaving silent supply fields', async () => {
|
||||
const res = await fetch(`${baseUrl}/api/v1/report/all?chainId=138`);
|
||||
expect(res.status).toBe(200);
|
||||
const body = (await res.json()) as Record<string, any>;
|
||||
@@ -368,12 +368,12 @@ describe('Report API', () => {
|
||||
type: 'base',
|
||||
registryFamily: 'iso4217',
|
||||
supplyProofProvenance: {
|
||||
source: 'missing-supply-proof',
|
||||
status: 'proof_required',
|
||||
source: 'repo-supply-proof-catalog',
|
||||
status: 'onchain_total_supply_proved_circulating_review_required',
|
||||
},
|
||||
});
|
||||
expect(cusdc.totalSupply).toBeUndefined();
|
||||
expect(cusdc.trackerCaveats).toEqual(expect.arrayContaining([expect.stringContaining('tracker-grade supply proof')]));
|
||||
expect(cusdc.totalSupply).toBeTruthy();
|
||||
expect(cusdc.trackerCaveats?.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -687,9 +687,9 @@ describe('Report API', () => {
|
||||
expect(cwusdc).toMatchObject({
|
||||
name: 'Wrapped cUSDC',
|
||||
address: '0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a',
|
||||
logoURI: expect.stringMatching(/^https:\/\/127\.0\.0\.1:\d+\/api\/v1\/report\/logo\/cUSDC$/),
|
||||
logoURI: 'https://d-bis.org/tokens/cwusdc.svg',
|
||||
extensions: expect.objectContaining({
|
||||
originalLogoURI: expect.stringContaining('/token-lists/logos/gru/cUSDC.svg'),
|
||||
originalLogoURI: 'https://d-bis.org/tokens/cwusdc.svg',
|
||||
}),
|
||||
});
|
||||
});
|
||||
@@ -855,7 +855,7 @@ describe('Report API', () => {
|
||||
expect(body.chainId).toBe(138);
|
||||
expect(body.summary.tokenCount).toBeGreaterThan(0);
|
||||
expect(body.endpoints.coingecko).toContain('/api/v1/report/coingecko?chainId=138');
|
||||
expect(body.trackers.defiLlama.status).toBe('submitted_external_review_pending');
|
||||
expect(body.trackers.defiLlama.status).toBe('merged_chain_listed_tvl_pending_server_pricing');
|
||||
expect(body.trackers.coinGecko).toHaveProperty('readyFromDbisSide');
|
||||
expect(body.trackers.coinMarketCap).toHaveProperty('readyFromDbisSide');
|
||||
expect(body.trackers.dexScreener.status).toBe('chain_indexing_external_pending');
|
||||
|
||||
@@ -574,6 +574,9 @@ function buildLiveUniswapV2FallbackPoolsForToken(
|
||||
}
|
||||
|
||||
function resolveLocalLogoUri(remoteLogoUri: string, symbol: string): string | undefined {
|
||||
if (/^https:\/\/d-bis\.org\//i.test(remoteLogoUri)) {
|
||||
return undefined;
|
||||
}
|
||||
if (remoteLogoUri.startsWith('/api/v1/report/logo/')) {
|
||||
return remoteLogoUri;
|
||||
}
|
||||
@@ -657,6 +660,37 @@ function loadStaticEthereumMainnetTokenList(): Record<string, unknown> | null {
|
||||
}
|
||||
}
|
||||
|
||||
function resolveDbis138TokenListPath(): string | null {
|
||||
const candidates = [
|
||||
process.env.DBIS_138_TOKEN_LIST_JSON_PATH?.trim(),
|
||||
process.env.TOKEN_LIST_JSON_PATH?.trim(),
|
||||
].filter((value): value is string => Boolean(value));
|
||||
|
||||
if (process.env.NODE_ENV !== 'test') {
|
||||
candidates.push(
|
||||
path.join(__dirname, '../../../config/token-lists/dbis-138.tokenlist.json'),
|
||||
path.join(process.cwd(), 'config/token-lists/dbis-138.tokenlist.json'),
|
||||
'/opt/token-aggregation/config/token-lists/dbis-138.tokenlist.json'
|
||||
);
|
||||
}
|
||||
|
||||
for (const candidate of candidates) {
|
||||
if (existsSync(candidate)) return candidate;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function loadDbis138TokenListFromFile(): Record<string, unknown> | null {
|
||||
const filePath = resolveDbis138TokenListPath();
|
||||
if (!filePath) return null;
|
||||
try {
|
||||
return JSON.parse(readFileSync(filePath, 'utf8')) as Record<string, unknown>;
|
||||
} catch (error) {
|
||||
logger.error('Failed to read dbis-138 token list:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function finalizeUniswapTokenListResponse(
|
||||
req: Request,
|
||||
res: Response,
|
||||
@@ -1611,6 +1645,13 @@ router.get(
|
||||
? [parseInt(chainIdParam, 10)].filter((n) => !isNaN(n))
|
||||
: getSupportedChainIds();
|
||||
|
||||
if (chainIds.length === 1 && chainIds[0] === 138) {
|
||||
const fileList = loadDbis138TokenListFromFile();
|
||||
if (fileList) {
|
||||
return finalizeUniswapTokenListResponse(req, res, fileList, chainIds);
|
||||
}
|
||||
}
|
||||
|
||||
const tokenListUrl = process.env.TOKEN_LIST_JSON_URL?.trim();
|
||||
if (tokenListUrl) {
|
||||
try {
|
||||
@@ -1670,7 +1711,7 @@ router.get(
|
||||
name: 'GRU Canonical Token List',
|
||||
version: { major: 1, minor: 0, patch: 0 },
|
||||
timestamp: new Date().toISOString(),
|
||||
logoURI: absolutePublicUrl(req, DBIS_CHAIN_138_LOGO_PATH),
|
||||
logoURI: 'https://d-bis.org/brand/chain-138.svg',
|
||||
tokens: list,
|
||||
},
|
||||
chainIds
|
||||
|
||||
@@ -929,9 +929,16 @@ export function resolveCanonicalQuoteAddress(chainId: number, address: string):
|
||||
* Every token must have logoURI for MetaMask to display icons. getLogoUriForSpec resolves
|
||||
* ac-tokens from base (c*), vdc/sdc from base; unknown symbols fall back to ETH_LOGO. */
|
||||
const IPFS_GATEWAY = 'https://ipfs.io/ipfs';
|
||||
/** Canonical hosted marks — https://d-bis.org/brand-assets */
|
||||
export const DBIS_BRAND_LOGO_BASE = 'https://d-bis.org';
|
||||
const GRU_LOGO_BASE =
|
||||
'https://raw.githubusercontent.com/Order-of-Hospitallers/proxmox-cp/main/token-lists/logos/gru';
|
||||
const ETH_LOGO = '/api/v1/report/logo/ETH';
|
||||
|
||||
export function dbisBrandLogoUrl(symbol: string): string {
|
||||
if (symbol.startsWith('Li')) return `${DBIS_BRAND_LOGO_BASE}/li/${symbol.toLowerCase()}.svg`;
|
||||
return `${DBIS_BRAND_LOGO_BASE}/tokens/${symbol.toLowerCase()}.svg`;
|
||||
}
|
||||
const LINK_LOGO = '/api/v1/report/logo/LINK';
|
||||
const GAS_NATIVE_LOGO_BY_CODE: Record<string, string> = {
|
||||
ETH: ETH_LOGO,
|
||||
@@ -943,9 +950,9 @@ const GAS_NATIVE_LOGO_BY_CODE: Record<string, string> = {
|
||||
CELO: '/api/v1/report/logo/CELO',
|
||||
WEMIX: '/api/v1/report/logo/WEMIX',
|
||||
};
|
||||
const USDC_LOGO = `${GRU_LOGO_BASE}/cUSDC.svg`;
|
||||
const USDT_LOGO = `${GRU_LOGO_BASE}/cUSDT.svg`;
|
||||
const BTC_LOGO = 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/bitcoin/info/logo.png';
|
||||
const USDC_LOGO = dbisBrandLogoUrl('cUSDC');
|
||||
const USDT_LOGO = dbisBrandLogoUrl('cUSDT');
|
||||
const BTC_LOGO = dbisBrandLogoUrl('cBTC');
|
||||
|
||||
const LOGO_BY_SYMBOL: Record<string, string> = {
|
||||
USDC: USDC_LOGO,
|
||||
@@ -957,30 +964,44 @@ const LOGO_BY_SYMBOL: Record<string, string> = {
|
||||
cAUSDT: USDT_LOGO,
|
||||
cUSDW: USDC_LOGO,
|
||||
cBTC: BTC_LOGO,
|
||||
cWAUSDT: USDT_LOGO,
|
||||
cWBTC: BTC_LOGO,
|
||||
cWUSDC: USDC_LOGO,
|
||||
cWUSDT: USDT_LOGO,
|
||||
cWUSDW: USDC_LOGO,
|
||||
cWAUSDT: dbisBrandLogoUrl('cWAUSDT'),
|
||||
cWBTC: dbisBrandLogoUrl('cWBTC'),
|
||||
cWUSDC: dbisBrandLogoUrl('cWUSDC'),
|
||||
cWUSDT: dbisBrandLogoUrl('cWUSDT'),
|
||||
cWUSDW: dbisBrandLogoUrl('cWUSDW'),
|
||||
cWEURC: dbisBrandLogoUrl('cWEURC'),
|
||||
cWEURT: dbisBrandLogoUrl('cWEURT'),
|
||||
cWGBPC: dbisBrandLogoUrl('cWGBPC'),
|
||||
cWGBPT: dbisBrandLogoUrl('cWGBPT'),
|
||||
cWAUDC: dbisBrandLogoUrl('cWAUDC'),
|
||||
cWJPYC: dbisBrandLogoUrl('cWJPYC'),
|
||||
cWCHFC: dbisBrandLogoUrl('cWCHFC'),
|
||||
cWCADC: dbisBrandLogoUrl('cWCADC'),
|
||||
cWXAUC: dbisBrandLogoUrl('cWXAUC'),
|
||||
cWXAUT: dbisBrandLogoUrl('cWXAUT'),
|
||||
cWEMIX: GAS_NATIVE_LOGO_BY_CODE.WEMIX,
|
||||
WETH: ETH_LOGO,
|
||||
WETH10: ETH_LOGO,
|
||||
LINK: LINK_LOGO,
|
||||
cEURC: `${GRU_LOGO_BASE}/cEURC.svg`,
|
||||
cEURT: `${GRU_LOGO_BASE}/cEURT.svg`,
|
||||
cGBPC: `${GRU_LOGO_BASE}/cGBPC.svg`,
|
||||
cGBPT: `${GRU_LOGO_BASE}/cGBPT.svg`,
|
||||
cAUDC: `${GRU_LOGO_BASE}/cAUDC.svg`,
|
||||
cJPYC: `${GRU_LOGO_BASE}/cJPYC.svg`,
|
||||
cCHFC: `${GRU_LOGO_BASE}/cCHFC.svg`,
|
||||
cCADC: `${GRU_LOGO_BASE}/cCADC.svg`,
|
||||
cXAUC: `${GRU_LOGO_BASE}/cXAUC.svg`,
|
||||
cXAUT: `${GRU_LOGO_BASE}/cXAUT.svg`,
|
||||
cAXAUC: `${GRU_LOGO_BASE}/cXAUC.svg`,
|
||||
cAXAUT: `${GRU_LOGO_BASE}/cXAUT.svg`,
|
||||
cWAXAUC: `${GRU_LOGO_BASE}/cXAUC.svg`,
|
||||
cWAXAUT: `${GRU_LOGO_BASE}/cXAUT.svg`,
|
||||
LiXAU: `${IPFS_GATEWAY}/QmUVY5trUM5N1UnS4abReb66fNzGw7kenjU9AjL7TgR3M1`,
|
||||
cEURC: dbisBrandLogoUrl('cEURC'),
|
||||
cEURT: dbisBrandLogoUrl('cEURT'),
|
||||
cGBPC: dbisBrandLogoUrl('cGBPC'),
|
||||
cGBPT: dbisBrandLogoUrl('cGBPT'),
|
||||
cAUDC: dbisBrandLogoUrl('cAUDC'),
|
||||
cJPYC: dbisBrandLogoUrl('cJPYC'),
|
||||
cCHFC: dbisBrandLogoUrl('cCHFC'),
|
||||
cCADC: dbisBrandLogoUrl('cCADC'),
|
||||
cXAUC: dbisBrandLogoUrl('cXAUC'),
|
||||
cXAUT: dbisBrandLogoUrl('cXAUT'),
|
||||
cAXAUC: dbisBrandLogoUrl('cXAUC'),
|
||||
cAXAUT: dbisBrandLogoUrl('cXAUT'),
|
||||
cWAXAUC: dbisBrandLogoUrl('cWXAUC'),
|
||||
cWAXAUT: dbisBrandLogoUrl('cWXAUT'),
|
||||
LiXAU: dbisBrandLogoUrl('LiXAU'),
|
||||
LiPMG: dbisBrandLogoUrl('LiPMG'),
|
||||
LiBMG1: dbisBrandLogoUrl('LiBMG1'),
|
||||
LiBMG2: dbisBrandLogoUrl('LiBMG2'),
|
||||
LiBMG3: dbisBrandLogoUrl('LiBMG3'),
|
||||
USDW: USDC_LOGO,
|
||||
EURW: `${IPFS_GATEWAY}/QmPh16PY241zNtePyeK7ep1uf1RcARV2ynGAuRU8U7sSqS`,
|
||||
GBPW: `${IPFS_GATEWAY}/QmT2nJ6WyhYBCsYJ6NfS1BPAqiGKkCEuMxiC8ye93Co1hF`,
|
||||
|
||||
Reference in New Issue
Block a user