eip7702-delegation-tracker
Version:
CLI tool for tracking and sweeping EIP-7702 delegation setup transactions on EVM chains
193 lines (166 loc) ⢠7.46 kB
JavaScript
/**
* Monitor Specific Contract for New Authorities
*
* This example monitors BSC network for new authorities delegating to
* contract address: 0x5a77f0dfc729700300c22e7b0111a5cfbc32431b
*/
const { EIP7702Scanner } = require('../lib/scanner');
// Configuration
const TARGET_CONTRACT = '0x5a77f0dfc729700300c22e7b0111a5cfbc32431b';
const BSC_WS_URL = 'wss://bnb-mainnet.g.alchemy.com/v2/YOUR_API_KEY';
const BSC_RPC_URL = 'https://bnb-mainnet.g.alchemy.com/v2/YOUR_API_KEY';
async function monitorContract() {
console.log('š EIP-7702 Authority Monitor for Specific Contract');
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
console.log(`š Target Contract: ${TARGET_CONTRACT}`);
console.log(`š Network: BSC (Chain ID: 56)`);
console.log(`š WebSocket: ${BSC_WS_URL.substring(0, 50)}...`);
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
// Initialize scanner with custom BSC endpoint
const scanner = new EIP7702Scanner(
'bsc',
BSC_RPC_URL,
BSC_WS_URL
);
// Track unique authorities for this contract
const authorities = new Set();
const delegationHistory = [];
let totalDelegations = 0;
// Monitor for delegations
scanner.on('delegation', (delegation) => {
// Check if this delegation is to our target contract
if (delegation.delegatedTo?.toLowerCase() === TARGET_CONTRACT.toLowerCase()) {
totalDelegations++;
const isNewAuthority = !authorities.has(delegation.authority);
// Add to tracking
authorities.add(delegation.authority);
delegationHistory.push({
...delegation,
timestamp: new Date(delegation.timestamp * 1000),
isNew: isNewAuthority
});
// Display delegation
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
if (isNewAuthority) {
console.log('š NEW AUTHORITY DETECTED!');
} else {
console.log('š EXISTING AUTHORITY RE-DELEGATING');
}
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
console.log(`š¤ Authority: ${delegation.authority}`);
console.log(`š Transaction: ${delegation.txHash}`);
console.log(`š¦ Block: ${delegation.blockNumber}`);
console.log(`š¢ Nonce: ${delegation.nonce || 'N/A'}`);
console.log(`ā° Time: ${new Date(delegation.timestamp * 1000).toLocaleString()}`);
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
console.log(`š Stats: ${authorities.size} unique authorities | ${totalDelegations} total delegations`);
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
// Optional: Alert for new authorities
if (isNewAuthority) {
handleNewAuthority(delegation.authority, delegation);
}
}
});
// Handle errors
scanner.on('error', (error) => {
console.error('ā Scanner error:', error.message);
// Optionally implement reconnection logic here
});
// Connection events
scanner.on('connected', () => {
console.log('ā
Connected to BSC network via Alchemy WebSocket\n');
});
scanner.on('disconnected', () => {
console.log('ā ļø Disconnected from BSC network, attempting reconnection...\n');
});
// Start monitoring
console.log('š Starting real-time monitoring...\n');
await scanner.watchBlocks();
// Also scan recent blocks for historical data (optional)
console.log('š Scanning last 100 blocks for historical delegations...\n');
try {
const currentBlock = await scanner.provider.getBlockNumber();
const startBlock = currentBlock - 100;
for (let block = startBlock; block <= currentBlock; block++) {
const delegations = await scanner.scanBlock(block);
delegations.forEach(delegation => {
if (delegation.delegatedTo?.toLowerCase() === TARGET_CONTRACT.toLowerCase()) {
if (!authorities.has(delegation.authority)) {
authorities.add(delegation.authority);
console.log(`š Historical authority found: ${delegation.authority} (Block: ${block})`);
}
}
});
}
console.log(`\nā
Historical scan complete. Found ${authorities.size} unique authorities.\n`);
} catch (error) {
console.error('Error scanning historical blocks:', error.message);
}
// Status updates every minute
setInterval(() => {
console.log(`ā° [${new Date().toLocaleTimeString()}] Monitoring... | ${authorities.size} authorities | ${totalDelegations} delegations`);
}, 60000);
// Keep process running
process.stdin.resume();
// Graceful shutdown
process.on('SIGINT', async () => {
console.log('\n\nš Final Report:');
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
console.log(`Contract: ${TARGET_CONTRACT}`);
console.log(`Network: BSC`);
console.log(`Total Unique Authorities: ${authorities.size}`);
console.log(`Total Delegations: ${totalDelegations}`);
if (authorities.size > 0) {
console.log('\nš All Authorities:');
Array.from(authorities).forEach((auth, index) => {
console.log(` ${index + 1}. ${auth}`);
});
}
console.log('\nStopping monitor...');
scanner.stop();
process.exit(0);
});
}
// Handler for new authorities (customize as needed)
function handleNewAuthority(authority, delegation) {
// This is where you would:
// - Send notifications (email, Discord, Telegram, etc.)
// - Store in database
// - Trigger webhooks
// - Log to file
// - etc.
console.log('š ALERT: New authority detected!');
console.log(` Authority: ${authority}`);
console.log(` First delegation TX: ${delegation.txHash}`);
// Example: Send to webhook
/*
fetch('https://your-webhook.com/new-authority', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
event: 'new_authority',
contract: TARGET_CONTRACT,
authority,
delegation,
timestamp: Date.now()
})
}).catch(console.error);
*/
// Example: Log to file
/*
const fs = require('fs');
const logEntry = {
timestamp: new Date().toISOString(),
event: 'new_authority',
authority,
txHash: delegation.txHash,
blockNumber: delegation.blockNumber
};
fs.appendFileSync('new-authorities.log', JSON.stringify(logEntry) + '\n');
*/
}
// Run the monitor
monitorContract().catch(error => {
console.error('Failed to start monitor:', error);
process.exit(1);
});