Files
proxmox/docs/archive/completion/BLOCKSCOUT_METAMASK_COMPLETE_RECOMMENDATIONS.md
defiQUG cb47cce074 Complete markdown files cleanup and organization
- Organized 252 files across project
- Root directory: 187 → 2 files (98.9% reduction)
- Moved configuration guides to docs/04-configuration/
- Moved troubleshooting guides to docs/09-troubleshooting/
- Moved quick start guides to docs/01-getting-started/
- Moved reports to reports/ directory
- Archived temporary files
- Generated comprehensive reports and documentation
- Created maintenance scripts and guides

All files organized according to established standards.
2026-01-06 01:46:25 -08:00

14 KiB

Blockscout MetaMask Integration - Complete Recommendations

Date: $(date)
Status: Fix Deployed
VMID: 5000
Frontend: /var/www/html/index.html


Completed Fixes

1. Ethers Library Loading

  • Added fallback CDN (unpkg.com)
  • Added automatic fallback detection
  • Added ethers availability checks
  • Improved error handling

2. Deployment

  • Fixed frontend deployed to /var/www/html/index.html
  • Nginx reloaded
  • Changes are live

🔧 Additional Recommendations

1. CDN Optimization & Caching

Current Implementation

<script src="https://cdn.ethers.io/lib/ethers-5.7.2.umd.min.js" 
        onerror="this.onerror=null; this.src='https://unpkg.com/ethers@5.7.2/dist/ethers.umd.min.js';"></script>

A. Add Integrity Checks (SRI)

<script src="https://cdn.ethers.io/lib/ethers-5.7.2.umd.min.js"
        integrity="sha384-..."
        crossorigin="anonymous"
        onerror="this.onerror=null; this.src='https://unpkg.com/ethers@5.7.2/dist/ethers.umd.min.js';"></script>

B. Preload Critical Resources

<link rel="preload" href="https://cdn.ethers.io/lib/ethers-5.7.2.umd.min.js" as="script">
<link rel="dns-prefetch" href="https://cdn.ethers.io">
<link rel="dns-prefetch" href="https://unpkg.com">

C. Local Fallback (Best Practice) Host ethers.js locally as ultimate fallback:

# Download ethers.js locally
cd /var/www/html
wget https://unpkg.com/ethers@5.7.2/dist/ethers.umd.min.js -O js/ethers.umd.min.js

# Update HTML to use local fallback
<script src="https://cdn.ethers.io/lib/ethers-5.7.2.umd.min.js"
        onerror="this.onerror=null; this.src='https://unpkg.com/ethers@5.7.2/dist/ethers.umd.min.js';"
        onerror="this.onerror=null; this.src='/js/ethers.umd.min.js';"></script>

2. MetaMask Connection Enhancements

A. Add Connection State Persistence

// Save connection state to localStorage
function saveConnectionState(address, chainId) {
    localStorage.setItem('metamask_connected', 'true');
    localStorage.setItem('metamask_address', address);
    localStorage.setItem('metamask_chainId', chainId);
}

// Restore connection on page load
function restoreConnection() {
    if (localStorage.getItem('metamask_connected') === 'true') {
        const savedAddress = localStorage.getItem('metamask_address');
        if (savedAddress && typeof window.ethereum !== 'undefined') {
            connectMetaMask();
        }
    }
}

B. Add Network Detection

async function detectNetwork() {
    if (typeof window.ethereum === 'undefined') return null;
    
    try {
        const chainId = await window.ethereum.request({ method: 'eth_chainId' });
        const chainIdDecimal = parseInt(chainId, 16);
        
        if (chainIdDecimal !== 138) {
            return {
                current: chainIdDecimal,
                required: 138,
                needsSwitch: true
            };
        }
        return { current: chainIdDecimal, required: 138, needsSwitch: false };
    } catch (error) {
        console.error('Network detection failed:', error);
        return null;
    }
}

C. Add Connection Retry Logic

async function connectMetaMaskWithRetry(maxRetries = 3) {
    for (let i = 0; i < maxRetries; i++) {
        try {
            await connectMetaMask();
            return true;
        } catch (error) {
            if (i === maxRetries - 1) throw error;
            await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
        }
    }
}

3. Error Handling & User Feedback

A. Enhanced Error Messages

