Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ VITE_SWAP_BUTTON_SWITCH="true"
VITE_PAYMASTER_URL="http://localhost:5050"
VITE_SENTRY_ENVIRONMENT="staging"
VITE_PULSE_NODE_URL="https://pulse.etherspot.io"
VITE_MOBULA_API_KEY="your_api_key_here"
62 changes: 40 additions & 22 deletions src/apps/insights/utils/logoUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ export const loadLogoCache = (): Record<string, LogoCacheEntry> => {
try {
const cached = localStorage.getItem(CACHE_KEY);
if (!cached) return {};

const cache: Record<string, LogoCacheEntry> = JSON.parse(cached);
const now = Date.now();

// Prune expired entries
const pruned: Record<string, LogoCacheEntry> = {};
Object.entries(cache).forEach(([symbol, entry]) => {
Expand All @@ -29,7 +29,7 @@ export const loadLogoCache = (): Record<string, LogoCacheEntry> => {
pruned[symbol] = entry;
}
});

return pruned;
} catch (err) {
console.error('Error loading logo cache:', err);
Expand All @@ -45,72 +45,90 @@ export const saveLogoCache = (cache: Record<string, LogoCacheEntry>) => {
}
};

export const getCachedLogo = (symbol: string, cache: Record<string, LogoCacheEntry>): string | null => {
export const getCachedLogo = (
symbol: string,
cache: Record<string, LogoCacheEntry>
): string | null => {
const entry = cache[symbol];
if (!entry) return null;

const ttl = entry.miss ? MISS_TTL_MS : HIT_TTL_MS;
if (Date.now() - entry.updatedAt >= ttl) return null;

if (entry.miss) return null; // Don't return misses as valid URLs
return entry.url || null;
};

/**
* Fetch logo for a symbol from Mobula API
*/
export const fetchLogoFromMobula = async (symbol: string): Promise<string | null> => {
export const fetchLogoFromMobula = async (
symbol: string
): Promise<string | null> => {
try {
console.log(`🔍 Querying Mobula for ${symbol}`);
const response = await fetch(
`https://explorer-api.mobula.io/api/1/search?mode=og&sortBy=volume_24h&input=${symbol}`
`https://api.mobula.io/api/1/search?mode=og&sortBy=volume_24h&input=${symbol}`,
Comment thread
vignesha22 marked this conversation as resolved.
{
method: 'GET',
headers: {
Authorization: `${import.meta.env.VITE_MOBULA_API_KEY || 'your_api_key_here'}`,
},
Comment thread
vignesha22 marked this conversation as resolved.
}
);
const data = await response.json();

if (data?.data?.length > 0) {
console.log(`📊 ${symbol} results: ${data.data.length} items`);

// Selection strategy: prefer exact symbol match with highest market_cap
let selectedToken = null;

// First, try exact symbol match (case-insensitive)
const exactMatches = data.data.filter(
(token: any) => token.symbol?.toUpperCase() === symbol
);

if (exactMatches.length > 0) {
// Pick highest market_cap, fallback to liquidity, then volume
selectedToken = exactMatches.reduce((best: any, current: any) => {
const bestScore = best.market_cap || best.liquidity || best.volume || 0;
const currentScore = current.market_cap || current.liquidity || current.volume || 0;
const bestScore =
best.market_cap || best.liquidity || best.volume || 0;
const currentScore =
current.market_cap || current.liquidity || current.volume || 0;
return currentScore > bestScore ? current : best;
});
console.log(`✓ ${symbol} exact match: ${selectedToken.name} (${selectedToken.symbol}) - market_cap: ${selectedToken.market_cap}`);
console.log(
`✓ ${symbol} exact match: ${selectedToken.name} (${selectedToken.symbol}) - market_cap: ${selectedToken.market_cap}`
);
} else {
// Fallback: pick item with highest market_cap that has a logo
selectedToken = data.data
.filter((token: any) => token.logo)
.reduce((best: any, current: any) => {
if (!best) return current;
const bestScore = best.market_cap || best.liquidity || best.volume || 0;
const currentScore = current.market_cap || current.liquidity || current.volume || 0;
const bestScore =
best.market_cap || best.liquidity || best.volume || 0;
const currentScore =
current.market_cap || current.liquidity || current.volume || 0;
return currentScore > bestScore ? current : best;
}, null);

if (selectedToken) {
console.log(`⚠️ ${symbol} fallback match: ${selectedToken.name} (${selectedToken.symbol})`);
console.log(
`⚠️ ${symbol} fallback match: ${selectedToken.name} (${selectedToken.symbol})`
);
}
}

if (selectedToken?.logo) {
return selectedToken.logo;
}
}

return null;
} catch (err) {
console.error(`❌ Failed to fetch logo for ${symbol}:`, err);
return null;
}
};

Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ exports[`<LeftColumnTokenMarketDataRow /> - ETH token row > renders and matches
<p
class="text-sm font-medium font-normal text-white"
>
10mo ago
1year ago
</p>
<p
class="text-sm font-medium font-normal mobile:hidden text-white"
Expand Down Expand Up @@ -106,7 +106,7 @@ exports[`<LeftColumnTokenMarketDataRow /> - ETH token row > renders and matches
<p
class="text-sm font-medium font-normal text-white"
>
10mo ago
1year ago
</p>
<p
class="text-sm font-medium font-normal mobile:hidden text-white"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ exports[`<TokensWithMarketDataTile /> > renders and matches snapshot 1`] = `
<p
class="text-sm font-medium font-normal text-white"
>
10mo ago
1year ago
</p>
<p
class="text-sm font-medium font-normal mobile:hidden text-white"
Expand Down Expand Up @@ -260,7 +260,7 @@ exports[`<TokensWithMarketDataTile /> > renders and matches snapshot 1`] = `
<p
class="text-sm font-medium font-normal text-white"
>
10mo ago
1year ago
</p>
<p
class="text-sm font-medium font-normal mobile:hidden text-white"
Expand Down Expand Up @@ -421,7 +421,7 @@ exports[`<TokensWithMarketDataTile /> > renders and matches snapshot 1`] = `
<p
class="text-sm font-medium font-normal text-white"
>
10mo ago
1year ago
</p>
<p
class="text-sm font-medium font-normal mobile:hidden text-white"
Expand Down Expand Up @@ -584,7 +584,7 @@ exports[`<TokensWithMarketDataTile /> > renders and matches snapshot 1`] = `
<p
class="text-sm font-medium font-normal text-white"
>
10mo ago
1year ago
</p>
<p
class="text-sm font-medium font-normal mobile:hidden text-white"
Expand Down Expand Up @@ -774,7 +774,7 @@ exports[`<TokensWithMarketDataTile /> > renders and matches snapshot 1`] = `
<p
class="text-sm font-medium font-normal text-white"
>
10mo ago
1year ago
</p>
<p
class="text-sm font-medium font-normal mobile:hidden text-white"
Expand Down Expand Up @@ -937,7 +937,7 @@ exports[`<TokensWithMarketDataTile /> > renders and matches snapshot 1`] = `
<p
class="text-sm font-medium font-normal text-white"
>
10mo ago
1year ago
</p>
<p
class="text-sm font-medium font-normal mobile:hidden text-white"
Expand Down Expand Up @@ -1098,7 +1098,7 @@ exports[`<TokensWithMarketDataTile /> > renders and matches snapshot 1`] = `
<p
class="text-sm font-medium font-normal text-white"
>
10mo ago
1year ago
</p>
<p
class="text-sm font-medium font-normal mobile:hidden text-white"
Expand Down Expand Up @@ -1261,7 +1261,7 @@ exports[`<TokensWithMarketDataTile /> > renders and matches snapshot 1`] = `
<p
class="text-sm font-medium font-normal text-white"
>
10mo ago
1year ago
</p>
<p
class="text-sm font-medium font-normal mobile:hidden text-white"
Expand Down
Loading