@pioneer-platform/pioneer-discovery 8.15.15 ā 8.15.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/package.json +1 -1
- package/scripts/.missing-icons.json +134 -0
- package/scripts/audit-asset-icons.js +164 -0
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
{
|
|
2
|
+
"timestamp": "2025-11-26T00:02:25.817Z",
|
|
3
|
+
"totalAssets": 14168,
|
|
4
|
+
"summary": {
|
|
5
|
+
"totalMissing": 4,
|
|
6
|
+
"s3Unavailable": 17
|
|
7
|
+
},
|
|
8
|
+
"missingIcons": [
|
|
9
|
+
{
|
|
10
|
+
"caip": "eip155:8453/erc20:0x8b15cbb7ecd9b8fff38da8ead55a20490b99ad11",
|
|
11
|
+
"symbol": "BALL",
|
|
12
|
+
"reason": "no_icon_url"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"caip": "eip155:8453/erc20:0x5b8a5b8e97292feff3a4a45aaf4a64c14fda27f6",
|
|
16
|
+
"symbol": "GRIF_GG",
|
|
17
|
+
"reason": "no_icon_url"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"caip": "eip155:8453/erc20:0x484c46efdc3f2f9ed6c28ef8a907b0da25245889",
|
|
21
|
+
"symbol": "TARD",
|
|
22
|
+
"reason": "no_icon_url"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"caip": "eip155:8453/erc20:0x29f3c0b678ffbe6c61bdca1054014f02be6c7450",
|
|
26
|
+
"symbol": "ANERI",
|
|
27
|
+
"reason": "no_icon_url"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"unavailableS3Icons": [
|
|
31
|
+
{
|
|
32
|
+
"caip": "bip122:000000000019d6689c085ae165831e93/slip44:0",
|
|
33
|
+
"symbol": "BTC",
|
|
34
|
+
"icon": "https://api.keepkey.info/coins/YmlwMTIyOjAwMDAwMDAwMDAxOWQ2Njg5YzA4NWFlMTY1ODMxZTkzL3NsaXA0NDow.png",
|
|
35
|
+
"reason": "s3_404"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"caip": "eip155:1/slip44:60",
|
|
39
|
+
"symbol": "ETH",
|
|
40
|
+
"icon": "https://api.keepkey.info/coins/ZWlwMTU1OjEvc2xpcDQ0OjYw.png",
|
|
41
|
+
"reason": "s3_404"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"caip": "cosmos:osmosis-1/slip44:118",
|
|
45
|
+
"symbol": "OSMO",
|
|
46
|
+
"icon": "https://api.keepkey.info/coins/Y29zbW9zOm9zbW9zaXMtMS9zbGlwNDQ6MTE4.png",
|
|
47
|
+
"reason": "s3_404"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"caip": "cosmos:thorchain-mainnet-v1/slip44:931",
|
|
51
|
+
"symbol": "RUNE",
|
|
52
|
+
"icon": "https://api.keepkey.info/coins/Y29zbW9zOnRob3JjaGFpbi1tYWlubmV0LXYxL3NsaXA0NDo5MzE=.png",
|
|
53
|
+
"reason": "s3_404"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"caip": "bip122:000000000000000000651ef99cb9fcbe/slip44:145",
|
|
57
|
+
"symbol": "BCH",
|
|
58
|
+
"icon": "https://api.keepkey.info/coins/YmlwMTIyOjAwMDAwMDAwMDAwMDAwMDAwMDY1MWVmOTljYjlmY2JlL3NsaXA0NDoxNDU=.png",
|
|
59
|
+
"reason": "s3_404"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"caip": "bip122:00000000001a91e3dace36e2be3bf030/slip44:3",
|
|
63
|
+
"symbol": "DOGE",
|
|
64
|
+
"icon": "https://api.keepkey.info/coins/YmlwMTIyOjAwMDAwMDAwMDAxYTkxZTNkYWNlMzZlMmJlM2JmMDMwL3NsaXA0NDoz.png",
|
|
65
|
+
"reason": "s3_404"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"caip": "bip122:000007d91d1254d60e2dd1ae58038307/slip44:5",
|
|
69
|
+
"symbol": "DASH",
|
|
70
|
+
"icon": "https://api.keepkey.info/coins/YmlwMTIyOjAwMDAwN2Q5MWQxMjU0ZDYwZTJkZDFhZTU4MDM4MzA3L3NsaXA0NDo1.png",
|
|
71
|
+
"reason": "s3_404"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"caip": "bip122:4da631f2ac1bed857bd968c67c913978/slip44:20",
|
|
75
|
+
"symbol": "DGB",
|
|
76
|
+
"icon": "https://api.keepkey.info/coins/YmlwMTIyOjRkYTYzMWYyYWMxYmVkODU3YmQ5NjhjNjdjOTEzOTc4L3NsaXA0NDoyMA==.png",
|
|
77
|
+
"reason": "s3_404"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"caip": "eip155:43114/slip44:60",
|
|
81
|
+
"symbol": "AVAX",
|
|
82
|
+
"icon": "https://api.keepkey.info/coins/ZWlwMTU1OjQzMTE0L3NsaXA0NDo2MA==.png",
|
|
83
|
+
"reason": "s3_404"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"caip": "eip155:137/slip44:60",
|
|
87
|
+
"symbol": "MATIC",
|
|
88
|
+
"icon": "https://api.keepkey.info/coins/ZWlwMTU1OjEzNy9zbGlwNDQ6NjA=.png",
|
|
89
|
+
"reason": "s3_404"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"caip": "eip155:42161/slip44:60",
|
|
93
|
+
"symbol": "ARB",
|
|
94
|
+
"icon": "https://api.keepkey.info/coins/ZWlwMTU1OjQyMTYxL3NsaXA0NDo2MA==.png",
|
|
95
|
+
"reason": "s3_404"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"caip": "eip155:10/slip44:60",
|
|
99
|
+
"symbol": "OP",
|
|
100
|
+
"icon": "https://api.keepkey.info/coins/ZWlwMTU1OjEwL3NsaXA0NDo2MA==.png",
|
|
101
|
+
"reason": "s3_404"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"caip": "eip155:8453/slip44:60",
|
|
105
|
+
"symbol": "BASE",
|
|
106
|
+
"icon": "https://api.keepkey.info/coins/ZWlwMTU1Ojg0NTMvc2xpcDQ0OjYw.png",
|
|
107
|
+
"reason": "s3_404"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"caip": "eip155:1/erc20:0x0173661769325565d4f011b2e5cda688689cc87c",
|
|
111
|
+
"symbol": "QLT",
|
|
112
|
+
"icon": "https://api.keepkey.info/coins/ZWlwMTU1OjEvZXJjMjA6MHgwMTczNjYxNzY5MzI1NTY1ZDRmMDExYjJlNWNkYTY4ODY4OWNjODdj.png",
|
|
113
|
+
"reason": "s3_404"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"caip": "eip155:1/erc20:0x01ba67aac7f75f647d94220cc98fb30fcc5105bf",
|
|
117
|
+
"symbol": "LYRA",
|
|
118
|
+
"icon": "https://api.keepkey.info/coins/ZWlwMTU1OjEvZXJjMjA6MHgwMWJhNjdhYWM3Zjc1ZjY0N2Q5NDIyMGNjOThmYjMwZmNjNTEwNWJm.png",
|
|
119
|
+
"reason": "s3_404"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"caip": "eip155:1/erc20:0x0198f46f520f33cd4329bd4be380a25a90536cd5",
|
|
123
|
+
"symbol": "PLA",
|
|
124
|
+
"icon": "https://api.keepkey.info/coins/ZWlwMTU1OjEvZXJjMjA6MHgwMTk4ZjQ2ZjUyMGYzM2NkNDMyOWJkNGJlMzgwYTI1YTkwNTM2Y2Q1.png",
|
|
125
|
+
"reason": "s3_404"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"caip": "eip155:1/erc20:0x01792e1548dc317bde6123fe92da1fe6d7311c3c",
|
|
129
|
+
"symbol": "SPIRAL",
|
|
130
|
+
"icon": "https://api.keepkey.info/coins/ZWlwMTU1OjEvZXJjMjA6MHgwMTc5MmUxNTQ4ZGMzMTdiZGU2MTIzZmU5MmRhMWZlNmQ3MzExYzNj.png",
|
|
131
|
+
"reason": "s3_404"
|
|
132
|
+
}
|
|
133
|
+
]
|
|
134
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Audit Asset Icons
|
|
4
|
+
*
|
|
5
|
+
* This script audits all asset icons to check:
|
|
6
|
+
* 1. Which icons are hosted on S3 (KeepKey, Pioneers, DigitalOcean)
|
|
7
|
+
* 2. Which icons are external (TrustWallet, ShapeShift, etc.)
|
|
8
|
+
* 3. Which icons are missing or return 404
|
|
9
|
+
*
|
|
10
|
+
* Creates an untracked file with missing icons for later processing.
|
|
11
|
+
*
|
|
12
|
+
* Usage: node scripts/audit-asset-icons.js
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
const https = require('https');
|
|
18
|
+
const http = require('http');
|
|
19
|
+
|
|
20
|
+
const ASSET_DATA_PATH = path.join(__dirname, '../src/generatedAssetData.json');
|
|
21
|
+
const MISSING_ICONS_PATH = path.join(__dirname, '.missing-icons.json');
|
|
22
|
+
|
|
23
|
+
// Check if URL returns 200
|
|
24
|
+
function checkUrl(url) {
|
|
25
|
+
return new Promise((resolve) => {
|
|
26
|
+
const protocol = url.startsWith('https') ? https : http;
|
|
27
|
+
const options = {
|
|
28
|
+
method: 'HEAD',
|
|
29
|
+
timeout: 5000,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const req = protocol.request(url, options, (res) => {
|
|
33
|
+
resolve(res.statusCode === 200);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
req.on('error', () => resolve(false));
|
|
37
|
+
req.on('timeout', () => {
|
|
38
|
+
req.destroy();
|
|
39
|
+
resolve(false);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
req.end();
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Categorize icon URL
|
|
47
|
+
function categorizeIcon(iconUrl) {
|
|
48
|
+
if (!iconUrl) return 'missing';
|
|
49
|
+
if (iconUrl.includes('keepkey.sfo3.cdn.digitaloceanspaces.com')) return 's3_keepkey';
|
|
50
|
+
if (iconUrl.includes('api.keepkey.info')) return 's3_api_keepkey';
|
|
51
|
+
if (iconUrl.includes('pioneers.dev')) return 's3_pioneers';
|
|
52
|
+
if (iconUrl.includes('rawcdn.githack.com/trustwallet')) return 'trustwallet';
|
|
53
|
+
if (iconUrl.includes('assets.coingecko.com')) return 'coingecko';
|
|
54
|
+
if (iconUrl.includes('raw.githubusercontent.com')) return 'github';
|
|
55
|
+
return 'other';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function auditIcons() {
|
|
59
|
+
console.log('š Auditing asset icons...\n');
|
|
60
|
+
|
|
61
|
+
// Load asset data
|
|
62
|
+
const assetData = JSON.parse(fs.readFileSync(ASSET_DATA_PATH, 'utf8'));
|
|
63
|
+
const assets = Object.entries(assetData);
|
|
64
|
+
const total = assets.length;
|
|
65
|
+
|
|
66
|
+
console.log(`š Total assets: ${total}\n`);
|
|
67
|
+
|
|
68
|
+
// Categorize icons
|
|
69
|
+
const categories = {
|
|
70
|
+
missing: [],
|
|
71
|
+
s3_keepkey: [],
|
|
72
|
+
s3_api_keepkey: [],
|
|
73
|
+
s3_pioneers: [],
|
|
74
|
+
trustwallet: [],
|
|
75
|
+
coingecko: [],
|
|
76
|
+
github: [],
|
|
77
|
+
other: [],
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
for (const [caip, asset] of assets) {
|
|
81
|
+
const category = categorizeIcon(asset.icon);
|
|
82
|
+
categories[category].push({ caip, icon: asset.icon, symbol: asset.symbol });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
console.log('š Icon Source Distribution:');
|
|
86
|
+
console.log(` Missing: ${categories.missing.length.toString().padStart(5)} (${((categories.missing.length/total)*100).toFixed(1)}%)`);
|
|
87
|
+
console.log(` S3 KeepKey: ${categories.s3_keepkey.length.toString().padStart(5)} (${((categories.s3_keepkey.length/total)*100).toFixed(1)}%)`);
|
|
88
|
+
console.log(` S3 API KeepKey: ${categories.s3_api_keepkey.length.toString().padStart(5)} (${((categories.s3_api_keepkey.length/total)*100).toFixed(1)}%)`);
|
|
89
|
+
console.log(` S3 Pioneers: ${categories.s3_pioneers.length.toString().padStart(5)} (${((categories.s3_pioneers.length/total)*100).toFixed(1)}%)`);
|
|
90
|
+
console.log(` TrustWallet: ${categories.trustwallet.length.toString().padStart(5)} (${((categories.trustwallet.length/total)*100).toFixed(1)}%)`);
|
|
91
|
+
console.log(` CoinGecko: ${categories.coingecko.length.toString().padStart(5)} (${((categories.coingecko.length/total)*100).toFixed(1)}%)`);
|
|
92
|
+
console.log(` GitHub: ${categories.github.length.toString().padStart(5)} (${((categories.github.length/total)*100).toFixed(1)}%)`);
|
|
93
|
+
console.log(` Other: ${categories.other.length.toString().padStart(5)} (${((categories.other.length/total)*100).toFixed(1)}%)`);
|
|
94
|
+
|
|
95
|
+
// Sample check S3 availability (first 20)
|
|
96
|
+
console.log('\nš Checking S3 icon availability (sample of 20)...');
|
|
97
|
+
const s3Icons = [...categories.s3_keepkey, ...categories.s3_api_keepkey, ...categories.s3_pioneers];
|
|
98
|
+
const sampleSize = Math.min(20, s3Icons.length);
|
|
99
|
+
let availableCount = 0;
|
|
100
|
+
let unavailableS3 = [];
|
|
101
|
+
|
|
102
|
+
for (let i = 0; i < sampleSize; i++) {
|
|
103
|
+
const { caip, icon, symbol } = s3Icons[i];
|
|
104
|
+
const available = await checkUrl(icon);
|
|
105
|
+
if (available) {
|
|
106
|
+
availableCount++;
|
|
107
|
+
} else {
|
|
108
|
+
unavailableS3.push({ caip, icon, symbol });
|
|
109
|
+
}
|
|
110
|
+
process.stdout.write(`\r Checked ${i + 1}/${sampleSize}... `);
|
|
111
|
+
}
|
|
112
|
+
console.log(`ā
${availableCount}/${sampleSize} available`);
|
|
113
|
+
|
|
114
|
+
if (unavailableS3.length > 0) {
|
|
115
|
+
console.log(`\nā ļø Found ${unavailableS3.length} unavailable S3 icons in sample:`);
|
|
116
|
+
unavailableS3.slice(0, 5).forEach(({ symbol, caip }) => {
|
|
117
|
+
console.log(` ${(symbol || 'N/A').padEnd(8)} ${caip.substring(0, 50)}...`);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Create missing icons report
|
|
122
|
+
const missingReport = {
|
|
123
|
+
timestamp: new Date().toISOString(),
|
|
124
|
+
totalAssets: total,
|
|
125
|
+
summary: {
|
|
126
|
+
totalMissing: categories.missing.length,
|
|
127
|
+
s3Unavailable: unavailableS3.length,
|
|
128
|
+
},
|
|
129
|
+
missingIcons: categories.missing.map(({ caip, symbol }) => ({
|
|
130
|
+
caip,
|
|
131
|
+
symbol: symbol || 'N/A',
|
|
132
|
+
reason: 'no_icon_url',
|
|
133
|
+
})),
|
|
134
|
+
unavailableS3Icons: unavailableS3.map(({ caip, icon, symbol }) => ({
|
|
135
|
+
caip,
|
|
136
|
+
symbol: symbol || 'N/A',
|
|
137
|
+
icon,
|
|
138
|
+
reason: 's3_404',
|
|
139
|
+
})),
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
fs.writeFileSync(MISSING_ICONS_PATH, JSON.stringify(missingReport, null, 2));
|
|
143
|
+
console.log(`\nš Missing icons report saved to: ${MISSING_ICONS_PATH}`);
|
|
144
|
+
|
|
145
|
+
// Show sample missing
|
|
146
|
+
if (categories.missing.length > 0) {
|
|
147
|
+
console.log(`\nā Sample assets with no icon URL (${Math.min(10, categories.missing.length)} of ${categories.missing.length}):`);
|
|
148
|
+
categories.missing.slice(0, 10).forEach(({ caip, symbol }) => {
|
|
149
|
+
console.log(` ${(symbol || 'N/A').padEnd(8)} ${caip.substring(0, 60)}...`);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
console.log('\nā
Audit complete!');
|
|
154
|
+
console.log(` Total missing/unavailable: ${categories.missing.length + unavailableS3.length}`);
|
|
155
|
+
console.log(` Report saved to: .missing-icons.json (untracked)`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Execute
|
|
159
|
+
auditIcons()
|
|
160
|
+
.then(() => process.exit(0))
|
|
161
|
+
.catch(err => {
|
|
162
|
+
console.error('ā Error:', err.message);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
});
|