const ERROR_MESSAGES = {
    NO_METAMASK: 'MetaMask is not installed. Please install MetaMask extension.',
    NO_ETHERS: 'Ethers library failed to load. Please refresh the page.',
    WRONG_NETWORK: 'Please switch to ChainID 138 (SMOM-DBIS-138) in MetaMask.',
    USER_REJECTED: 'Connection request was rejected. Please try again.',
    NETWORK_ERROR: 'Network error. Please check your connection and try again.'
};

function getErrorMessage(error) {
    if (error.code === 4001) return ERROR_MESSAGES.USER_REJECTED;
    if (error.code === 4902) return ERROR_MESSAGES.WRONG_NETWORK;
    if (error.message.includes('ethers')) return ERROR_MESSAGES.NO_ETHERS;
    return error.message || ERROR_MESSAGES.NETWORK_ERROR;
}

B. Toast Notifications

Add a toast notification system for better UX:

function showToast(message, type = 'info', duration = 3000) {
    const toast = document.createElement('div');
    toast.className = `toast toast-${type}`;
    toast.textContent = message;
    document.body.appendChild(toast);
    
    setTimeout(() => {
        toast.classList.add('show');
    }, 10);
    
    setTimeout(() => {
        toast.classList.remove('show');
        setTimeout(() => toast.remove(), 300);
    }, duration);
}

4. Performance Optimizations

A. Lazy Load MetaMask Functions

// Only load MetaMask-related code when needed
let metamaskLoaded = false;

async function loadMetaMaskSupport() {
    if (metamaskLoaded) return;
    
    // Dynamically import MetaMask functions
    const module = await import('./metamask-support.js');
    metamaskLoaded = true;
    return module;
}

// Call when user clicks "Connect MetaMask"
document.getElementById('connectMetaMask').addEventListener('click', async () => {
    await loadMetaMaskSupport();
    connectMetaMask();
});

B. Debounce Balance Updates

function debounce(func, wait) {
    let timeout;
    return function executedFunction(...args) {
        const later = () => {
            clearTimeout(timeout);
            func(...args);
        };
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
    };
}

const debouncedRefresh = debounce(refreshWETHBalances, 1000);

C. Cache Contract Instances

let contractCache = {};

function getContract(address, abi, provider) {
    const key = `${address}-${provider.connection?.url || 'default'}`;
    if (!contractCache[key]) {
        contractCache[key] = new ethers.Contract(address, abi, provider);
    }
    return contractCache[key];
}

5. Security Enhancements

A. Validate Contract Addresses

function isValidAddress(address) {
    return /^0x[a-fA-F0-9]{40}$/.test(address);
}

function validateContractAddress(address, expectedAddress) {
    if (!isValidAddress(address)) {
        throw new Error('Invalid contract address format');
    }
    if (address.toLowerCase() !== expectedAddress.toLowerCase()) {
        throw new Error('Contract address mismatch');
    }
}

B. Add Transaction Confirmation

async function confirmTransaction(txHash, description) {
    const confirmed = confirm(
        `${description}\n\n` +
        `Transaction: ${txHash}\n\n` +
        `View on explorer: https://explorer.d-bis.org/tx/${txHash}\n\n` +
        `Continue?`
    );
    return confirmed;
}

C. Rate Limiting

const rateLimiter = {
    requests: [],
    maxRequests: 10,
    window: 60000, // 1 minute
    
    canMakeRequest() {
        const now = Date.now();
        this.requests = this.requests.filter(time => now - time < this.window);
        
        if (this.requests.length >= this.maxRequests) {
            return false;
        }
        
        this.requests.push(now);
        return true;
    }
};

6. Monitoring & Analytics

A. Error Tracking

function trackError(error, context) {
    // Send to analytics service
    if (typeof gtag !== 'undefined') {
        gtag('event', 'exception', {
            description: error.message,
            fatal: false,
            context: context
        });
    }
    
    // Log to console in development
    if (window.location.hostname === 'localhost') {
        console.error('Error:', error, 'Context:', context);
    }
}

B. Connection Metrics

const connectionMetrics = {
    startTime: null,
    attempts: 0,
    successes: 0,
    failures: 0,
    
    start() {
        this.startTime = Date.now();
        this.attempts++;
    },
    
    success() {
        this.successes++;
        const duration = Date.now() - this.startTime;
        console.log(`Connection successful in ${duration}ms`);
    },
    
    failure(error) {
        this.failures++;
        console.error('Connection failed:', error);
    }
};

7. Accessibility Improvements

A. ARIA Labels

<button 
    id="connectMetaMask" 
    onclick="connectMetaMask()"
    aria-label="Connect MetaMask wallet"
    aria-describedby="metamask-help">
    Connect MetaMask
