From ffd1bb6d2d4c77321609e24255e8ef0895a79c18 Mon Sep 17 00:00:00 2001 From: niks3089 Date: Mon, 19 Feb 2024 14:28:19 +0530 Subject: [PATCH] das-api: Include mint-extensions in the response --- digital_asset_types/src/dapi/common/asset.rs | 28 ++++ digital_asset_types/src/rpc/asset.rs | 3 + .../token_extensions/mint.rs | 151 +++++++++--------- 3 files changed, 106 insertions(+), 76 deletions(-) diff --git a/digital_asset_types/src/dapi/common/asset.rs b/digital_asset_types/src/dapi/common/asset.rs index 655eefdc4..9fd9a3881 100644 --- a/digital_asset_types/src/dapi/common/asset.rs +++ b/digital_asset_types/src/dapi/common/asset.rs @@ -16,6 +16,7 @@ use log::warn; use mime_guess::Mime; use sea_orm::DbErr; +use serde_json::Map; use serde_json::Value; use std::cmp::Ordering; use std::collections::HashMap; @@ -47,6 +48,30 @@ pub fn file_from_str(str: String) -> File { } } +fn filter_non_null_fields(value: Option<&Value>) -> Option { + match value { + Some(Value::Null) => None, + Some(Value::Object(map)) => { + if map.values().all(|v| matches!(v, Value::Null)) { + None + } else { + let filtered_map: Map = map + .into_iter() + .filter(|(_k, v)| !matches!(v, Value::Null)) + .map(|(k, v)| (k.clone(), v.clone())) + .collect(); + + if filtered_map.is_empty() { + None + } else { + Some(Value::Object(filtered_map)) + } + } + } + _ => value.cloned(), + } +} + pub fn build_asset_response( assets: Vec, limit: u64, @@ -368,6 +393,8 @@ pub fn asset_to_rpc(asset: FullAsset, options: &Options) -> Result Result, pub mutable: bool, pub burnt: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub mint_extensions: Option, } diff --git a/nft_ingester/src/program_transformers/token_extensions/mint.rs b/nft_ingester/src/program_transformers/token_extensions/mint.rs index 5f4a78bdd..b1bec2d96 100644 --- a/nft_ingester/src/program_transformers/token_extensions/mint.rs +++ b/nft_ingester/src/program_transformers/token_extensions/mint.rs @@ -69,7 +69,6 @@ pub async fn handle_token2022_mint_account<'a, 'b, 'c>( } fn should_upsert_asset(m: &MintAccount) -> bool { - // TODO: when member extension is live, we'll need to index their group address in the collections_info is_token_nft(m) || m.extensions.metadata.is_some() } @@ -226,95 +225,95 @@ async fn upsert_asset( } } } - } - - let extensions = serde_json::to_value(m.extensions.clone()) - .map_err(|e| IngesterError::SerializatonError(e.to_string()))?; - let class = match is_nft { - true => SpecificationAssetClass::Nft, - false => SpecificationAssetClass::FungibleToken, - }; + let extensions = serde_json::to_value(m.extensions.clone()) + .map_err(|e| IngesterError::SerializatonError(e.to_string()))?; - let mut asset_model = asset::ActiveModel { - id: Set(key_bytes.clone()), - owner_type: Set(owner_type), - supply: Set(m.account.supply as i64), - supply_mint: Set(Some(key_bytes.clone())), - specification_version: Set(Some(SpecificationVersions::V1)), - specification_asset_class: Set(Some(class)), - nonce: Set(Some(0)), - seq: Set(Some(0)), - compressed: Set(false), - compressible: Set(false), - asset_data: Set(Some(key_bytes.clone())), - slot_updated: Set(Some(slot)), - burnt: Set(false), - mint_extensions: Set(Some(extensions)), - ..Default::default() - }; - - let auth_address: Option> = m.extensions.metadata.clone().and_then(|m| { - let auth_pubkey: Option = m.update_authority.into(); - auth_pubkey.map(|value| value.to_bytes().to_vec()) - }); + let class = match is_nft { + true => SpecificationAssetClass::Nft, + false => SpecificationAssetClass::FungibleToken, + }; - if let Some(authority) = auth_address { - let model = asset_authority::ActiveModel { - asset_id: Set(key_bytes.clone()), - authority: Set(authority), - seq: Set(0), - slot_updated: Set(slot), + let mut asset_model = asset::ActiveModel { + id: Set(key_bytes.clone()), + owner_type: Set(owner_type), + supply: Set(m.account.supply as i64), + supply_mint: Set(Some(key_bytes.clone())), + specification_version: Set(Some(SpecificationVersions::V1)), + specification_asset_class: Set(Some(class)), + nonce: Set(Some(0)), + seq: Set(Some(0)), + compressed: Set(false), + compressible: Set(false), + asset_data: Set(Some(key_bytes.clone())), + slot_updated: Set(Some(slot)), + burnt: Set(false), + mint_extensions: Set(Some(extensions)), ..Default::default() }; - let mut query = asset_authority::Entity::insert(model) + let auth_address: Option> = m.extensions.metadata.clone().and_then(|m| { + let auth_pubkey: Option = m.update_authority.into(); + auth_pubkey.map(|value| value.to_bytes().to_vec()) + }); + + if let Some(authority) = auth_address { + let model = asset_authority::ActiveModel { + asset_id: Set(key_bytes.clone()), + authority: Set(authority), + seq: Set(0), + slot_updated: Set(slot), + ..Default::default() + }; + + let mut query = asset_authority::Entity::insert(model) + .on_conflict( + OnConflict::columns([asset_authority::Column::AssetId]) + .update_columns([ + asset_authority::Column::Authority, + asset_authority::Column::Seq, + asset_authority::Column::SlotUpdated, + ]) + .to_owned(), + ) + .build(DbBackend::Postgres); + query.sql = format!( + "{} WHERE excluded.slot_updated > asset_authority.slot_updated", + query.sql + ); + txn.execute(query) + .await + .map_err(|db_err| IngesterError::AssetIndexError(db_err.to_string()))?; + } + + let mut asset_query = asset::Entity::insert(asset_model) .on_conflict( - OnConflict::columns([asset_authority::Column::AssetId]) - .update_columns([ - asset_authority::Column::Authority, - asset_authority::Column::Seq, - asset_authority::Column::SlotUpdated, + OnConflict::columns([asset::Column::Id]) + .update_columns(vec![ + asset::Column::OwnerType, + asset::Column::Supply, + asset::Column::SupplyMint, + asset::Column::SpecificationVersion, + asset::Column::SpecificationAssetClass, + asset::Column::Nonce, + asset::Column::Seq, + asset::Column::Compressed, + asset::Column::Compressible, + asset::Column::AssetData, + asset::Column::SlotUpdated, + asset::Column::Burnt, ]) .to_owned(), ) .build(DbBackend::Postgres); - query.sql = format!( - "{} WHERE excluded.slot_updated > asset_authority.slot_updated", - query.sql - ); - txn.execute(query) - .await - .map_err(|db_err| IngesterError::AssetIndexError(db_err.to_string()))?; - } - - let mut asset_query = asset::Entity::insert(asset_model) - .on_conflict( - OnConflict::columns([asset::Column::Id]) - .update_columns(vec![ - asset::Column::OwnerType, - asset::Column::Supply, - asset::Column::SupplyMint, - asset::Column::SpecificationVersion, - asset::Column::SpecificationAssetClass, - asset::Column::Nonce, - asset::Column::Seq, - asset::Column::Compressed, - asset::Column::Compressible, - asset::Column::AssetData, - asset::Column::SlotUpdated, - asset::Column::Burnt, - ]) - .to_owned(), - ) - .build(DbBackend::Postgres); - asset_query.sql = format!( + asset_query.sql = format!( "{} WHERE excluded.slot_updated_mint_account >= asset.slot_updated_mint_account OR asset.slot_updated_mint_account IS NULL", asset_query.sql ); - txn.execute(asset_query) - .await - .map_err(|db_err| IngesterError::AssetIndexError(db_err.to_string()))?; + txn.execute(asset_query) + .await + .map_err(|db_err| IngesterError::AssetIndexError(db_err.to_string()))?; + } Ok(()) }