SC CODE: Function InitializePrivate() Uint64
10 IF init() == 0 THEN GOTO 30
20 RETURN 1
30 STORE("nameHdr", "dashboard-pool.js")
31 STORE("descrHdr", "Transaction pool analysis module")
32 STORE("iconURLHdr", "")
33 STORE("dURL", "explorer.tela")
34 STORE("docType", "TELA-JS-1")
35 STORE("subDir", "")
36 STORE("fileCheckC", "343564962da02ec3b1bd8b383d03af19fd22c141e2843ba0a4464d9ea911e29")
37 STORE("fileCheckS", "2b244b336fe7595448c7404588e1873c599d79677b05b84b7325522cad345516")
100 RETURN 0
End Function
Function init() Uint64
10 IF EXISTS("owner") == 0 THEN GOTO 30
20 RETURN 1
30 STORE("owner", address())
50 STORE("docVersion", "1.0.0")
60 STORE("hash", HEX(TXID()))
70 STORE("likes", 0)
80 STORE("dislikes", 0)
100 RETURN 0
End Function
Function address() String
10 DIM s as String
20 LET s = SIGNER()
30 IF IS_ADDRESS_VALID(s) THEN GOTO 50
40 RETURN "anon"
50 RETURN ADDRESS_STRING(s)
End Function
Function Rate(r Uint64) Uint64
10 DIM addr as String
15 LET addr = address()
16 IF r < 100 && EXISTS(addr) == 0 && addr != "anon" THEN GOTO 30
20 RETURN 1
30 STORE(addr, ""+r+"_"+BLOCK_HEIGHT())
40 IF r < 50 THEN GOTO 70
50 STORE("likes", LOAD("likes")+1)
60 RETURN 0
70 STORE("dislikes", LOAD("dislikes")+1)
100 RETURN 0
End Function
/*
({
name:'dashboard-pool',
version:'1.0.0',
// Transaction pool monitoring variables
lastKnownPoolSize: 0,
lastKnownPoolStats: {},
lastKnownTxHashes: new Set(),
poolActivity: [],
monitoringEnabled: true,
refreshInterval: null,
async renderPoolModule() {
return `
<!-- Transaction Pool Analysis -->
<div class="enhanced-card">
<div class="card-header">
<h2 style="color: #fff; font-size: 1.6rem; font-weight: 700; margin: 0;">Transaction Pool Analysis</h2>
<div class="actions">
<button onclick="window.dashboardPool.toggleMonitoring()" id="pool-toggle-btn" style="background: rgba(74,222,128,0.1); border: 1px solid #4ade80; color: #4ade80; padding: 0.5rem 1rem; border-radius: 6px; cursor: pointer; transition: all 0.2s ease; font-size: 0.8rem; font-weight: 500;">● LIVE</button>
</div>
</div>
<div class="card-content">
<div class="section-info" style="color: #b3b3b3; font-size: 0.9rem; margin-bottom: 1.5rem;">Real-time mempool monitoring and analysis • <span id="pool-last-updated" style="color: #4ade80; font-weight: 500;">Live</span></div>
<div class="stats-grid" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 1rem;" id="transaction-pool-analysis">
<div class="enhanced-stat-card" style="background: rgba(0,0,0,0.2); border: 1px solid rgba(185,89,182,0.3); border-radius: 8px; padding: 1.5rem; text-align: center; transition: all 0.2s ease;">
<div style="color: #b3b3b3; font-size: 0.9rem; margin-bottom: 0.75rem; text-transform: uppercase; letter-spacing: 0.5px;">Pool Size</div>
<div style="color: #b959b6; font-size: 1.8rem; font-weight: 700;" id="pool-tx-count">Loading...</div>
</div>
<div class="enhanced-stat-card" style="background: rgba(0,0,0,0.2); border: 1px solid rgba(82,200,219,0.3); border-radius: 8px; padding: 1.5rem; text-align: center; transition: all 0.2s ease;">
<div style="color: #b3b3b3; font-size: 0.9rem; margin-bottom: 0.75rem; text-transform: uppercase; letter-spacing: 0.5px;">Total Size</div>
<div style="color: #52c8db; font-size: 1.8rem; font-weight: 700;" id="pool-total-size">Loading...</div>
</div>
<div class="enhanced-stat-card" style="background: rgba(0,0,0,0.2); border: 1px solid rgba(74,222,128,0.3); border-radius: 8px; padding: 1.5rem; text-align: center; transition: all 0.2s ease;">
<div style="color: #b3b3b3; font-size: 0.9rem; margin-bottom: 0.75rem; text-transform: uppercase; letter-spacing: 0.5px;">Avg Fee</div>
<div style="color: #4ade80; font-size: 1.8rem; font-weight: 700;" id="pool-avg-fee">Loading...</div>
</div>
<div class="enhanced-stat-card" style="background: rgba(0,0,0,0.2); border: 1px solid rgba(251,191,36,0.3); border-radius: 8px; padding: 1.5rem; text-align: center; transition: all 0.2s ease;">
<div style="color: #b3b3b3; font-size: 0.9rem; margin-bottom: 0.75rem; text-transform: uppercase; letter-spacing: 0.5px;">Activity</div>
<div style="color: #fbbf24; font-size: 1.8rem; font-weight: 700;" id="pool-activity">Loading...</div>
</div>
</div>
<!-- Pool Activity Feed -->
<div style="margin-top: 2rem;">
<h3 style="color: #52c8db; margin-bottom: 1rem; font-size: 1.2rem; font-weight: 600;">Recent Pool Activity</h3>
<div style="background: rgba(0,0,0,0.2); border: 1px solid rgba(82,200,219,0.3); border-radius: 8px; padding: 1.5rem; max-height: 250px; overflow-y: auto;" id="pool-activity-feed">
<div style="color: #b3b3b3; text-align: center; padding: 2rem; font-style: italic;">Monitoring transaction pool...</div>
</div>
</div>
</div>
</div>`;
},
async updateModule() {
if(!this.monitoringEnabled) return;
// Check if we're on dashboard or pool page
if(window.r !== 'home' && window.r !== 'pool' && window.r !== '' && window.r) return;
try {
let poolData = null;
// Use cached data to prevent redundant XSWD calls
poolData = await window.getCachedData('poolData', async () => {
// Try enhanced method first, then fallback to raw DERO call
try {
if (window.xswd && typeof window.xswd.getTxPoolWithStats === 'function') {
const result = await window.xswd.getTxPoolWithStats();
return result;
}
} catch(e) {
console.warn('Enhanced pool method failed, using fallback:', e.message);
}
// Fallback to raw DERO call and process data ourselves
const rawPool = await window.xswd?.call?.('DERO.GetTxPool') || await window.xswdCore?.call?.('DERO.GetTxPool');
if (rawPool?.txs) {
const txs = rawPool.txs;
return {
txs: txs,
stats: {
total_count: txs.length,
total_size: txs.reduce((acc,tx) => acc + (tx.size||0), 0),
avg_fee: txs.length > 0 ? txs.reduce((acc,tx) => acc + (tx.fee||0), 0) / txs.length : 0
}
};
}
return null;
});
if(poolData && poolData.stats) {
const stats = poolData.stats;
const currentTxHashes = new Set(poolData.txs || []);
const txChanges = this.detectTransactionChanges(currentTxHashes);
// Update display elements - check if they exist first
const txCountEl = document.getElementById('pool-tx-count');
if(txCountEl) txCountEl.textContent = stats.total_count || 0;
const totalSizeEl = document.getElementById('pool-total-size');
if(totalSizeEl) totalSizeEl.textContent = this.formatPoolSize(stats.total_size || 0);
const avgFeeEl = document.getElementById('pool-avg-fee');
if(avgFeeEl) avgFeeEl.textContent = this.formatPoolFee(stats.avg_fee || 0);
// Update activity indicator
const activityEl = document.getElementById('pool-activity');
if(activityEl) {
if(txChanges.newTxs.length > 0 || txChanges.confirmedTxs.length > 0) {
activityEl.textContent = '🆕 NEW';
activityEl.style.color = '#fbbf24';
setTimeout(() => {
activityEl.textContent = 'Active';
activityEl.style.color = '#4ade80';
}, 3000);
} else if(stats.total_count > 0) {
activityEl.textContent = 'Active';
activityEl.style.color = '#4ade80';
} else {
activityEl.textContent = 'Empty';
activityEl.style.color = '#888';
}
}
// Update status and activity feed
const poolStatusEl = document.getElementById('pool-last-updated');
if(poolStatusEl) {
const timeStr = new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit', second:'2-digit'});
let hasActivity = false;
// Add new transactions to activity feed
txChanges.newTxs.forEach(hash => {
const responsiveHash = this.formatTxHashResponsive(hash, `#tx/${hash}`);
this.addPoolActivity('new_tx', `${responsiveHash} added to pool`, timeStr);
hasActivity = true;
});
// Add confirmed transactions to activity feed
txChanges.confirmedTxs.forEach(hash => {
const responsiveHash = this.formatTxHashResponsive(hash, `#tx/${hash}`);
this.addPoolActivity('confirmed_tx', `${responsiveHash} confirmed in block`, timeStr);
hasActivity = true;
});
if(hasActivity) {
poolStatusEl.textContent = `ACTIVITY at ${timeStr}`;
poolStatusEl.style.color = '#fbbf24';
// Update activity feed and check responsive hashes
setTimeout(() => {
this.updatePoolActivityFeed();
}, 100);
setTimeout(() => {
poolStatusEl.textContent = 'Live';
poolStatusEl.style.color = '#4ade80';
}, 5000);
} else {
poolStatusEl.textContent = `Updated ${timeStr}`;
poolStatusEl.style.color = '#4ade80';
}
}
// Store current data for next comparison
this.lastKnownPoolSize = stats.total_count;
this.lastKnownPoolStats = stats;
this.lastKnownTxHashes = currentTxHashes;
} else {
// No pool data available - show empty state
const txCountEl = document.getElementById('pool-tx-count');
if(txCountEl) txCountEl.textContent = '0';
const totalSizeEl = document.getElementById('pool-total-size');
if(totalSizeEl) totalSizeEl.textContent = '0 B';
const avgFeeEl = document.getElementById('pool-avg-fee');
if(avgFeeEl) avgFeeEl.textContent = '0';
const activityEl = document.getElementById('pool-activity');
if(activityEl) {
activityEl.textContent = 'Empty';
activityEl.style.color = '#888';
}
const poolStatusEl = document.getElementById('pool-last-updated');
if(poolStatusEl) poolStatusEl.textContent = `Updated ${new Date().toLocaleTimeString()}`;
// Clear activity feed
const feedEl = document.getElementById('pool-activity-feed');
if(feedEl) {
feedEl.innerHTML = '<div style="color:#666;text-align:center;padding:2rem">✅ Pool is empty - network processing efficiently</div>';
}
}
} catch(error) {
console.error('Pool module update failed:', error);
// Show error state
const txCountEl = document.getElementById('pool-tx-count');
if(txCountEl) txCountEl.textContent = 'Error';
const activityEl = document.getElementById('pool-activity');
if(activityEl) {
activityEl.textContent = 'Error';
activityEl.style.color = '#ef4444';
}
const poolStatusEl = document.getElementById('pool-last-updated');
if(poolStatusEl) {
poolStatusEl.textContent = 'Pool Error';
poolStatusEl.style.color = '#ef4444';
}
}
},
detectTransactionChanges(currentTxHashes) {
// Find new transactions (in current but not in last known)
const newTxs = [];
currentTxHashes.forEach(hash => {
if(!this.lastKnownTxHashes.has(hash)) {
newTxs.push(hash);
}
});
// Find confirmed transactions (in last known but not in current)
const confirmedTxs = [];
this.lastKnownTxHashes.forEach(hash => {
if(!currentTxHashes.has(hash)) {
confirmedTxs.push(hash);
}
});
return {
newTxs: newTxs,
confirmedTxs: confirmedTxs,
hasChanges: newTxs.length > 0 || confirmedTxs.length > 0
};
},
formatTxHash(hash) {
if(!hash || hash.length < 16) return 'Unknown';
return hash.substring(0, 8) + '...' + hash.substring(hash.length - 6);
},
formatTxHashResponsive(hash, linkHref) {
if (!hash || hash.length < 16) return 'Unknown';
const fullHash = hash;
const truncatedHash = hash.substring(0, 8) + '...' + hash.substring(hash.length - 8);
const linkStart = linkHref ? `<a href="${linkHref}" style="color:#52c8db;text-decoration:none;font-weight:500;" onmouseover="this.style.textDecoration='underline'" onmouseout="this.style.textDecoration='none'">` : '';
const linkEnd = linkHref ? '</a>' : '';
return `<span class="hash-container hash-responsive">
<span class="hash-full">${linkStart}${fullHash}${linkEnd}</span>
<span class="hash-truncated">${linkStart}${truncatedHash}${linkEnd}</span>
</span>`;
},
formatPoolSize(bytes) {
if(!bytes || bytes === 0) return '0 B';
if(bytes >= 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
if(bytes >= 1024) return (bytes / 1024).toFixed(1) + ' KB';
return bytes + ' B';
},
formatPoolFee(fee) {
if(!fee || fee === 0) return '0';
return fee.toFixed(5);
},
addPoolActivity(type, message, timestamp) {
const activity = {
type: type,
message: message,
timestamp: timestamp,
time: Date.now()
};
// Add to beginning of array (newest first)
this.poolActivity.unshift(activity);
// Keep only last 10 activities
if(this.poolActivity.length > 10) {
this.poolActivity = this.poolActivity.slice(0, 10);
}
// Update activity feed display
this.updatePoolActivityFeed();
},
updatePoolActivityFeed() {
const feedEl = document.getElementById('pool-activity-feed');
if(!feedEl) return;
if(this.poolActivity.length === 0) {
feedEl.innerHTML = '<div style="color:#666;text-align:center;padding:2rem">No recent pool activity</div>';
return;
}
const activityHtml = this.poolActivity.map(activity => {
let icon = '💳';
let color = '#4ade80';
if(activity.type === 'new_tx') {
icon = '🆕';
color = '#fbbf24';
} else if(activity.type === 'confirmed_tx') {
icon = '✅';
color = '#10b981';
}
return `<div style="display:flex;align-items:center;justify-content:space-between;padding:0.5rem 0;border-bottom:1px solid rgba(255,255,255,0.05)">
<div style="display:flex;align-items:center;gap:0.75rem">
<span style="font-size:1.1rem">${icon}</span>
<span style="color:#fff;font-size:0.9rem">${activity.message}</span>
</div>
<span style="color:#888;font-size:0.8rem">${activity.timestamp}</span>
</div>`;
}).join('');
feedEl.innerHTML = activityHtml;
// Check responsive hash display after updating content
if(window.checkHashDisplay) window.checkHashDisplay();
},
toggleMonitoring() {
this.monitoringEnabled = !this.monitoringEnabled;
const btn = document.getElementById('pool-toggle-btn');
if(btn) {
if(this.monitoringEnabled) {
btn.textContent = '● LIVE';
btn.style.color = '#4ade80';
btn.style.borderColor = '#4ade80';
this.updateModule();
} else {
btn.textContent = '○ STOPPED';
btn.style.color = '#888';
btn.style.borderColor = '#555';
const poolStatusEl = document.getElementById('pool-last-updated');
if(poolStatusEl) {
poolStatusEl.textContent = 'Stopped';
poolStatusEl.style.color = '#888';
}
}
}
return this.monitoringEnabled;
},
stopMonitoring() {
this.monitoringEnabled = false;
const poolStatusEl = document.getElementById('pool-last-updated');
if(poolStatusEl) {
poolStatusEl.textContent = 'Stopped';
poolStatusEl.style.color = '#888';
}
this.stopAutoRefresh();
},
startAutoRefresh() {
// Clear any existing interval
this.stopAutoRefresh();
// Set up auto-refresh every 10 seconds
this.refreshInterval = setInterval(() => {
if (this.monitoringEnabled && (window.r === 'pool' || window.r === 'home')) {
this.updateModule();
}
}, 10000);
},
stopAutoRefresh() {
if (this.refreshInterval) {
clearInterval(this.refreshInterval);
this.refreshInterval = null;
}
}
})
*/ |
SC Arguments: [Name:SC_ACTION Type:uint64 Value:'1' Name:SC_CODE Type:string Value:'Function InitializePrivate() Uint64
10 IF init() == 0 THEN GOTO 30
20 RETURN 1
30 STORE("nameHdr", "dashboard-pool.js")
31 STORE("descrHdr", "Transaction pool analysis module")
32 STORE("iconURLHdr", "")
33 STORE("dURL", "explorer.tela")
34 STORE("docType", "TELA-JS-1")
35 STORE("subDir", "")
36 STORE("fileCheckC", "343564962da02ec3b1bd8b383d03af19fd22c141e2843ba0a4464d9ea911e29")
37 STORE("fileCheckS", "2b244b336fe7595448c7404588e1873c599d79677b05b84b7325522cad345516")
100 RETURN 0
End Function
Function init() Uint64
10 IF EXISTS("owner") == 0 THEN GOTO 30
20 RETURN 1
30 STORE("owner", address())
50 STORE("docVersion", "1.0.0")
60 STORE("hash", HEX(TXID()))
70 STORE("likes", 0)
80 STORE("dislikes", 0)
100 RETURN 0
End Function
Function address() String
10 DIM s as String
20 LET s = SIGNER()
30 IF IS_ADDRESS_VALID(s) THEN GOTO 50
40 RETURN "anon"
50 RETURN ADDRESS_STRING(s)
End Function
Function Rate(r Uint64) Uint64
10 DIM addr as String
15 LET addr = address()
16 IF r < 100 && EXISTS(addr) == 0 && addr != "anon" THEN GOTO 30
20 RETURN 1
30 STORE(addr, ""+r+"_"+BLOCK_HEIGHT())
40 IF r < 50 THEN GOTO 70
50 STORE("likes", LOAD("likes")+1)
60 RETURN 0
70 STORE("dislikes", LOAD("dislikes")+1)
100 RETURN 0
End Function
/*
({
name:'dashboard-pool',
version:'1.0.0',
// Transaction pool monitoring variables
lastKnownPoolSize: 0,
lastKnownPoolStats: {},
lastKnownTxHashes: new Set(),
poolActivity: [],
monitoringEnabled: true,
refreshInterval: null,
async renderPoolModule() {
return `
<!-- Transaction Pool Analysis -->
<div class="enhanced-card">
<div class="card-header">
<h2 style="color: #fff; font-size: 1.6rem; font-weight: 700; margin: 0;">Transaction Pool Analysis</h2>
<div class="actions">
<button onclick="window.dashboardPool.toggleMonitoring()" id="pool-toggle-btn" style="background: rgba(74,222,128,0.1); border: 1px solid #4ade80; color: #4ade80; padding: 0.5rem 1rem; border-radius: 6px; cursor: pointer; transition: all 0.2s ease; font-size: 0.8rem; font-weight: 500;">● LIVE</button>
</div>
</div>
<div class="card-content">
<div class="section-info" style="color: #b3b3b3; font-size: 0.9rem; margin-bottom: 1.5rem;">Real-time mempool monitoring and analysis • <span id="pool-last-updated" style="color: #4ade80; font-weight: 500;">Live</span></div>
<div class="stats-grid" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 1rem;" id="transaction-pool-analysis">
<div class="enhanced-stat-card" style="background: rgba(0,0,0,0.2); border: 1px solid rgba(185,89,182,0.3); border-radius: 8px; padding: 1.5rem; text-align: center; transition: all 0.2s ease;">
<div style="color: #b3b3b3; font-size: 0.9rem; margin-bottom: 0.75rem; text-transform: uppercase; letter-spacing: 0.5px;">Pool Size</div>
<div style="color: #b959b6; font-size: 1.8rem; font-weight: 700;" id="pool-tx-count">Loading...</div>
</div>
<div class="enhanced-stat-card" style="background: rgba(0,0,0,0.2); border: 1px solid rgba(82,200,219,0.3); border-radius: 8px; padding: 1.5rem; text-align: center; transition: all 0.2s ease;">
<div style="color: #b3b3b3; font-size: 0.9rem; margin-bottom: 0.75rem; text-transform: uppercase; letter-spacing: 0.5px;">Total Size</div>
<div style="color: #52c8db; font-size: 1.8rem; font-weight: 700;" id="pool-total-size">Loading...</div>
</div>
<div class="enhanced-stat-card" style="background: rgba(0,0,0,0.2); border: 1px solid rgba(74,222,128,0.3); border-radius: 8px; padding: 1.5rem; text-align: center; transition: all 0.2s ease;">
<div style="color: #b3b3b3; font-size: 0.9rem; margin-bottom: 0.75rem; text-transform: uppercase; letter-spacing: 0.5px;">Avg Fee</div>
<div style="color: #4ade80; font-size: 1.8rem; font-weight: 700;" id="pool-avg-fee">Loading...</div>
</div>
<div class="enhanced-stat-card" style="background: rgba(0,0,0,0.2); border: 1px solid rgba(251,191,36,0.3); border-radius: 8px; padding: 1.5rem; text-align: center; transition: all 0.2s ease;">
<div style="color: #b3b3b3; font-size: 0.9rem; margin-bottom: 0.75rem; text-transform: uppercase; letter-spacing: 0.5px;">Activity</div>
<div style="color: #fbbf24; font-size: 1.8rem; font-weight: 700;" id="pool-activity">Loading...</div>
</div>
</div>
<!-- Pool Activity Feed -->
<div style="margin-top: 2rem;">
<h3 style="color: #52c8db; margin-bottom: 1rem; font-size: 1.2rem; font-weight: 600;">Recent Pool Activity</h3>
<div style="background: rgba(0,0,0,0.2); border: 1px solid rgba(82,200,219,0.3); border-radius: 8px; padding: 1.5rem; max-height: 250px; overflow-y: auto;" id="pool-activity-feed">
<div style="color: #b3b3b3; text-align: center; padding: 2rem; font-style: italic;">Monitoring transaction pool...</div>
</div>
</div>
</div>
</div>`;
},
async updateModule() {
if(!this.monitoringEnabled) return;
// Check if we're on dashboard or pool page
if(window.r !== 'home' && window.r !== 'pool' && window.r !== '' && window.r) return;
try {
let poolData = null;
// Use cached data to prevent redundant XSWD calls
poolData = await window.getCachedData('poolData', async () => {
// Try enhanced method first, then fallback to raw DERO call
try {
if (window.xswd && typeof window.xswd.getTxPoolWithStats === 'function') {
const result = await window.xswd.getTxPoolWithStats();
return result;
}
} catch(e) {
console.warn('Enhanced pool method failed, using fallback:', e.message);
}
// Fallback to raw DERO call and process data ourselves
const rawPool = await window.xswd?.call?.('DERO.GetTxPool') || await window.xswdCore?.call?.('DERO.GetTxPool');
if (rawPool?.txs) {
const txs = rawPool.txs;
return {
txs: txs,
stats: {
total_count: txs.length,
total_size: txs.reduce((acc,tx) => acc + (tx.size||0), 0),
avg_fee: txs.length > 0 ? txs.reduce((acc,tx) => acc + (tx.fee||0), 0) / txs.length : 0
}
};
}
return null;
});
if(poolData && poolData.stats) {
const stats = poolData.stats;
const currentTxHashes = new Set(poolData.txs || []);
const txChanges = this.detectTransactionChanges(currentTxHashes);
// Update display elements - check if they exist first
const txCountEl = document.getElementById('pool-tx-count');
if(txCountEl) txCountEl.textContent = stats.total_count || 0;
const totalSizeEl = document.getElementById('pool-total-size');
if(totalSizeEl) totalSizeEl.textContent = this.formatPoolSize(stats.total_size || 0);
const avgFeeEl = document.getElementById('pool-avg-fee');
if(avgFeeEl) avgFeeEl.textContent = this.formatPoolFee(stats.avg_fee || 0);
// Update activity indicator
const activityEl = document.getElementById('pool-activity');
if(activityEl) {
if(txChanges.newTxs.length > 0 || txChanges.confirmedTxs.length > 0) {
activityEl.textContent = '🆕 NEW';
activityEl.style.color = '#fbbf24';
setTimeout(() => {
activityEl.textContent = 'Active';
activityEl.style.color = '#4ade80';
}, 3000);
} else if(stats.total_count > 0) {
activityEl.textContent = 'Active';
activityEl.style.color = '#4ade80';
} else {
activityEl.textContent = 'Empty';
activityEl.style.color = '#888';
}
}
// Update status and activity feed
const poolStatusEl = document.getElementById('pool-last-updated');
if(poolStatusEl) {
const timeStr = new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit', second:'2-digit'});
let hasActivity = false;
// Add new transactions to activity feed
txChanges.newTxs.forEach(hash => {
const responsiveHash = this.formatTxHashResponsive(hash, `#tx/${hash}`);
this.addPoolActivity('new_tx', `${responsiveHash} added to pool`, timeStr);
hasActivity = true;
});
// Add confirmed transactions to activity feed
txChanges.confirmedTxs.forEach(hash => {
const responsiveHash = this.formatTxHashResponsive(hash, `#tx/${hash}`);
this.addPoolActivity('confirmed_tx', `${responsiveHash} confirmed in block`, timeStr);
hasActivity = true;
});
if(hasActivity) {
poolStatusEl.textContent = `ACTIVITY at ${timeStr}`;
poolStatusEl.style.color = '#fbbf24';
// Update activity feed and check responsive hashes
setTimeout(() => {
this.updatePoolActivityFeed();
}, 100);
setTimeout(() => {
poolStatusEl.textContent = 'Live';
poolStatusEl.style.color = '#4ade80';
}, 5000);
} else {
poolStatusEl.textContent = `Updated ${timeStr}`;
poolStatusEl.style.color = '#4ade80';
}
}
// Store current data for next comparison
this.lastKnownPoolSize = stats.total_count;
this.lastKnownPoolStats = stats;
this.lastKnownTxHashes = currentTxHashes;
} else {
// No pool data available - show empty state
const txCountEl = document.getElementById('pool-tx-count');
if(txCountEl) txCountEl.textContent = '0';
const totalSizeEl = document.getElementById('pool-total-size');
if(totalSizeEl) totalSizeEl.textContent = '0 B';
const avgFeeEl = document.getElementById('pool-avg-fee');
if(avgFeeEl) avgFeeEl.textContent = '0';
const activityEl = document.getElementById('pool-activity');
if(activityEl) {
activityEl.textContent = 'Empty';
activityEl.style.color = '#888';
}
const poolStatusEl = document.getElementById('pool-last-updated');
if(poolStatusEl) poolStatusEl.textContent = `Updated ${new Date().toLocaleTimeString()}`;
// Clear activity feed
const feedEl = document.getElementById('pool-activity-feed');
if(feedEl) {
feedEl.innerHTML = '<div style="color:#666;text-align:center;padding:2rem">✅ Pool is empty - network processing efficiently</div>';
}
}
} catch(error) {
console.error('Pool module update failed:', error);
// Show error state
const txCountEl = document.getElementById('pool-tx-count');
if(txCountEl) txCountEl.textContent = 'Error';
const activityEl = document.getElementById('pool-activity');
if(activityEl) {
activityEl.textContent = 'Error';
activityEl.style.color = '#ef4444';
}
const poolStatusEl = document.getElementById('pool-last-updated');
if(poolStatusEl) {
poolStatusEl.textContent = 'Pool Error';
poolStatusEl.style.color = '#ef4444';
}
}
},
detectTransactionChanges(currentTxHashes) {
// Find new transactions (in current but not in last known)
const newTxs = [];
currentTxHashes.forEach(hash => {
if(!this.lastKnownTxHashes.has(hash)) {
newTxs.push(hash);
}
});
// Find confirmed transactions (in last known but not in current)
const confirmedTxs = [];
this.lastKnownTxHashes.forEach(hash => {
if(!currentTxHashes.has(hash)) {
confirmedTxs.push(hash);
}
});
return {
newTxs: newTxs,
confirmedTxs: confirmedTxs,
hasChanges: newTxs.length > 0 || confirmedTxs.length > 0
};
},
formatTxHash(hash) {
if(!hash || hash.length < 16) return 'Unknown';
return hash.substring(0, 8) + '...' + hash.substring(hash.length - 6);
},
formatTxHashResponsive(hash, linkHref) {
if (!hash || hash.length < 16) return 'Unknown';
const fullHash = hash;
const truncatedHash = hash.substring(0, 8) + '...' + hash.substring(hash.length - 8);
const linkStart = linkHref ? `<a href="${linkHref}" style="color:#52c8db;text-decoration:none;font-weight:500;" onmouseover="this.style.textDecoration='underline'" onmouseout="this.style.textDecoration='none'">` : '';
const linkEnd = linkHref ? '</a>' : '';
return `<span class="hash-container hash-responsive">
<span class="hash-full">${linkStart}${fullHash}${linkEnd}</span>
<span class="hash-truncated">${linkStart}${truncatedHash}${linkEnd}</span>
</span>`;
},
formatPoolSize(bytes) {
if(!bytes || bytes === 0) return '0 B';
if(bytes >= 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
if(bytes >= 1024) return (bytes / 1024).toFixed(1) + ' KB';
return bytes + ' B';
},
formatPoolFee(fee) {
if(!fee || fee === 0) return '0';
return fee.toFixed(5);
},
addPoolActivity(type, message, timestamp) {
const activity = {
type: type,
message: message,
timestamp: timestamp,
time: Date.now()
};
// Add to beginning of array (newest first)
this.poolActivity.unshift(activity);
// Keep only last 10 activities
if(this.poolActivity.length > 10) {
this.poolActivity = this.poolActivity.slice(0, 10);
}
// Update activity feed display
this.updatePoolActivityFeed();
},
updatePoolActivityFeed() {
const feedEl = document.getElementById('pool-activity-feed');
if(!feedEl) return;
if(this.poolActivity.length === 0) {
feedEl.innerHTML = '<div style="color:#666;text-align:center;padding:2rem">No recent pool activity</div>';
return;
}
const activityHtml = this.poolActivity.map(activity => {
let icon = '💳';
let color = '#4ade80';
if(activity.type === 'new_tx') {
icon = '🆕';
color = '#fbbf24';
} else if(activity.type === 'confirmed_tx') {
icon = '✅';
color = '#10b981';
}
return `<div style="display:flex;align-items:center;justify-content:space-between;padding:0.5rem 0;border-bottom:1px solid rgba(255,255,255,0.05)">
<div style="display:flex;align-items:center;gap:0.75rem">
<span style="font-size:1.1rem">${icon}</span>
<span style="color:#fff;font-size:0.9rem">${activity.message}</span>
</div>
<span style="color:#888;font-size:0.8rem">${activity.timestamp}</span>
</div>`;
}).join('');
feedEl.innerHTML = activityHtml;
// Check responsive hash display after updating content
if(window.checkHashDisplay) window.checkHashDisplay();
},
toggleMonitoring() {
this.monitoringEnabled = !this.monitoringEnabled;
const btn = document.getElementById('pool-toggle-btn');
if(btn) {
if(this.monitoringEnabled) {
btn.textContent = '● LIVE';
btn.style.color = '#4ade80';
btn.style.borderColor = '#4ade80';
this.updateModule();
} else {
btn.textContent = '○ STOPPED';
btn.style.color = '#888';
btn.style.borderColor = '#555';
const poolStatusEl = document.getElementById('pool-last-updated');
if(poolStatusEl) {
poolStatusEl.textContent = 'Stopped';
poolStatusEl.style.color = '#888';
}
}
}
return this.monitoringEnabled;
},
stopMonitoring() {
this.monitoringEnabled = false;
const poolStatusEl = document.getElementById('pool-last-updated');
if(poolStatusEl) {
poolStatusEl.textContent = 'Stopped';
poolStatusEl.style.color = '#888';
}
this.stopAutoRefresh();
},
startAutoRefresh() {
// Clear any existing interval
this.stopAutoRefresh();
// Set up auto-refresh every 10 seconds
this.refreshInterval = setInterval(() => {
if (this.monitoringEnabled && (window.r === 'pool' || window.r === 'home')) {
this.updateModule();
}
}, 10000);
},
stopAutoRefresh() {
if (this.refreshInterval) {
clearInterval(this.refreshInterval);
this.refreshInterval = null;
}
}
})
*/'] |