@@ -377,6 +377,36 @@ impl StaticHandler {
377377 Ok ( query_result. 0 )
378378 }
379379
380+ async fn get_first_token_metadata (
381+ & self ,
382+ contract_address : & str ,
383+ ) -> Result < ( serde_json:: Value , String ) > {
384+ // Find tokens with this contract address that have non-empty metadata
385+ let pattern = format ! ( "{}:%" , contract_address) ;
386+ let query_str = format ! (
387+ "SELECT metadata, id FROM {TOKENS_TABLE} WHERE id LIKE ? AND metadata != '' ORDER BY id LIMIT 100"
388+ ) ;
389+ let query_results = sqlx:: query_as :: < _ , ( String , String ) > ( & query_str)
390+ . bind ( & pattern)
391+ . fetch_all ( & self . pool )
392+ . await
393+ . context ( "Failed to find any tokens for contract address" ) ?;
394+
395+ // Try to find a token with valid metadata that contains an image field
396+ for ( metadata_str, token_id) in query_results {
397+ if let Ok ( metadata) = serde_json:: from_str :: < serde_json:: Value > ( & metadata_str) {
398+ if metadata. get ( "image" ) . is_some ( ) {
399+ return Ok ( ( metadata, token_id) ) ;
400+ }
401+ }
402+ }
403+
404+ Err ( anyhow:: anyhow!(
405+ "No tokens found with valid image metadata for contract address: {}" ,
406+ contract_address
407+ ) )
408+ }
409+
380410 async fn check_if_image_outdated (
381411 & self ,
382412 token_image_dir : & Utf8PathBuf ,
@@ -506,16 +536,80 @@ impl StaticHandler {
506536 token_id : & str ,
507537 db_timestamp : Option < & str > ,
508538 ) -> anyhow:: Result < String > {
539+ let is_contract = !token_id. contains ( ':' ) ;
540+
509541 // For both tokens and contracts, we can use the same query since contract address is the ID for contracts
510542 let query_str = format ! ( "SELECT metadata FROM {TOKENS_TABLE} WHERE id = ?" ) ;
511543 let query_result = sqlx:: query_as :: < _ , ( String , ) > ( & query_str)
512544 . bind ( token_id)
513545 . fetch_one ( & self . pool )
514- . await
515- . context ( "Failed to fetch metadata from database" ) ?;
546+ . await ;
547+
548+ // Try to get metadata and image_uri, with fallback for contracts
549+ let metadata = match query_result {
550+ Ok ( result) => {
551+ // Check if metadata is empty or whitespace-only
552+ let metadata_str = result. 0 . trim ( ) ;
553+ if metadata_str. is_empty ( ) {
554+ if is_contract {
555+ // Fallback: try to find first token with this contract address
556+ debug ! ( target: LOG_TARGET , contract_address = %token_id, "Empty metadata for contract, searching for first token" ) ;
557+ let ( fallback_metadata, fallback_token_id) =
558+ self . get_first_token_metadata ( token_id) . await ?;
559+ debug ! ( target: LOG_TARGET , contract_address = %token_id, fallback_token = %fallback_token_id, "Using fallback token image" ) ;
560+ fallback_metadata
561+ } else {
562+ return Err ( anyhow:: anyhow!( "Empty metadata for token" ) ) ;
563+ }
564+ } else {
565+ // Try to parse the metadata
566+ match serde_json:: from_str :: < serde_json:: Value > ( metadata_str) {
567+ Ok ( metadata) => {
568+ // Check if image field exists
569+ if metadata. get ( "image" ) . is_some ( ) {
570+ metadata
571+ } else if is_contract {
572+ // Fallback: try to find first token with this contract address
573+ debug ! ( target: LOG_TARGET , contract_address = %token_id, "No image found in contract metadata, searching for first token" ) ;
574+ let ( fallback_metadata, fallback_token_id) =
575+ self . get_first_token_metadata ( token_id) . await ?;
576+ debug ! ( target: LOG_TARGET , contract_address = %token_id, fallback_token = %fallback_token_id, "Using fallback token image" ) ;
577+ fallback_metadata
578+ } else {
579+ return Err ( anyhow:: anyhow!( "Image URL not found in metadata" ) ) ;
580+ }
581+ }
582+ Err ( e) => {
583+ if is_contract {
584+ // Fallback: try to find first token with this contract address
585+ debug ! ( target: LOG_TARGET , contract_address = %token_id, error = ?e, "Failed to parse contract metadata, searching for first token" ) ;
586+ let ( fallback_metadata, fallback_token_id) =
587+ self . get_first_token_metadata ( token_id) . await ?;
588+ debug ! ( target: LOG_TARGET , contract_address = %token_id, fallback_token = %fallback_token_id, "Using fallback token image" ) ;
589+ fallback_metadata
590+ } else {
591+ return Err ( anyhow:: anyhow!( "Failed to parse metadata: {}" , e) ) ;
592+ }
593+ }
594+ }
595+ }
596+ }
597+ Err ( _) if is_contract => {
598+ // Fallback: try to find first token with this contract address
599+ debug ! ( target: LOG_TARGET , contract_address = %token_id, "Contract metadata not found, searching for first token" ) ;
600+ let ( fallback_metadata, fallback_token_id) =
601+ self . get_first_token_metadata ( token_id) . await ?;
602+ debug ! ( target: LOG_TARGET , contract_address = %token_id, fallback_token = %fallback_token_id, "Using fallback token image" ) ;
603+ fallback_metadata
604+ }
605+ Err ( e) => {
606+ return Err ( anyhow:: anyhow!(
607+ "Failed to fetch metadata from database: {}" ,
608+ e
609+ ) ) ;
610+ }
611+ } ;
516612
517- let metadata: serde_json:: Value =
518- serde_json:: from_str ( & query_result. 0 ) . context ( "Failed to parse metadata" ) ?;
519613 let image_uri = metadata
520614 . get ( "image" )
521615 . context ( "Image URL not found in metadata" ) ?
0 commit comments