Skip to content

Commit

Permalink
Show Fungibles Filter (#215)
Browse files Browse the repository at this point in the history
  • Loading branch information
Nagaprasadvr authored Jan 13, 2025
1 parent a3ac6e6 commit 3e4fb88
Show file tree
Hide file tree
Showing 41 changed files with 1,095 additions and 44 deletions.
12 changes: 12 additions & 0 deletions digital_asset_types/src/dao/extensions/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::dao::{
asset, asset_authority, asset_creators, asset_data, asset_grouping,
asset_v1_account_attachments,
sea_orm_active_enums::{OwnerType, RoyaltyTargetType},
token_accounts,
};

#[derive(Copy, Clone, Debug, EnumIter)]
Expand All @@ -13,6 +14,7 @@ pub enum Relation {
AssetAuthority,
AssetCreators,
AssetGrouping,
TokenAccounts,
}

impl RelationTrait for Relation {
Expand All @@ -22,6 +24,10 @@ impl RelationTrait for Relation {
.from(asset::Column::AssetData)
.to(asset_data::Column::Id)
.into(),
Self::TokenAccounts => asset::Entity::belongs_to(token_accounts::Entity)
.from(asset::Column::Id)
.to(token_accounts::Column::Mint)
.into(),
Self::AssetV1AccountAttachments => {
asset::Entity::has_many(asset_v1_account_attachments::Entity).into()
}
Expand Down Expand Up @@ -62,6 +68,12 @@ impl Related<asset_grouping::Entity> for asset::Entity {
}
}

impl Related<token_accounts::Entity> for asset::Entity {
fn to() -> RelationDef {
Relation::TokenAccounts.def()
}
}

impl Default for RoyaltyTargetType {
fn default() -> Self {
Self::Creators
Expand Down
1 change: 1 addition & 0 deletions digital_asset_types/src/dao/extensions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ pub mod asset_data;
pub mod asset_grouping;
pub mod asset_v1_account_attachment;
pub mod instruction;
pub mod token_accounts;
25 changes: 25 additions & 0 deletions digital_asset_types/src/dao/extensions/token_accounts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use sea_orm::{EntityTrait, EnumIter, Related, RelationDef, RelationTrait};

use crate::dao::{asset, token_accounts};

#[derive(Copy, Clone, Debug, EnumIter)]
pub enum Relation {
Asset,
}

impl RelationTrait for Relation {
fn def(&self) -> RelationDef {
match self {
Self::Asset => token_accounts::Entity::belongs_to(asset::Entity)
.from(token_accounts::Column::Mint)
.to(asset::Column::Id)
.into(),
}
}
}

impl Related<asset::Entity> for token_accounts::Entity {
fn to() -> RelationDef {
Relation::Asset.def()
}
}
6 changes: 4 additions & 2 deletions digital_asset_types/src/dao/full_asset.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::asset_v1_account_attachments;
use super::{asset_v1_account_attachments, tokens};
use crate::dao::{asset, asset_authority, asset_creators, asset_data, asset_grouping};

#[derive(Clone, Debug, PartialEq)]
pub struct FullAssetGroup {
pub id: i64,
pub asset_id: Vec<u8>,
Expand All @@ -15,7 +16,8 @@ pub struct FullAssetGroup {
#[derive(Clone, Debug, PartialEq)]
pub struct FullAsset {
pub asset: asset::Model,
pub data: Option<asset_data::Model>,
pub data: asset_data::Model,
pub token_info: Option<tokens::Model>,
pub authorities: Vec<asset_authority::Model>,
pub creators: Vec<asset_creators::Model>,
pub inscription: Option<asset_v1_account_attachments::Model>,
Expand Down
51 changes: 42 additions & 9 deletions digital_asset_types/src/dao/scopes/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
cl_audits_v2,
extensions::{self, instruction::PascalCase},
sea_orm_active_enums::{Instruction, V1AccountAttachments},
token_accounts, Cursor, FullAsset, GroupingSize, Pagination,
token_accounts, tokens, Cursor, FullAsset, GroupingSize, Pagination,
},
rpc::{
filter::AssetSortDirection,
Expand Down Expand Up @@ -161,7 +161,7 @@ pub async fn get_assets_by_owner(
options: &Options,
) -> Result<Vec<FullAsset>, DbErr> {
let cond = Condition::all()
.add(asset::Column::Owner.eq(owner))
.add(asset::Column::Owner.eq(owner.clone()))
.add(asset::Column::Supply.gt(0));

get_assets_by_condition(
Expand Down Expand Up @@ -286,11 +286,12 @@ pub async fn get_related_for_assets(
let id = asset.id.clone();
let fa = FullAsset {
asset,
data: Some(ad.clone()),
data: ad.clone(),
authorities: vec![],
creators: vec![],
groups: vec![],
inscription: None,
token_info: None,
};
acc.insert(id, fa);
};
Expand Down Expand Up @@ -338,6 +339,17 @@ pub async fn get_related_for_assets(
}
}

if options.show_fungible {
find_tokens(conn, ids.clone())
.await?
.into_iter()
.for_each(|t| {
if let Some(asset) = assets_map.get_mut(&t.mint.clone()) {
asset.token_info = Some(t);
}
});
}

let cond = if options.show_unverified_collections {
Condition::all()
} else {
Expand Down Expand Up @@ -436,13 +448,21 @@ pub async fn get_by_id(
None
};

let asset_data: (asset::Model, Option<asset_data::Model>) =
let token_info = if options.show_fungible {
find_tokens(conn, vec![asset_id.clone()])
.await?
.into_iter()
.next()
} else {
None
};

let (asset, data): (asset::Model, asset_data::Model) =
asset_data.one(conn).await.and_then(|o| match o {
Some((a, d)) => Ok((a, d)),
Some((a, Some(d))) => Ok((a, d)),
_ => Err(DbErr::RecordNotFound("Asset Not Found".to_string())),
})?;

let (asset, data) = asset_data;
let authorities: Vec<asset_authority::Model> = asset_authority::Entity::find()
.filter(asset_authority::Column::AssetId.eq(asset.id.clone()))
.order_by_asc(asset_authority::Column::AssetId)
Expand Down Expand Up @@ -489,6 +509,7 @@ pub async fn get_by_id(
creators,
inscription,
groups,
token_info,
})
}

Expand Down Expand Up @@ -655,11 +676,11 @@ pub async fn get_token_accounts(
Ok(token_accounts)
}

pub fn get_edition_data_from_json<T: DeserializeOwned>(data: Value) -> Result<T, DbErr> {
fn get_edition_data_from_json<T: DeserializeOwned>(data: Value) -> Result<T, DbErr> {
serde_json::from_value(data).map_err(|e| DbErr::Custom(e.to_string()))
}

pub fn attachment_to_nft_edition(
fn attachment_to_nft_edition(
attachment: asset_v1_account_attachments::Model,
) -> Result<NftEdition, DbErr> {
let data: Edition = attachment
Expand Down Expand Up @@ -761,7 +782,8 @@ pub async fn get_nft_editions(
cursor,
})
}
pub async fn get_inscription_by_mint(

async fn get_inscription_by_mint(
conn: &impl ConnectionTrait,
mint: Vec<u8>,
) -> Result<asset_v1_account_attachments::Model, DbErr> {
Expand All @@ -781,3 +803,14 @@ pub async fn get_inscription_by_mint(
_ => Err(DbErr::RecordNotFound("Inscription Not Found".to_string())),
})
}

async fn find_tokens(
conn: &impl ConnectionTrait,
ids: Vec<Vec<u8>>,
) -> Result<Vec<tokens::Model>, DbErr> {
tokens::Entity::find()
.filter(tokens::Column::Mint.is_in(ids))
.all(conn)
.await
.map_err(|_| DbErr::RecordNotFound("Token (s) Not Found".to_string()))
}
62 changes: 38 additions & 24 deletions digital_asset_types/src/dapi/common/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::rpc::options::Options;
use crate::rpc::response::TokenAccountList;
use crate::rpc::response::TransactionSignatureList;
use crate::rpc::response::{AssetList, DasError};
use crate::rpc::TokenInfo;
use crate::rpc::TokenInscriptionInfo;
use crate::rpc::{
Asset as RpcAsset, Authority, Compression, Content, Creator, File, Group, Interface,
Expand Down Expand Up @@ -376,36 +377,32 @@ pub fn asset_to_rpc(asset: FullAsset, options: &Options) -> Result<RpcAsset, DbE
creators,
groups,
inscription,
token_info,
} = asset;
let rpc_authorities = to_authority(authorities);
let rpc_creators = to_creators(creators);
let rpc_groups = to_grouping(groups, options)?;
let interface = get_interface(&asset)?;
let content = get_content(&data);
let mut chain_data_selector_fn = jsonpath_lib::selector(&data.chain_data);
let chain_data_selector = &mut chain_data_selector_fn;

let (content, edition_nonce, basis_points, mutable, uses) = if let Some(data) = &data {
let mut chain_data_selector_fn = jsonpath_lib::selector(&data.chain_data);
let chain_data_selector = &mut chain_data_selector_fn;
(
get_content(data),
safe_select(chain_data_selector, "$.edition_nonce").and_then(|v| v.as_u64()),
safe_select(chain_data_selector, "$.primary_sale_happened")
.and_then(|v| v.as_bool())
.unwrap_or(false),
data.chain_data_mutability.clone().into(),
data.chain_data.get("uses").map(|u| Uses {
use_method: u
.get("use_method")
.and_then(|s| s.as_str())
.unwrap_or("Single")
.to_string()
.into(),
total: u.get("total").and_then(|t| t.as_u64()).unwrap_or(0),
remaining: u.get("remaining").and_then(|t| t.as_u64()).unwrap_or(0),
}),
)
} else {
(None, None, false, false, None)
};
let edition_nonce =
safe_select(chain_data_selector, "$.edition_nonce").and_then(|v| v.as_u64());
let basis_points = safe_select(chain_data_selector, "$.primary_sale_happened")
.and_then(|v| v.as_bool())
.unwrap_or(false);
let mutable = data.chain_data_mutability.clone().into();
let uses = data.chain_data.get("uses").map(|u| Uses {
use_method: u
.get("use_method")
.and_then(|s| s.as_str())
.unwrap_or("Single")
.to_string()
.into(),
total: u.get("total").and_then(|t| t.as_u64()).unwrap_or(0),
remaining: u.get("remaining").and_then(|t| t.as_u64()).unwrap_or(0),
});

let mpl_core_info = match interface {
Interface::MplCoreAsset | Interface::MplCoreCollection => Some(MplCoreInfo {
Expand Down Expand Up @@ -441,6 +438,22 @@ pub fn asset_to_rpc(asset: FullAsset, options: &Options) -> Result<RpcAsset, DbE
None
};

let token_info = if options.show_fungible {
token_info.map(|token_info| TokenInfo {
supply: token_info.supply.try_into().unwrap_or(0),
decimals: token_info.decimals as u8,
mint_authority: token_info
.mint_authority
.map(|s| bs58::encode(s).into_string()),
freeze_authority: token_info
.freeze_authority
.map(|s| bs58::encode(s).into_string()),
token_program: bs58::encode(token_info.token_program).into_string(),
})
} else {
None
};

Ok(RpcAsset {
interface: interface.clone(),
id: bs58::encode(asset.id).into_string(),
Expand Down Expand Up @@ -499,6 +512,7 @@ pub fn asset_to_rpc(asset: FullAsset, options: &Options) -> Result<RpcAsset, DbE
},
uses,
burnt: asset.burnt,
token_info,
mint_extensions: asset.mint_extensions,
inscription,
plugins: asset.mpl_core_plugins,
Expand Down
13 changes: 13 additions & 0 deletions digital_asset_types/src/rpc/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,17 @@ pub struct TokenInscriptionInfo {
pub validation_hash: Option<String>,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct TokenInfo {
pub supply: u64,
pub decimals: u8,
pub token_program: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub mint_authority: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub freeze_authority: Option<String>,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema, Default)]
pub struct Asset {
pub interface: Interface,
Expand Down Expand Up @@ -422,6 +433,8 @@ pub struct Asset {
#[serde(skip_serializing_if = "Option::is_none")]
pub inscription: Option<TokenInscriptionInfo>,
#[serde(skip_serializing_if = "Option::is_none")]
pub token_info: Option<TokenInfo>,
#[serde(skip_serializing_if = "Option::is_none")]
pub plugins: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub unknown_plugins: Option<Value>,
Expand Down
2 changes: 2 additions & 0 deletions digital_asset_types/src/rpc/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ pub struct Options {
pub show_zero_balance: bool,
#[serde(default)]
pub show_inscription: bool,
#[serde(default)]
pub show_fungible: bool,
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use super::common::*;
use das_api::{
api::{self, ApiContract},
error::DasApiError,
};
use function_name::named;

use das_api::api::{self, ApiContract};

use itertools::Itertools;

use serial_test::serial;

use super::common::*;

#[tokio::test]
#[serial]
#[named]
Expand Down Expand Up @@ -134,7 +133,7 @@ async fn test_fungible_token_get_asset_scenario_1() {
#[tokio::test]
#[serial]
#[named]
async fn test_fungible_token_get_asset_scenario_2() {
async fn test_token_keg_fungible_with_no_metadata() {
let name = trim_test_name(function_name!());
let setup = TestSetup::new_with_options(
name.clone(),
Expand All @@ -156,7 +155,7 @@ async fn test_fungible_token_get_asset_scenario_2() {
"#;

let request: api::GetAsset = serde_json::from_str(request).unwrap();
let response = setup.das_api.get_asset(request).await.unwrap();
let response = setup.das_api.get_asset(request).await;

insta::assert_json_snapshot!(name, response);
assert!(matches!(response, Err(DasApiError::DatabaseError(_))));
}
1 change: 1 addition & 0 deletions integration_tests/tests/integration_tests/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ mod mpl_core_tests;
mod nft_editions_tests;
mod regular_nft_tests;
mod show_collection_metadata_option_tests;
mod show_fungible_flag_tests;
mod show_inscription_flag_tests;
mod test_get_assets_with_multiple_same_ids;
mod test_show_zero_balance_filter;
Expand Down
Loading

0 comments on commit 3e4fb88

Please sign in to comment.