Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add showFungible option flag to das #215

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions digital_asset_types/src/dao/full_asset.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use crate::dao::{asset, asset_authority, asset_creators, asset_data, asset_grouping};

use super::tokens;

#[derive(Clone, Debug, PartialEq)]
pub struct FullAsset {
pub asset: asset::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 groups: Vec<asset_grouping::Model>,
Expand Down
32 changes: 28 additions & 4 deletions digital_asset_types/src/dao/scopes/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use crate::{
asset_authority, asset_creators, asset_data, asset_grouping, cl_audits_v2,
extensions::{self, instruction::PascalCase},
sea_orm_active_enums::Instruction,
Cursor, FullAsset, GroupingSize, Pagination,
tokens, Cursor, FullAsset, GroupingSize, Pagination,
},
rpc::filter::AssetSortDirection,
rpc::{filter::AssetSortDirection, options::Options},
};
use indexmap::IndexMap;
use sea_orm::{entity::*, query::*, ConnectionTrait, DbErr, Order};
Expand Down Expand Up @@ -149,11 +149,12 @@ pub async fn get_assets_by_owner(
sort_direction: Order,
pagination: &Pagination,
limit: u64,
show_unverified_collections: bool,
options: &Options,
) -> Result<Vec<FullAsset>, DbErr> {
let cond = Condition::all()
.add(asset::Column::Owner.eq(owner))
.add(asset::Column::Supply.gt(0));

get_assets_by_condition(
conn,
cond,
Expand All @@ -162,7 +163,7 @@ pub async fn get_assets_by_owner(
sort_direction,
pagination,
limit,
show_unverified_collections,
options.show_unverified_collections,
)
.await
}
Expand All @@ -176,6 +177,7 @@ pub async fn get_assets(
let cond = Condition::all()
.add(asset::Column::Id.is_in(asset_ids))
.add(asset::Column::Supply.gt(0));

get_assets_by_condition(
conn,
cond,
Expand Down Expand Up @@ -278,6 +280,7 @@ pub async fn get_related_for_assets(
authorities: vec![],
creators: vec![],
groups: vec![],
token_info: None,
};
acc.insert(id, fa);
};
Expand Down Expand Up @@ -385,12 +388,19 @@ pub async fn get_by_id(
conn: &impl ConnectionTrait,
asset_id: Vec<u8>,
include_no_supply: bool,
options: &Options,
) -> Result<FullAsset, DbErr> {
let mut asset_data =
asset::Entity::find_by_id(asset_id.clone()).find_also_related(asset_data::Entity);
if !include_no_supply {
asset_data = asset_data.filter(Condition::all().add(asset::Column::Supply.gt(0)));
}

let token_info = if options.show_fungible {
get_token_by_id(conn, asset_id.clone()).await.ok()
} else {
None
};
Comment on lines +407 to +411
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be done by joining in this info into the asset query so there aren't 2 round trips to the db?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currently we can use find_with_related for only 2 models

let asset_data: (asset::Model, asset_data::Model) =
asset_data.one(conn).await.and_then(|o| match o {
Some((a, Some(d))) => Ok((a, d)),
Expand Down Expand Up @@ -430,6 +440,7 @@ pub async fn get_by_id(
authorities,
creators,
groups: grouping,
token_info,
})
}

Expand Down Expand Up @@ -553,3 +564,16 @@ fn filter_out_stale_creators(creators: &mut Vec<asset_creators::Model>) {
}
}
}

pub async fn get_token_by_id(
conn: &impl ConnectionTrait,
id: Vec<u8>,
) -> Result<tokens::Model, DbErr> {
tokens::Entity::find_by_id(id)
.one(conn)
.await
.and_then(|o| match o {
Some(t) => Ok(t),
_ => Err(DbErr::RecordNotFound("Token Not Found".to_string())),
})
}
2 changes: 1 addition & 1 deletion digital_asset_types/src/dapi/assets_by_owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub async fn get_assets_by_owner(
sort_direction,
&pagination,
page_options.limit,
options.show_unverified_collections,
options,
)
.await?;
Ok(build_asset_response(
Expand Down
20 changes: 20 additions & 0 deletions digital_asset_types/src/dapi/common/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::rpc::filter::{AssetSortBy, AssetSortDirection, AssetSorting};
use crate::rpc::options::Options;
use crate::rpc::response::TransactionSignatureList;
use crate::rpc::response::{AssetError, AssetList};
use crate::rpc::TokenInfo;
use crate::rpc::{
Asset as RpcAsset, Authority, Compression, Content, Creator, File, Group, Interface,
MetadataMap, MplCoreInfo, Ownership, Royalty, Scope, Supply, Uses,
Expand Down Expand Up @@ -355,6 +356,7 @@ pub fn asset_to_rpc(asset: FullAsset, options: &Options) -> Result<RpcAsset, DbE
authorities,
creators,
groups,
token_info,
} = asset;
let rpc_authorities = to_authority(authorities);
let rpc_creators = to_creators(creators);
Expand All @@ -377,6 +379,23 @@ pub fn asset_to_rpc(asset: FullAsset, options: &Options) -> Result<RpcAsset, DbE
_ => None,
};

let token_info = if options.show_fungible && token_info.is_some() {
let token_info = token_info.unwrap();
Some(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
};
Nagaprasadvr marked this conversation as resolved.
Show resolved Hide resolved

Ok(RpcAsset {
interface: interface.clone(),
id: bs58::encode(asset.id).into_string(),
Expand Down Expand Up @@ -444,6 +463,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,
token_info,
plugins: asset.mpl_core_plugins,
unknown_plugins: asset.mpl_core_unknown_plugins,
mpl_core_info,
Expand Down
2 changes: 1 addition & 1 deletion digital_asset_types/src/dapi/get_asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub async fn get_asset(
id: Vec<u8>,
options: &Options,
) -> Result<Asset, DbErr> {
let asset = scopes::asset::get_by_id(db, id, false).await?;
let asset = scopes::asset::get_by_id(db, id, false, options).await?;
asset_to_rpc(asset, options)
}

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 @@ -366,6 +366,17 @@ pub struct MplCoreInfo {
pub plugins_json_version: Option<i32>,
}

#[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)]
pub struct Asset {
pub interface: Interface,
Expand All @@ -389,6 +400,8 @@ pub struct Asset {
pub mutable: bool,
pub burnt: bool,
#[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 @@ -6,4 +6,6 @@ use serde::{Deserialize, Serialize};
pub struct Options {
#[serde(default)]
pub show_unverified_collections: bool,
#[serde(default)]
pub show_fungible: bool,
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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 @@ -4,3 +4,4 @@ mod common;
mod general_scenario_tests;
mod mpl_core_tests;
mod regular_nft_tests;
mod show_fungible_flag_tests;
Nagaprasadvr marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use function_name::named;

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

use itertools::Itertools;

use serial_test::serial;

use super::common::*;

#[tokio::test]
#[serial]
#[named]
async fn test_get_asset_with_show_fungible_scenario_1() {
let name = trim_test_name(function_name!());
let setup = TestSetup::new_with_options(
name.clone(),
TestSetupOptions {
network: Some(Network::Mainnet),
},
)
.await;

let seeds: Vec<SeedEvent> = seed_accounts([
"Ca84nWhQu41DMRnjdhRrLZty1i9txepMhAhz5qLLGcBw",
"7z6b5TE4WX4mgcQjuNBTDxK4SE75sbgEg5WWJwoUeie8",
]);

apply_migrations_and_delete_data(setup.db.clone()).await;
index_seed_events(&setup, seeds.iter().collect_vec()).await;

let request = r#"
{
"id": "Ca84nWhQu41DMRnjdhRrLZty1i9txepMhAhz5qLLGcBw",
"displayOptions": {
"showFungible": true
}

}
"#;

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

insta::assert_json_snapshot!(name, response);
}

#[tokio::test]
#[serial]
#[named]
async fn test_get_asset_with_show_fungible_scenario_2() {
let name = trim_test_name(function_name!());
let setup = TestSetup::new_with_options(
name.clone(),
TestSetupOptions {
network: Some(Network::Mainnet),
},
)
.await;

let seeds: Vec<SeedEvent> = seed_accounts([
"AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM",
"7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK",
]);

apply_migrations_and_delete_data(setup.db.clone()).await;
index_seed_events(&setup, seeds.iter().collect_vec()).await;

let request = r#"
{
"id": "AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM",
"displayOptions": {
"showFungible": true
}
}
"#;

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

insta::assert_json_snapshot!(name, response);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
source: integration_tests/tests/integration_tests/show_fungible_flag_tests.rs
expression: response
snapshot_kind: text
---
{
"interface": "ProgrammableNFT",
"id": "Ca84nWhQu41DMRnjdhRrLZty1i9txepMhAhz5qLLGcBw",
"content": {
"$schema": "https://schema.metaplex.com/nft1.0.json",
"json_uri": "https://nftstorage.link/ipfs/bafkreibmdapcawep5fb77lvcuvoivft3w3wsnc4qworrntjbg6abc5vwti",
"files": [],
"metadata": {
"name": "Claynosaurz #1096",
"symbol": "DINO",
"token_standard": "ProgrammableNonFungible"
},
"links": {}
},
"authorities": [
{
"address": "B7B2g3WbdZMDV3YcDGRGhEt5KyWqDJZFwRR8zpWVEkUF",
"scopes": [
"full"
]
}
],
"compression": {
"eligible": false,
"compressed": false,
"data_hash": "",
"creator_hash": "",
"asset_hash": "",
"tree": "",
"seq": 0,
"leaf_id": 0
},
"grouping": [
{
"group_key": "collection",
"group_value": "6mszaj17KSfVqADrQj3o4W3zoLMTykgmV37W4QadCczK"
}
],
"royalty": {
"royalty_model": "creators",
"target": null,
"percent": 0.05,
"basis_points": 500,
"primary_sale_happened": true,
"locked": false
},
"creators": [
{
"address": "AoebZtN5iKpVyUBc82aouWhugVknLzjUmEEUezxviYNo",
"share": 0,
"verified": true
},
{
"address": "36tfiBtaDGjAMKd6smPacHQhe4MXycLL6f9ww9CD1naT",
"share": 100,
"verified": false
}
],
"ownership": {
"frozen": false,
"delegated": false,
"delegate": null,
"ownership_model": "single",
"owner": ""
},
Nagaprasadvr marked this conversation as resolved.
Show resolved Hide resolved
"supply": null,
"mutable": true,
"burnt": false,
"token_info": {
"supply": 1,
"decimals": 0,
"token_program": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"mint_authority": "EwSfdqoZPBW6JJN1SBkM2pPgpihDVbByuxKdmiXurxYF",
"freeze_authority": "EwSfdqoZPBW6JJN1SBkM2pPgpihDVbByuxKdmiXurxYF"
}
}
Loading