@@ -4,12 +4,12 @@ import { useState, useEffect, useCallback, useRef } from "react";
44import { JsonRpcProvider , Wallet , parseUnits , formatEther } from "ethers" ;
55import { HDNodeWallet } from "ethers" ;
66import { TransactionRequest } from "ethers" ;
7+ import { FutureGateway , Gateway } from "@/types" ;
78
89type TxInfo = {
910 hash : string ;
1011 sendTimeMs : number ;
1112 blockNumber ?: number ;
12- txIndex ?: number ;
1313 latencyMs ?: number ;
1414} ;
1515
@@ -61,9 +61,11 @@ export default function Home() {
6161 const [ pingLatency , setPingLatency ] = useState < number > ( 0 ) ;
6262 const [ autoSend , setAutoSend ] = useState ( false ) ;
6363 const isPolling = useRef ( false ) ;
64+ const [ gateways , setGateways ] = useState < Gateway [ ] > ( [ ] ) ;
65+ const [ futureGateways , setFutureGateways ] = useState < FutureGateway [ ] > ( [ ] ) ;
6466
6567 const ethValue = parseUnits ( "1" , "gwei" ) ;
66- const gasPrice = parseUnits ( "0.01 " , "gwei" ) ;
68+ const gasPrice = parseUnits ( "0.1 " , "gwei" ) ;
6769
6870 // Initialize provider and chain ID on mount
6971 useEffect ( ( ) => {
@@ -92,15 +94,25 @@ export default function Home() {
9294 updated . set ( nonce , {
9395 ...info ,
9496 blockNumber : rcpt . blockNumber ,
95- txIndex : rcpt . index ,
9697 latencyMs : Date . now ( ) - info . sendTimeMs ,
9798 } ) ;
9899 } else {
99100 stillPending . set ( nonce , info ) ;
100101 }
101102 }
102103
103- setConfirmedTxs ( ( prev ) => new Map ( [ ...prev , ...updated ] ) ) ;
104+ setConfirmedTxs ( ( prev ) => {
105+ // Combine previous and new transactions
106+ const allTxs = new Map ( [ ...prev , ...updated ] ) ;
107+
108+ // Sort by nonce (descending) and take only the first 100
109+ const sortedEntries = Array . from ( allTxs . entries ( ) )
110+ . sort ( ( [ nonceA ] , [ nonceB ] ) => nonceB - nonceA )
111+ . slice ( 0 , 100 ) ;
112+
113+ // Create new Map with only the latest 100 transactions
114+ return new Map ( sortedEntries ) ;
115+ } ) ;
104116
105117 setPendingTxs ( ( prev ) => {
106118 const next = new Map ( prev ) ;
@@ -162,7 +174,7 @@ export default function Home() {
162174 } ;
163175
164176 updateBlockNumber ( ) ;
165- const interval = setInterval ( updateBlockNumber , 1500 ) ;
177+ const interval = setInterval ( updateBlockNumber , 1000 ) ;
166178 return ( ) => clearInterval ( interval ) ;
167179 } , [ provider ] ) ;
168180
@@ -256,6 +268,24 @@ export default function Home() {
256268 return ( ) => clearInterval ( interval ) ;
257269 } , [ autoSend , wallet , handleSend ] ) ; // Added handleSend to dependencies
258270
271+ useEffect ( ( ) => {
272+ const fetchGateways = async ( ) => {
273+ try {
274+ const response = await fetch ( "/api/registry" ) ;
275+ const data = await response . json ( ) ;
276+
277+ setGateways ( data . gateways ) ;
278+ setFutureGateways ( data . futureGateways ) ;
279+ } catch ( error ) {
280+ console . error ( "Failed to fetch gateways:" , error ) ;
281+ }
282+ } ;
283+
284+ fetchGateways ( ) ;
285+ const interval = setInterval ( fetchGateways , 5000 ) ;
286+ return ( ) => clearInterval ( interval ) ;
287+ } , [ ] ) ;
288+
259289 return (
260290 < div className = "min-h-screen bg-[#0A0A0C] p-8 font-sans text-gray-100 flex flex-col" >
261291 < div className = "max-w-6xl mx-auto flex-grow w-full" >
@@ -281,6 +311,94 @@ export default function Home() {
281311 </ form >
282312 </ div >
283313
314+ < div className = "bg-[#161618] rounded-xl overflow-hidden border border-[#2A2A2E] mb-6" >
315+ < table className = "w-full" >
316+ < thead className = "bg-[#1A1A1C] border-b border-[#2A2A2E]" >
317+ < tr >
318+ < th className = "text-left p-4 text-sm text-gray-400 font-medium" >
319+ Gateway
320+ </ th >
321+ < th className = "text-left p-4 text-sm text-gray-400 font-medium" >
322+ Address
323+ </ th >
324+ < th className = "text-left p-4 text-sm text-gray-400 font-medium" >
325+ Role
326+ </ th >
327+ < th className = "text-left p-4 text-sm text-gray-400 font-medium" >
328+ Ping (sequencer)
329+ </ th >
330+ </ tr >
331+ </ thead >
332+ < tbody >
333+ { ( ( ) => {
334+ const currentUrl = futureGateways . find (
335+ ( gw ) => gw . blockNumber === currentBlock
336+ ) ?. url ;
337+
338+ const nextUrl = futureGateways . find (
339+ ( gw ) => gw . blockNumber > currentBlock && gw . url !== currentUrl
340+ ) ?. url ;
341+
342+ const blocksLeft = futureGateways . filter (
343+ ( gw ) =>
344+ gw . url === currentUrl && gw . blockNumber >= currentBlock
345+ ) . length ;
346+
347+ return gateways . map ( ( gateway , i ) => {
348+ const isCurrent = currentUrl === gateway . url ;
349+ const isNext = nextUrl === gateway . url ;
350+
351+ return (
352+ < tr
353+ key = { i }
354+ className = { `border-b border-[#2A2A2E] ${
355+ isCurrent ? "bg-[#2A2A2E]" : ""
356+ } `}
357+ >
358+ < td className = "p-4" >
359+ < p className = "font-mono text-[#00FFB2]" >
360+ { gateway . url }
361+ </ p >
362+ </ td >
363+ < td className = "p-4" >
364+ < p className = "font-mono text-[#00FFB2]" >
365+ { gateway . address }
366+ </ p >
367+ </ td >
368+ < td className = "p-4" >
369+ { isCurrent && (
370+ < span className = "px-3 py-1.5 rounded-lg text-sm bg-[#00FFB2] text-[#0A0A0C] whitespace-nowrap" >
371+ Leader ({ blocksLeft } blocks)
372+ </ span >
373+ ) }
374+ { isNext && (
375+ < span className = "px-3 py-1.5 rounded-lg text-xs font-medium bg-[#2A2A2E] text-[#7F5FFF] border border-[#7F5FFF]" >
376+ Next
377+ </ span >
378+ ) }
379+ { ! isCurrent && ! isNext && (
380+ < span className = "text-gray-400" > Standby</ span >
381+ ) }
382+ </ td >
383+ < td className = "p-4" >
384+ < span
385+ className = {
386+ gateway . ping
387+ ? "font-mono text-[#00FFB2]"
388+ : "text-gray-400"
389+ }
390+ >
391+ { gateway . ping ? `${ gateway . ping } ms` : "-" }
392+ </ span >
393+ </ td >
394+ </ tr >
395+ ) ;
396+ } ) ;
397+ } ) ( ) }
398+ </ tbody >
399+ </ table >
400+ </ div >
401+
284402 { ! wallet ? (
285403 < div className = "flex justify-center items-center min-h-[200px]" >
286404 < button
@@ -304,30 +422,53 @@ export default function Home() {
304422 < p className = "text-gray-300" >
305423 Balance:{ " " }
306424 < span className = "font-mono text-[#00FFB2]" >
307- { formatEther ( balance ) } ETH
425+ { balance === BigInt ( 0 )
426+ ? "Waiting for airdrop..."
427+ : `${ formatEther ( balance ) } ETH` }
308428 </ span >
309429 </ p >
310430 </ div >
311431
312432 < div className = "flex flex-col gap-2 items-end" >
313433 < button
314434 onClick = { handleSend }
315- className = "bg-[#2A2A2E] hover:bg-[#3A3A3E] text-[#00FFB2] px-6 py-2 rounded-lg transition-colors duration-200 border border-[#00FFB2]"
435+ disabled = { balance === BigInt ( 0 ) }
436+ className = { `px-6 py-2 rounded-lg transition-colors duration-200 border ${
437+ balance === BigInt ( 0 )
438+ ? "bg-[#1A1A1C] text-gray-500 border-gray-500 cursor-not-allowed"
439+ : "bg-[#2A2A2E] hover:bg-[#3A3A3E] text-[#00FFB2] border-[#00FFB2]"
440+ } `}
316441 >
317442 Send TX
318443 </ button >
319444 < div className = "flex items-center gap-2" >
320- < label className = "text-sm text-gray-300" > Auto Send</ label >
445+ < label
446+ className = { `text-sm ${
447+ balance === BigInt ( 0 )
448+ ? "text-gray-500"
449+ : "text-gray-300"
450+ } `}
451+ >
452+ Auto Send
453+ </ label >
321454 < button
322- onClick = { ( ) => setAutoSend ( ! autoSend ) }
455+ onClick = { ( ) =>
456+ balance > BigInt ( 0 ) && setAutoSend ( ! autoSend )
457+ }
323458 className = { `relative inline-flex h-6 w-11 items-center rounded-full transition-colors duration-200 ${
324- autoSend ? "bg-[#00FFB2]" : "bg-[#2A2A2E]"
459+ balance === BigInt ( 0 )
460+ ? "bg-[#1A1A1C] cursor-not-allowed"
461+ : autoSend
462+ ? "bg-[#00FFB2]"
463+ : "bg-[#2A2A2E]"
325464 } `}
326465 >
327466 < span
328- className = { `inline-block h-4 w-4 transform rounded-full bg-white transition-transform duration-200 ${
329- autoSend ? "translate-x-6" : "translate-x-1"
330- } `}
467+ className = { `inline-block h-4 w-4 transform rounded-full transition-transform duration-200 ${
468+ autoSend
469+ ? "translate-x-6 bg-white"
470+ : "translate-x-1 bg-gray-400"
471+ } ${ balance === BigInt ( 0 ) ? "bg-gray-600" : "" } `}
331472 />
332473 </ button >
333474 </ div >
@@ -350,7 +491,7 @@ export default function Home() {
350491 </ p >
351492 </ div >
352493 < div className = "space-y-1" >
353- < p className = "text-sm text-gray-400" > Ping Latency</ p >
494+ < p className = "text-sm text-gray-400" > Ping Latency (RPC) </ p >
354495 < p className = "text-2xl font-mono text-[#00FFB2]" >
355496 { pingLatency } ms
356497 </ p >
@@ -403,19 +544,21 @@ export default function Home() {
403544 Status
404545 </ th >
405546 < th className = "px-4 py-2 text-left text-xs font-medium text-gray-400 uppercase tracking-wider" >
406- Block#
547+ Block #
407548 </ th >
408549 < th className = "px-4 py-2 text-left text-xs font-medium text-gray-400 uppercase tracking-wider" >
409- Txn Idx
550+ Latency
410551 </ th >
411- < th className = "px-4 py-2 text-left text-xs font-medium text-gray-400 uppercase tracking-wider" >
412- Latency (ms)
552+ { /* <th className="px-4 py-2 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">
553+ Gateway
413554 </th>
555+ <th className="px-4 py-2 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">
556+ Network
557+ </th> */ }
414558 </ tr >
415559 </ thead >
416560 < tbody className = "divide-y divide-[#2A2A2E]" >
417561 { [ ...confirmedTxs . entries ( ) , ...pendingTxs . entries ( ) ]
418- // sort ascending by nonce; for descending swap a and b
419562 . sort ( ( [ nonceA ] , [ nonceB ] ) => nonceB - nonceA )
420563 . slice ( 0 , 50 )
421564 . map ( ( [ nonce , info ] ) => (
@@ -433,7 +576,7 @@ export default function Home() {
433576 rel = "noopener noreferrer"
434577 className = "hover:text-[#00FFB2] hover:underline"
435578 >
436- { info . hash }
579+ { info . hash . slice ( 0 , 10 ) } ...
437580 </ a >
438581 </ td >
439582 < td className = "px-4 py-2 text-sm" >
@@ -451,11 +594,14 @@ export default function Home() {
451594 { info . blockNumber ?? "-" }
452595 </ td >
453596 < td className = "px-4 py-2 font-mono text-sm text-gray-300" >
454- { info . txIndex ?? "-" }
597+ { info . latencyMs ? info . latencyMs + "ms" : "-" }
455598 </ td >
456- < td className = "px-4 py-2 font-mono text-sm text-gray-300" >
457- { info . latencyMs ?? "-" }
599+ { /* <td className="px-4 py-2 font-mono text-sm text-gray-300">
600+ -
458601 </td>
602+ <td className="px-4 py-2 font-mono text-sm text-gray-300">
603+ -
604+ </td> */ }
459605 </ tr >
460606 ) ) }
461607 </ tbody >
0 commit comments