</button>
<div id="metamask-help" class="sr-only">
    Connect your MetaMask wallet to interact with WETH utilities
</div>

B. Keyboard Navigation

document.addEventListener('keydown', (e) => {
    if (e.key === 'Enter' && e.target.id === 'connectMetaMask') {
        connectMetaMask();
    }
});

8. Testing Recommendations

A. Unit Tests

// test/metamask-connection.test.js
describe('MetaMask Connection', () => {
    test('should detect MetaMask availability', () => {
        window.ethereum = { isMetaMask: true };
        expect(checkMetaMaskConnection()).toBe(true);
    });
    
    test('should handle missing ethers library', () => {
        delete window.ethers;
        expect(() => ensureEthers()).toThrow();
    });
});

B. Integration Tests

  • Test with MetaMask extension installed
  • Test with MetaMask not installed
  • Test network switching
  • Test transaction signing
  • Test error scenarios

C. E2E Tests

// Use Playwright or Cypress
test('connect MetaMask and wrap WETH', async ({ page }) => {
    await page.goto('https://explorer.d-bis.org');
    await page.click('#connectMetaMask');
    // ... test flow
});

9. Documentation Updates

A. User Guide

Create docs/METAMASK_USER_GUIDE.md:

  • How to install MetaMask
  • How to add ChainID 138
  • How to connect wallet
  • How to use WETH utilities
  • Troubleshooting common issues

B. Developer Guide

Create docs/METAMASK_DEVELOPER_GUIDE.md:

  • Architecture overview
  • API reference
  • Extension points
  • Testing guide
  • Deployment guide

10. Infrastructure Improvements

A. Content Security Policy (CSP)

# Add to nginx config
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.ethers.io https://unpkg.com; style-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com;";

B. Service Worker for Offline Support

// sw.js
self.addEventListener('fetch', (event) => {
    if (event.request.url.includes('ethers.umd.min.js')) {
        event.respondWith(
            caches.match(event.request).then((response) => {
                return response || fetch(event.request);
            })
        );
    }
});

C. Health Check Endpoint

// Add to API
app.get('/health/metamask', (req, res) => {
    res.json({
        ethers_loaded: typeof ethers !== 'undefined',
        metamask_available: typeof window.ethereum !== 'undefined',
        network_id: 138,
        status: 'ok'
    });
});

11. Backup & Recovery

A. Version Control

# Create backup before updates
cp /var/www/html/index.html /var/www/html/index.html.backup.$(date +%Y%m%d)

# Git version control
cd /var/www/html
git init
git add index.html
git commit -m "Update: Add ethers fallback CDN"

B. Rollback Script

#!/bin/bash
# rollback-frontend.sh
BACKUP_FILE="/var/www/html/index.html.backup.$(date +%Y%m%d)"
if [ -f "$BACKUP_FILE" ]; then
    cp "$BACKUP_FILE" /var/www/html/index.html
    systemctl reload nginx
    echo "Rolled back to: $BACKUP_FILE"
fi

12. Monitoring & Alerts

A. Error Monitoring

  • Set up Sentry or similar for error tracking
  • Monitor ethers.js loading failures
  • Track MetaMask connection failures
  • Alert on high error rates

B. Performance Monitoring

  • Track page load times
  • Monitor CDN response times
  • Track MetaMask connection success rate
  • Monitor transaction success rates

📋 Implementation Priority

High Priority (Do Now)

  1. Deploy ethers fallback fix (DONE)
  2. Add local ethers.js fallback
  3. Add connection state persistence
  4. Improve error messages

Medium Priority (Next Sprint)

  1. Add network detection
  2. Add toast notifications
  3. Add SRI checks
  4. Add CSP headers

Low Priority (Future)

  1. Add service worker
  2. Add comprehensive testing
  3. Add analytics
  4. Add accessibility improvements

🔍 Verification Checklist

  • Ethers library loads from primary CDN
  • Fallback CDN works if primary fails
  • MetaMask connection works
  • Error messages are clear
  • Local fallback available
  • Connection state persists
  • Network switching works
  • All WETH functions work
  • Mobile responsive
  • Accessibility compliant

📚 Additional Resources


🎯 Success Metrics

  • Connection Success Rate: > 95%
  • Ethers Load Time: < 2 seconds
  • Error Rate: < 1%
  • User Satisfaction: Positive feedback
  • Transaction Success Rate: > 98%

Status: Core fix deployed
Next Steps: Implement high-priority recommendations
Last Updated: $(date)