11import { type NextRequest , NextResponse } from "next/server" ;
2+ import { createPublicClient , type Hash , http } from "viem" ;
3+ import { mainnet } from "viem/chains" ;
24import {
35 bundleHistoryFromAuditEvents ,
4- getAuditEventsByBundle ,
6+ getJoinedAuditEventsByBundle ,
57} from "@/lib/audit-events" ;
6- import type { BundleEvent } from "@/lib/transaction-data" ;
8+ import type { BundleEvent , BundleTransaction } from "@/lib/transaction-data" ;
9+ import { getBundleHistory } from "@/lib/s3" ;
10+
11+ const RPC_URL = process . env . TIPS_UI_RPC_URL || "http://localhost:8545" ;
12+
13+ const client = createPublicClient ( {
14+ chain : mainnet ,
15+ transport : http ( RPC_URL ) ,
16+ } ) ;
717
818export interface BundleHistoryResponse {
919 hash : string ;
1020 history : BundleEvent [ ] ;
1121}
1222
23+ function bigintToHex ( value : bigint | null | undefined ) : string {
24+ return value === null || value === undefined ? "0x0" : `0x${ value . toString ( 16 ) } ` ;
25+ }
26+
27+ function numberToHex ( value : number | null | undefined ) : string {
28+ return value === null || value === undefined ? "0x0" : `0x${ value . toString ( 16 ) } ` ;
29+ }
30+
31+ async function enrichBundleTransactionsFromRpc (
32+ history : BundleEvent [ ] ,
33+ ) : Promise < BundleEvent [ ] > {
34+ const hashes = Array . from (
35+ new Set (
36+ history . flatMap ( ( event ) =>
37+ event . data . bundle ?. txs . map ( ( tx ) => tx . hash ) . filter ( Boolean ) ?? [ ] ,
38+ ) ,
39+ ) ,
40+ ) ;
41+ const transactions = new Map < string , BundleTransaction > ( ) ;
42+
43+ await Promise . all (
44+ hashes . map ( async ( hash ) => {
45+ try {
46+ const tx = await client . getTransaction ( { hash : hash as Hash } ) ;
47+ transactions . set ( hash , {
48+ signer : tx . from ,
49+ type : tx . typeHex ?? "" ,
50+ chainId : numberToHex ( tx . chainId ) ,
51+ nonce : numberToHex ( tx . nonce ) ,
52+ gas : bigintToHex ( tx . gas ) ,
53+ maxFeePerGas : bigintToHex ( tx . maxFeePerGas ?? tx . gasPrice ) ,
54+ maxPriorityFeePerGas : bigintToHex ( tx . maxPriorityFeePerGas ) ,
55+ to : tx . to ,
56+ value : bigintToHex ( tx . value ) ,
57+ accessList : [ ...( tx . accessList ?? [ ] ) ] ,
58+ input : tx . input ,
59+ r : tx . r ,
60+ s : tx . s ,
61+ yParity : numberToHex ( tx . yParity ) ,
62+ v : bigintToHex ( tx . v ) ,
63+ hash : tx . hash ,
64+ } ) ;
65+ } catch ( error ) {
66+ console . error ( `Failed to fetch transaction ${ hash } from RPC:` , error ) ;
67+ }
68+ } ) ,
69+ ) ;
70+
71+ return history . map ( ( event ) => {
72+ if ( ! event . data . bundle ) return event ;
73+ return {
74+ ...event ,
75+ data : {
76+ ...event . data ,
77+ bundle : {
78+ ...event . data . bundle ,
79+ txs : event . data . bundle . txs . map ( ( tx ) => transactions . get ( tx . hash ) ?? tx ) ,
80+ } ,
81+ } ,
82+ } ;
83+ } ) ;
84+ }
85+
1386export async function GET (
1487 _request : NextRequest ,
1588 { params } : { params : Promise < { hash : string } > } ,
1689) {
1790 try {
1891 const { hash } = await params ;
1992
20- const bundle = bundleHistoryFromAuditEvents (
21- hash ,
22- await getAuditEventsByBundle ( hash ) ,
23- ) ;
93+ const bundle = await getAuditBundleHistory ( hash ) ;
2494 if ( ! bundle ) {
2595 return NextResponse . json ( { error : "Bundle not found" } , { status : 404 } ) ;
2696 }
2797
28- const history = bundle . history ;
98+ const history = await enrichBundleTransactionsFromRpc ( bundle . history ) ;
2999 history . sort ( ( lhs , rhs ) =>
30100 lhs . data . timestamp < rhs . data . timestamp ? - 1 : 1 ,
31101 ) ;
32102
33103 const response : BundleHistoryResponse = {
34104 hash,
35- history : bundle . history ,
105+ history,
36106 } ;
37107
38108 return NextResponse . json ( response ) ;
@@ -44,3 +114,13 @@ export async function GET(
44114 ) ;
45115 }
46116}
117+
118+ async function getAuditBundleHistory ( hash : string ) {
119+ try {
120+ const events = await getJoinedAuditEventsByBundle ( hash ) ;
121+ return bundleHistoryFromAuditEvents ( hash , events ) ?? getBundleHistory ( hash ) ;
122+ } catch ( error ) {
123+ console . error ( "Falling back to S3 bundle history:" , error ) ;
124+ return getBundleHistory ( hash ) ;
125+ }
126+ }
0 commit comments