Skip to content

Commit c46f4d7

Browse files
authored
Update index.html
1 parent d7d24e6 commit c46f4d7

1 file changed

Lines changed: 183 additions & 0 deletions

File tree

index.html

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2587,6 +2587,189 @@ <h3 class="font-bold text-orange-800 mb-2 text-sm">🎯 Target Price</h3>
25872587
// Initialize
25882588
updateTargetPriceLabels();
25892589
</script>
2590+
<!--
2591+
=====================================================================
2592+
CUSTOM TOKEN METADATA FETCHING
2593+
Add this script tag RIGHT BEFORE the closing </body> tag
2594+
=====================================================================
2595+
-->
2596+
<script>
2597+
// ERC20 ABI for fetching token metadata
2598+
const TOKEN_METADATA_ABI = [
2599+
"function name() view returns (string)",
2600+
"function symbol() view returns (string)",
2601+
"function decimals() view returns (uint8)"
2602+
];
2603+
2604+
// Function to validate and fetch token metadata
2605+
async function fetchTokenMetadata(address) {
2606+
try {
2607+
// Validate address format
2608+
if (!address || !address.match(/^0x[a-fA-F0-9]{40}$/)) {
2609+
return { valid: false, error: 'Invalid address format' };
2610+
}
2611+
2612+
// Create provider (using ethers.js which is already loaded)
2613+
const provider = new ethers.providers.JsonRpcProvider('https://mainnet.base.org');
2614+
2615+
// Create contract instance
2616+
const tokenContract = new ethers.Contract(address, TOKEN_METADATA_ABI, provider);
2617+
2618+
// Fetch name, symbol, and decimals in parallel
2619+
const [name, symbol, decimals] = await Promise.all([
2620+
tokenContract.name(),
2621+
tokenContract.symbol(),
2622+
tokenContract.decimals()
2623+
]);
2624+
2625+
return {
2626+
valid: true,
2627+
address: address,
2628+
name: name,
2629+
symbol: symbol,
2630+
decimals: decimals
2631+
};
2632+
} catch (error) {
2633+
console.error('Token metadata fetch error:', error);
2634+
return {
2635+
valid: false,
2636+
error: 'Unable to read token contract. Make sure this is a valid ERC20 token on Base.'
2637+
};
2638+
}
2639+
}
2640+
2641+
// Function to display token info below the input
2642+
function displayTokenInfo(inputElement, metadata) {
2643+
// Remove existing info display if any
2644+
const existingInfo = inputElement.parentElement.querySelector('.token-info-display');
2645+
if (existingInfo) {
2646+
existingInfo.remove();
2647+
}
2648+
2649+
if (metadata.valid) {
2650+
// Create success message with token info
2651+
const infoDiv = document.createElement('div');
2652+
infoDiv.className = 'token-info-display mt-2 p-2 bg-green-50 border border-green-300 rounded-lg text-xs animate-fadeIn';
2653+
infoDiv.innerHTML = `
2654+
<div class="flex items-center gap-2">
2655+
<span class="text-green-600 font-bold">✓ Token Recognized:</span>
2656+
<span class="font-bold text-gray-800">${metadata.symbol}</span>
2657+
</div>
2658+
<div class="text-gray-600 mt-1">${metadata.name}</div>
2659+
`;
2660+
inputElement.parentElement.appendChild(infoDiv);
2661+
2662+
// Store metadata for later use
2663+
inputElement.dataset.symbol = metadata.symbol;
2664+
inputElement.dataset.name = metadata.name;
2665+
inputElement.dataset.decimals = metadata.decimals;
2666+
inputElement.dataset.valid = 'true';
2667+
2668+
} else {
2669+
// Create error message
2670+
const infoDiv = document.createElement('div');
2671+
infoDiv.className = 'token-info-display mt-2 p-2 bg-red-50 border border-red-300 rounded-lg text-xs animate-fadeIn';
2672+
infoDiv.innerHTML = `
2673+
<div class="flex items-center gap-2">
2674+
<span class="text-red-600 font-bold">✗ Error:</span>
2675+
</div>
2676+
<div class="text-red-700 mt-1">${metadata.error}</div>
2677+
`;
2678+
inputElement.parentElement.appendChild(infoDiv);
2679+
2680+
// Mark as invalid
2681+
inputElement.dataset.valid = 'false';
2682+
}
2683+
}
2684+
2685+
// Add debounce helper to avoid too many API calls
2686+
function debounce(func, wait) {
2687+
let timeout;
2688+
return function executedFunction(...args) {
2689+
const later = () => {
2690+
clearTimeout(timeout);
2691+
func(...args);
2692+
};
2693+
clearTimeout(timeout);
2694+
timeout = setTimeout(later, wait);
2695+
};
2696+
}
2697+
2698+
// Enhanced event listener for customTokenIn
2699+
const validateTokenIn = debounce(async function() {
2700+
const address = this.value.trim();
2701+
if (address && address.length === 42) { // Valid address length
2702+
// Show loading state
2703+
this.style.borderColor = '#fdba74'; // orange
2704+
const loadingDiv = document.createElement('div');
2705+
loadingDiv.className = 'token-info-display mt-2 text-xs text-orange-600 flex items-center gap-2';
2706+
loadingDiv.innerHTML = '<span class="spinner"></span> Fetching token info...';
2707+
this.parentElement.appendChild(loadingDiv);
2708+
2709+
const metadata = await fetchTokenMetadata(address);
2710+
2711+
// Remove loading message
2712+
const loadingElement = this.parentElement.querySelector('.token-info-display');
2713+
if (loadingElement) loadingElement.remove();
2714+
2715+
// Display results
2716+
displayTokenInfo(this, metadata);
2717+
2718+
// Update border color based on validity
2719+
if (metadata.valid) {
2720+
this.style.borderColor = '#86efac'; // green
2721+
} else {
2722+
this.style.borderColor = '#fca5a5'; // red
2723+
}
2724+
}
2725+
}, 800); // Wait 800ms after user stops typing
2726+
2727+
document.getElementById('customTokenIn').addEventListener('input', validateTokenIn);
2728+
2729+
// Enhanced event listener for customTokenOut
2730+
const validateTokenOut = debounce(async function() {
2731+
const address = this.value.trim();
2732+
if (address && address.length === 42) { // Valid address length
2733+
// Show loading state
2734+
this.style.borderColor = '#86efac'; // green tint while loading
2735+
const loadingDiv = document.createElement('div');
2736+
loadingDiv.className = 'token-info-display mt-2 text-xs text-green-600 flex items-center gap-2';
2737+
loadingDiv.innerHTML = '<span class="spinner"></span> Fetching token info...';
2738+
this.parentElement.appendChild(loadingDiv);
2739+
2740+
const metadata = await fetchTokenMetadata(address);
2741+
2742+
// Remove loading message
2743+
const loadingElement = this.parentElement.querySelector('.token-info-display');
2744+
if (loadingElement) loadingElement.remove();
2745+
2746+
// Display results
2747+
displayTokenInfo(this, metadata);
2748+
2749+
// Update border color based on validity
2750+
if (metadata.valid) {
2751+
this.style.borderColor = '#86efac'; // green
2752+
} else {
2753+
this.style.borderColor = '#fca5a5'; // red
2754+
}
2755+
}
2756+
}, 800); // Wait 800ms after user stops typing
2757+
2758+
document.getElementById('customTokenOut').addEventListener('input', validateTokenOut);
2759+
2760+
console.log('✅ Custom token metadata validation loaded');
2761+
</script>
2762+
2763+
<!-- Add fade-in animation for smooth appearance -->
2764+
<style>
2765+
@keyframes fadeIn {
2766+
from { opacity: 0; transform: translateY(-10px); }
2767+
to { opacity: 1; transform: translateY(0); }
2768+
}
2769+
.animate-fadeIn {
2770+
animation: fadeIn 0.3s ease-in;
2771+
}
2772+
</style>
25902773
</body>
25912774
</html>
25922775

0 commit comments

Comments
 (0)