Skip to content

Commit

Permalink
das-api: Include mint-extensions in the response
Browse files Browse the repository at this point in the history
  • Loading branch information
niks3089 committed Feb 19, 2024
1 parent 1e04239 commit ffd1bb6
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 76 deletions.
28 changes: 28 additions & 0 deletions digital_asset_types/src/dapi/common/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -47,6 +48,30 @@ pub fn file_from_str(str: String) -> File {
}
}

fn filter_non_null_fields(value: Option<&Value>) -> Option<Value> {
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<String, Value> = 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<FullAsset>,
limit: u64,
Expand Down Expand Up @@ -368,6 +393,8 @@ pub fn asset_to_rpc(asset: FullAsset, options: &Options) -> Result<RpcAsset, DbE
.unwrap_or(false);
let edition_nonce =
safe_select(chain_data_selector, "$.edition_nonce").and_then(|v| v.as_u64());

let mint_ext = filter_non_null_fields(asset.mint_extensions.as_ref());
Ok(RpcAsset {
interface: interface.clone(),
id: bs58::encode(asset.id).into_string(),
Expand Down Expand Up @@ -435,6 +462,7 @@ pub fn asset_to_rpc(asset: FullAsset, options: &Options) -> Result<RpcAsset, DbE
remaining: u.get("remaining").and_then(|t| t.as_u64()).unwrap_or(0),
}),
burnt: asset.burnt,
mint_extensions: mint_ext,
})
}

Expand Down
3 changes: 3 additions & 0 deletions digital_asset_types/src/rpc/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::collections::BTreeMap;

use crate::dao::sea_orm_active_enums::ChainMutability;
use schemars::JsonSchema;
use serde_json::Value;
use {
serde::{Deserialize, Serialize},
std::collections::HashMap,
Expand Down Expand Up @@ -364,4 +365,6 @@ pub struct Asset {
pub supply: Option<Supply>,
pub mutable: bool,
pub burnt: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub mint_extensions: Option<Value>,
}
151 changes: 75 additions & 76 deletions nft_ingester/src/program_transformers/token_extensions/mint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}

Expand Down Expand Up @@ -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<Vec<u8>> = m.extensions.metadata.clone().and_then(|m| {
let auth_pubkey: Option<Pubkey> = 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<Vec<u8>> = m.extensions.metadata.clone().and_then(|m| {
let auth_pubkey: Option<Pubkey> = 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(())
}

Expand Down

0 comments on commit ffd1bb6

Please sign in to comment.