@@ -3,6 +3,9 @@ import { useMemo } from "react";
3
3
import type { NextPage } from "next" ;
4
4
import { useRouter } from "next/router" ;
5
5
6
+ import type { OptimismDecodedData } from "@blobscan/api/src/blob-parse/optimism" ;
7
+ import type dayjs from "@blobscan/dayjs" ;
8
+
6
9
import { RollupBadge } from "~/components/Badges/RollupBadge" ;
7
10
import { Card } from "~/components/Cards/Card" ;
8
11
import { BlobCard } from "~/components/Cards/SurfaceCards/BlobCard" ;
@@ -16,6 +19,7 @@ import { Link } from "~/components/Link";
16
19
import { NavArrows } from "~/components/NavArrows" ;
17
20
import { BlockStatus } from "~/components/Status" ;
18
21
import { api } from "~/api-client" ;
22
+ import Loading from "~/icons/loading.svg" ;
19
23
import NextError from "~/pages/_error" ;
20
24
import type { TransactionWithExpandedBlockAndBlob } from "~/types" ;
21
25
import {
@@ -256,62 +260,10 @@ const Tx: NextPage = () => {
256
260
/>
257
261
258
262
{ decodedData && (
259
- < Card header = "Decoded Fields" >
260
- < div >
261
- < InfoGrid
262
- fields = { [
263
- {
264
- name : "Timestamp since L2 genesis" ,
265
- value : (
266
- < div className = "whitespace-break-spaces" >
267
- { tx
268
- ? formatTimestamp (
269
- tx . blockTimestamp . subtract (
270
- decodedData . timestampSinceL2Genesis ,
271
- "ms"
272
- )
273
- )
274
- : "" }
275
- </ div >
276
- ) ,
277
- } ,
278
- {
279
- name : "Last L1 origin number" ,
280
- value : decodedData . lastL1OriginNumber ,
281
- } ,
282
- {
283
- name : "Parent L2 block hash" ,
284
- value : "0x" + decodedData . parentL2BlockHash + "..." ,
285
- } ,
286
- {
287
- name : "L1 origin block hash" ,
288
- value : (
289
- < BlockHash
290
- fullHash = { decodedData . fullL1OriginBlockHash }
291
- partialHash = { decodedData . l1OriginBlockHash }
292
- />
293
- ) ,
294
- } ,
295
- {
296
- name : "Number of L2 blocks" ,
297
- value : decodedData . numberOfL2Blocks ,
298
- } ,
299
- {
300
- name : "Changed by L1 origin" ,
301
- value : decodedData . changedByL1Origin ,
302
- } ,
303
- {
304
- name : "Total transactions" ,
305
- value : decodedData . totalTxs ,
306
- } ,
307
- {
308
- name : "Contract creation transactions" ,
309
- value : decodedData . contractCreationTxsNumber ,
310
- } ,
311
- ] }
312
- />
313
- </ div >
314
- </ Card >
263
+ < OptimismCard
264
+ decodedData = { decodedData }
265
+ txTimestamp = { tx ? tx . blockTimestamp : undefined }
266
+ />
315
267
) }
316
268
317
269
< Card header = { `Blobs ${ tx ? `(${ tx . blobs . length } )` : "" } ` } >
@@ -325,28 +277,95 @@ const Tx: NextPage = () => {
325
277
) ;
326
278
} ;
327
279
328
- type BlockHashProps = {
329
- partialHash : string ;
330
- fullHash : string | undefined ;
280
+ type OptimismCardProps = {
281
+ decodedData : OptimismDecodedData ;
282
+ txTimestamp : dayjs . Dayjs | undefined ;
331
283
} ;
332
284
333
- const BlockHash : FC < BlockHashProps > = ( { fullHash, partialHash } ) => {
334
- if ( fullHash === undefined ) {
335
- return "0x" + partialHash + "..." ;
336
- }
285
+ const OptimismCard : FC < OptimismCardProps > = ( { decodedData, txTimestamp } ) => {
286
+ const { data : blockExists , isLoading } = api . block . checkBlockExists . useQuery ( {
287
+ blockNumber : decodedData . lastL1OriginNumber ,
288
+ } ) ;
289
+
290
+ const blockLink = blockExists
291
+ ? `https://blobscan.com/block/${ decodedData . lastL1OriginNumber } `
292
+ : `https://etherscan.io/block/${ decodedData . lastL1OriginNumber } ` ;
293
+
294
+ const hash = `0x${ decodedData . l1OriginBlockHash } ...` ;
295
+
296
+ const timestamp = txTimestamp
297
+ ? formatTimestamp (
298
+ txTimestamp . subtract ( decodedData . timestampSinceL2Genesis , "ms" )
299
+ )
300
+ : undefined ;
337
301
338
- const prefixedFullHash = "0x" + fullHash ;
302
+ if ( isLoading ) {
303
+ return (
304
+ < Card header = "Loading Decoded Fields..." >
305
+ < div className = "flex h-32 items-center justify-center" >
306
+ < Loading className = "h-8 w-8 animate-spin" />
307
+ </ div >
308
+ </ Card >
309
+ ) ;
310
+ }
339
311
340
312
return (
341
- < div className = "flex items-center gap-2" >
342
- < Link href = { `https://blobscan.com/block/${ prefixedFullHash } ` } >
343
- { prefixedFullHash }
344
- </ Link >
345
- < CopyToClipboard
346
- value = { prefixedFullHash }
347
- tooltipText = "Copy L1 origin block hash"
348
- />
349
- </ div >
313
+ < Card header = "Decoded Fields" >
314
+ < div >
315
+ < InfoGrid
316
+ fields = { [
317
+ {
318
+ name : "Timestamp since L2 genesis" ,
319
+ value : < div className = "whitespace-break-spaces" > { timestamp } </ div > ,
320
+ } ,
321
+ {
322
+ name : "Last L1 origin number" ,
323
+ value : (
324
+ < div className = "flex items-center gap-2" >
325
+ < Link href = { blockLink } > { decodedData . lastL1OriginNumber } </ Link >
326
+ < CopyToClipboard
327
+ value = { decodedData . lastL1OriginNumber . toString ( ) }
328
+ tooltipText = "Copy Last L1 origin number"
329
+ />
330
+ </ div >
331
+ ) ,
332
+ } ,
333
+ {
334
+ name : "Parent L2 block hash" ,
335
+ value : "0x" + decodedData . parentL2BlockHash + "..." ,
336
+ } ,
337
+ {
338
+ name : "L1 origin block hash" ,
339
+ value : (
340
+ < div className = "flex items-center gap-2" >
341
+ < Link href = { blockLink } > { hash } </ Link >
342
+ < CopyToClipboard
343
+ value = { hash }
344
+ tooltipText = "Copy L1 origin block hash"
345
+ />
346
+ </ div >
347
+ ) ,
348
+ } ,
349
+ {
350
+ name : "Number of L2 blocks" ,
351
+ value : decodedData . numberOfL2Blocks ,
352
+ } ,
353
+ {
354
+ name : "Changed by L1 origin" ,
355
+ value : decodedData . changedByL1Origin ,
356
+ } ,
357
+ {
358
+ name : "Total transactions" ,
359
+ value : decodedData . totalTxs ,
360
+ } ,
361
+ {
362
+ name : "Contract creation transactions" ,
363
+ value : decodedData . contractCreationTxsNumber ,
364
+ } ,
365
+ ] }
366
+ />
367
+ </ div >
368
+ </ Card >
350
369
) ;
351
370
} ;
352
371
0 commit comments