diff --git a/Api.Dockerfile b/Api.Dockerfile index cbc4ee6ee..f4920c444 100644 --- a/Api.Dockerfile +++ b/Api.Dockerfile @@ -1,5 +1,5 @@ FROM das-api/builder AS files -FROM rust:1.75-slim-bullseye +FROM rust:1.83-slim-bullseye ARG APP=/usr/src/app RUN apt update \ && apt install -y curl ca-certificates tzdata \ diff --git a/Builder.Dockerfile b/Builder.Dockerfile index 6ee7cbaed..ce42b0853 100644 --- a/Builder.Dockerfile +++ b/Builder.Dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.75-bullseye AS builder +FROM rust:1.83-bullseye AS builder RUN apt-get update -y && \ apt-get install -y build-essential make git @@ -6,7 +6,6 @@ RUN mkdir /rust RUN mkdir /rust/bins COPY Cargo.toml /rust COPY core /rust/core -COPY backfill /rust/backfill COPY das_api /rust/das_api COPY digital_asset_types /rust/digital_asset_types COPY integration_tests /rust/integration_tests @@ -21,6 +20,6 @@ WORKDIR /rust RUN --mount=type=cache,target=/rust/target,id=das-rust \ cargo build --release --bins && cp `find /rust/target/release -maxdepth 1 -type f | sed 's/^\.\///' | grep -v "\." ` /rust/bins -FROM rust:1.75-slim-bullseye as final +FROM rust:1.83-slim-bullseye as final COPY --from=builder /rust/bins /das/ CMD echo "Built the DAS API bins!" diff --git a/Cargo.lock b/Cargo.lock index 073908a5a..70a34016d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2150,6 +2150,7 @@ dependencies = [ "jsonpath_lib", "log", "mime_guess", + "mpl-token-metadata", "num-derive 0.3.3", "num-traits", "schemars", @@ -4902,6 +4903,7 @@ dependencies = [ "solana-transaction-status", "spl-account-compression", "spl-token", + "spl-token-2022", "sqlx", "thiserror 1.0.69", "tokio", diff --git a/Ingest.Dockerfile b/Ingest.Dockerfile index a0a6023d6..b8b8f0c00 100644 --- a/Ingest.Dockerfile +++ b/Ingest.Dockerfile @@ -1,5 +1,5 @@ FROM das-api/builder AS files -FROM rust:1.75-slim-bullseye +FROM rust:1.83-slim-bullseye ARG APP=/usr/src/app RUN apt update \ && apt install -y curl ca-certificates tzdata \ diff --git a/Load.Dockerfile b/Load.Dockerfile index ae4ee3ec1..f12283cf7 100644 --- a/Load.Dockerfile +++ b/Load.Dockerfile @@ -1,5 +1,5 @@ FROM das-api/builder AS files -FROM rust:1.75-slim-bullseye +FROM rust:1.83-slim-bullseye ARG APP=/usr/src/app RUN apt update \ && apt install -y curl ca-certificates tzdata \ diff --git a/Migrator.Dockerfile b/Migrator.Dockerfile index d275aa7d6..c2c74cd26 100644 --- a/Migrator.Dockerfile +++ b/Migrator.Dockerfile @@ -1,6 +1,6 @@ FROM das-api/builder AS files -FROM rust:1.75-bullseye +FROM rust:1.83-bullseye COPY init.sql /init.sql ENV INIT_FILE_PATH=/init.sql COPY --from=files /das/migration /bins/migration diff --git a/Proxy.Dockerfile b/Proxy.Dockerfile index add959fab..a17de6dcc 100644 --- a/Proxy.Dockerfile +++ b/Proxy.Dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.75-bullseye AS builder +FROM rust:1.83-bullseye AS builder RUN cargo install wasm-pack RUN mkdir /rust diff --git a/blockbuster/src/instruction.rs b/blockbuster/src/instruction.rs index 4345e29ed..6a5a04f54 100644 --- a/blockbuster/src/instruction.rs +++ b/blockbuster/src/instruction.rs @@ -14,7 +14,7 @@ pub struct InstructionBundle<'a> { pub slot: u64, } -impl<'a> Default for InstructionBundle<'a> { +impl Default for InstructionBundle<'_> { fn default() -> Self { InstructionBundle { txn_id: "", diff --git a/blockbuster/src/programs/mod.rs b/blockbuster/src/programs/mod.rs index 8da2feed0..474bce179 100644 --- a/blockbuster/src/programs/mod.rs +++ b/blockbuster/src/programs/mod.rs @@ -2,12 +2,14 @@ use bubblegum::BubblegumInstruction; use mpl_core_program::MplCoreAccountState; use token_account::TokenProgramAccount; use token_extensions::TokenExtensionsProgramAccount; +use token_inscriptions::TokenInscriptionAccount; use token_metadata::TokenMetadataAccountState; pub mod bubblegum; pub mod mpl_core_program; pub mod token_account; pub mod token_extensions; +pub mod token_inscriptions; pub mod token_metadata; // Note: `ProgramParseResult` used to contain the following variants that have been deprecated and @@ -30,5 +32,6 @@ pub enum ProgramParseResult<'a> { TokenMetadata(&'a TokenMetadataAccountState), TokenProgramAccount(&'a TokenProgramAccount), TokenExtensionsProgramAccount(&'a TokenExtensionsProgramAccount), + TokenInscriptionAccount(&'a TokenInscriptionAccount), Unknown, } diff --git a/blockbuster/src/programs/token_extensions/extension.rs b/blockbuster/src/programs/token_extensions/extension.rs index c9a0b9b4a..cd531a23d 100644 --- a/blockbuster/src/programs/token_extensions/extension.rs +++ b/blockbuster/src/programs/token_extensions/extension.rs @@ -13,7 +13,6 @@ use spl_token_2022::extension::{ default_account_state::DefaultAccountState, group_member_pointer::GroupMemberPointer, group_pointer::GroupPointer, - immutable_owner::ImmutableOwner, interest_bearing_mint::{BasisPoints, InterestBearingConfig}, memo_transfer::MemoTransfer, metadata_pointer::MetadataPointer, @@ -77,9 +76,6 @@ pub struct ShadowDefaultAccountState { pub state: PodAccountState, } -#[derive(Clone, Copy, Debug, Default, PartialEq, Zeroable, Serialize, Deserialize)] -pub struct ShadowImmutableOwner; - #[derive(Clone, Copy, Debug, Default, PartialEq, Zeroable, Serialize, Deserialize)] pub struct ShadowInterestBearingConfig { pub rate_authority: OptionalNonZeroPubkey, @@ -97,20 +93,16 @@ pub struct ShadowMemoTransfer { #[derive(Clone, Copy, Debug, Default, PartialEq, Zeroable, Serialize, Deserialize)] pub struct ShadowMetadataPointer { - pub authority: OptionalNonZeroPubkey, pub metadata_address: OptionalNonZeroPubkey, } #[derive(Clone, Copy, Debug, Default, PartialEq, Zeroable, Serialize, Deserialize)] pub struct ShadowGroupMemberPointer { - pub authority: OptionalNonZeroPubkey, pub member_address: OptionalNonZeroPubkey, } #[derive(Clone, Copy, Debug, Default, PartialEq, Zeroable, Serialize, Deserialize)] pub struct ShadowGroupPointer { - /// Authority that can set the group address - pub authority: OptionalNonZeroPubkey, /// Account address that holds the group pub group_address: OptionalNonZeroPubkey, } @@ -233,7 +225,7 @@ impl Serialize for ShadowAeCiphertext { } } -impl<'de> Visitor<'de> for ShadowElGamalCiphertextVisitor { +impl Visitor<'_> for ShadowElGamalCiphertextVisitor { type Value = ShadowElGamalCiphertext; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { @@ -348,12 +340,6 @@ impl From for ShadowDefaultAccountState { } } -impl From for ShadowImmutableOwner { - fn from(_: ImmutableOwner) -> Self { - ShadowImmutableOwner - } -} - impl From for ShadowConfidentialTransferFeeAmount { fn from(original: ConfidentialTransferFeeAmount) -> Self { ShadowConfidentialTransferFeeAmount { @@ -381,7 +367,6 @@ impl From for ShadowMemoTransfer { impl From for ShadowMetadataPointer { fn from(original: MetadataPointer) -> Self { ShadowMetadataPointer { - authority: original.authority, metadata_address: original.metadata_address, } } @@ -390,7 +375,6 @@ impl From for ShadowMetadataPointer { impl From for ShadowGroupPointer { fn from(original: GroupPointer) -> Self { ShadowGroupPointer { - authority: original.authority, group_address: original.group_address, } } @@ -420,7 +404,6 @@ impl From for ShadowTokenGroupMember { impl From for ShadowGroupMemberPointer { fn from(original: GroupMemberPointer) -> Self { ShadowGroupMemberPointer { - authority: original.authority, member_address: original.member_address, } } diff --git a/blockbuster/src/programs/token_extensions/mod.rs b/blockbuster/src/programs/token_extensions/mod.rs index ec1633c9c..6272f96b5 100644 --- a/blockbuster/src/programs/token_extensions/mod.rs +++ b/blockbuster/src/programs/token_extensions/mod.rs @@ -4,6 +4,7 @@ use crate::{ program_handler::{ParseResult, ProgramParser}, programs::ProgramParseResult, }; + use serde::{Deserialize, Serialize}; use solana_sdk::{pubkey::Pubkey, pubkeys}; use spl_token_2022::{ @@ -14,10 +15,12 @@ use spl_token_2022::{ default_account_state::DefaultAccountState, group_member_pointer::GroupMemberPointer, group_pointer::GroupPointer, + immutable_owner::ImmutableOwner, interest_bearing_mint::InterestBearingConfig, memo_transfer::MemoTransfer, metadata_pointer::MetadataPointer, mint_close_authority::MintCloseAuthority, + non_transferable::{NonTransferable, NonTransferableAccount}, permanent_delegate::PermanentDelegate, transfer_fee::{TransferFeeAmount, TransferFeeConfig}, transfer_hook::TransferHook, @@ -41,7 +44,6 @@ use self::extension::{ pub struct MintAccountExtensions { pub default_account_state: Option, pub confidential_transfer_mint: Option, - pub confidential_transfer_account: Option, pub confidential_transfer_fee_config: Option, pub interest_bearing_config: Option, pub transfer_fee_config: Option, @@ -54,6 +56,29 @@ pub struct MintAccountExtensions { pub token_group: Option, pub group_member_pointer: Option, pub token_group_member: Option, + // TODO : add this when spl-token-2022 is updated + // pub scaled_ui_amount: Option, + pub non_transferable: Option, + pub immutable_owner: Option, +} + +impl MintAccountExtensions { + pub fn is_some(&self) -> bool { + self.default_account_state.is_some() + || self.confidential_transfer_mint.is_some() + || self.confidential_transfer_fee_config.is_some() + || self.interest_bearing_config.is_some() + || self.transfer_fee_config.is_some() + || self.mint_close_authority.is_some() + || self.permanent_delegate.is_some() + || self.metadata_pointer.is_some() + || self.metadata.is_some() + || self.transfer_hook.is_some() + || self.group_pointer.is_some() + || self.token_group.is_some() + || self.group_member_pointer.is_some() + || self.token_group_member.is_some() + } } #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] @@ -62,6 +87,17 @@ pub struct TokenAccountExtensions { pub cpi_guard: Option, pub memo_transfer: Option, pub transfer_fee_amount: Option, + pub immutable_owner: Option, + pub non_transferable_account: Option, +} + +impl TokenAccountExtensions { + pub fn is_some(&self) -> bool { + self.confidential_transfer.is_some() + || self.cpi_guard.is_some() + || self.memo_transfer.is_some() + || self.transfer_fee_amount.is_some() + } } #[derive(Debug, PartialEq)] pub struct TokenAccount { @@ -134,6 +170,16 @@ impl ProgramParser for Token2022AccountParser { let cpi_guard = account.get_extension::().ok().copied(); let memo_transfer = account.get_extension::().ok().copied(); let transfer_fee_amount = account.get_extension::().ok().copied(); + let immutable_owner = account + .get_extension::() + .ok() + .copied() + .map(|_| true); + let non_transferable_account = account + .get_extension::() + .ok() + .copied() + .map(|_| true); // Create a structured account with extensions let structured_account = TokenAccount { @@ -144,6 +190,8 @@ impl ProgramParser for Token2022AccountParser { cpi_guard: cpi_guard.map(ShadowCpiGuard::from), memo_transfer: memo_transfer.map(ShadowMemoTransfer::from), transfer_fee_amount: transfer_fee_amount.map(ShadowTransferFeeAmount::from), + immutable_owner, + non_transferable_account, }, }; @@ -153,10 +201,7 @@ impl ProgramParser for Token2022AccountParser { .get_extension::() .ok() .copied(); - let confidential_transfer_account = mint - .get_extension::() - .ok() - .copied(); + let confidential_transfer_fee_config = mint .get_extension::() .ok() @@ -174,14 +219,23 @@ impl ProgramParser for Token2022AccountParser { let group_member_pointer = mint.get_extension::().ok().copied(); let token_group_member = mint.get_extension::().ok().copied(); let transfer_hook = mint.get_extension::().ok().copied(); + let non_transferable = mint + .get_extension::() + .ok() + .copied() + .map(|_| true); + + let immutable_owner = mint + .get_extension::() + .ok() + .copied() + .map(|_| true); let structured_mint = MintAccount { account: mint.base, extensions: MintAccountExtensions { confidential_transfer_mint: confidential_transfer_mint .map(ShadowConfidentialTransferMint::from), - confidential_transfer_account: confidential_transfer_account - .map(ShadowConfidentialTransferAccount::from), confidential_transfer_fee_config: confidential_transfer_fee_config .map(ShadowConfidentialTransferFeeConfig::from), default_account_state: default_account_state @@ -198,6 +252,8 @@ impl ProgramParser for Token2022AccountParser { token_group: token_group.map(ShadowTokenGroup::from), group_member_pointer: group_member_pointer.map(ShadowGroupMemberPointer::from), token_group_member: token_group_member.map(ShadowTokenGroupMember::from), + non_transferable, + immutable_owner, }, }; result = TokenExtensionsProgramAccount::MintAccount(structured_mint); diff --git a/blockbuster/src/programs/token_inscriptions/mod.rs b/blockbuster/src/programs/token_inscriptions/mod.rs new file mode 100644 index 000000000..7e40f5e07 --- /dev/null +++ b/blockbuster/src/programs/token_inscriptions/mod.rs @@ -0,0 +1,141 @@ +use serde::{Deserialize, Serialize}; +use solana_sdk::{pubkey::Pubkey, pubkeys}; + +use crate::{ + error::BlockbusterError, + program_handler::{ParseResult, ProgramParser}, +}; + +use super::ProgramParseResult; + +pubkeys!( + inscription_program_id, + "inscokhJarcjaEs59QbQ7hYjrKz25LEPRfCbP8EmdUp" +); + +pub struct TokenInscriptionParser; + +#[derive(Debug, Serialize, Deserialize)] +pub struct InscriptionData { + pub authority: String, + pub root: String, + pub content: String, + pub encoding: String, + pub inscription_data: String, + pub order: u64, + pub size: u32, + pub validation_hash: Option, +} + +impl InscriptionData { + pub const BASE_SIZE: usize = 121; + pub const INSCRIPTION_ACC_DATA_DISC: [u8; 8] = [232, 120, 205, 47, 153, 239, 229, 224]; + + pub fn try_unpack_data(data: &[u8]) -> Result { + let acc_disc = &data[0..8]; + + if acc_disc != Self::INSCRIPTION_ACC_DATA_DISC { + return Err(BlockbusterError::InvalidAccountType); + } + + if data.len() < Self::BASE_SIZE { + return Err(BlockbusterError::CustomDeserializationError( + "Inscription Data is too short".to_string(), + )); + } + + let authority = Pubkey::try_from(&data[8..40]).unwrap(); + let mint = Pubkey::try_from(&data[40..72]).unwrap(); + let inscription_data = Pubkey::try_from(&data[72..104]).unwrap(); + let order = u64::from_le_bytes(data[104..112].try_into().unwrap()); + let size = u32::from_le_bytes(data[112..116].try_into().unwrap()); + let content_type_len = u32::from_le_bytes(data[116..120].try_into().unwrap()) as usize; + let content = String::from_utf8(data[120..120 + content_type_len].to_vec()).unwrap(); + let encoding_len = u32::from_le_bytes( + data[120 + content_type_len..124 + content_type_len] + .try_into() + .unwrap(), + ) as usize; + + let encoding = String::from_utf8( + data[124 + content_type_len..124 + content_type_len + encoding_len].to_vec(), + ) + .unwrap(); + + let validation_exists = u8::from_le_bytes( + data[124 + content_type_len + encoding_len..124 + content_type_len + encoding_len + 1] + .try_into() + .unwrap(), + ); + + let validation_hash = if validation_exists == 1 { + let validation_hash_len = u32::from_le_bytes( + data[124 + content_type_len + encoding_len + 1 + ..128 + content_type_len + encoding_len + 1] + .try_into() + .unwrap(), + ) as usize; + Some( + String::from_utf8( + data[128 + content_type_len + encoding_len + 1 + ..128 + content_type_len + encoding_len + 1 + validation_hash_len] + .to_vec(), + ) + .unwrap(), + ) + } else { + None + }; + Ok(InscriptionData { + authority: authority.to_string(), + root: mint.to_string(), + content, + encoding, + inscription_data: inscription_data.to_string(), + order, + size, + validation_hash, + }) + } +} + +pub struct TokenInscriptionAccount { + pub data: InscriptionData, +} + +impl ParseResult for TokenInscriptionAccount { + fn result(&self) -> &Self + where + Self: Sized, + { + self + } + fn result_type(&self) -> ProgramParseResult { + ProgramParseResult::TokenInscriptionAccount(self) + } +} + +impl ProgramParser for TokenInscriptionParser { + fn key(&self) -> Pubkey { + inscription_program_id() + } + fn key_match(&self, key: &Pubkey) -> bool { + key == &inscription_program_id() + } + + fn handles_account_updates(&self) -> bool { + true + } + + fn handles_instructions(&self) -> bool { + false + } + + fn handle_account( + &self, + account_data: &[u8], + ) -> Result, BlockbusterError> { + let data = InscriptionData::try_unpack_data(account_data)?; + Ok(Box::new(TokenInscriptionAccount { data })) + } +} diff --git a/core/src/metadata_json.rs b/core/src/metadata_json.rs index 1c87d6825..fd8640ad2 100644 --- a/core/src/metadata_json.rs +++ b/core/src/metadata_json.rs @@ -66,6 +66,7 @@ pub struct MetadataJsonDownloadWorkerArgs { } impl MetadataJsonDownloadWorkerArgs { + #[allow(clippy::result_large_err)] pub fn start( &self, pool: sqlx::PgPool, @@ -103,6 +104,7 @@ impl MetadataJsonDownloadWorkerArgs { } #[derive(thiserror::Error, Debug)] +#[allow(clippy::large_enum_variant)] pub enum MetadataJsonDownloadWorkerError { #[error("send error: {0}")] Send(#[from] SendError), diff --git a/das_api/src/api/api_impl.rs b/das_api/src/api/api_impl.rs index 902303be4..84ca2c550 100644 --- a/das_api/src/api/api_impl.rs +++ b/das_api/src/api/api_impl.rs @@ -1,21 +1,21 @@ use digital_asset_types::{ dao::{ - scopes::asset::get_grouping, + scopes::asset::{get_grouping, get_nft_editions}, sea_orm_active_enums::{ OwnerType, RoyaltyTargetType, SpecificationAssetClass, SpecificationVersions, }, Cursor, PageOptions, SearchAssetsQuery, }, dapi::{ - get_asset, get_asset_proofs, get_asset_signatures, get_assets, get_assets_by_authority, - get_assets_by_creator, get_assets_by_group, get_assets_by_owner, get_proof_for_asset, - search_assets, + common::create_pagination, get_asset, get_asset_proofs, get_asset_signatures, get_assets, + get_assets_by_authority, get_assets_by_creator, get_assets_by_group, get_assets_by_owner, + get_proof_for_asset, get_token_accounts, search_assets, }, rpc::{ filter::{AssetSortBy, SearchConditionType}, - response::GetGroupingResponse, + response::{GetGroupingResponse, TokenAccountList}, + OwnershipModel, RoyaltyModel, }, - rpc::{OwnershipModel, RoyaltyModel}, }; use open_rpc_derive::document_rpc; use sea_orm::{sea_query::ConditionType, ConnectionTrait, DbBackend, Statement}; @@ -23,6 +23,7 @@ use sea_orm::{sea_query::ConditionType, ConnectionTrait, DbBackend, Statement}; use crate::error::DasApiError; use crate::validation::{validate_opt_pubkey, validate_search_with_name}; use open_rpc_schema::document::OpenrpcDocument; +use std::collections::HashSet; use { crate::api::*, crate::config::Config, @@ -148,6 +149,13 @@ pub fn not_found(asset_id: &String) -> DbErr { DbErr::RecordNotFound(format!("Asset Proof for {} Not Found", asset_id)) } +pub fn remove_duplicates_ids(ids: Vec) -> Vec { + let mut hash_set = HashSet::new(); + ids.into_iter() + .filter(|id| hash_set.insert(id.clone())) + .collect() +} + #[document_rpc] #[async_trait] impl ApiContract for DasApi { @@ -218,6 +226,7 @@ impl ApiContract for DasApi { ) -> Result>, DasApiError> { let GetAssets { ids, options } = payload; + let ids = remove_duplicates_ids(ids); let batch_size = ids.len(); if batch_size > 1000 { return Err(DasApiError::BatchSizeExceededError); @@ -284,6 +293,7 @@ impl ApiContract for DasApi { options, cursor, } = payload; + validate_pubkey(group_value.clone())?; let before: Option = before.filter(|before| !before.is_empty()); let after: Option = after.filter(|after| !after.is_empty()); let sort_by = sort_by.unwrap_or_default(); @@ -374,6 +384,7 @@ impl ApiContract for DasApi { negate, condition_type, interface, + token_type, owner_address, owner_type, creator_address, @@ -403,7 +414,7 @@ impl ApiContract for DasApi { // Deserialize search assets query let spec: Option<(SpecificationVersions, SpecificationAssetClass)> = - interface.map(|x| x.into()); + interface.clone().map(|x| x.into()); let specification_version = spec.clone().map(|x| x.0); let specification_asset_class = spec.map(|x| x.1); let condition_type = condition_type.map(|x| match x { @@ -431,8 +442,10 @@ impl ApiContract for DasApi { let saq = SearchAssetsQuery { negate, condition_type, + interface, specification_version, specification_asset_class, + token_type, owner_address, owner_type, creator_address, @@ -501,6 +514,7 @@ impl ApiContract for DasApi { .await .map_err(Into::into) } + async fn get_grouping( self: &DasApi, payload: GetGrouping, @@ -516,4 +530,59 @@ impl ApiContract for DasApi { group_size: gs.size, }) } + + async fn get_nft_editions( + self: &DasApi, + payload: GetNftEditions, + ) -> Result { + let GetNftEditions { + mint_address, + page, + limit, + before, + after, + cursor, + } = payload; + + let page_options = self.validate_pagination(limit, page, &before, &after, &cursor, None)?; + let mint_address = validate_pubkey(mint_address.clone())?; + let pagination = create_pagination(&page_options)?; + get_nft_editions( + &self.db_connection, + mint_address, + &pagination, + page_options.limit, + ) + .await + .map_err(Into::into) + } + + async fn get_token_accounts( + self: &DasApi, + payload: GetTokenAccounts, + ) -> Result { + let GetTokenAccounts { + owner_address, + mint_address, + limit, + page, + before, + after, + options, + cursor, + } = payload; + let owner_address = validate_opt_pubkey(&owner_address)?; + let mint_address = validate_opt_pubkey(&mint_address)?; + let options = options.unwrap_or_default(); + let page_options = self.validate_pagination(limit, page, &before, &after, &cursor, None)?; + get_token_accounts( + &self.db_connection, + owner_address, + mint_address, + &page_options, + &options, + ) + .await + .map_err(Into::into) + } } diff --git a/das_api/src/api/mod.rs b/das_api/src/api/mod.rs index 2e1da73ca..6d1bb299f 100644 --- a/das_api/src/api/mod.rs +++ b/das_api/src/api/mod.rs @@ -1,8 +1,10 @@ use crate::error::DasApiError; use async_trait::async_trait; -use digital_asset_types::rpc::filter::{AssetSortDirection, SearchConditionType}; +use digital_asset_types::rpc::filter::{AssetSortDirection, SearchConditionType, TokenTypeClass}; use digital_asset_types::rpc::options::Options; -use digital_asset_types::rpc::response::{AssetList, TransactionSignatureList}; +use digital_asset_types::rpc::response::{ + AssetList, NftEditions, TokenAccountList, TransactionSignatureList, +}; use digital_asset_types::rpc::{filter::AssetSorting, response::GetGroupingResponse}; use digital_asset_types::rpc::{Asset, AssetProof, Interface, OwnershipModel, RoyaltyModel}; use open_rpc_derive::{document_rpc, rpc}; @@ -94,6 +96,7 @@ pub struct SearchAssets { pub negate: Option, pub condition_type: Option, pub interface: Option, + pub token_type: Option, pub owner_address: Option, pub owner_type: Option, pub creator_address: Option, @@ -147,6 +150,18 @@ pub struct GetGrouping { pub group_value: String, } +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[serde(deny_unknown_fields, rename_all = "camelCase")] +pub struct GetNftEditions { + pub mint_address: String, + pub page: Option, + pub limit: Option, + pub before: Option, + pub after: Option, + #[serde(default)] + pub cursor: Option, +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Default)] #[serde(deny_unknown_fields, rename_all = "camelCase")] pub struct GetAssetSignatures { @@ -163,6 +178,21 @@ pub struct GetAssetSignatures { pub sort_direction: Option, } +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] +#[serde(deny_unknown_fields, rename_all = "camelCase")] +pub struct GetTokenAccounts { + pub owner_address: Option, + pub mint_address: Option, + pub limit: Option, + pub page: Option, + pub before: Option, + pub after: Option, + #[serde(default, alias = "displayOptions")] + pub options: Option, + #[serde(default)] + pub cursor: Option, +} + #[document_rpc] #[async_trait] pub trait ApiContract: Send + Sync + 'static { @@ -251,4 +281,21 @@ pub trait ApiContract: Send + Sync + 'static { summary = "Get a list of assets grouped by a specific authority" )] async fn get_grouping(&self, payload: GetGrouping) -> Result; + + #[rpc( + name = "getTokenAccounts", + params = "named", + summary = "Get a list of token accounts by owner or mint" + )] + async fn get_token_accounts( + &self, + payload: GetTokenAccounts, + ) -> Result; + + #[rpc( + name = "getNftEditions", + params = "named", + summary = "Get all printable editions for a master edition NFT mint" + )] + async fn get_nft_editions(&self, payload: GetNftEditions) -> Result; } diff --git a/das_api/src/builder.rs b/das_api/src/builder.rs index 25edb0aa2..2b81da370 100644 --- a/das_api/src/builder.rs +++ b/das_api/src/builder.rs @@ -118,6 +118,29 @@ impl RpcApiBuilder { Ok(rpc_context.schema()) })?; + module.register_async_method( + "get_token_accounts", + |rpc_params, rpc_context| async move { + let payload = rpc_params.parse::()?; + rpc_context + .get_token_accounts(payload) + .await + .map_err(Into::into) + }, + )?; + + module.register_alias("getTokenAccounts", "get_token_accounts")?; + + module.register_async_method("get_nft_editions", |rpc_params, rpc_context| async move { + let payload = rpc_params.parse::()?; + rpc_context + .get_nft_editions(payload) + .await + .map_err(Into::into) + })?; + + module.register_alias("getNftEditions", "get_nft_editions")?; + Ok(module) } } diff --git a/digital_asset_types/Cargo.toml b/digital_asset_types/Cargo.toml index 449f6e78d..53d7bc0d5 100644 --- a/digital_asset_types/Cargo.toml +++ b/digital_asset_types/Cargo.toml @@ -29,6 +29,7 @@ spl-concurrent-merkle-tree = { workspace = true } thiserror = { workspace = true } tokio = { workspace = true, features = ["macros"] } url = { workspace = true } +mpl-token-metadata = { workspace = true } [features] default = ["json_types", "sql_types"] diff --git a/digital_asset_types/src/dao/extensions/asset.rs b/digital_asset_types/src/dao/extensions/asset.rs index 18525e39e..1d8e7f1d3 100644 --- a/digital_asset_types/src/dao/extensions/asset.rs +++ b/digital_asset_types/src/dao/extensions/asset.rs @@ -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)] @@ -13,6 +14,7 @@ pub enum Relation { AssetAuthority, AssetCreators, AssetGrouping, + TokenAccounts, } impl RelationTrait for Relation { @@ -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() } @@ -62,6 +68,12 @@ impl Related for asset::Entity { } } +impl Related for asset::Entity { + fn to() -> RelationDef { + Relation::TokenAccounts.def() + } +} + impl Default for RoyaltyTargetType { fn default() -> Self { Self::Creators @@ -76,7 +88,7 @@ impl Default for asset::Model { specification_version: None, specification_asset_class: None, owner: None, - owner_type: OwnerType::Single, + owner_type: OwnerType::Unknown, delegate: None, frozen: Default::default(), supply: Default::default(), @@ -103,6 +115,7 @@ impl Default for asset::Model { owner_delegate_seq: None, leaf_seq: None, base_info_seq: None, + mint_extensions: None, mpl_core_plugins: None, mpl_core_unknown_plugins: None, mpl_core_collection_current_size: None, diff --git a/digital_asset_types/src/dao/extensions/asset_grouping.rs b/digital_asset_types/src/dao/extensions/asset_grouping.rs index 49b091efb..d474c63bb 100644 --- a/digital_asset_types/src/dao/extensions/asset_grouping.rs +++ b/digital_asset_types/src/dao/extensions/asset_grouping.rs @@ -1,11 +1,12 @@ use sea_orm::{EntityTrait, EnumIter, Related, RelationDef, RelationTrait}; -use crate::dao::{asset, asset_authority, asset_grouping}; +use crate::dao::{asset, asset_authority, asset_data, asset_grouping}; #[derive(Copy, Clone, Debug, EnumIter)] pub enum Relation { Asset, AssetAuthority, + AssetData, } impl RelationTrait for Relation { @@ -19,6 +20,10 @@ impl RelationTrait for Relation { .from(asset_grouping::Column::AssetId) .to(asset_authority::Column::Id) .into(), + Self::AssetData => asset_grouping::Entity::belongs_to(asset_data::Entity) + .from(asset_grouping::Column::AssetId) + .to(asset_data::Column::Id) + .into(), } } } @@ -34,3 +39,9 @@ impl Related for asset_grouping::Entity { Relation::AssetAuthority.def() } } + +impl Related for asset_grouping::Entity { + fn to() -> RelationDef { + Relation::AssetData.def() + } +} diff --git a/digital_asset_types/src/dao/extensions/mod.rs b/digital_asset_types/src/dao/extensions/mod.rs index bcfc3e130..af3baad66 100644 --- a/digital_asset_types/src/dao/extensions/mod.rs +++ b/digital_asset_types/src/dao/extensions/mod.rs @@ -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; diff --git a/digital_asset_types/src/dao/extensions/token_accounts.rs b/digital_asset_types/src/dao/extensions/token_accounts.rs new file mode 100644 index 000000000..a8c8f60eb --- /dev/null +++ b/digital_asset_types/src/dao/extensions/token_accounts.rs @@ -0,0 +1,26 @@ +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 for token_accounts::Entity { + fn to() -> RelationDef { + Relation::Asset.def() + } +} diff --git a/digital_asset_types/src/dao/full_asset.rs b/digital_asset_types/src/dao/full_asset.rs index fda932d21..05e67b3ae 100644 --- a/digital_asset_types/src/dao/full_asset.rs +++ b/digital_asset_types/src/dao/full_asset.rs @@ -1,12 +1,28 @@ use crate::dao::{asset, asset_authority, asset_creators, asset_data, asset_grouping}; +use super::asset_v1_account_attachments; + +use super::tokens; + +pub struct FullAssetGroup { + pub id: i64, + pub asset_id: Vec, + pub group_key: String, + pub group_value: Option, + pub seq: Option, + pub slot_updated: Option, + pub verified: bool, + pub group_info_seq: Option, +} #[derive(Clone, Debug, PartialEq)] pub struct FullAsset { pub asset: asset::Model, - pub data: asset_data::Model, + pub data: Option, + pub token_info: Option, pub authorities: Vec, pub creators: Vec, - pub groups: Vec, + pub groups: Vec<(asset_grouping::Model, Option)>, + pub inscription: Option, } #[derive(Clone, Debug, PartialEq)] pub struct AssetRelated { diff --git a/digital_asset_types/src/dao/generated/asset.rs b/digital_asset_types/src/dao/generated/asset.rs index f70e0b383..f2f74d6a9 100644 --- a/digital_asset_types/src/dao/generated/asset.rs +++ b/digital_asset_types/src/dao/generated/asset.rs @@ -50,6 +50,7 @@ pub struct Model { pub owner_delegate_seq: Option, pub leaf_seq: Option, pub base_info_seq: Option, + pub mint_extensions: Option, pub mpl_core_plugins: Option, pub mpl_core_unknown_plugins: Option, pub mpl_core_collection_num_minted: Option, @@ -93,6 +94,7 @@ pub enum Column { OwnerDelegateSeq, LeafSeq, BaseInfoSeq, + MintExtensions, MplCorePlugins, MplCoreUnknownPlugins, MplCoreCollectionNumMinted, @@ -153,6 +155,7 @@ impl ColumnTrait for Column { Self::OwnerDelegateSeq => ColumnType::BigInteger.def().null(), Self::LeafSeq => ColumnType::BigInteger.def().null(), Self::BaseInfoSeq => ColumnType::BigInteger.def().null(), + Self::MintExtensions => ColumnType::JsonBinary.def().null(), Self::MplCorePlugins => ColumnType::JsonBinary.def().null(), Self::MplCoreUnknownPlugins => ColumnType::JsonBinary.def().null(), Self::MplCoreCollectionNumMinted => ColumnType::Integer.def().null(), diff --git a/digital_asset_types/src/dao/generated/sea_orm_active_enums.rs b/digital_asset_types/src/dao/generated/sea_orm_active_enums.rs index e4d0e012d..cf7470c6f 100644 --- a/digital_asset_types/src/dao/generated/sea_orm_active_enums.rs +++ b/digital_asset_types/src/dao/generated/sea_orm_active_enums.rs @@ -66,6 +66,8 @@ pub enum V1AccountAttachments { MasterEditionV1, #[sea_orm(string_value = "master_edition_v2")] MasterEditionV2, + #[sea_orm(string_value = "token_inscription")] + TokenInscription, #[sea_orm(string_value = "unknown")] Unknown, } diff --git a/digital_asset_types/src/dao/generated/token_accounts.rs b/digital_asset_types/src/dao/generated/token_accounts.rs index 380e29b42..d758403b8 100644 --- a/digital_asset_types/src/dao/generated/token_accounts.rs +++ b/digital_asset_types/src/dao/generated/token_accounts.rs @@ -24,6 +24,7 @@ pub struct Model { pub delegated_amount: i64, pub slot_updated: i64, pub token_program: Vec, + pub extensions: Option, } #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] @@ -38,6 +39,7 @@ pub enum Column { DelegatedAmount, SlotUpdated, TokenProgram, + Extensions, } #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] @@ -69,6 +71,7 @@ impl ColumnTrait for Column { Self::DelegatedAmount => ColumnType::BigInteger.def(), Self::SlotUpdated => ColumnType::BigInteger.def(), Self::TokenProgram => ColumnType::Binary.def(), + Self::Extensions => ColumnType::Json.def().null(), } } } diff --git a/digital_asset_types/src/dao/generated/tokens.rs b/digital_asset_types/src/dao/generated/tokens.rs index 326b8d968..ed1e5598d 100644 --- a/digital_asset_types/src/dao/generated/tokens.rs +++ b/digital_asset_types/src/dao/generated/tokens.rs @@ -23,6 +23,7 @@ pub struct Model { pub close_authority: Option>, pub extension_data: Option>, pub slot_updated: i64, + pub extensions: Option, } #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] @@ -36,6 +37,7 @@ pub enum Column { CloseAuthority, ExtensionData, SlotUpdated, + Extensions, } #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] @@ -66,6 +68,7 @@ impl ColumnTrait for Column { Self::CloseAuthority => ColumnType::Binary.def().null(), Self::ExtensionData => ColumnType::Binary.def().null(), Self::SlotUpdated => ColumnType::BigInteger.def(), + Self::Extensions => ColumnType::JsonBinary.def().null(), } } } @@ -77,3 +80,13 @@ impl RelationTrait for Relation { } impl ActiveModelBehavior for ActiveModel {} + +pub trait IsNonFungible { + fn is_non_fungible(&self) -> bool; +} + +impl IsNonFungible for Model { + fn is_non_fungible(&self) -> bool { + self.decimals == 0 && self.supply == 1.into() + } +} diff --git a/digital_asset_types/src/dao/mod.rs b/digital_asset_types/src/dao/mod.rs index bf1e540ab..8e6dc4ecb 100644 --- a/digital_asset_types/src/dao/mod.rs +++ b/digital_asset_types/src/dao/mod.rs @@ -2,6 +2,8 @@ mod full_asset; mod generated; pub mod scopes; +use crate::rpc::{filter::TokenTypeClass, Interface}; + use self::sea_orm_active_enums::{ OwnerType, RoyaltyTargetType, SpecificationAssetClass, SpecificationVersions, }; @@ -52,8 +54,10 @@ pub struct SearchAssetsQuery { pub negate: Option, /// Defaults to [ConditionType::All] pub condition_type: Option, + pub interface: Option, pub specification_version: Option, pub specification_asset_class: Option, + pub token_type: Option, pub owner_address: Option>, pub owner_type: Option, pub creator_address: Option>, @@ -75,6 +79,33 @@ pub struct SearchAssetsQuery { } impl SearchAssetsQuery { + pub fn check_for_onwer_type_and_token_type(&self) -> Result<(), DbErr> { + if self.token_type.is_some() && self.owner_type.is_some() { + return Err(DbErr::Custom( + "`owner_type` is not supported when using `token_type` field".to_string(), + )); + } + Ok(()) + } + + pub fn check_for_owner_address_and_token_type(&self) -> Result<(), DbErr> { + if self.owner_address.is_none() && self.token_type.is_some() { + return Err(DbErr::Custom( + "Must provide `owner_address` when using `token_type` field".to_string(), + )); + } + Ok(()) + } + pub fn check_for_token_type_and_interface(&self) -> Result<(), DbErr> { + if self.token_type.is_some() && self.interface.is_some() { + return Err(DbErr::Custom( + "`specification_asset_class` is not supported when using `token_type` field" + .to_string(), + )); + } + Ok(()) + } + pub fn conditions(&self) -> Result<(Condition, Vec), DbErr> { let mut conditions = match self.condition_type { // None --> default to all when no option is provided @@ -88,16 +119,38 @@ impl SearchAssetsQuery { .clone() .map(|x| asset::Column::SpecificationVersion.eq(x)), ) - .add_option( + .add_option({ + self.check_for_owner_address_and_token_type()?; + self.check_for_onwer_type_and_token_type()?; + self.token_type.as_ref().map(|x| match x { + TokenTypeClass::Compressed => asset::Column::TreeId.is_not_null(), + TokenTypeClass::Nft => asset::Column::TreeId.is_null().and( + asset::Column::SpecificationAssetClass + .eq(SpecificationAssetClass::Nft) + .or(asset::Column::SpecificationAssetClass + .eq(SpecificationAssetClass::MplCoreAsset)) + .or(asset::Column::SpecificationAssetClass + .eq(SpecificationAssetClass::ProgrammableNft)), + ), + TokenTypeClass::NonFungible => asset::Column::SpecificationAssetClass + .eq(SpecificationAssetClass::Nft) + .or(asset::Column::SpecificationAssetClass + .eq(SpecificationAssetClass::ProgrammableNft)) + .or(asset::Column::SpecificationAssetClass + .eq(SpecificationAssetClass::MplCoreAsset)), + TokenTypeClass::Fungible => asset::Column::SpecificationAssetClass + .eq(SpecificationAssetClass::FungibleAsset) + .or(asset::Column::SpecificationAssetClass + .eq(SpecificationAssetClass::FungibleToken)), + TokenTypeClass::All => asset::Column::SpecificationAssetClass.is_not_null(), + }) + }) + .add_option({ + self.check_for_token_type_and_interface()?; self.specification_asset_class .clone() - .map(|x| asset::Column::SpecificationAssetClass.eq(x)), - ) - .add_option( - self.owner_address - .to_owned() - .map(|x| asset::Column::Owner.eq(x)), - ) + .map(|x| asset::Column::SpecificationAssetClass.eq(x)) + }) .add_option( self.delegate .to_owned() @@ -145,16 +198,34 @@ impl SearchAssetsQuery { if let Some(o) = self.owner_type.clone() { conditions = conditions.add(asset::Column::OwnerType.eq(o)); } else { - // Default to NFTs - // - // In theory, the owner_type=single check should be sufficient, - // however there is an old bug that has marked some non-NFTs as "single" with supply > 1. - // The supply check guarentees we do not include those. - conditions = conditions.add_option(Some( - asset::Column::OwnerType - .eq(OwnerType::Single) - .and(asset::Column::Supply.lte(1)), - )); + match self.token_type { + Some(TokenTypeClass::Fungible) => { + conditions = conditions.add_option(Some( + asset::Column::OwnerType.eq(OwnerType::Token).and( + (asset::Column::SpecificationAssetClass + .eq(SpecificationAssetClass::FungibleToken)) + .or(asset::Column::SpecificationAssetClass + .eq(SpecificationAssetClass::FungibleAsset)), + ), + )); + } + Some(TokenTypeClass::All) => { + conditions = conditions + .add_option(Some(asset::Column::SpecificationAssetClass.is_not_null())); + } + _ => { + // Default to NFTs + // + // In theory, the owner_type=single check should be sufficient, + // however there is an old bug that has marked some non-NFTs as "single" with supply > 1. + // The supply check guarentees we do not include those. + conditions = conditions.add_option(Some( + asset::Column::OwnerType + .eq(OwnerType::Single) + .and(asset::Column::Supply.lte(1)), + )); + } + } } if let Some(c) = self.creator_address.to_owned() { @@ -194,6 +265,25 @@ impl SearchAssetsQuery { joins.push(rel); } + if let Some(o) = self.owner_address.to_owned() { + if self.token_type == Some(TokenTypeClass::Fungible) + || self.token_type == Some(TokenTypeClass::All) + { + conditions = conditions.add(token_accounts::Column::Owner.eq(o)); + let rel = extensions::token_accounts::Relation::Asset + .def() + .rev() + .on_condition(|left, right| { + Expr::tbl(right, token_accounts::Column::Mint) + .eq(Expr::tbl(left, asset::Column::Id)) + .into_condition() + }); + joins.push(rel); + } else { + conditions = conditions.add(asset::Column::Owner.eq(o)); + } + } + if let Some(g) = self.grouping.to_owned() { let cond = Condition::all() .add(asset_grouping::Column::GroupKey.eq(g.0)) diff --git a/digital_asset_types/src/dao/scopes/asset.rs b/digital_asset_types/src/dao/scopes/asset.rs index 58e4cbbaf..f2113c7f6 100644 --- a/digital_asset_types/src/dao/scopes/asset.rs +++ b/digital_asset_types/src/dao/scopes/asset.rs @@ -1,15 +1,25 @@ use crate::{ dao::{ asset::{self}, - asset_authority, asset_creators, asset_data, asset_grouping, cl_audits_v2, + asset_authority, asset_creators, asset_data, asset_grouping, asset_v1_account_attachments, + cl_audits_v2, extensions::{self, instruction::PascalCase}, - sea_orm_active_enums::Instruction, - Cursor, FullAsset, GroupingSize, Pagination, + sea_orm_active_enums::{Instruction, V1AccountAttachments}, + token_accounts, tokens, Cursor, FullAsset, GroupingSize, Pagination, + }, + rpc::{ + filter::AssetSortDirection, + options::Options, + response::{NftEdition, NftEditions}, }, - rpc::filter::AssetSortDirection, }; use indexmap::IndexMap; +use mpl_token_metadata::accounts::{Edition, MasterEdition}; +use sea_orm::sea_query::Expr; use sea_orm::{entity::*, query::*, ConnectionTrait, DbErr, Order}; +use serde::de::DeserializeOwned; +use serde_json::Value; +use solana_sdk::pubkey::Pubkey; use std::collections::HashMap; pub fn paginate( @@ -60,7 +70,7 @@ pub async fn get_by_creator( sort_direction: Order, pagination: &Pagination, limit: u64, - show_unverified_collections: bool, + options: &Options, ) -> Result, DbErr> { let mut condition = Condition::all() .add(asset_creators::Column::Creator.eq(creator.clone())) @@ -76,7 +86,7 @@ pub async fn get_by_creator( sort_direction, pagination, limit, - show_unverified_collections, + options, Some(creator), ) .await @@ -112,13 +122,13 @@ pub async fn get_by_grouping( sort_direction: Order, pagination: &Pagination, limit: u64, - show_unverified_collections: bool, + options: &Options, ) -> Result, DbErr> { let mut condition = asset_grouping::Column::GroupKey .eq(group_key) .and(asset_grouping::Column::GroupValue.eq(group_value)); - if !show_unverified_collections { + if !options.show_unverified_collections { condition = condition.and( asset_grouping::Column::Verified .eq(true) @@ -136,7 +146,7 @@ pub async fn get_by_grouping( sort_direction, pagination, limit, - show_unverified_collections, + options, None, ) .await @@ -149,11 +159,12 @@ pub async fn get_assets_by_owner( sort_direction: Order, pagination: &Pagination, limit: u64, - show_unverified_collections: bool, + options: &Options, ) -> Result, 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( conn, cond, @@ -162,7 +173,7 @@ pub async fn get_assets_by_owner( sort_direction, pagination, limit, - show_unverified_collections, + options, ) .await } @@ -172,10 +183,12 @@ pub async fn get_assets( asset_ids: Vec>, pagination: &Pagination, limit: u64, + options: &Options, ) -> Result, DbErr> { let cond = Condition::all() .add(asset::Column::Id.is_in(asset_ids)) .add(asset::Column::Supply.gt(0)); + get_assets_by_condition( conn, cond, @@ -185,7 +198,7 @@ pub async fn get_assets( Order::Asc, pagination, limit, - false, + options, ) .await } @@ -197,7 +210,7 @@ pub async fn get_by_authority( sort_direction: Order, pagination: &Pagination, limit: u64, - show_unverified_collections: bool, + options: &Options, ) -> Result, DbErr> { let cond = Condition::all() .add(asset_authority::Column::Authority.eq(authority)) @@ -210,7 +223,7 @@ pub async fn get_by_authority( sort_direction, pagination, limit, - show_unverified_collections, + options, None, ) .await @@ -225,7 +238,7 @@ async fn get_by_related_condition( sort_direction: Order, pagination: &Pagination, limit: u64, - show_unverified_collections: bool, + options: &Options, required_creator: Option>, ) -> Result, DbErr> where @@ -244,19 +257,19 @@ where let assets = paginate(pagination, limit, stmt, sort_direction, asset::Column::Id) .all(conn) .await?; - get_related_for_assets(conn, assets, show_unverified_collections, required_creator).await + get_related_for_assets(conn, assets, options, required_creator).await } pub async fn get_related_for_assets( conn: &impl ConnectionTrait, assets: Vec, - show_unverified_collections: bool, + options: &Options, required_creator: Option>, ) -> Result, DbErr> { let asset_ids = assets.iter().map(|a| a.id.clone()).collect::>(); let asset_data: Vec = asset_data::Entity::find() - .filter(asset_data::Column::Id.is_in(asset_ids)) + .filter(asset_data::Column::Id.is_in(asset_ids.clone())) .all(conn) .await?; let asset_data_map = asset_data.into_iter().fold(HashMap::new(), |mut acc, ad| { @@ -274,10 +287,12 @@ pub async fn get_related_for_assets( let id = asset.id.clone(); let fa = FullAsset { asset, - data: ad.clone(), + data: Some(ad.clone()), authorities: vec![], creators: vec![], groups: vec![], + token_info: None, + inscription: None, }; acc.insert(id, fa); }; @@ -287,7 +302,7 @@ pub async fn get_related_for_assets( // Get all creators for all assets in `assets_map``. let creators = asset_creators::Entity::find() - .filter(asset_creators::Column::AssetId.is_in(ids.clone())) + .filter(asset_creators::Column::AssetId.is_in(ids)) .order_by_asc(asset_creators::Column::AssetId) .order_by_asc(asset_creators::Column::Position) .all(conn) @@ -325,7 +340,15 @@ pub async fn get_related_for_assets( } } - let cond = if show_unverified_collections { + for id in ids.clone() { + if let Ok(t) = get_token_by_id(conn, id.clone()).await { + if let Some(asset) = assets_map.get_mut(&id) { + asset.token_info = Some(t); + } + } + } + + let cond = if options.show_unverified_collections { Condition::all() } else { Condition::any() @@ -335,16 +358,42 @@ pub async fn get_related_for_assets( .add(asset_grouping::Column::Verified.is_null()) }; - let grouping = asset_grouping::Entity::find() + let grouping_base_query = asset_grouping::Entity::find() .filter(asset_grouping::Column::AssetId.is_in(ids.clone())) .filter(asset_grouping::Column::GroupValue.is_not_null()) .filter(cond) - .order_by_asc(asset_grouping::Column::AssetId) - .all(conn) - .await?; - for g in grouping.into_iter() { - if let Some(asset) = assets_map.get_mut(&g.asset_id) { - asset.groups.push(g); + .order_by_asc(asset_grouping::Column::AssetId); + + if options.show_collection_metadata { + let combined_group_query = grouping_base_query + .find_also_related(asset_data::Entity) + .all(conn) + .await?; + + if options.show_inscription { + let attachments = asset_v1_account_attachments::Entity::find() + .filter(asset_v1_account_attachments::Column::AssetId.is_in(asset_ids)) + .all(conn) + .await?; + + for a in attachments.into_iter() { + if let Some(asset) = assets_map.get_mut(&a.id) { + asset.inscription = Some(a); + } + } + } + + for (g, a) in combined_group_query.into_iter() { + if let Some(asset) = assets_map.get_mut(&g.asset_id) { + asset.groups.push((g, a)); + } + } + } else { + let single_group_query = grouping_base_query.all(conn).await?; + for g in single_group_query.into_iter() { + if let Some(asset) = assets_map.get_mut(&g.asset_id) { + asset.groups.push((g, None)); + } } } @@ -360,7 +409,7 @@ pub async fn get_assets_by_condition( sort_direction: Order, pagination: &Pagination, limit: u64, - show_unverified_collections: bool, + options: &Options, ) -> Result, DbErr> { let mut stmt = asset::Entity::find(); for def in joins { @@ -376,8 +425,7 @@ pub async fn get_assets_by_condition( let assets = paginate(pagination, limit, stmt, sort_direction, asset::Column::Id) .all(conn) .await?; - let full_assets = - get_related_for_assets(conn, assets, show_unverified_collections, None).await?; + let full_assets = get_related_for_assets(conn, assets, options, None).await?; Ok(full_assets) } @@ -385,15 +433,29 @@ pub async fn get_by_id( conn: &impl ConnectionTrait, asset_id: Vec, include_no_supply: bool, + options: &Options, ) -> Result { 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 asset_data: (asset::Model, asset_data::Model) = + + let token_info = if options.show_fungible { + get_token_by_id(conn, asset_id.clone()).await.ok() + } else { + None + }; + + let inscription = if options.show_inscription { + get_inscription_by_mint(conn, asset_id.clone()).await.ok() + } else { + None + }; + + let asset_data: (asset::Model, Option) = asset_data.one(conn).await.and_then(|o| match o { - Some((a, Some(d))) => Ok((a, d)), + Some((a, d)) => Ok((a, d)), _ => Err(DbErr::RecordNotFound("Asset Not Found".to_string())), })?; @@ -411,7 +473,7 @@ pub async fn get_by_id( filter_out_stale_creators(&mut creators); - let grouping: Vec = asset_grouping::Entity::find() + let grouping_query = asset_grouping::Entity::find() .filter(asset_grouping::Column::AssetId.eq(asset.id.clone())) .filter(asset_grouping::Column::GroupValue.is_not_null()) .filter( @@ -421,15 +483,30 @@ pub async fn get_by_id( // Therefore if verified is null, we can assume that the group is verified. .add(asset_grouping::Column::Verified.is_null()), ) - .order_by_asc(asset_grouping::Column::AssetId) - .all(conn) - .await?; + .order_by_asc(asset_grouping::Column::AssetId); + + let groups = if options.show_collection_metadata { + grouping_query + .find_also_related(asset_data::Entity) + .all(conn) + .await? + } else { + grouping_query + .all(conn) + .await? + .into_iter() + .map(|g| (g, None)) + .collect::>() + }; + Ok(FullAsset { asset, data, authorities, creators, - groups: grouping, + groups, + token_info, + inscription, }) } @@ -553,3 +630,185 @@ fn filter_out_stale_creators(creators: &mut Vec) { } } } +pub async fn get_token_accounts( + conn: &impl ConnectionTrait, + owner_address: Option>, + mint_address: Option>, + pagination: &Pagination, + limit: u64, + options: &Options, +) -> Result, DbErr> { + let mut condition = Condition::all(); + + if owner_address.is_none() && mint_address.is_none() { + return Err(DbErr::Custom( + "Either 'owner_address' or 'mint_address' must be provided".to_string(), + )); + } + + if options.show_zero_balance { + condition = condition.add(token_accounts::Column::Amount.gte(0)); + } else { + condition = condition.add(token_accounts::Column::Amount.gt(0)); + } + + if let Some(owner) = owner_address { + condition = condition.add(token_accounts::Column::Owner.eq(owner)); + } + if let Some(mint) = mint_address { + condition = condition.add(token_accounts::Column::Mint.eq(mint)); + } + + let token_accounts = paginate( + pagination, + limit, + token_accounts::Entity::find().filter(condition), + Order::Asc, + token_accounts::Column::Pubkey, + ) + .all(conn) + .await?; + + Ok(token_accounts) +} + +pub fn get_edition_data_from_json(data: Value) -> Result { + serde_json::from_value(data).map_err(|e| DbErr::Custom(e.to_string())) +} + +pub fn attachment_to_nft_edition( + attachment: asset_v1_account_attachments::Model, +) -> Result { + let data: Edition = attachment + .data + .clone() + .ok_or(DbErr::RecordNotFound("Edition data not found".to_string())) + .map(get_edition_data_from_json)??; + + Ok(NftEdition { + mint_address: attachment + .asset_id + .clone() + .map(|id| bs58::encode(id).into_string()) + .unwrap_or("".to_string()), + edition_number: data.edition, + edition_address: bs58::encode(attachment.id.clone()).into_string(), + }) +} + +pub async fn get_nft_editions( + conn: &impl ConnectionTrait, + mint_address: Pubkey, + pagination: &Pagination, + limit: u64, +) -> Result { + let master_edition_pubkey = MasterEdition::find_pda(&mint_address).0; + + // to fetch nft editions associated with a mint we need to fetch the master edition first + let master_edition = + asset_v1_account_attachments::Entity::find_by_id(master_edition_pubkey.to_bytes().to_vec()) + .one(conn) + .await? + .ok_or(DbErr::RecordNotFound( + "Master Edition not found".to_string(), + ))?; + + let master_edition_data: MasterEdition = master_edition + .data + .clone() + .ok_or(DbErr::RecordNotFound( + "Master Edition data not found".to_string(), + )) + .map(get_edition_data_from_json)??; + + let mut stmt = asset_v1_account_attachments::Entity::find(); + + stmt = stmt.filter( + asset_v1_account_attachments::Column::AttachmentType + .eq(V1AccountAttachments::Edition) + // The data field is a JSON field that contains the edition data. + .and(asset_v1_account_attachments::Column::Data.is_not_null()) + // The parent field is a string field that contains the master edition pubkey ( mapping edition to master edition ) + .and(Expr::cust(&format!( + "data->>'parent' = '{}'", + master_edition_pubkey + ))), + ); + + let nft_editions = paginate( + pagination, + limit, + stmt, + Order::Asc, + asset_v1_account_attachments::Column::Id, + ) + .all(conn) + .await? + .into_iter() + .map(attachment_to_nft_edition) + .collect::, _>>()?; + + let (page, before, after, cursor) = match pagination { + Pagination::Keyset { before, after } => { + let bef = before.clone().and_then(|x| String::from_utf8(x).ok()); + let aft = after.clone().and_then(|x| String::from_utf8(x).ok()); + (None, bef, aft, None) + } + Pagination::Page { page } => (Some(*page as u32), None, None, None), + Pagination::Cursor(_) => { + if let Some(last_asset) = nft_editions.last() { + let cursor_str = bs58::encode(last_asset.edition_address.clone()).into_string(); + (None, None, None, Some(cursor_str)) + } else { + (None, None, None, None) + } + } + }; + + Ok(NftEditions { + total: nft_editions.len() as u32, + master_edition_address: master_edition_pubkey.to_string(), + supply: master_edition_data.supply, + max_supply: master_edition_data.max_supply, + editions: nft_editions, + limit: limit as u32, + page, + before, + after, + cursor, + }) +} + +pub async fn get_token_by_id( + conn: &impl ConnectionTrait, + id: Vec, +) -> Result { + 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())), + }) +} + +pub async fn get_inscription_by_mint( + conn: &impl ConnectionTrait, + mint: Vec, +) -> Result { + asset_v1_account_attachments::Entity::find() + .filter( + asset_v1_account_attachments::Column::Data + .is_not_null() + .and(Expr::cust(&format!( + "data->>'root' = '{}'", + bs58::encode(mint).into_string() + ))), + ) + .one(conn) + .await + .and_then(|o| match o { + Some(t) => Ok(t), + _ => Err(DbErr::RecordNotFound("Inscription Not Found".to_string())), + }) +} diff --git a/digital_asset_types/src/dapi/assets_by_authority.rs b/digital_asset_types/src/dapi/assets_by_authority.rs index 59404f3e0..b52891062 100644 --- a/digital_asset_types/src/dapi/assets_by_authority.rs +++ b/digital_asset_types/src/dapi/assets_by_authority.rs @@ -24,7 +24,7 @@ pub async fn get_assets_by_authority( sort_direction, &pagination, page_options.limit, - options.show_unverified_collections, + options, ) .await?; Ok(build_asset_response( diff --git a/digital_asset_types/src/dapi/assets_by_creator.rs b/digital_asset_types/src/dapi/assets_by_creator.rs index 9ce5de591..3a2b1e53e 100644 --- a/digital_asset_types/src/dapi/assets_by_creator.rs +++ b/digital_asset_types/src/dapi/assets_by_creator.rs @@ -27,7 +27,7 @@ pub async fn get_assets_by_creator( sort_direction, &pagination, page_options.limit, - options.show_unverified_collections, + options, ) .await?; Ok(build_asset_response( diff --git a/digital_asset_types/src/dapi/assets_by_group.rs b/digital_asset_types/src/dapi/assets_by_group.rs index 68784b9f4..36f4ae534 100644 --- a/digital_asset_types/src/dapi/assets_by_group.rs +++ b/digital_asset_types/src/dapi/assets_by_group.rs @@ -27,7 +27,7 @@ pub async fn get_assets_by_group( sort_direction, &pagination, page_options.limit, - options.show_unverified_collections, + options, ) .await?; Ok(build_asset_response( diff --git a/digital_asset_types/src/dapi/assets_by_owner.rs b/digital_asset_types/src/dapi/assets_by_owner.rs index c3c4da3a5..5f342fe9a 100644 --- a/digital_asset_types/src/dapi/assets_by_owner.rs +++ b/digital_asset_types/src/dapi/assets_by_owner.rs @@ -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( diff --git a/digital_asset_types/src/dapi/change_logs.rs b/digital_asset_types/src/dapi/change_logs.rs index fdd19ddf9..4742696f0 100644 --- a/digital_asset_types/src/dapi/change_logs.rs +++ b/digital_asset_types/src/dapi/change_logs.rs @@ -206,7 +206,7 @@ fn build_asset_proof( let mut final_node_list = vec![SimpleChangeLog::default(); req_indexes.len()]; for node in required_nodes.iter() { if node.level < final_node_list.len().try_into().unwrap() { - final_node_list[node.level as usize] = node.to_owned(); + node.clone_into(&mut final_node_list[node.level as usize]) } } for (i, (n, nin)) in final_node_list diff --git a/digital_asset_types/src/dapi/common/asset.rs b/digital_asset_types/src/dapi/common/asset.rs index c9a9dd486..1ac3c772c 100644 --- a/digital_asset_types/src/dapi/common/asset.rs +++ b/digital_asset_types/src/dapi/common/asset.rs @@ -1,16 +1,21 @@ -use crate::dao::sea_orm_active_enums::SpecificationVersions; +use crate::dao::token_accounts; use crate::dao::FullAsset; use crate::dao::PageOptions; use crate::dao::Pagination; use crate::dao::{asset, asset_authority, asset_creators, asset_data, asset_grouping}; use crate::rpc::filter::{AssetSortBy, AssetSortDirection, AssetSorting}; use crate::rpc::options::Options; +use crate::rpc::response::TokenAccountList; use crate::rpc::response::TransactionSignatureList; -use crate::rpc::response::{AssetError, AssetList}; +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, - MetadataMap, MplCoreInfo, Ownership, Royalty, Scope, Supply, Uses, + MetadataMap, MplCoreInfo, Ownership, Royalty, Scope, Supply, TokenAccount as RpcTokenAccount, + Uses, }; +use blockbuster::programs::token_inscriptions::InscriptionData; use jsonpath_lib::JsonPathError; use log::warn; use mime_guess::Mime; @@ -71,16 +76,27 @@ pub fn build_asset_response( } }; - let (items, errors) = asset_list_to_rpc(assets, options); - AssetList { + let base_asset_list = AssetList { total, limit: limit as u32, page: page.map(|x| x as u32), before, after, + items: vec![], + errors: vec![], + cursor, + }; + + if assets.is_empty() { + return base_asset_list; + } + + let (items, errors) = asset_list_to_rpc(assets, options); + + AssetList { items, errors, - cursor, + ..base_asset_list } } @@ -278,14 +294,8 @@ pub fn v1_content_from_json(asset_data: &asset_data::Model) -> Result Result { - match asset.specification_version { - Some(SpecificationVersions::V1) | Some(SpecificationVersions::V0) => { - v1_content_from_json(data) - } - Some(_) => Err(DbErr::Custom("Version Not Implemented".to_string())), - None => Err(DbErr::Custom("Specification version not found".to_string())), - } +pub fn get_content(data: &asset_data::Model) -> Option { + v1_content_from_json(data).ok() } pub fn to_authority(authority: Vec) -> Vec { @@ -310,34 +320,56 @@ pub fn to_creators(creators: Vec) -> Vec { } pub fn to_grouping( - groups: Vec, + groups: Vec<(asset_grouping::Model, Option)>, options: &Options, ) -> Result, DbErr> { let result: Vec = groups .iter() - .filter_map(|model| { + .filter_map(|(asset_group, asset_data)| { let verified = match options.show_unverified_collections { // Null verified indicates legacy data, meaning it is verified. - true => Some(model.verified), + true => Some(asset_group.verified), false => None, }; // Filter out items where group_value is None. - model.group_value.clone().map(|group_value| Group { - group_key: model.group_key.clone(), - group_value: Some(group_value), - verified, + asset_group.group_value.clone().map(|group_value| { + let collection_metadata = asset_data.as_ref().map(|data| { + let mut metadata_selector_fn = jsonpath_lib::selector(&data.metadata); + let metadata_selector = &mut metadata_selector_fn; + let mut meta: MetadataMap = MetadataMap::new(); + + if let Some(name) = safe_select(metadata_selector, "$.name") { + meta.set_item("name", name.clone()); + } + if let Some(symbol) = safe_select(metadata_selector, "$.symbol") { + meta.set_item("symbol", symbol.clone()); + } + if let Some(image) = safe_select(metadata_selector, "$.image") { + meta.set_item("image", image.clone()); + } + if let Some(external_url) = safe_select(metadata_selector, "$.external_url") { + meta.set_item("external_url", external_url.clone()); + } + + meta + }); + + Group { + group_key: asset_group.group_key.clone(), + group_value: Some(group_value), + verified, + collection_metadata, + } }) }) .collect(); + Ok(result) } pub fn get_interface(asset: &asset::Model) -> Result { Ok(Interface::from(( - asset - .specification_version - .as_ref() - .ok_or(DbErr::Custom("Specification version not found".to_string()))?, + asset.specification_version.as_ref(), asset .specification_asset_class .as_ref() @@ -355,19 +387,39 @@ pub fn asset_to_rpc(asset: FullAsset, options: &Options) -> Result Some(MplCoreInfo { num_minted: asset.mpl_core_collection_num_minted, @@ -377,12 +429,53 @@ pub fn asset_to_rpc(asset: FullAsset, options: &Options) -> Result 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 + }; + + let inscription = if options.show_inscription { + inscription + .and_then(|i| { + i.data.map(|d| -> Result { + let deserialized_data: InscriptionData = + serde_json::from_value(d).map_err(|e| { + DbErr::Custom(format!("Failed to deserialize inscription data: {}", e)) + })?; + Ok(TokenInscriptionInfo { + authority: deserialized_data.authority, + root: deserialized_data.root, + content: deserialized_data.content, + encoding: deserialized_data.encoding, + inscription_data: deserialized_data.inscription_data, + order: deserialized_data.order, + size: deserialized_data.size, + validation_hash: deserialized_data.validation_hash, + }) + }) + }) + .and_then(|i| i.ok()) + } else { + None + }; + Ok(RpcAsset { interface: interface.clone(), id: bs58::encode(asset.id).into_string(), - content: Some(content), + content, authorities: Some(rpc_authorities), - mutable: data.chain_data_mutability.into(), + mutable, compression: Some(Compression { eligible: asset.compressible, compressed: asset.compressed, @@ -415,7 +508,7 @@ pub fn asset_to_rpc(asset: FullAsset, options: &Options) -> Result Result Some(Supply { edition_nonce, @@ -433,17 +526,11 @@ pub fn asset_to_rpc(asset: FullAsset, options: &Options) -> Result None, }, - 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), - }), + uses, burnt: asset.burnt, + token_info, + inscription, + mint_extensions: asset.mint_extensions, plugins: asset.mpl_core_plugins, unknown_plugins: asset.mpl_core_unknown_plugins, mpl_core_info, @@ -455,14 +542,14 @@ pub fn asset_to_rpc(asset: FullAsset, options: &Options) -> Result, options: &Options, -) -> (Vec, Vec) { +) -> (Vec, Vec) { asset_list .into_iter() .fold((vec![], vec![]), |(mut assets, mut errors), asset| { let id = bs58::encode(asset.asset.id.clone()).into_string(); match asset_to_rpc(asset, options) { Ok(rpc_asset) => assets.push(rpc_asset), - Err(e) => errors.push(AssetError { + Err(e) => errors.push(DasError { id, error: e.to_string(), }), @@ -470,3 +557,86 @@ pub fn asset_list_to_rpc( (assets, errors) }) } +pub fn token_account_to_rpc( + token_account: token_accounts::Model, + _options: &Options, +) -> Result { + let address = bs58::encode(token_account.pubkey.clone()).into_string(); + let mint = bs58::encode(token_account.mint.clone()).into_string(); + let owner = bs58::encode(token_account.owner.clone()).into_string(); + let delegate = token_account + .delegate + .map(|d| bs58::encode(d).into_string()); + let close_authority = token_account + .close_authority + .map(|d| bs58::encode(d).into_string()); + + Ok(RpcTokenAccount { + address, + mint, + amount: token_account.amount as u64, + owner, + frozen: token_account.frozen, + delegate, + delegated_amount: token_account.delegated_amount as u64, + close_authority, + extensions: None, + }) +} + +pub fn token_account_list_to_rpc( + token_accounts: Vec, + options: &Options, +) -> (Vec, Vec) { + token_accounts.into_iter().fold( + (vec![], vec![]), + |(mut accounts, mut errors), token_account| { + let id = bs58::encode(token_account.pubkey.clone()).into_string(); + match token_account_to_rpc(token_account, options) { + Ok(rpc_token_account) => accounts.push(rpc_token_account), + Err(e) => errors.push(DasError { + id, + error: e.to_string(), + }), + } + (accounts, errors) + }, + ) +} + +pub fn build_token_list_response( + token_accounts: Vec, + limit: u64, + pagination: &Pagination, + options: &Options, +) -> TokenAccountList { + let total = token_accounts.len() as u32; + let (page, before, after, cursor) = match pagination { + Pagination::Keyset { before, after } => { + let bef = before.clone().and_then(|x| String::from_utf8(x).ok()); + let aft = after.clone().and_then(|x| String::from_utf8(x).ok()); + (None, bef, aft, None) + } + Pagination::Page { page } => (Some(*page as u32), None, None, None), + Pagination::Cursor(_) => { + if let Some(last_token_account) = token_accounts.last() { + let cursor_str = bs58::encode(&last_token_account.pubkey.clone()).into_string(); + (None, None, None, Some(cursor_str)) + } else { + (None, None, None, None) + } + } + }; + + let (items, errors) = token_account_list_to_rpc(token_accounts, options); + TokenAccountList { + total, + limit: limit as u32, + page, + before, + after, + token_accounts: items, + cursor, + errors, + } +} diff --git a/digital_asset_types/src/dapi/get_asset.rs b/digital_asset_types/src/dapi/get_asset.rs index 3740562c3..2ec7d9006 100644 --- a/digital_asset_types/src/dapi/get_asset.rs +++ b/digital_asset_types/src/dapi/get_asset.rs @@ -11,7 +11,7 @@ pub async fn get_asset( id: Vec, options: &Options, ) -> Result { - 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) } @@ -22,7 +22,7 @@ pub async fn get_assets( options: &Options, ) -> Result, DbErr> { let pagination = Pagination::Page { page: 1 }; - let assets = scopes::asset::get_assets(db, ids, &pagination, limit).await?; + let assets = scopes::asset::get_assets(db, ids, &pagination, limit, options).await?; let asset_list = build_asset_response(assets, limit, &pagination, options); let asset_map = asset_list .items diff --git a/digital_asset_types/src/dapi/get_token_accounts.rs b/digital_asset_types/src/dapi/get_token_accounts.rs new file mode 100644 index 000000000..28dcfc503 --- /dev/null +++ b/digital_asset_types/src/dapi/get_token_accounts.rs @@ -0,0 +1,35 @@ +use sea_orm::{DatabaseConnection, DbErr}; + +use crate::{ + dao::PageOptions, + rpc::{options::Options, response::TokenAccountList}, +}; + +use super::common::{build_token_list_response, create_pagination}; + +pub async fn get_token_accounts( + db: &DatabaseConnection, + owner_address: Option>, + mint_address: Option>, + page_options: &PageOptions, + options: &Options, +) -> Result { + let pagination = create_pagination(page_options)?; + + let token_accounts = crate::dao::scopes::asset::get_token_accounts( + db, + owner_address, + mint_address, + &pagination, + page_options.limit, + options, + ) + .await?; + + Ok(build_token_list_response( + token_accounts, + page_options.limit, + &pagination, + options, + )) +} diff --git a/digital_asset_types/src/dapi/mod.rs b/digital_asset_types/src/dapi/mod.rs index e9481169a..488a474bd 100644 --- a/digital_asset_types/src/dapi/mod.rs +++ b/digital_asset_types/src/dapi/mod.rs @@ -5,6 +5,7 @@ mod assets_by_owner; mod change_logs; mod get_asset; mod get_asset_signatures; +mod get_token_accounts; mod search_assets; pub mod common; @@ -16,4 +17,5 @@ pub use assets_by_owner::*; pub use change_logs::*; pub use get_asset::*; pub use get_asset_signatures::*; +pub use get_token_accounts::*; pub use search_assets::*; diff --git a/digital_asset_types/src/dapi/search_assets.rs b/digital_asset_types/src/dapi/search_assets.rs index a7ee65509..85a0f190d 100644 --- a/digital_asset_types/src/dapi/search_assets.rs +++ b/digital_asset_types/src/dapi/search_assets.rs @@ -23,7 +23,7 @@ pub async fn search_assets( sort_direction, &pagination, page_options.limit, - options.show_unverified_collections, + options, ) .await?; Ok(build_asset_response( diff --git a/digital_asset_types/src/rpc/asset.rs b/digital_asset_types/src/rpc/asset.rs index 751ef3841..ba27c4cad 100644 --- a/digital_asset_types/src/rpc/asset.rs +++ b/digital_asset_types/src/rpc/asset.rs @@ -21,22 +21,22 @@ pub struct AssetProof { pub tree_id: String, } -#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, JsonSchema, Default)] pub enum Interface { #[serde(rename = "V1_NFT")] V1NFT, #[serde(rename = "V1_PRINT")] V1PRINT, - #[serde(rename = "LEGACY_NFT")] + #[serde(rename = "V2_NFT")] + Nft, // TODO: change on version bump + #[serde(rename = "LEGACY_NFT")] #[allow(non_camel_case_types)] LEGACY_NFT, - #[serde(rename = "V2_NFT")] - Nft, #[serde(rename = "FungibleAsset")] FungibleAsset, - #[serde(rename = "Custom")] - Custom, + #[serde(rename = "FungibleToken")] + FungibleToken, #[serde(rename = "Identity")] Identity, #[serde(rename = "Executable")] @@ -47,19 +47,28 @@ pub enum Interface { MplCoreAsset, #[serde(rename = "MplCoreCollection")] MplCoreCollection, + #[default] + #[serde(rename = "Custom")] + Custom, } -impl From<(&SpecificationVersions, &SpecificationAssetClass)> for Interface { - fn from(i: (&SpecificationVersions, &SpecificationAssetClass)) -> Self { +impl From<(Option<&SpecificationVersions>, &SpecificationAssetClass)> for Interface { + fn from(i: (Option<&SpecificationVersions>, &SpecificationAssetClass)) -> Self { match i { - (SpecificationVersions::V1, SpecificationAssetClass::Nft) => Interface::V1NFT, - (SpecificationVersions::V1, SpecificationAssetClass::PrintableNft) => Interface::V1NFT, - (SpecificationVersions::V0, SpecificationAssetClass::Nft) => Interface::LEGACY_NFT, - (SpecificationVersions::V1, SpecificationAssetClass::ProgrammableNft) => { + (Some(SpecificationVersions::V1), SpecificationAssetClass::Nft) => Interface::V1NFT, + (Some(SpecificationVersions::V1), SpecificationAssetClass::PrintableNft) => { + Interface::V1NFT + } + (Some(SpecificationVersions::V0), SpecificationAssetClass::Nft) => { + Interface::LEGACY_NFT + } + (Some(SpecificationVersions::V1), SpecificationAssetClass::ProgrammableNft) => { Interface::ProgrammableNFT } (_, SpecificationAssetClass::MplCoreAsset) => Interface::MplCoreAsset, (_, SpecificationAssetClass::MplCoreCollection) => Interface::MplCoreCollection, + (_, SpecificationAssetClass::FungibleAsset) => Interface::FungibleAsset, + (_, SpecificationAssetClass::FungibleToken) => Interface::FungibleToken, _ => Interface::Custom, } } @@ -87,6 +96,10 @@ impl From for (SpecificationVersions, SpecificationAssetClass) { SpecificationVersions::V1, SpecificationAssetClass::MplCoreCollection, ), + Interface::FungibleToken => ( + SpecificationVersions::V1, + SpecificationAssetClass::FungibleToken, + ), _ => (SpecificationVersions::V1, SpecificationAssetClass::Unknown), } } @@ -219,6 +232,8 @@ pub struct Group { pub group_value: Option, #[serde(skip_serializing_if = "Option::is_none")] pub verified: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub collection_metadata: Option, } #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, JsonSchema)] @@ -367,6 +382,30 @@ pub struct MplCoreInfo { } #[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, + #[serde(skip_serializing_if = "Option::is_none")] + pub freeze_authority: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct TokenInscriptionInfo { + pub authority: String, + pub root: String, + pub inscription_data: String, + pub content: String, + pub encoding: String, + pub order: u64, + pub size: u32, + pub validation_hash: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema, Default)] + pub struct Asset { pub interface: Interface, pub id: String, @@ -382,13 +421,21 @@ pub struct Asset { pub royalty: Option, #[serde(skip_serializing_if = "Option::is_none")] pub creators: Option>, - pub ownership: Ownership, + #[serde(skip_serializing_if = "Option::is_none")] + pub ownership: Option, #[serde(skip_serializing_if = "Option::is_none")] pub uses: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub supply: Option, pub mutable: bool, pub burnt: bool, #[serde(skip_serializing_if = "Option::is_none")] + pub token_info: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub inscription: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub mint_extensions: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub plugins: Option, #[serde(skip_serializing_if = "Option::is_none")] pub unknown_plugins: Option, @@ -399,3 +446,16 @@ pub struct Asset { #[serde(skip_serializing_if = "Option::is_none")] pub unknown_external_plugins: Option, } +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default, JsonSchema)] +#[serde(default)] +pub struct TokenAccount { + pub address: String, + pub mint: String, + pub amount: u64, + pub owner: String, + pub frozen: bool, + pub delegate: Option, + pub delegated_amount: u64, + pub close_authority: Option, + pub extensions: Option, +} diff --git a/digital_asset_types/src/rpc/filter.rs b/digital_asset_types/src/rpc/filter.rs index a471f21fb..e90b4a158 100644 --- a/digital_asset_types/src/rpc/filter.rs +++ b/digital_asset_types/src/rpc/filter.rs @@ -1,4 +1,5 @@ use schemars::JsonSchema; +use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)] @@ -31,6 +32,15 @@ pub enum AssetSortBy { None, } +#[derive(Debug, Clone, PartialEq, Eq, EnumIter, Serialize, Deserialize, JsonSchema)] +pub enum TokenTypeClass { + Fungible, + NonFungible, + Compressed, + Nft, + All, +} + #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)] pub enum AssetSortDirection { #[serde(rename = "asc")] diff --git a/digital_asset_types/src/rpc/options.rs b/digital_asset_types/src/rpc/options.rs index a1fafa2c4..9102d015e 100644 --- a/digital_asset_types/src/rpc/options.rs +++ b/digital_asset_types/src/rpc/options.rs @@ -6,4 +6,12 @@ use serde::{Deserialize, Serialize}; pub struct Options { #[serde(default)] pub show_unverified_collections: bool, + #[serde(default)] + pub show_fungible: bool, + #[serde(default)] + pub show_collection_metadata: bool, + #[serde(default)] + pub show_inscription: bool, + #[serde(default)] + pub show_zero_balance: bool, } diff --git a/digital_asset_types/src/rpc/response.rs b/digital_asset_types/src/rpc/response.rs index 53076c8b2..5589eaf99 100644 --- a/digital_asset_types/src/rpc/response.rs +++ b/digital_asset_types/src/rpc/response.rs @@ -1,12 +1,13 @@ use schemars::JsonSchema; + use { - crate::rpc::Asset, + crate::rpc::{Asset, TokenAccount}, serde::{Deserialize, Serialize}, }; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default, JsonSchema)] #[serde(default)] -pub struct AssetError { +pub struct DasError { pub id: String, pub error: String, } @@ -34,7 +35,7 @@ pub struct AssetList { pub cursor: Option, pub items: Vec, #[serde(skip_serializing_if = "Vec::is_empty")] - pub errors: Vec, + pub errors: Vec, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default, JsonSchema)] @@ -50,3 +51,47 @@ pub struct TransactionSignatureList { pub after: Option, pub items: Vec<(String, String)>, } + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default, JsonSchema)] +#[serde(default)] +pub struct TokenAccountList { + pub total: u32, + pub limit: u32, + #[serde(skip_serializing_if = "Option::is_none")] + pub page: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub before: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub after: Option, + pub token_accounts: Vec, + pub cursor: Option, + pub errors: Vec, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default, JsonSchema)] +#[serde(default)] +pub struct NftEdition { + pub mint_address: String, + pub edition_address: String, + pub edition_number: u64, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default, JsonSchema)] +#[serde(default)] +pub struct NftEditions { + pub total: u32, + pub limit: u32, + pub master_edition_address: String, + pub supply: u64, + pub max_supply: Option, + #[serde(skip_serializing_if = "Vec::is_empty")] + pub editions: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub page: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub before: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub after: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub cursor: Option, +} diff --git a/digital_asset_types/tests/common.rs b/digital_asset_types/tests/common.rs index 0dcad71ef..5288b8b5a 100644 --- a/digital_asset_types/tests/common.rs +++ b/digital_asset_types/tests/common.rs @@ -1,4 +1,4 @@ -use blockbuster::token_metadata::types::{Collection, Creator, TokenStandard, Uses}; +use blockbuster::token_metadata::types::{Creator, TokenStandard}; use digital_asset_types::dao::sea_orm_active_enums::{ SpecificationAssetClass, SpecificationVersions, }; @@ -30,10 +30,6 @@ pub struct MockMetadataArgs { pub edition_nonce: Option, /// Since we cannot easily change Metadata, we add the new DataV2 fields here at the end. pub token_standard: Option, - /// Collection - pub collection: Option, - /// Uses - pub uses: Option, pub creators: Vec, } @@ -169,6 +165,7 @@ pub fn create_asset( mpl_core_plugins_json_version: None, mpl_core_external_plugins: None, mpl_core_unknown_external_plugins: None, + mint_extensions: None, }, ) } diff --git a/digital_asset_types/tests/get_asset_by_id.rs b/digital_asset_types/tests/get_asset_by_id.rs index 7af4ecae0..87ca83572 100644 --- a/digital_asset_types/tests/get_asset_by_id.rs +++ b/digital_asset_types/tests/get_asset_by_id.rs @@ -27,8 +27,6 @@ async fn get_asset_by_id() -> Result<(), DbErr> { is_mutable: true, edition_nonce: None, token_standard: Some(TokenStandard::NonFungible), - collection: None, - uses: None, creators: vec![Creator { address: creator_1, share: 100, diff --git a/digital_asset_types/tests/get_assets_by_authority.rs b/digital_asset_types/tests/get_assets_by_authority.rs index 4735b9149..f39caf049 100644 --- a/digital_asset_types/tests/get_assets_by_authority.rs +++ b/digital_asset_types/tests/get_assets_by_authority.rs @@ -37,8 +37,6 @@ async fn get_assets_by_owner() -> Result<(), DbErr> { primary_sale_happened: true, is_mutable: true, edition_nonce: None, - collection: None, - uses: None, token_standard: Some(TokenStandard::NonFungible), creators: vec![Creator { address: creator_1, @@ -90,8 +88,6 @@ async fn get_assets_by_owner() -> Result<(), DbErr> { is_mutable: true, edition_nonce: None, token_standard: Some(TokenStandard::NonFungible), - collection: None, - uses: None, creators: vec![Creator { address: creator_2, share: 100, @@ -142,8 +138,6 @@ async fn get_assets_by_owner() -> Result<(), DbErr> { is_mutable: true, edition_nonce: None, token_standard: Some(TokenStandard::NonFungible), - collection: None, - uses: None, creators: vec![ Creator { address: creator_2, diff --git a/digital_asset_types/tests/get_assets_by_creator.rs b/digital_asset_types/tests/get_assets_by_creator.rs index bbc4c0eea..535c0fc3c 100644 --- a/digital_asset_types/tests/get_assets_by_creator.rs +++ b/digital_asset_types/tests/get_assets_by_creator.rs @@ -41,8 +41,6 @@ async fn get_assets_by_creator() -> Result<(), DbErr> { is_mutable: true, edition_nonce: None, token_standard: Some(TokenStandard::NonFungible), - collection: None, - uses: None, creators: vec![Creator { address: creator_1, share: 100, @@ -93,8 +91,6 @@ async fn get_assets_by_creator() -> Result<(), DbErr> { is_mutable: true, edition_nonce: None, token_standard: Some(TokenStandard::NonFungible), - collection: None, - uses: None, creators: vec![Creator { address: creator_2, share: 100, @@ -145,8 +141,6 @@ async fn get_assets_by_creator() -> Result<(), DbErr> { is_mutable: true, edition_nonce: None, token_standard: Some(TokenStandard::NonFungible), - collection: None, - uses: None, creators: vec![ Creator { address: creator_2, diff --git a/digital_asset_types/tests/get_assets_by_group.rs b/digital_asset_types/tests/get_assets_by_group.rs index 2ff0ec7a8..52fa6d889 100644 --- a/digital_asset_types/tests/get_assets_by_group.rs +++ b/digital_asset_types/tests/get_assets_by_group.rs @@ -43,8 +43,6 @@ async fn get_assets_by_group() -> Result<(), DbErr> { is_mutable: true, edition_nonce: None, token_standard: Some(TokenStandard::NonFungible), - collection: None, - uses: None, creators: vec![Creator { address: creator_1, share: 100, @@ -95,8 +93,6 @@ async fn get_assets_by_group() -> Result<(), DbErr> { is_mutable: true, edition_nonce: None, token_standard: Some(TokenStandard::NonFungible), - collection: None, - uses: None, creators: vec![Creator { address: creator_2, share: 100, @@ -149,8 +145,6 @@ async fn get_assets_by_group() -> Result<(), DbErr> { is_mutable: true, edition_nonce: None, token_standard: Some(TokenStandard::NonFungible), - collection: None, - uses: None, creators: vec![ Creator { address: creator_2, diff --git a/digital_asset_types/tests/get_assets_by_owner.rs b/digital_asset_types/tests/get_assets_by_owner.rs index 4735b9149..f39caf049 100644 --- a/digital_asset_types/tests/get_assets_by_owner.rs +++ b/digital_asset_types/tests/get_assets_by_owner.rs @@ -37,8 +37,6 @@ async fn get_assets_by_owner() -> Result<(), DbErr> { primary_sale_happened: true, is_mutable: true, edition_nonce: None, - collection: None, - uses: None, token_standard: Some(TokenStandard::NonFungible), creators: vec![Creator { address: creator_1, @@ -90,8 +88,6 @@ async fn get_assets_by_owner() -> Result<(), DbErr> { is_mutable: true, edition_nonce: None, token_standard: Some(TokenStandard::NonFungible), - collection: None, - uses: None, creators: vec![Creator { address: creator_2, share: 100, @@ -142,8 +138,6 @@ async fn get_assets_by_owner() -> Result<(), DbErr> { is_mutable: true, edition_nonce: None, token_standard: Some(TokenStandard::NonFungible), - collection: None, - uses: None, creators: vec![ Creator { address: creator_2, diff --git a/grpc-ingest/src/config.rs b/grpc-ingest/src/config.rs index b34ba8fe8..ae8f0eb52 100644 --- a/grpc-ingest/src/config.rs +++ b/grpc-ingest/src/config.rs @@ -111,19 +111,6 @@ impl ConfigIngestStream { } } -#[derive(Debug, Clone, Deserialize, Default)] -#[serde(default)] -pub struct ConfigTopograph { - #[serde(default = "ConfigTopograph::default_num_threads")] - pub num_threads: usize, -} - -impl ConfigTopograph { - pub const fn default_num_threads() -> usize { - 5 - } -} - #[derive(Debug, Clone, Default, Deserialize)] #[serde(default)] pub struct ConfigPrometheus { @@ -293,16 +280,6 @@ impl ConfigPostgres { #[derive(Debug, Clone, Default, Deserialize)] pub struct ConfigIngesterDownloadMetadata { pub stream: ConfigIngestStream, - #[serde( - default = "ConfigIngesterDownloadMetadata::default_num_threads", - deserialize_with = "deserialize_usize_str" - )] - pub num_threads: usize, - #[serde( - default = "ConfigIngesterDownloadMetadata::default_max_attempts", - deserialize_with = "deserialize_usize_str" - )] - pub max_attempts: usize, #[serde( default = "ConfigIngesterDownloadMetadata::default_request_timeout", deserialize_with = "deserialize_duration_str", @@ -314,40 +291,13 @@ pub struct ConfigIngesterDownloadMetadata { deserialize_with = "deserialize_usize_str" )] pub stream_maxlen: usize, - #[serde( - default = "ConfigIngesterDownloadMetadata::default_stream_max_size", - deserialize_with = "deserialize_usize_str" - )] - pub pipeline_max_size: usize, - #[serde( - default = "ConfigIngesterDownloadMetadata::default_pipeline_max_idle", - deserialize_with = "deserialize_duration_str", - rename = "pipeline_max_idle_ms" - )] - pub pipeline_max_idle: Duration, } impl ConfigIngesterDownloadMetadata { - pub const fn default_num_threads() -> usize { - 2 - } - - pub const fn default_pipeline_max_idle() -> Duration { - Duration::from_millis(10) - } - - pub const fn default_stream_max_size() -> usize { - 10 - } - pub const fn default_stream_maxlen() -> usize { 10_000_000 } - pub const fn default_max_attempts() -> usize { - 3 - } - pub const fn default_request_timeout() -> Duration { Duration::from_millis(3_000) } @@ -362,11 +312,6 @@ pub struct ConfigMonitor { #[derive(Debug, Clone, Deserialize)] pub struct ConfigBubblegumVerify { - #[serde( - default = "ConfigBubblegumVerify::default_report_interval", - deserialize_with = "deserialize_duration_str" - )] - pub report_interval: Duration, #[serde(default)] pub only_trees: Option>, #[serde( @@ -377,9 +322,6 @@ pub struct ConfigBubblegumVerify { } impl ConfigBubblegumVerify { - pub const fn default_report_interval() -> Duration { - Duration::from_millis(5 * 60 * 1000) - } pub const fn default_max_concurrency() -> usize { 20 } diff --git a/grpc-ingest/src/redis.rs b/grpc-ingest/src/redis.rs index 9da08f0ab..ea28236b3 100644 --- a/grpc-ingest/src/redis.rs +++ b/grpc-ingest/src/redis.rs @@ -69,8 +69,7 @@ impl RedisStreamMessage for AccountInfo { let SubscribeUpdateAccount { account, slot, .. } = Message::decode(account_data.as_ref())?; - let account = - account.ok_or_else(|| RedisStreamMessageError::InvalidSubscribeUpdateAccount)?; + let account = account.ok_or(RedisStreamMessageError::InvalidSubscribeUpdateAccount)?; Ok(Self { slot, @@ -208,7 +207,7 @@ impl MessageHandler for DownloadMetadataJsonHandle { } impl DownloadMetadataJsonHandle { - pub fn new(download_metadata: Arc) -> Self { + pub const fn new(download_metadata: Arc) -> Self { Self(download_metadata) } } @@ -222,7 +221,7 @@ impl Clone for DownloadMetadataJsonHandle { pub struct AccountHandle(Arc); impl AccountHandle { - pub fn new(program_transformer: Arc) -> Self { + pub const fn new(program_transformer: Arc) -> Self { Self(program_transformer) } } @@ -252,7 +251,7 @@ impl Clone for AccountHandle { pub struct TransactionHandle(Arc); impl TransactionHandle { - pub fn new(program_transformer: Arc) -> Self { + pub const fn new(program_transformer: Arc) -> Self { Self(program_transformer) } } @@ -287,7 +286,7 @@ pub struct Acknowledge { } impl Acknowledge { - pub fn new(config: Arc, connection: MultiplexedConnection) -> Self { + pub const fn new(config: Arc, connection: MultiplexedConnection) -> Self { Self { config, connection } } } diff --git a/integration_tests/tests/data/accounts/fungible_token_get_asset/5x38Kp4hvdomTCnCrAny4UtMUt5rQBdB6px2K1Ui45Wq b/integration_tests/tests/data/accounts/fungible_token_get_asset/5x38Kp4hvdomTCnCrAny4UtMUt5rQBdB6px2K1Ui45Wq new file mode 100644 index 000000000..a6006eeb7 Binary files /dev/null and b/integration_tests/tests/data/accounts/fungible_token_get_asset/5x38Kp4hvdomTCnCrAny4UtMUt5rQBdB6px2K1Ui45Wq differ diff --git a/integration_tests/tests/data/accounts/fungible_token_get_asset/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v b/integration_tests/tests/data/accounts/fungible_token_get_asset/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v new file mode 100644 index 000000000..182b80a9a Binary files /dev/null and b/integration_tests/tests/data/accounts/fungible_token_get_asset/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v differ diff --git a/integration_tests/tests/data/accounts/fungible_token_get_asset_scenario_1/5x38Kp4hvdomTCnCrAny4UtMUt5rQBdB6px2K1Ui45Wq b/integration_tests/tests/data/accounts/fungible_token_get_asset_scenario_1/5x38Kp4hvdomTCnCrAny4UtMUt5rQBdB6px2K1Ui45Wq new file mode 100644 index 000000000..1326753e3 Binary files /dev/null and b/integration_tests/tests/data/accounts/fungible_token_get_asset_scenario_1/5x38Kp4hvdomTCnCrAny4UtMUt5rQBdB6px2K1Ui45Wq differ diff --git a/integration_tests/tests/data/accounts/fungible_token_get_asset_scenario_1/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v b/integration_tests/tests/data/accounts/fungible_token_get_asset_scenario_1/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v new file mode 100644 index 000000000..3ffad1cc0 Binary files /dev/null and b/integration_tests/tests/data/accounts/fungible_token_get_asset_scenario_1/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v differ diff --git a/integration_tests/tests/data/accounts/fungible_token_get_asset_scenario_2/wKocBVvHQoVaiwWoCs9JYSVye4YZRrv5Cucf7fDqnz1 b/integration_tests/tests/data/accounts/fungible_token_get_asset_scenario_2/wKocBVvHQoVaiwWoCs9JYSVye4YZRrv5Cucf7fDqnz1 new file mode 100644 index 000000000..49c0c5373 Binary files /dev/null and b/integration_tests/tests/data/accounts/fungible_token_get_asset_scenario_2/wKocBVvHQoVaiwWoCs9JYSVye4YZRrv5Cucf7fDqnz1 differ diff --git a/integration_tests/tests/data/accounts/get_asset_by_authority_with_show_fungible/7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK b/integration_tests/tests/data/accounts/get_asset_by_authority_with_show_fungible/7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK new file mode 100644 index 000000000..a4776424f Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_by_authority_with_show_fungible/7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK differ diff --git a/integration_tests/tests/data/accounts/get_asset_by_authority_with_show_fungible/8Xv3SpX94HHf32Apg4TeSeS3i2p6wuXeE8FBZr168Hti b/integration_tests/tests/data/accounts/get_asset_by_authority_with_show_fungible/8Xv3SpX94HHf32Apg4TeSeS3i2p6wuXeE8FBZr168Hti new file mode 100644 index 000000000..1470bf74a Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_by_authority_with_show_fungible/8Xv3SpX94HHf32Apg4TeSeS3i2p6wuXeE8FBZr168Hti differ diff --git a/integration_tests/tests/data/accounts/get_asset_by_authority_with_show_fungible/AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM b/integration_tests/tests/data/accounts/get_asset_by_authority_with_show_fungible/AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM new file mode 100644 index 000000000..14163db13 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_by_authority_with_show_fungible/AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM differ diff --git a/integration_tests/tests/data/accounts/get_asset_by_creator_with_show_fungible/7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK b/integration_tests/tests/data/accounts/get_asset_by_creator_with_show_fungible/7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK new file mode 100644 index 000000000..eee1c6f44 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_by_creator_with_show_fungible/7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK differ diff --git a/integration_tests/tests/data/accounts/get_asset_by_creator_with_show_fungible/8Xv3SpX94HHf32Apg4TeSeS3i2p6wuXeE8FBZr168Hti b/integration_tests/tests/data/accounts/get_asset_by_creator_with_show_fungible/8Xv3SpX94HHf32Apg4TeSeS3i2p6wuXeE8FBZr168Hti new file mode 100644 index 000000000..2b0af9ec3 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_by_creator_with_show_fungible/8Xv3SpX94HHf32Apg4TeSeS3i2p6wuXeE8FBZr168Hti differ diff --git a/integration_tests/tests/data/accounts/get_asset_by_creator_with_show_fungible/AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM b/integration_tests/tests/data/accounts/get_asset_by_creator_with_show_fungible/AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM new file mode 100644 index 000000000..200463c35 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_by_creator_with_show_fungible/AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM differ diff --git a/integration_tests/tests/data/accounts/get_asset_by_owner_with_show_fungible/7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK b/integration_tests/tests/data/accounts/get_asset_by_owner_with_show_fungible/7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK new file mode 100644 index 000000000..607ad146f Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_by_owner_with_show_fungible/7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK differ diff --git a/integration_tests/tests/data/accounts/get_asset_by_owner_with_show_fungible/8Xv3SpX94HHf32Apg4TeSeS3i2p6wuXeE8FBZr168Hti b/integration_tests/tests/data/accounts/get_asset_by_owner_with_show_fungible/8Xv3SpX94HHf32Apg4TeSeS3i2p6wuXeE8FBZr168Hti new file mode 100644 index 000000000..fdc448537 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_by_owner_with_show_fungible/8Xv3SpX94HHf32Apg4TeSeS3i2p6wuXeE8FBZr168Hti differ diff --git a/integration_tests/tests/data/accounts/get_asset_by_owner_with_show_fungible/AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM b/integration_tests/tests/data/accounts/get_asset_by_owner_with_show_fungible/AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM new file mode 100644 index 000000000..a0da0ece2 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_by_owner_with_show_fungible/AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM differ diff --git a/integration_tests/tests/data/accounts/get_asset_with_show_collection_metadata_option/7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK b/integration_tests/tests/data/accounts/get_asset_with_show_collection_metadata_option/7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK new file mode 100644 index 000000000..8825aa196 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_with_show_collection_metadata_option/7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK differ diff --git a/integration_tests/tests/data/accounts/get_asset_with_show_collection_metadata_option/8Xv3SpX94HHf32Apg4TeSeS3i2p6wuXeE8FBZr168Hti b/integration_tests/tests/data/accounts/get_asset_with_show_collection_metadata_option/8Xv3SpX94HHf32Apg4TeSeS3i2p6wuXeE8FBZr168Hti new file mode 100644 index 000000000..4ce4fb62c Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_with_show_collection_metadata_option/8Xv3SpX94HHf32Apg4TeSeS3i2p6wuXeE8FBZr168Hti differ diff --git a/integration_tests/tests/data/accounts/get_asset_with_show_collection_metadata_option/AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM b/integration_tests/tests/data/accounts/get_asset_with_show_collection_metadata_option/AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM new file mode 100644 index 000000000..1c60720cb Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_with_show_collection_metadata_option/AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM differ diff --git a/integration_tests/tests/data/accounts/get_asset_with_show_collection_metadata_option/F9Lw3ki3hJ7PF9HQXsBzoY8GyE6sPoEZZdXJBsTTD2rk b/integration_tests/tests/data/accounts/get_asset_with_show_collection_metadata_option/F9Lw3ki3hJ7PF9HQXsBzoY8GyE6sPoEZZdXJBsTTD2rk new file mode 100644 index 000000000..5999bdd44 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_with_show_collection_metadata_option/F9Lw3ki3hJ7PF9HQXsBzoY8GyE6sPoEZZdXJBsTTD2rk differ diff --git a/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_1/7z6b5TE4WX4mgcQjuNBTDxK4SE75sbgEg5WWJwoUeie8 b/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_1/7z6b5TE4WX4mgcQjuNBTDxK4SE75sbgEg5WWJwoUeie8 new file mode 100644 index 000000000..7670328be Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_1/7z6b5TE4WX4mgcQjuNBTDxK4SE75sbgEg5WWJwoUeie8 differ diff --git a/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_1/8myaCN6KcKVkMqroXuLJq6QsqRcPbvme4wV5Ubfr5mDC b/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_1/8myaCN6KcKVkMqroXuLJq6QsqRcPbvme4wV5Ubfr5mDC new file mode 100644 index 000000000..69f99d0d5 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_1/8myaCN6KcKVkMqroXuLJq6QsqRcPbvme4wV5Ubfr5mDC differ diff --git a/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_1/Ca84nWhQu41DMRnjdhRrLZty1i9txepMhAhz5qLLGcBw b/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_1/Ca84nWhQu41DMRnjdhRrLZty1i9txepMhAhz5qLLGcBw new file mode 100644 index 000000000..f273bd7c1 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_1/Ca84nWhQu41DMRnjdhRrLZty1i9txepMhAhz5qLLGcBw differ diff --git a/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_2/7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK b/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_2/7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK new file mode 100644 index 000000000..de4e24d36 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_2/7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK differ diff --git a/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_2/8Xv3SpX94HHf32Apg4TeSeS3i2p6wuXeE8FBZr168Hti b/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_2/8Xv3SpX94HHf32Apg4TeSeS3i2p6wuXeE8FBZr168Hti new file mode 100644 index 000000000..3ffe5ac43 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_2/8Xv3SpX94HHf32Apg4TeSeS3i2p6wuXeE8FBZr168Hti differ diff --git a/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_2/AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM b/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_2/AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM new file mode 100644 index 000000000..4922084e3 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_2/AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM differ diff --git a/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_3/2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo b/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_3/2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo new file mode 100644 index 000000000..b2c948152 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_3/2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo differ diff --git a/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_4/8yn5oqFMwYA8SgGqWwKq1Hia8aM5gh1DWmHEL34hMqBX b/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_4/8yn5oqFMwYA8SgGqWwKq1Hia8aM5gh1DWmHEL34hMqBX new file mode 100644 index 000000000..4e6e98e0e Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_4/8yn5oqFMwYA8SgGqWwKq1Hia8aM5gh1DWmHEL34hMqBX differ diff --git a/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_4/J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn b/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_4/J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn new file mode 100644 index 000000000..a57203317 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_with_show_fungible_scenario_4/J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn differ diff --git a/integration_tests/tests/data/accounts/get_asset_with_show_inscription_scenario_1/4Q18N6XrfJHgDbRTaHJR328jN9dixCLQAQhDsTsRzg3v b/integration_tests/tests/data/accounts/get_asset_with_show_inscription_scenario_1/4Q18N6XrfJHgDbRTaHJR328jN9dixCLQAQhDsTsRzg3v new file mode 100644 index 000000000..7443f1f46 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_with_show_inscription_scenario_1/4Q18N6XrfJHgDbRTaHJR328jN9dixCLQAQhDsTsRzg3v differ diff --git a/integration_tests/tests/data/accounts/get_asset_with_show_inscription_scenario_1/9FkS3kZV4MoGps14tUSp7iVnizGbxcK4bDEhSoF5oYAZ b/integration_tests/tests/data/accounts/get_asset_with_show_inscription_scenario_1/9FkS3kZV4MoGps14tUSp7iVnizGbxcK4bDEhSoF5oYAZ new file mode 100644 index 000000000..1478546cd Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_with_show_inscription_scenario_1/9FkS3kZV4MoGps14tUSp7iVnizGbxcK4bDEhSoF5oYAZ differ diff --git a/integration_tests/tests/data/accounts/get_asset_with_show_inscription_scenario_1/AKo9P7S8FE9NYeAcrtZEpimwQAXJMp8Lrt8p4dMkHkY2 b/integration_tests/tests/data/accounts/get_asset_with_show_inscription_scenario_1/AKo9P7S8FE9NYeAcrtZEpimwQAXJMp8Lrt8p4dMkHkY2 new file mode 100644 index 000000000..b6b5149df Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_with_show_inscription_scenario_1/AKo9P7S8FE9NYeAcrtZEpimwQAXJMp8Lrt8p4dMkHkY2 differ diff --git a/integration_tests/tests/data/accounts/get_asset_with_show_inscription_scenario_1/DarH4z6SmdVzPrt8krAygpLodhdjvNAstP3taj2tysN2 b/integration_tests/tests/data/accounts/get_asset_with_show_inscription_scenario_1/DarH4z6SmdVzPrt8krAygpLodhdjvNAstP3taj2tysN2 new file mode 100644 index 000000000..cc574d2ce Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_with_show_inscription_scenario_1/DarH4z6SmdVzPrt8krAygpLodhdjvNAstP3taj2tysN2 differ diff --git a/integration_tests/tests/data/accounts/get_asset_with_show_inscription_scenario_1/HMixBLSkuhiGgVbcGhqJar476xzu1bC8wM7yHsc1iXwP b/integration_tests/tests/data/accounts/get_asset_with_show_inscription_scenario_1/HMixBLSkuhiGgVbcGhqJar476xzu1bC8wM7yHsc1iXwP new file mode 100644 index 000000000..ee9399855 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_asset_with_show_inscription_scenario_1/HMixBLSkuhiGgVbcGhqJar476xzu1bC8wM7yHsc1iXwP differ diff --git a/integration_tests/tests/data/accounts/get_assets_with_multiple_same_ids/2ecGsTKbj7FecLwxTHaodZRFwza7m7LamqDG4YjczZMj b/integration_tests/tests/data/accounts/get_assets_with_multiple_same_ids/2ecGsTKbj7FecLwxTHaodZRFwza7m7LamqDG4YjczZMj new file mode 100644 index 000000000..1ae41d2d6 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_assets_with_multiple_same_ids/2ecGsTKbj7FecLwxTHaodZRFwza7m7LamqDG4YjczZMj differ diff --git a/integration_tests/tests/data/accounts/get_assets_with_multiple_same_ids/DZAZ3mGuq7nCYGzUyw4MiA74ysr15EfqLpzCzX2cRVng b/integration_tests/tests/data/accounts/get_assets_with_multiple_same_ids/DZAZ3mGuq7nCYGzUyw4MiA74ysr15EfqLpzCzX2cRVng new file mode 100644 index 000000000..3e817c9dc Binary files /dev/null and b/integration_tests/tests/data/accounts/get_assets_with_multiple_same_ids/DZAZ3mGuq7nCYGzUyw4MiA74ysr15EfqLpzCzX2cRVng differ diff --git a/integration_tests/tests/data/accounts/get_assets_with_multiple_same_ids/F9Lw3ki3hJ7PF9HQXsBzoY8GyE6sPoEZZdXJBsTTD2rk b/integration_tests/tests/data/accounts/get_assets_with_multiple_same_ids/F9Lw3ki3hJ7PF9HQXsBzoY8GyE6sPoEZZdXJBsTTD2rk new file mode 100644 index 000000000..4908e565b Binary files /dev/null and b/integration_tests/tests/data/accounts/get_assets_with_multiple_same_ids/F9Lw3ki3hJ7PF9HQXsBzoY8GyE6sPoEZZdXJBsTTD2rk differ diff --git a/integration_tests/tests/data/accounts/get_assets_with_multiple_same_ids/JEKKtnGvjiZ8GtATnMVgadHU41AuTbFkMW8oD2tdyV9X b/integration_tests/tests/data/accounts/get_assets_with_multiple_same_ids/JEKKtnGvjiZ8GtATnMVgadHU41AuTbFkMW8oD2tdyV9X new file mode 100644 index 000000000..eee1c3953 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_assets_with_multiple_same_ids/JEKKtnGvjiZ8GtATnMVgadHU41AuTbFkMW8oD2tdyV9X differ diff --git a/integration_tests/tests/data/accounts/get_nft_editions/4V9QuYLpiMu4ZQmhdEHmgATdgiHkDeJfvZi84BfkYcez b/integration_tests/tests/data/accounts/get_nft_editions/4V9QuYLpiMu4ZQmhdEHmgATdgiHkDeJfvZi84BfkYcez new file mode 100644 index 000000000..558488282 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_nft_editions/4V9QuYLpiMu4ZQmhdEHmgATdgiHkDeJfvZi84BfkYcez differ diff --git a/integration_tests/tests/data/accounts/get_nft_editions/8SHfqzJYABeGfiG1apwiEYt6TvfGQiL1pdwEjvTKsyiZ b/integration_tests/tests/data/accounts/get_nft_editions/8SHfqzJYABeGfiG1apwiEYt6TvfGQiL1pdwEjvTKsyiZ new file mode 100644 index 000000000..10eae717a Binary files /dev/null and b/integration_tests/tests/data/accounts/get_nft_editions/8SHfqzJYABeGfiG1apwiEYt6TvfGQiL1pdwEjvTKsyiZ differ diff --git a/integration_tests/tests/data/accounts/get_nft_editions/9ZmY7qCaq7WbrR7RZdHWCNS9FrFRPwRqU84wzWfmqLDz b/integration_tests/tests/data/accounts/get_nft_editions/9ZmY7qCaq7WbrR7RZdHWCNS9FrFRPwRqU84wzWfmqLDz new file mode 100644 index 000000000..c8244da85 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_nft_editions/9ZmY7qCaq7WbrR7RZdHWCNS9FrFRPwRqU84wzWfmqLDz differ diff --git a/integration_tests/tests/data/accounts/get_nft_editions/9yQecKKYSHxez7fFjJkUvkz42TLmkoXzhyZxEf2pw8pz b/integration_tests/tests/data/accounts/get_nft_editions/9yQecKKYSHxez7fFjJkUvkz42TLmkoXzhyZxEf2pw8pz new file mode 100644 index 000000000..75d190842 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_nft_editions/9yQecKKYSHxez7fFjJkUvkz42TLmkoXzhyZxEf2pw8pz differ diff --git a/integration_tests/tests/data/accounts/get_nft_editions/AoxgzXKEsJmUyF5pBb3djn9cJFA26zh2SQHvd9EYijZV b/integration_tests/tests/data/accounts/get_nft_editions/AoxgzXKEsJmUyF5pBb3djn9cJFA26zh2SQHvd9EYijZV new file mode 100644 index 000000000..31abb9fb6 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_nft_editions/AoxgzXKEsJmUyF5pBb3djn9cJFA26zh2SQHvd9EYijZV differ diff --git a/integration_tests/tests/data/accounts/get_nft_editions/Ey2Qb8kLctbchQsMnhZs5DjY32To2QtPuXNwWvk4NosL b/integration_tests/tests/data/accounts/get_nft_editions/Ey2Qb8kLctbchQsMnhZs5DjY32To2QtPuXNwWvk4NosL new file mode 100644 index 000000000..cf8f217c8 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_nft_editions/Ey2Qb8kLctbchQsMnhZs5DjY32To2QtPuXNwWvk4NosL differ diff --git a/integration_tests/tests/data/accounts/get_nft_editions/GJvFDcBWf6aDncd1TBzx2ou1rgLFYaMBdbYLBa9oTAEw b/integration_tests/tests/data/accounts/get_nft_editions/GJvFDcBWf6aDncd1TBzx2ou1rgLFYaMBdbYLBa9oTAEw new file mode 100644 index 000000000..80ea336fb Binary files /dev/null and b/integration_tests/tests/data/accounts/get_nft_editions/GJvFDcBWf6aDncd1TBzx2ou1rgLFYaMBdbYLBa9oTAEw differ diff --git a/integration_tests/tests/data/accounts/get_nft_editions/giWoA4jqHFkodPJgtbRYRcYtiXbsVytnxnEao3QT2gg b/integration_tests/tests/data/accounts/get_nft_editions/giWoA4jqHFkodPJgtbRYRcYtiXbsVytnxnEao3QT2gg new file mode 100644 index 000000000..a63f177f0 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_nft_editions/giWoA4jqHFkodPJgtbRYRcYtiXbsVytnxnEao3QT2gg differ diff --git a/integration_tests/tests/data/accounts/get_token_accounts/jKLTJu7nE1zLmC2J2xjVVBm4G7vJcKGCGQX36Jrsba2 b/integration_tests/tests/data/accounts/get_token_accounts/jKLTJu7nE1zLmC2J2xjVVBm4G7vJcKGCGQX36Jrsba2 new file mode 100644 index 000000000..b4c5bef73 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_token_accounts/jKLTJu7nE1zLmC2J2xjVVBm4G7vJcKGCGQX36Jrsba2 differ diff --git a/integration_tests/tests/data/accounts/get_token_accounts_by_mint/jKLTJu7nE1zLmC2J2xjVVBm4G7vJcKGCGQX36Jrsba2 b/integration_tests/tests/data/accounts/get_token_accounts_by_mint/jKLTJu7nE1zLmC2J2xjVVBm4G7vJcKGCGQX36Jrsba2 new file mode 100644 index 000000000..71c23c91d Binary files /dev/null and b/integration_tests/tests/data/accounts/get_token_accounts_by_mint/jKLTJu7nE1zLmC2J2xjVVBm4G7vJcKGCGQX36Jrsba2 differ diff --git a/integration_tests/tests/data/accounts/get_token_accounts_by_owner/3Pv9H5UzU8T9BwgutXrcn2wLohS1JUZuk3x8paiRyzui b/integration_tests/tests/data/accounts/get_token_accounts_by_owner/3Pv9H5UzU8T9BwgutXrcn2wLohS1JUZuk3x8paiRyzui new file mode 100644 index 000000000..20e262776 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_token_accounts_by_owner/3Pv9H5UzU8T9BwgutXrcn2wLohS1JUZuk3x8paiRyzui differ diff --git a/integration_tests/tests/data/accounts/get_token_accounts_by_owner/jKLTJu7nE1zLmC2J2xjVVBm4G7vJcKGCGQX36Jrsba2 b/integration_tests/tests/data/accounts/get_token_accounts_by_owner/jKLTJu7nE1zLmC2J2xjVVBm4G7vJcKGCGQX36Jrsba2 new file mode 100644 index 000000000..868b38969 Binary files /dev/null and b/integration_tests/tests/data/accounts/get_token_accounts_by_owner/jKLTJu7nE1zLmC2J2xjVVBm4G7vJcKGCGQX36Jrsba2 differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_all/42AYryUGNmJMe9ycBXZekkYvdTehgbtECHs7SLu5JJTB b/integration_tests/tests/data/accounts/search_asset_with_token_type_all/42AYryUGNmJMe9ycBXZekkYvdTehgbtECHs7SLu5JJTB new file mode 100644 index 000000000..17af7f79e Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_all/42AYryUGNmJMe9ycBXZekkYvdTehgbtECHs7SLu5JJTB differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_all/7oSzJpyztTuK124EyPAw2nbF4Vaj2P9MU9vww1QN1k8p b/integration_tests/tests/data/accounts/search_asset_with_token_type_all/7oSzJpyztTuK124EyPAw2nbF4Vaj2P9MU9vww1QN1k8p new file mode 100644 index 000000000..118ca2a0c Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_all/7oSzJpyztTuK124EyPAw2nbF4Vaj2P9MU9vww1QN1k8p differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_all/7sVGLDmpnYqX5EvTg7i3tpRNEugeaUyDC9HtPSb3V3DS b/integration_tests/tests/data/accounts/search_asset_with_token_type_all/7sVGLDmpnYqX5EvTg7i3tpRNEugeaUyDC9HtPSb3V3DS new file mode 100644 index 000000000..05f08bf57 Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_all/7sVGLDmpnYqX5EvTg7i3tpRNEugeaUyDC9HtPSb3V3DS differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_all/8t77ShMViat27Sjphvi1FVPaGrhFcttPAkEnLCFp49Bo b/integration_tests/tests/data/accounts/search_asset_with_token_type_all/8t77ShMViat27Sjphvi1FVPaGrhFcttPAkEnLCFp49Bo new file mode 100644 index 000000000..36feef591 Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_all/8t77ShMViat27Sjphvi1FVPaGrhFcttPAkEnLCFp49Bo differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_all/DVHQquD7pQFUsBoPpW816CU8zQrQCua9mw4Znh9FyKZJ b/integration_tests/tests/data/accounts/search_asset_with_token_type_all/DVHQquD7pQFUsBoPpW816CU8zQrQCua9mw4Znh9FyKZJ new file mode 100644 index 000000000..450366f15 Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_all/DVHQquD7pQFUsBoPpW816CU8zQrQCua9mw4Znh9FyKZJ differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_all/HboN9TsoMSKJAp388G752pSUscb8iZwgdH459KSJxbZT b/integration_tests/tests/data/accounts/search_asset_with_token_type_all/HboN9TsoMSKJAp388G752pSUscb8iZwgdH459KSJxbZT new file mode 100644 index 000000000..db36302a3 Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_all/HboN9TsoMSKJAp388G752pSUscb8iZwgdH459KSJxbZT differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_fungible/6BRNfDfdq1nKyU1TQiCEQLWyPtD8EwUH9Kt2ahsbidUx b/integration_tests/tests/data/accounts/search_asset_with_token_type_fungible/6BRNfDfdq1nKyU1TQiCEQLWyPtD8EwUH9Kt2ahsbidUx new file mode 100644 index 000000000..5ae2375a0 Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_fungible/6BRNfDfdq1nKyU1TQiCEQLWyPtD8EwUH9Kt2ahsbidUx differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_fungible/7BajpcYgnxmWK91RhrfsdB3Tm83PcDwPvMC8ZinvtTY6 b/integration_tests/tests/data/accounts/search_asset_with_token_type_fungible/7BajpcYgnxmWK91RhrfsdB3Tm83PcDwPvMC8ZinvtTY6 new file mode 100644 index 000000000..2d30ad308 Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_fungible/7BajpcYgnxmWK91RhrfsdB3Tm83PcDwPvMC8ZinvtTY6 differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_fungible/7EYnhQoR9YM3N7UoaKRoA44Uy8JeaZV3qyouov87awMs b/integration_tests/tests/data/accounts/search_asset_with_token_type_fungible/7EYnhQoR9YM3N7UoaKRoA44Uy8JeaZV3qyouov87awMs new file mode 100644 index 000000000..48f5f5651 Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_fungible/7EYnhQoR9YM3N7UoaKRoA44Uy8JeaZV3qyouov87awMs differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_non_fungible/47ackukZJRBkQSufwFnhTkmTzB11Ww8375EDXTwY75wk b/integration_tests/tests/data/accounts/search_asset_with_token_type_non_fungible/47ackukZJRBkQSufwFnhTkmTzB11Ww8375EDXTwY75wk new file mode 100644 index 000000000..d13dae66e Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_non_fungible/47ackukZJRBkQSufwFnhTkmTzB11Ww8375EDXTwY75wk differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_non_fungible/8t77ShMViat27Sjphvi1FVPaGrhFcttPAkEnLCFp49Bo b/integration_tests/tests/data/accounts/search_asset_with_token_type_non_fungible/8t77ShMViat27Sjphvi1FVPaGrhFcttPAkEnLCFp49Bo new file mode 100644 index 000000000..eac706841 Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_non_fungible/8t77ShMViat27Sjphvi1FVPaGrhFcttPAkEnLCFp49Bo differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_non_fungible/AH6VcoSbCGGv8BHeN7K766VUWMcdFRTaXpLvGTLSdAmk b/integration_tests/tests/data/accounts/search_asset_with_token_type_non_fungible/AH6VcoSbCGGv8BHeN7K766VUWMcdFRTaXpLvGTLSdAmk new file mode 100644 index 000000000..47c32c19e Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_non_fungible/AH6VcoSbCGGv8BHeN7K766VUWMcdFRTaXpLvGTLSdAmk differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_non_fungible/DVHQquD7pQFUsBoPpW816CU8zQrQCua9mw4Znh9FyKZJ b/integration_tests/tests/data/accounts/search_asset_with_token_type_non_fungible/DVHQquD7pQFUsBoPpW816CU8zQrQCua9mw4Znh9FyKZJ new file mode 100644 index 000000000..8268e82ec Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_non_fungible/DVHQquD7pQFUsBoPpW816CU8zQrQCua9mw4Znh9FyKZJ differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_non_fungible/ELNshcVjEgQ6nSsogWEQjRTr9EaEHJzKcSenqe2kyx5J b/integration_tests/tests/data/accounts/search_asset_with_token_type_non_fungible/ELNshcVjEgQ6nSsogWEQjRTr9EaEHJzKcSenqe2kyx5J new file mode 100644 index 000000000..6d8ed5e48 Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_non_fungible/ELNshcVjEgQ6nSsogWEQjRTr9EaEHJzKcSenqe2kyx5J differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_non_fungible/HboN9TsoMSKJAp388G752pSUscb8iZwgdH459KSJxbZT b/integration_tests/tests/data/accounts/search_asset_with_token_type_non_fungible/HboN9TsoMSKJAp388G752pSUscb8iZwgdH459KSJxbZT new file mode 100644 index 000000000..f930ec392 Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_non_fungible/HboN9TsoMSKJAp388G752pSUscb8iZwgdH459KSJxbZT differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_regular_nft/2w81QrLYTwSDkNwXgCqKAwrC1Tu6R9mh9BHcxys2Bup2 b/integration_tests/tests/data/accounts/search_asset_with_token_type_regular_nft/2w81QrLYTwSDkNwXgCqKAwrC1Tu6R9mh9BHcxys2Bup2 new file mode 100644 index 000000000..a7efd35f9 Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_regular_nft/2w81QrLYTwSDkNwXgCqKAwrC1Tu6R9mh9BHcxys2Bup2 differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_regular_nft/42AYryUGNmJMe9ycBXZekkYvdTehgbtECHs7SLu5JJTB b/integration_tests/tests/data/accounts/search_asset_with_token_type_regular_nft/42AYryUGNmJMe9ycBXZekkYvdTehgbtECHs7SLu5JJTB new file mode 100644 index 000000000..9c7db2557 Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_regular_nft/42AYryUGNmJMe9ycBXZekkYvdTehgbtECHs7SLu5JJTB differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_regular_nft/7oSzJpyztTuK124EyPAw2nbF4Vaj2P9MU9vww1QN1k8p b/integration_tests/tests/data/accounts/search_asset_with_token_type_regular_nft/7oSzJpyztTuK124EyPAw2nbF4Vaj2P9MU9vww1QN1k8p new file mode 100644 index 000000000..22ba70ff4 Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_regular_nft/7oSzJpyztTuK124EyPAw2nbF4Vaj2P9MU9vww1QN1k8p differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_regular_nft/7sVGLDmpnYqX5EvTg7i3tpRNEugeaUyDC9HtPSb3V3DS b/integration_tests/tests/data/accounts/search_asset_with_token_type_regular_nft/7sVGLDmpnYqX5EvTg7i3tpRNEugeaUyDC9HtPSb3V3DS new file mode 100644 index 000000000..dc785fa4b Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_regular_nft/7sVGLDmpnYqX5EvTg7i3tpRNEugeaUyDC9HtPSb3V3DS differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_regular_nft/CyyZ43boZTaP4mJsbTVUpinFJGMQXSMstJvDeatpEo4S b/integration_tests/tests/data/accounts/search_asset_with_token_type_regular_nft/CyyZ43boZTaP4mJsbTVUpinFJGMQXSMstJvDeatpEo4S new file mode 100644 index 000000000..a75763c95 Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_regular_nft/CyyZ43boZTaP4mJsbTVUpinFJGMQXSMstJvDeatpEo4S differ diff --git a/integration_tests/tests/data/accounts/search_asset_with_token_type_regular_nft/iRjBSW4tnw42qxf3tycTYKki1d4bcETt9AfjEwoHYgy b/integration_tests/tests/data/accounts/search_asset_with_token_type_regular_nft/iRjBSW4tnw42qxf3tycTYKki1d4bcETt9AfjEwoHYgy new file mode 100644 index 000000000..dc89d878f Binary files /dev/null and b/integration_tests/tests/data/accounts/search_asset_with_token_type_regular_nft/iRjBSW4tnw42qxf3tycTYKki1d4bcETt9AfjEwoHYgy differ diff --git a/integration_tests/tests/data/accounts/show_zero_balance_filter/BE1CkzRjLTXAWcSVCaqzycwXsZ18Yuk3jMDMnPUoHjjS b/integration_tests/tests/data/accounts/show_zero_balance_filter/BE1CkzRjLTXAWcSVCaqzycwXsZ18Yuk3jMDMnPUoHjjS new file mode 100644 index 000000000..e6349a5bf Binary files /dev/null and b/integration_tests/tests/data/accounts/show_zero_balance_filter/BE1CkzRjLTXAWcSVCaqzycwXsZ18Yuk3jMDMnPUoHjjS differ diff --git a/integration_tests/tests/data/accounts/show_zero_balance_filter/CyqarC6hyNYvb3EDueyeYrnGeAUjCDtMvWrbtdAnA53a b/integration_tests/tests/data/accounts/show_zero_balance_filter/CyqarC6hyNYvb3EDueyeYrnGeAUjCDtMvWrbtdAnA53a new file mode 100644 index 000000000..53ce3c8dd Binary files /dev/null and b/integration_tests/tests/data/accounts/show_zero_balance_filter/CyqarC6hyNYvb3EDueyeYrnGeAUjCDtMvWrbtdAnA53a differ diff --git a/integration_tests/tests/data/accounts/show_zero_balance_filter_being_disabled/BE1CkzRjLTXAWcSVCaqzycwXsZ18Yuk3jMDMnPUoHjjS b/integration_tests/tests/data/accounts/show_zero_balance_filter_being_disabled/BE1CkzRjLTXAWcSVCaqzycwXsZ18Yuk3jMDMnPUoHjjS new file mode 100644 index 000000000..60708bfc3 Binary files /dev/null and b/integration_tests/tests/data/accounts/show_zero_balance_filter_being_disabled/BE1CkzRjLTXAWcSVCaqzycwXsZ18Yuk3jMDMnPUoHjjS differ diff --git a/integration_tests/tests/data/accounts/show_zero_balance_filter_being_disabled/CyqarC6hyNYvb3EDueyeYrnGeAUjCDtMvWrbtdAnA53a b/integration_tests/tests/data/accounts/show_zero_balance_filter_being_disabled/CyqarC6hyNYvb3EDueyeYrnGeAUjCDtMvWrbtdAnA53a new file mode 100644 index 000000000..35c77e585 Binary files /dev/null and b/integration_tests/tests/data/accounts/show_zero_balance_filter_being_disabled/CyqarC6hyNYvb3EDueyeYrnGeAUjCDtMvWrbtdAnA53a differ diff --git a/integration_tests/tests/data/accounts/show_zero_balance_filter_being_enabled/BE1CkzRjLTXAWcSVCaqzycwXsZ18Yuk3jMDMnPUoHjjS b/integration_tests/tests/data/accounts/show_zero_balance_filter_being_enabled/BE1CkzRjLTXAWcSVCaqzycwXsZ18Yuk3jMDMnPUoHjjS new file mode 100644 index 000000000..22f7b4fcc Binary files /dev/null and b/integration_tests/tests/data/accounts/show_zero_balance_filter_being_enabled/BE1CkzRjLTXAWcSVCaqzycwXsZ18Yuk3jMDMnPUoHjjS differ diff --git a/integration_tests/tests/data/accounts/show_zero_balance_filter_being_enabled/CyqarC6hyNYvb3EDueyeYrnGeAUjCDtMvWrbtdAnA53a b/integration_tests/tests/data/accounts/show_zero_balance_filter_being_enabled/CyqarC6hyNYvb3EDueyeYrnGeAUjCDtMvWrbtdAnA53a new file mode 100644 index 000000000..b7ad72ee8 Binary files /dev/null and b/integration_tests/tests/data/accounts/show_zero_balance_filter_being_enabled/CyqarC6hyNYvb3EDueyeYrnGeAUjCDtMvWrbtdAnA53a differ diff --git a/integration_tests/tests/data/accounts/token_extensions_get_asset/BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y b/integration_tests/tests/data/accounts/token_extensions_get_asset/BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y new file mode 100644 index 000000000..357411c17 Binary files /dev/null and b/integration_tests/tests/data/accounts/token_extensions_get_asset/BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y differ diff --git a/integration_tests/tests/data/accounts/token_extensions_get_asset_scenario1/BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y b/integration_tests/tests/data/accounts/token_extensions_get_asset_scenario1/BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y new file mode 100644 index 000000000..c864c0089 Binary files /dev/null and b/integration_tests/tests/data/accounts/token_extensions_get_asset_scenario1/BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y differ diff --git a/integration_tests/tests/data/accounts/token_extensions_get_asset_scenario2/HVbpJAQGNpkgBaYBZQBR1t7yFdvaYVp2vCQQfKKEN4tM b/integration_tests/tests/data/accounts/token_extensions_get_asset_scenario2/HVbpJAQGNpkgBaYBZQBR1t7yFdvaYVp2vCQQfKKEN4tM new file mode 100644 index 000000000..a4c739eb4 Binary files /dev/null and b/integration_tests/tests/data/accounts/token_extensions_get_asset_scenario2/HVbpJAQGNpkgBaYBZQBR1t7yFdvaYVp2vCQQfKKEN4tM differ diff --git a/integration_tests/tests/data/accounts/token_extensions_get_asset_scenario_1/BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y b/integration_tests/tests/data/accounts/token_extensions_get_asset_scenario_1/BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y new file mode 100644 index 000000000..805898376 Binary files /dev/null and b/integration_tests/tests/data/accounts/token_extensions_get_asset_scenario_1/BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y differ diff --git a/integration_tests/tests/data/accounts/token_extensions_get_asset_scenario_2/HVbpJAQGNpkgBaYBZQBR1t7yFdvaYVp2vCQQfKKEN4tM b/integration_tests/tests/data/accounts/token_extensions_get_asset_scenario_2/HVbpJAQGNpkgBaYBZQBR1t7yFdvaYVp2vCQQfKKEN4tM new file mode 100644 index 000000000..951ce886c Binary files /dev/null and b/integration_tests/tests/data/accounts/token_extensions_get_asset_scenario_2/HVbpJAQGNpkgBaYBZQBR1t7yFdvaYVp2vCQQfKKEN4tM differ diff --git a/integration_tests/tests/data/accounts/token_extensions_get_asset_scenario_3/2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo b/integration_tests/tests/data/accounts/token_extensions_get_asset_scenario_3/2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo new file mode 100644 index 000000000..2f1cdbc62 Binary files /dev/null and b/integration_tests/tests/data/accounts/token_extensions_get_asset_scenario_3/2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo differ diff --git a/integration_tests/tests/data/largest_token_account_ids/2w81QrLYTwSDkNwXgCqKAwrC1Tu6R9mh9BHcxys2Bup2/2w81QrLYTwSDkNwXgCqKAwrC1Tu6R9mh9BHcxys2Bup2 b/integration_tests/tests/data/largest_token_account_ids/2w81QrLYTwSDkNwXgCqKAwrC1Tu6R9mh9BHcxys2Bup2/2w81QrLYTwSDkNwXgCqKAwrC1Tu6R9mh9BHcxys2Bup2 new file mode 100644 index 000000000..3dc3aa9c3 --- /dev/null +++ b/integration_tests/tests/data/largest_token_account_ids/2w81QrLYTwSDkNwXgCqKAwrC1Tu6R9mh9BHcxys2Bup2/2w81QrLYTwSDkNwXgCqKAwrC1Tu6R9mh9BHcxys2Bup2 @@ -0,0 +1,2 @@ + +œÅ¸ëñ¡9”ž€ÆmR¨i\Ÿ¾âê ½ë]Ê \ No newline at end of file diff --git a/integration_tests/tests/data/largest_token_account_ids/42AYryUGNmJMe9ycBXZekkYvdTehgbtECHs7SLu5JJTB/42AYryUGNmJMe9ycBXZekkYvdTehgbtECHs7SLu5JJTB b/integration_tests/tests/data/largest_token_account_ids/42AYryUGNmJMe9ycBXZekkYvdTehgbtECHs7SLu5JJTB/42AYryUGNmJMe9ycBXZekkYvdTehgbtECHs7SLu5JJTB new file mode 100644 index 000000000..c9241fcba --- /dev/null +++ b/integration_tests/tests/data/largest_token_account_ids/42AYryUGNmJMe9ycBXZekkYvdTehgbtECHs7SLu5JJTB/42AYryUGNmJMe9ycBXZekkYvdTehgbtECHs7SLu5JJTB @@ -0,0 +1,2 @@ +e 9;§:þ$fúÊEÁv½KA¶ +º”\«%.‰ò \ No newline at end of file diff --git a/integration_tests/tests/data/largest_token_account_ids/8t77ShMViat27Sjphvi1FVPaGrhFcttPAkEnLCFp49Bo/8t77ShMViat27Sjphvi1FVPaGrhFcttPAkEnLCFp49Bo b/integration_tests/tests/data/largest_token_account_ids/8t77ShMViat27Sjphvi1FVPaGrhFcttPAkEnLCFp49Bo/8t77ShMViat27Sjphvi1FVPaGrhFcttPAkEnLCFp49Bo new file mode 100644 index 000000000..eb66ffa10 Binary files /dev/null and b/integration_tests/tests/data/largest_token_account_ids/8t77ShMViat27Sjphvi1FVPaGrhFcttPAkEnLCFp49Bo/8t77ShMViat27Sjphvi1FVPaGrhFcttPAkEnLCFp49Bo differ diff --git a/integration_tests/tests/data/largest_token_account_ids/AH6VcoSbCGGv8BHeN7K766VUWMcdFRTaXpLvGTLSdAmk/AH6VcoSbCGGv8BHeN7K766VUWMcdFRTaXpLvGTLSdAmk b/integration_tests/tests/data/largest_token_account_ids/AH6VcoSbCGGv8BHeN7K766VUWMcdFRTaXpLvGTLSdAmk/AH6VcoSbCGGv8BHeN7K766VUWMcdFRTaXpLvGTLSdAmk new file mode 100644 index 000000000..7bc1e9a00 --- /dev/null +++ b/integration_tests/tests/data/largest_token_account_ids/AH6VcoSbCGGv8BHeN7K766VUWMcdFRTaXpLvGTLSdAmk/AH6VcoSbCGGv8BHeN7K766VUWMcdFRTaXpLvGTLSdAmk @@ -0,0 +1 @@ +.BŽQ–*pp-¥ëÊUÉìûîž·„gå›óîÏ>þ \ No newline at end of file diff --git a/integration_tests/tests/data/transactions/search_asset_with_token_type_compressed/4URwUGBjbsF7UBUYdSC546tnBy7nD67txsso8D9CR9kGLtbbYh9NkGw15tEp16LLasmJX5VQR4Seh8gDjTrtdpoC b/integration_tests/tests/data/transactions/search_asset_with_token_type_compressed/4URwUGBjbsF7UBUYdSC546tnBy7nD67txsso8D9CR9kGLtbbYh9NkGw15tEp16LLasmJX5VQR4Seh8gDjTrtdpoC new file mode 100644 index 000000000..a9f81afe7 Binary files /dev/null and b/integration_tests/tests/data/transactions/search_asset_with_token_type_compressed/4URwUGBjbsF7UBUYdSC546tnBy7nD67txsso8D9CR9kGLtbbYh9NkGw15tEp16LLasmJX5VQR4Seh8gDjTrtdpoC differ diff --git a/integration_tests/tests/data/transactions/search_asset_with_token_type_compressed/4nKDSvw2kGpccZWLEPnfdP7J1SEexQFRP3xWc9NBtQ1qQeGu3bu5WnAdpcLbjQ4iyX6BQ5QGF69wevE8ZeeY5poA b/integration_tests/tests/data/transactions/search_asset_with_token_type_compressed/4nKDSvw2kGpccZWLEPnfdP7J1SEexQFRP3xWc9NBtQ1qQeGu3bu5WnAdpcLbjQ4iyX6BQ5QGF69wevE8ZeeY5poA new file mode 100644 index 000000000..23b8337f4 Binary files /dev/null and b/integration_tests/tests/data/transactions/search_asset_with_token_type_compressed/4nKDSvw2kGpccZWLEPnfdP7J1SEexQFRP3xWc9NBtQ1qQeGu3bu5WnAdpcLbjQ4iyX6BQ5QGF69wevE8ZeeY5poA differ diff --git a/integration_tests/tests/integration_tests/fungibles_and_token_extensions_tests.rs b/integration_tests/tests/integration_tests/fungibles_and_token_extensions_tests.rs new file mode 100644 index 000000000..6115b3103 --- /dev/null +++ b/integration_tests/tests/integration_tests/fungibles_and_token_extensions_tests.rs @@ -0,0 +1,162 @@ +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_token_extensions_get_asset_scenario_1() { + let name = trim_test_name(function_name!()); + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { + network: Some(Network::Devnet), + }, + ) + .await; + + let seeds: Vec = seed_accounts(["BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y"]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "id": "BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y" + } + "#; + + 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_token_extensions_get_asset_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 = seed_accounts(["HVbpJAQGNpkgBaYBZQBR1t7yFdvaYVp2vCQQfKKEN4tM"]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "id": "HVbpJAQGNpkgBaYBZQBR1t7yFdvaYVp2vCQQfKKEN4tM" + } + "#; + + 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_token_extensions_get_asset_scenario_3() { + let name = trim_test_name(function_name!()); + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { + network: Some(Network::Mainnet), + }, + ) + .await; + + let seeds: Vec = seed_accounts(["2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo"]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "id": "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo" + } + "#; + + 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_fungible_token_get_asset_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 = seed_accounts([ + "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + "5x38Kp4hvdomTCnCrAny4UtMUt5rQBdB6px2K1Ui45Wq", + ]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "id": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" + } + "#; + + 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_fungible_token_get_asset_scenario_2() { + let name = trim_test_name(function_name!()); + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { + network: Some(Network::Devnet), + }, + ) + .await; + + let seeds: Vec = seed_accounts(["wKocBVvHQoVaiwWoCs9JYSVye4YZRrv5Cucf7fDqnz1"]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "id": "wKocBVvHQoVaiwWoCs9JYSVye4YZRrv5Cucf7fDqnz1" + } + "#; + + 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); +} diff --git a/integration_tests/tests/integration_tests/main.rs b/integration_tests/tests/integration_tests/main.rs index 7220ca96c..c14c435e9 100644 --- a/integration_tests/tests/integration_tests/main.rs +++ b/integration_tests/tests/integration_tests/main.rs @@ -1,6 +1,15 @@ mod account_update_tests; mod cnft_tests; mod common; +mod fungibles_and_token_extensions_tests; mod general_scenario_tests; mod mpl_core_tests; +mod nft_editions_tests; mod regular_nft_tests; +mod show_fungible_flag_tests; +mod show_inscription_flag_tests; +mod test_get_assets_with_multiple_same_ids; +mod test_show_collection_metadata_option; +mod test_show_zero_balance_filter; +mod token_accounts_tests; +mod token_type_test; diff --git a/integration_tests/tests/integration_tests/nft_editions_tests.rs b/integration_tests/tests/integration_tests/nft_editions_tests.rs new file mode 100644 index 000000000..61929f2f5 --- /dev/null +++ b/integration_tests/tests/integration_tests/nft_editions_tests.rs @@ -0,0 +1,50 @@ +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_nft_editions() { + let name = trim_test_name(function_name!()); + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { + network: Some(Network::Mainnet), + }, + ) + .await; + + let seeds: Vec = seed_accounts([ + "Ey2Qb8kLctbchQsMnhZs5DjY32To2QtPuXNwWvk4NosL", + "9ZmY7qCaq7WbrR7RZdHWCNS9FrFRPwRqU84wzWfmqLDz", + "8SHfqzJYABeGfiG1apwiEYt6TvfGQiL1pdwEjvTKsyiZ", + "GJvFDcBWf6aDncd1TBzx2ou1rgLFYaMBdbYLBa9oTAEw", + "9ZmY7qCaq7WbrR7RZdHWCNS9FrFRPwRqU84wzWfmqLDz", + "AoxgzXKEsJmUyF5pBb3djn9cJFA26zh2SQHvd9EYijZV", + "9yQecKKYSHxez7fFjJkUvkz42TLmkoXzhyZxEf2pw8pz", + "4V9QuYLpiMu4ZQmhdEHmgATdgiHkDeJfvZi84BfkYcez", + "giWoA4jqHFkodPJgtbRYRcYtiXbsVytnxnEao3QT2gg", + ]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "mintAddress": "Ey2Qb8kLctbchQsMnhZs5DjY32To2QtPuXNwWvk4NosL", + "limit":10 + } + "#; + + let request: api::GetNftEditions = serde_json::from_str(request).unwrap(); + let response = setup.das_api.get_nft_editions(request).await.unwrap(); + + insta::assert_json_snapshot!(name, response); +} diff --git a/integration_tests/tests/integration_tests/show_fungible_flag_tests.rs b/integration_tests/tests/integration_tests/show_fungible_flag_tests.rs new file mode 100644 index 000000000..3a7626106 --- /dev/null +++ b/integration_tests/tests/integration_tests/show_fungible_flag_tests.rs @@ -0,0 +1,269 @@ +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 = seed_accounts([ + "Ca84nWhQu41DMRnjdhRrLZty1i9txepMhAhz5qLLGcBw", + "7z6b5TE4WX4mgcQjuNBTDxK4SE75sbgEg5WWJwoUeie8", + "8myaCN6KcKVkMqroXuLJq6QsqRcPbvme4wV5Ubfr5mDC", + ]); + + 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 = seed_accounts([ + "AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM", + "7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK", + "8Xv3SpX94HHf32Apg4TeSeS3i2p6wuXeE8FBZr168Hti", + ]); + + 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); +} + +#[tokio::test] +#[serial] +#[named] +async fn test_get_asset_with_show_fungible_scenario_3() { + let name = trim_test_name(function_name!()); + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { + network: Some(Network::Mainnet), + }, + ) + .await; + + let seeds: Vec = seed_accounts(["2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo"]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "id": "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo", + "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_4() { + let name = trim_test_name(function_name!()); + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { + network: Some(Network::Mainnet), + }, + ) + .await; + + let seeds: Vec = seed_accounts([ + "J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn", + "8yn5oqFMwYA8SgGqWwKq1Hia8aM5gh1DWmHEL34hMqBX", + ]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "id": "J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn", + "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_by_owner_with_show_fungible() { + let name = trim_test_name(function_name!()); + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { + network: Some(Network::Mainnet), + }, + ) + .await; + + let seeds: Vec = seed_accounts([ + "AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM", + "7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK", + "8Xv3SpX94HHf32Apg4TeSeS3i2p6wuXeE8FBZr168Hti", + ]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "ownerAddress": "GqPnSDXwp4JFtKS7YZ2HERgBbYLKpKVYy9TpVunzLRa9", + "displayOptions": { + "showFungible": true + } + } + "#; + + let request: api::GetAssetsByOwner = serde_json::from_str(request).unwrap(); + let response = setup.das_api.get_assets_by_owner(request).await.unwrap(); + + insta::assert_json_snapshot!(name, response); +} + +#[tokio::test] +#[serial] +#[named] +async fn test_get_asset_by_authority_with_show_fungible() { + let name = trim_test_name(function_name!()); + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { + network: Some(Network::Mainnet), + }, + ) + .await; + + let seeds: Vec = seed_accounts([ + "AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM", + "7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK", + "8Xv3SpX94HHf32Apg4TeSeS3i2p6wuXeE8FBZr168Hti", + ]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "authorityAddress": "2RtGg6fsFiiF1EQzHqbd66AhW7R5bWeQGpTbv2UMkCdW", + "displayOptions": { + "showFungible": true + } + } + "#; + + let request: api::GetAssetsByAuthority = serde_json::from_str(request).unwrap(); + let response = setup + .das_api + .get_assets_by_authority(request) + .await + .unwrap(); + + insta::assert_json_snapshot!(name, response); +} + +#[tokio::test] +#[serial] +#[named] +async fn test_get_asset_by_creator_with_show_fungible() { + let name = trim_test_name(function_name!()); + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { + network: Some(Network::Mainnet), + }, + ) + .await; + + let seeds: Vec = seed_accounts([ + "AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM", + "7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK", + "8Xv3SpX94HHf32Apg4TeSeS3i2p6wuXeE8FBZr168Hti", + ]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "creatorAddress": "5XvhfmRjwXkGp3jHGmaKpqeerNYjkuZZBYLVQYdeVcRv", + "displayOptions": { + "showFungible": true + } + } + "#; + + let request: api::GetAssetsByCreator = serde_json::from_str(request).unwrap(); + let response = setup.das_api.get_assets_by_creator(request).await.unwrap(); + + insta::assert_json_snapshot!(name, response); +} diff --git a/integration_tests/tests/integration_tests/show_inscription_flag_tests.rs b/integration_tests/tests/integration_tests/show_inscription_flag_tests.rs new file mode 100644 index 000000000..7c5dffdff --- /dev/null +++ b/integration_tests/tests/integration_tests/show_inscription_flag_tests.rs @@ -0,0 +1,46 @@ +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_inscription_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 = seed_accounts([ + "9FkS3kZV4MoGps14tUSp7iVnizGbxcK4bDEhSoF5oYAZ", + "HMixBLSkuhiGgVbcGhqJar476xzu1bC8wM7yHsc1iXwP", + "DarH4z6SmdVzPrt8krAygpLodhdjvNAstP3taj2tysN2", + ]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "id": "9FkS3kZV4MoGps14tUSp7iVnizGbxcK4bDEhSoF5oYAZ", + "displayOptions": { + "showInscription": 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); +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__account_update_tests__account_updates-metadata-updated.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__account_update_tests__account_updates-metadata-updated.snap index fe306fab3..7ede46288 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__account_update_tests__account_updates-metadata-updated.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__account_update_tests__account_updates-metadata-updated.snap @@ -1,6 +1,7 @@ --- source: integration_tests/tests/integration_tests/account_update_tests.rs expression: response_new_slot +snapshot_kind: text --- { "interface": "ProgrammableNFT", @@ -62,7 +63,6 @@ expression: response_new_slot "ownership_model": "single", "owner": "BzbdvwEkQKeghTY53aZxTYjUienhdbkNVkgrLV6cErke" }, - "supply": null, "mutable": false, "burnt": false } diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__account_update_tests__account_updates-token-updated.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__account_update_tests__account_updates-token-updated.snap index 5dac7346d..90985a04a 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__account_update_tests__account_updates-token-updated.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__account_update_tests__account_updates-token-updated.snap @@ -1,6 +1,7 @@ --- source: integration_tests/tests/integration_tests/account_update_tests.rs expression: response_new_slot +snapshot_kind: text --- { "interface": "ProgrammableNFT", @@ -62,7 +63,6 @@ expression: response_new_slot "ownership_model": "single", "owner": "1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM" }, - "supply": null, "mutable": true, "burnt": false } diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__account_update_tests__account_updates-with-all-updates.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__account_update_tests__account_updates-with-all-updates.snap index d0978550e..4a314f738 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__account_update_tests__account_updates-with-all-updates.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__account_update_tests__account_updates-with-all-updates.snap @@ -1,6 +1,7 @@ --- source: integration_tests/tests/integration_tests/account_update_tests.rs expression: setup.das_api.get_asset(request.clone()).await.unwrap() +snapshot_kind: text --- { "interface": "ProgrammableNFT", @@ -62,7 +63,6 @@ expression: setup.das_api.get_asset(request.clone()).await.unwrap() "ownership_model": "single", "owner": "1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM" }, - "supply": null, "mutable": false, "burnt": false } diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__account_update_tests__account_updates.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__account_update_tests__account_updates.snap index 2deeb3b43..e37b12286 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__account_update_tests__account_updates.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__account_update_tests__account_updates.snap @@ -1,6 +1,7 @@ --- source: integration_tests/tests/integration_tests/account_update_tests.rs expression: response +snapshot_kind: text --- { "interface": "ProgrammableNFT", @@ -62,7 +63,6 @@ expression: response "ownership_model": "single", "owner": "BzbdvwEkQKeghTY53aZxTYjUienhdbkNVkgrLV6cErke" }, - "supply": null, "mutable": true, "burnt": false } diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__fungibles_and_token_extensions_tests__fungible_token_get_asset_scenario_1.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__fungibles_and_token_extensions_tests__fungible_token_get_asset_scenario_1.snap new file mode 100644 index 000000000..16be64a22 --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__fungibles_and_token_extensions_tests__fungible_token_get_asset_scenario_1.snap @@ -0,0 +1,56 @@ +--- +source: integration_tests/tests/integration_tests/fungibles_and_token_extensions_tests.rs +expression: response +snapshot_kind: text +--- +{ + "interface": "FungibleToken", + "id": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "", + "files": [], + "metadata": { + "name": "USD Coin", + "symbol": "USDC" + }, + "links": {} + }, + "authorities": [ + { + "address": "2wmVCSfPxGPjrnMMn7rchp4uaeoTqN39mXFC2zhPdri9", + "scopes": [ + "full" + ] + } + ], + "compression": { + "eligible": false, + "compressed": false, + "data_hash": "", + "creator_hash": "", + "asset_hash": "", + "tree": "", + "seq": 0, + "leaf_id": 0 + }, + "grouping": [], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.0, + "basis_points": 0, + "primary_sale_happened": false, + "locked": false + }, + "creators": [], + "ownership": { + "frozen": false, + "delegated": false, + "delegate": null, + "ownership_model": "token", + "owner": "" + }, + "mutable": true, + "burnt": false +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__fungibles_and_token_extensions_tests__fungible_token_get_asset_scenario_2.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__fungibles_and_token_extensions_tests__fungible_token_get_asset_scenario_2.snap new file mode 100644 index 000000000..2357ddf57 --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__fungibles_and_token_extensions_tests__fungible_token_get_asset_scenario_2.snap @@ -0,0 +1,39 @@ +--- +source: integration_tests/tests/integration_tests/fungibles_and_token_extensions_tests.rs +expression: response +snapshot_kind: text +--- +{ + "interface": "FungibleToken", + "id": "wKocBVvHQoVaiwWoCs9JYSVye4YZRrv5Cucf7fDqnz1", + "authorities": [], + "compression": { + "eligible": false, + "compressed": false, + "data_hash": "", + "creator_hash": "", + "asset_hash": "", + "tree": "", + "seq": 0, + "leaf_id": 0 + }, + "grouping": [], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.0, + "basis_points": 0, + "primary_sale_happened": false, + "locked": false + }, + "creators": [], + "ownership": { + "frozen": false, + "delegated": false, + "delegate": null, + "ownership_model": "token", + "owner": "" + }, + "mutable": false, + "burnt": false +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__fungibles_and_token_extensions_tests__token_extensions_get_asset_scenario_1.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__fungibles_and_token_extensions_tests__token_extensions_get_asset_scenario_1.snap new file mode 100644 index 000000000..e11162d34 --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__fungibles_and_token_extensions_tests__token_extensions_get_asset_scenario_1.snap @@ -0,0 +1,62 @@ +--- +source: integration_tests/tests/integration_tests/fungibles_and_token_extensions_tests.rs +expression: response +snapshot_kind: text +--- +{ + "interface": "FungibleToken", + "id": "BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://acme.com/demo.json", + "files": [], + "metadata": { + "name": "DAS Dev", + "symbol": "DAS" + }, + "links": {} + }, + "authorities": [], + "compression": { + "eligible": false, + "compressed": false, + "data_hash": "", + "creator_hash": "", + "asset_hash": "", + "tree": "", + "seq": 0, + "leaf_id": 0 + }, + "grouping": [], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.0, + "basis_points": 0, + "primary_sale_happened": false, + "locked": false + }, + "creators": [], + "ownership": { + "frozen": false, + "delegated": false, + "delegate": null, + "ownership_model": "token", + "owner": "" + }, + "mutable": true, + "burnt": false, + "mint_extensions": { + "metadata": { + "uri": "https://acme.com/demo.json", + "mint": "BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y", + "name": "DAS Dev", + "symbol": "DAS", + "update_authority": "Em34oqDQYQZ9b6ycPHD28K47mttrRsdNu1S1pgK6NtPL", + "additional_metadata": [] + }, + "metadata_pointer": { + "metadata_address": "BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y" + } + } +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__fungibles_and_token_extensions_tests__token_extensions_get_asset_scenario_2.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__fungibles_and_token_extensions_tests__token_extensions_get_asset_scenario_2.snap new file mode 100644 index 000000000..6df591f6c --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__fungibles_and_token_extensions_tests__token_extensions_get_asset_scenario_2.snap @@ -0,0 +1,77 @@ +--- +source: integration_tests/tests/integration_tests/fungibles_and_token_extensions_tests.rs +expression: response +snapshot_kind: text +--- +{ + "interface": "FungibleToken", + "id": "HVbpJAQGNpkgBaYBZQBR1t7yFdvaYVp2vCQQfKKEN4tM", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://token-metadata.paxos.com/usdp_metadata/prod/solana/usdp_metadata.json", + "files": [], + "metadata": { + "name": "Pax Dollar", + "symbol": "USDP" + }, + "links": {} + }, + "authorities": [], + "compression": { + "eligible": false, + "compressed": false, + "data_hash": "", + "creator_hash": "", + "asset_hash": "", + "tree": "", + "seq": 0, + "leaf_id": 0 + }, + "grouping": [], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.0, + "basis_points": 0, + "primary_sale_happened": false, + "locked": false + }, + "creators": [], + "ownership": { + "frozen": false, + "delegated": false, + "delegate": null, + "ownership_model": "token", + "owner": "" + }, + "mutable": true, + "burnt": false, + "mint_extensions": { + "metadata": { + "uri": "https://token-metadata.paxos.com/usdp_metadata/prod/solana/usdp_metadata.json", + "mint": "HVbpJAQGNpkgBaYBZQBR1t7yFdvaYVp2vCQQfKKEN4tM", + "name": "Pax Dollar", + "symbol": "USDP", + "update_authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk", + "additional_metadata": [] + }, + "transfer_hook": { + "authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk", + "program_id": null + }, + "metadata_pointer": { + "metadata_address": "HVbpJAQGNpkgBaYBZQBR1t7yFdvaYVp2vCQQfKKEN4tM" + }, + "permanent_delegate": { + "delegate": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk" + }, + "mint_close_authority": { + "close_authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk" + }, + "confidential_transfer_mint": { + "authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk", + "auditor_elgamal_pubkey": null, + "auto_approve_new_accounts": false + } + } +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__fungibles_and_token_extensions_tests__token_extensions_get_asset_scenario_3.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__fungibles_and_token_extensions_tests__token_extensions_get_asset_scenario_3.snap new file mode 100644 index 000000000..ba9c9e79f --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__fungibles_and_token_extensions_tests__token_extensions_get_asset_scenario_3.snap @@ -0,0 +1,196 @@ +--- +source: integration_tests/tests/integration_tests/fungibles_and_token_extensions_tests.rs +expression: response +snapshot_kind: text +--- +{ + "interface": "FungibleToken", + "id": "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://token-metadata.paxos.com/pyusd_metadata/prod/solana/pyusd_metadata.json", + "files": [], + "metadata": { + "name": "PayPal USD", + "symbol": "PYUSD" + }, + "links": {} + }, + "authorities": [], + "compression": { + "eligible": false, + "compressed": false, + "data_hash": "", + "creator_hash": "", + "asset_hash": "", + "tree": "", + "seq": 0, + "leaf_id": 0 + }, + "grouping": [], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.0, + "basis_points": 0, + "primary_sale_happened": false, + "locked": false + }, + "creators": [], + "ownership": { + "frozen": false, + "delegated": false, + "delegate": null, + "ownership_model": "token", + "owner": "" + }, + "mutable": true, + "burnt": false, + "mint_extensions": { + "metadata": { + "uri": "https://token-metadata.paxos.com/pyusd_metadata/prod/solana/pyusd_metadata.json", + "mint": "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo", + "name": "PayPal USD", + "symbol": "PYUSD", + "update_authority": "9nEfZqzTP3dfVWmzQy54TzsZqSQqDFVW4PhXdG9vYCVD", + "additional_metadata": [] + }, + "transfer_hook": { + "authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk", + "program_id": null + }, + "metadata_pointer": { + "metadata_address": "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo" + }, + "permanent_delegate": { + "delegate": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk" + }, + "transfer_fee_config": { + "withheld_amount": 0, + "newer_transfer_fee": { + "epoch": 605, + "maximum_fee": 0, + "transfer_fee_basis_points": 0 + }, + "older_transfer_fee": { + "epoch": 605, + "maximum_fee": 0, + "transfer_fee_basis_points": 0 + }, + "withdraw_withheld_authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk", + "transfer_fee_config_authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk" + }, + "mint_close_authority": { + "close_authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk" + }, + "confidential_transfer_mint": { + "authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk", + "auditor_elgamal_pubkey": null, + "auto_approve_new_accounts": false + }, + "confidential_transfer_fee_config": { + "authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk", + "withheld_amount": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "harvest_to_mint_enabled": true, + "withdraw_withheld_authority_elgamal_pubkey": [ + 28, + 55, + 230, + 67, + 59, + 115, + 4, + 221, + 130, + 115, + 122, + 228, + 13, + 155, + 139, + 243, + 196, + 159, + 91, + 14, + 108, + 73, + 168, + 213, + 51, + 40, + 179, + 229, + 6, + 144, + 28, + 87 + ] + } + } +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__general_scenario_tests__asset_parsing.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__general_scenario_tests__asset_parsing.snap index 27d495e3a..9843eb6b3 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__general_scenario_tests__asset_parsing.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__general_scenario_tests__asset_parsing.snap @@ -1,6 +1,7 @@ --- source: integration_tests/tests/integration_tests/general_scenario_tests.rs expression: response +snapshot_kind: text --- { "interface": "ProgrammableNFT", @@ -62,7 +63,6 @@ expression: response "ownership_model": "single", "owner": "BzbdvwEkQKeghTY53aZxTYjUienhdbkNVkgrLV6cErke" }, - "supply": null, "mutable": true, "burnt": false } diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__general_scenario_tests__creators_reordering.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__general_scenario_tests__creators_reordering.snap index 2ed4bf732..7b50b3a93 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__general_scenario_tests__creators_reordering.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__general_scenario_tests__creators_reordering.snap @@ -1,6 +1,7 @@ --- source: integration_tests/tests/integration_tests/general_scenario_tests.rs expression: response +snapshot_kind: text --- { "interface": "ProgrammableNFT", @@ -77,7 +78,6 @@ expression: response "ownership_model": "single", "owner": "AZgXpkRSetUJHy6C3NBvG6jNe49MpgrkZ2RkdMkjCjkW" }, - "supply": null, "mutable": true, "burnt": false } diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_autograph_plugin.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_autograph_plugin.snap index 1a8cfd344..552549a56 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_autograph_plugin.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_autograph_plugin.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 487 expression: response +snapshot_kind: text --- { "interface": "MplCoreAsset", @@ -51,7 +51,6 @@ expression: response "ownership_model": "single", "owner": "APrZTeVysBJqAznfLXS71NAzjr2fCVTSF1A66MeErzM7" }, - "supply": null, "mutable": true, "burnt": false, "plugins": { diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_autograph_plugin_with_signature.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_autograph_plugin_with_signature.snap index 4277369f1..2753ea8e2 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_autograph_plugin_with_signature.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_autograph_plugin_with_signature.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 516 expression: response +snapshot_kind: text --- { "interface": "MplCoreAsset", @@ -51,7 +51,6 @@ expression: response "ownership_model": "single", "owner": "ACxrDWeCPic6voU6a8vyadpL8nSW15Un5vT76LDpxD4N" }, - "supply": null, "mutable": true, "burnt": false, "plugins": { diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset.snap index 0b9a6039f..a72d1bfc8 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 37 expression: response +snapshot_kind: text --- { "interface": "MplCoreAsset", @@ -62,7 +62,6 @@ expression: response "ownership_model": "single", "owner": "APrZTeVysBJqAznfLXS71NAzjr2fCVTSF1A66MeErzM7" }, - "supply": null, "mutable": true, "burnt": false, "plugins": { diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_app_data_with_binary_data_and_owner_is_data_authority.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_app_data_with_binary_data_and_owner_is_data_authority.snap index b0d613582..e48244c90 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_app_data_with_binary_data_and_owner_is_data_authority.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_app_data_with_binary_data_and_owner_is_data_authority.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 603 expression: response +snapshot_kind: text --- { "interface": "MplCoreAsset", @@ -51,7 +51,6 @@ expression: response "ownership_model": "single", "owner": "HKwwF4sPVYFPgqEgxth4GZRZjJ9o4E3wA8eu2QM5Vt3H" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_app_data_with_json_data_and_update_authority_is_data_authority.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_app_data_with_json_data_and_update_authority_is_data_authority.snap index ba7f6bca3..d7f66a390 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_app_data_with_json_data_and_update_authority_is_data_authority.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_app_data_with_json_data_and_update_authority_is_data_authority.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 633 expression: response +snapshot_kind: text --- { "interface": "MplCoreAsset", @@ -51,7 +51,6 @@ expression: response "ownership_model": "single", "owner": "HKwwF4sPVYFPgqEgxth4GZRZjJ9o4E3wA8eu2QM5Vt3H" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_app_data_with_msg_pack_data_and_address_is_data_authority.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_app_data_with_msg_pack_data_and_address_is_data_authority.snap index 2031b1797..38619bc7f 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_app_data_with_msg_pack_data_and_address_is_data_authority.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_app_data_with_msg_pack_data_and_address_is_data_authority.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 662 expression: response +snapshot_kind: text --- { "interface": "MplCoreAsset", @@ -51,7 +51,6 @@ expression: response "ownership_model": "single", "owner": "HKwwF4sPVYFPgqEgxth4GZRZjJ9o4E3wA8eu2QM5Vt3H" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_data_section_with_binary_data.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_data_section_with_binary_data.snap index 85e72340b..3fe19c33d 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_data_section_with_binary_data.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_data_section_with_binary_data.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 721 expression: response +snapshot_kind: text --- { "interface": "MplCoreAsset", @@ -56,7 +56,6 @@ expression: response "ownership_model": "single", "owner": "HKwwF4sPVYFPgqEgxth4GZRZjJ9o4E3wA8eu2QM5Vt3H" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_data_section_with_json_data.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_data_section_with_json_data.snap index 9524d637f..410235155 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_data_section_with_json_data.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_data_section_with_json_data.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 780 expression: response +snapshot_kind: text --- { "interface": "MplCoreAsset", @@ -56,7 +56,6 @@ expression: response "ownership_model": "single", "owner": "HKwwF4sPVYFPgqEgxth4GZRZjJ9o4E3wA8eu2QM5Vt3H" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_data_section_with_msg_pack_data.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_data_section_with_msg_pack_data.snap index 840e75768..0294d65bf 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_data_section_with_msg_pack_data.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_data_section_with_msg_pack_data.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 839 expression: response +snapshot_kind: text --- { "interface": "MplCoreAsset", @@ -56,7 +56,6 @@ expression: response "ownership_model": "single", "owner": "HKwwF4sPVYFPgqEgxth4GZRZjJ9o4E3wA8eu2QM5Vt3H" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_edition.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_edition.snap index 6333a1260..f86780213 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_edition.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_edition.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 216 expression: response +snapshot_kind: text --- { "interface": "MplCoreAsset", @@ -51,7 +51,6 @@ expression: response "ownership_model": "single", "owner": "APrZTeVysBJqAznfLXS71NAzjr2fCVTSF1A66MeErzM7" }, - "supply": null, "mutable": true, "burnt": false, "plugins": { diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_multiple_internal_and_external_plugins.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_multiple_internal_and_external_plugins.snap index 60e77e446..a941b9087 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_multiple_internal_and_external_plugins.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_multiple_internal_and_external_plugins.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 458 expression: response +snapshot_kind: text --- { "interface": "MplCoreAsset", @@ -57,7 +57,6 @@ expression: response "ownership_model": "single", "owner": "APrZTeVysBJqAznfLXS71NAzjr2fCVTSF1A66MeErzM7" }, - "supply": null, "mutable": true, "burnt": false, "plugins": { diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_oracle_custom_offset_and_base_address_config.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_oracle_custom_offset_and_base_address_config.snap index ac19d3d3a..08ad3c6dd 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_oracle_custom_offset_and_base_address_config.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_oracle_custom_offset_and_base_address_config.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 361 expression: response +snapshot_kind: text --- { "interface": "MplCoreAsset", @@ -51,7 +51,6 @@ expression: response "ownership_model": "single", "owner": "APrZTeVysBJqAznfLXS71NAzjr2fCVTSF1A66MeErzM7" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_oracle_external_plugin_on_collection.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_oracle_external_plugin_on_collection.snap index 40802d2a6..520d97d9b 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_oracle_external_plugin_on_collection.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_oracle_external_plugin_on_collection.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 274 expression: response +snapshot_kind: text --- { "interface": "MplCoreCollection", @@ -51,7 +51,6 @@ expression: response "ownership_model": "single", "owner": "APrZTeVysBJqAznfLXS71NAzjr2fCVTSF1A66MeErzM7" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_oracle_multiple_lifecycle_events.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_oracle_multiple_lifecycle_events.snap index f42fdf792..9bf617915 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_oracle_multiple_lifecycle_events.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_oracle_multiple_lifecycle_events.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 332 expression: response +snapshot_kind: text --- { "interface": "MplCoreAsset", @@ -51,7 +51,6 @@ expression: response "ownership_model": "single", "owner": "APrZTeVysBJqAznfLXS71NAzjr2fCVTSF1A66MeErzM7" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_oracle_no_offset.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_oracle_no_offset.snap index 51d44c25c..fcbfab1d2 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_oracle_no_offset.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_oracle_no_offset.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 390 expression: response +snapshot_kind: text --- { "interface": "MplCoreAsset", @@ -51,7 +51,6 @@ expression: response "ownership_model": "single", "owner": "APrZTeVysBJqAznfLXS71NAzjr2fCVTSF1A66MeErzM7" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_pubkey_in_rule_set.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_pubkey_in_rule_set.snap index bfbe6538e..05acfc8ac 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_pubkey_in_rule_set.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_pubkey_in_rule_set.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 245 expression: response +snapshot_kind: text --- { "interface": "MplCoreAsset", @@ -62,7 +62,6 @@ expression: response "ownership_model": "single", "owner": "8LsUNkb7bLaAcZ7NjRKPuvcyRGTWbm9BxzUpVKjqdV8o" }, - "supply": null, "mutable": true, "burnt": false, "plugins": { diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_two_oracle_external_plugins.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_two_oracle_external_plugins.snap index b9d26a436..1da1d1281 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_two_oracle_external_plugins.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_asset_with_two_oracle_external_plugins.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 274 expression: response +snapshot_kind: text --- { "interface": "MplCoreAsset", @@ -51,7 +51,6 @@ expression: response "ownership_model": "single", "owner": "APrZTeVysBJqAznfLXS71NAzjr2fCVTSF1A66MeErzM7" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_assets_by_authority.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_assets_by_authority.snap index 5acbdeb5d..53017c8fe 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_assets_by_authority.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_assets_by_authority.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 108 expression: response +snapshot_kind: text --- { "total": 2, @@ -61,7 +61,6 @@ expression: response "ownership_model": "single", "owner": "GzYvuu9aUYXmnardj4svbAcCNmefiaGu2E3knGw9NJQQ" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, @@ -118,7 +117,6 @@ expression: response "ownership_model": "single", "owner": "APrZTeVysBJqAznfLXS71NAzjr2fCVTSF1A66MeErzM7" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_assets_by_group.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_assets_by_group.snap index 431a64ec4..f338c6fb7 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_assets_by_group.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_assets_by_group.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 149 expression: response +snapshot_kind: text --- { "total": 3, @@ -61,7 +61,6 @@ expression: response "ownership_model": "single", "owner": "APrZTeVysBJqAznfLXS71NAzjr2fCVTSF1A66MeErzM7" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, @@ -123,7 +122,6 @@ expression: response "ownership_model": "single", "owner": "APrZTeVysBJqAznfLXS71NAzjr2fCVTSF1A66MeErzM7" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, @@ -185,7 +183,6 @@ expression: response "ownership_model": "single", "owner": "APrZTeVysBJqAznfLXS71NAzjr2fCVTSF1A66MeErzM7" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_assets_by_group_with_oracle_and_custom_pda_all_seeds.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_assets_by_group_with_oracle_and_custom_pda_all_seeds.snap index f9cea5683..a4236f53d 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_assets_by_group_with_oracle_and_custom_pda_all_seeds.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_assets_by_group_with_oracle_and_custom_pda_all_seeds.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 429 expression: response +snapshot_kind: text --- { "total": 1, @@ -61,7 +61,6 @@ expression: response "ownership_model": "single", "owner": "FAe4nM85BQ8b1nWEc5TTeogQGnNDWsuGYU84vuiPc7kE" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_assets_by_owner.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_assets_by_owner.snap index 7b190b8a9..946d8a9af 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_assets_by_owner.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_assets_by_owner.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 187 expression: response +snapshot_kind: text --- { "total": 1, @@ -61,7 +61,6 @@ expression: response "ownership_model": "single", "owner": "7uScVQiT4vArB88dHrZoeVKWbtsRJmNp9r5Gce5VQpXS" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_collection.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_collection.snap index 1d854ee47..14a95dbb2 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_collection.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_collection.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 66 expression: response +snapshot_kind: text --- { "interface": "MplCoreCollection", @@ -51,7 +51,6 @@ expression: response "ownership_model": "single", "owner": "APrZTeVysBJqAznfLXS71NAzjr2fCVTSF1A66MeErzM7" }, - "supply": null, "mutable": true, "burnt": false, "plugins": { diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_collection_with_linked_app_data_with_binary_data_and_address_is_data_authority.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_collection_with_linked_app_data_with_binary_data_and_address_is_data_authority.snap index 38d0e3771..4e3b7c0c2 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_collection_with_linked_app_data_with_binary_data_and_address_is_data_authority.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_collection_with_linked_app_data_with_binary_data_and_address_is_data_authority.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 692 expression: response +snapshot_kind: text --- { "interface": "MplCoreCollection", @@ -51,7 +51,6 @@ expression: response "ownership_model": "single", "owner": "APrZTeVysBJqAznfLXS71NAzjr2fCVTSF1A66MeErzM7" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_collection_with_linked_app_data_with_json_data_and_owner_is_data_authority.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_collection_with_linked_app_data_with_json_data_and_owner_is_data_authority.snap index b7ef57f77..2ed4afdc1 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_collection_with_linked_app_data_with_json_data_and_owner_is_data_authority.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_collection_with_linked_app_data_with_json_data_and_owner_is_data_authority.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 751 expression: response +snapshot_kind: text --- { "interface": "MplCoreCollection", @@ -51,7 +51,6 @@ expression: response "ownership_model": "single", "owner": "APrZTeVysBJqAznfLXS71NAzjr2fCVTSF1A66MeErzM7" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_collection_with_linked_app_data_with_msg_pack_data_and_update_authority_is_data_authority.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_collection_with_linked_app_data_with_msg_pack_data_and_update_authority_is_data_authority.snap index ff0cfbdbf..526a7a545 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_collection_with_linked_app_data_with_msg_pack_data_and_update_authority_is_data_authority.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_collection_with_linked_app_data_with_msg_pack_data_and_update_authority_is_data_authority.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 810 expression: response +snapshot_kind: text --- { "interface": "MplCoreCollection", @@ -51,7 +51,6 @@ expression: response "ownership_model": "single", "owner": "APrZTeVysBJqAznfLXS71NAzjr2fCVTSF1A66MeErzM7" }, - "supply": null, "mutable": true, "burnt": false, "plugins": {}, diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_verified_creators_plugin.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_verified_creators_plugin.snap index 6387d404c..cbd495062 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_verified_creators_plugin.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_verified_creators_plugin.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 545 expression: response +snapshot_kind: text --- { "interface": "MplCoreAsset", @@ -51,7 +51,6 @@ expression: response "ownership_model": "single", "owner": "APrZTeVysBJqAznfLXS71NAzjr2fCVTSF1A66MeErzM7" }, - "supply": null, "mutable": true, "burnt": false, "plugins": { diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_verified_creators_plugin_with_signature.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_verified_creators_plugin_with_signature.snap index 96428d6a1..36b1cd541 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_verified_creators_plugin_with_signature.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_verified_creators_plugin_with_signature.snap @@ -1,7 +1,7 @@ --- source: integration_tests/tests/integration_tests/mpl_core_tests.rs -assertion_line: 574 expression: response +snapshot_kind: text --- { "interface": "MplCoreAsset", @@ -51,7 +51,6 @@ expression: response "ownership_model": "single", "owner": "D9SSaw4tz5AGpfWynYJ66jDCVNTsbLBkqT8rxQFenqj4" }, - "supply": null, "mutable": true, "burnt": false, "plugins": { diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__nft_editions_tests__get_nft_editions.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__nft_editions_tests__get_nft_editions.snap new file mode 100644 index 000000000..d67779b90 --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__nft_editions_tests__get_nft_editions.snap @@ -0,0 +1,24 @@ +--- +source: integration_tests/tests/integration_tests/nft_editions_tests.rs +expression: response +snapshot_kind: text +--- +{ + "total": 2, + "limit": 10, + "master_edition_address": "8SHfqzJYABeGfiG1apwiEYt6TvfGQiL1pdwEjvTKsyiZ", + "supply": 60, + "max_supply": 69, + "editions": [ + { + "mint_address": "GJvFDcBWf6aDncd1TBzx2ou1rgLFYaMBdbYLBa9oTAEw", + "edition_address": "AoxgzXKEsJmUyF5pBb3djn9cJFA26zh2SQHvd9EYijZV", + "edition_number": 1 + }, + { + "mint_address": "9yQecKKYSHxez7fFjJkUvkz42TLmkoXzhyZxEf2pw8pz", + "edition_address": "giWoA4jqHFkodPJgtbRYRcYtiXbsVytnxnEao3QT2gg", + "edition_number": 2 + } + ] +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_get_asset.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_get_asset.snap index c62b3de1c..befc56b19 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_get_asset.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_get_asset.snap @@ -1,6 +1,7 @@ --- source: integration_tests/tests/integration_tests/regular_nft_tests.rs expression: response +snapshot_kind: text --- { "interface": "ProgrammableNFT", @@ -67,7 +68,6 @@ expression: response "ownership_model": "single", "owner": "A59E2tNJEqNN9TDnzgGnmLmnTsdRDoPocGx3n1w2dqZw" }, - "supply": null, "mutable": true, "burnt": false } diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_get_asset_batch-2-and-a-missing-1.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_get_asset_batch-2-and-a-missing-1.snap index 0825ec1b2..2f859cbb6 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_get_asset_batch-2-and-a-missing-1.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_get_asset_batch-2-and-a-missing-1.snap @@ -1,6 +1,7 @@ --- source: integration_tests/tests/integration_tests/regular_nft_tests.rs expression: response +snapshot_kind: text --- [ { @@ -68,7 +69,6 @@ expression: response "ownership_model": "single", "owner": "9PacVenjPyQYiWBha89UYRM1nn6mf9bGY7vi32zY6DLn" }, - "supply": null, "mutable": true, "burnt": false }, @@ -138,7 +138,6 @@ expression: response "ownership_model": "single", "owner": "3H3d3hfpZVVdVwuFAxDtDSFN2AdR7kwiDA3ynbnbkhc9" }, - "supply": null, "mutable": true, "burnt": false } diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_get_asset_batch-only-2-different-2.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_get_asset_batch-only-2-different-2.snap index 36c9961f9..565f843d4 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_get_asset_batch-only-2-different-2.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_get_asset_batch-only-2-different-2.snap @@ -1,6 +1,7 @@ --- source: integration_tests/tests/integration_tests/regular_nft_tests.rs expression: response +snapshot_kind: text --- [ { @@ -68,7 +69,6 @@ expression: response "ownership_model": "single", "owner": "9PacVenjPyQYiWBha89UYRM1nn6mf9bGY7vi32zY6DLn" }, - "supply": null, "mutable": true, "burnt": false }, @@ -137,7 +137,6 @@ expression: response "ownership_model": "single", "owner": "3H3d3hfpZVVdVwuFAxDtDSFN2AdR7kwiDA3ynbnbkhc9" }, - "supply": null, "mutable": true, "burnt": false } diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_get_asset_batch-only-2.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_get_asset_batch-only-2.snap index f07052af1..7647ef26c 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_get_asset_batch-only-2.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_get_asset_batch-only-2.snap @@ -1,6 +1,7 @@ --- source: integration_tests/tests/integration_tests/regular_nft_tests.rs expression: response +snapshot_kind: text --- [ { @@ -68,7 +69,6 @@ expression: response "ownership_model": "single", "owner": "BaBQKh34KrqZzd4ifSHQYMf86HiBGASN6TWUi1ZwfyKv" }, - "supply": null, "mutable": true, "burnt": false }, @@ -137,7 +137,6 @@ expression: response "ownership_model": "single", "owner": "9PacVenjPyQYiWBha89UYRM1nn6mf9bGY7vi32zY6DLn" }, - "supply": null, "mutable": true, "burnt": false } diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_get_asset_by_group.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_get_asset_by_group.snap index 87920f33b..ce44d4bc4 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_get_asset_by_group.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_get_asset_by_group.snap @@ -1,6 +1,7 @@ --- source: integration_tests/tests/integration_tests/regular_nft_tests.rs expression: response +snapshot_kind: text --- { "total": 1, @@ -77,7 +78,6 @@ expression: response "ownership_model": "single", "owner": "9qUcfdADyrrTSetFjNjF9Ro7LKAqzJkzZV6WKLHfv5MU" }, - "supply": null, "mutable": true, "burnt": false } diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_search_assets.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_search_assets.snap index bd321f698..415fdbb43 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_search_assets.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__regular_nft_tests__reg_search_assets.snap @@ -72,7 +72,6 @@ expression: response "ownership_model": "single", "owner": "6Cr66AabRYymhZgYQSfTCo6FVpH18wXrMZswAbcErpyX" }, - "supply": null, "mutable": true, "burnt": false } diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_by_authority_with_show_fungible.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_by_authority_with_show_fungible.snap new file mode 100644 index 000000000..9481283d0 --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_by_authority_with_show_fungible.snap @@ -0,0 +1,87 @@ +--- +source: integration_tests/tests/integration_tests/show_fungible_flag_tests.rs +expression: response +snapshot_kind: text +--- +{ + "total": 1, + "limit": 1000, + "cursor": "AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM", + "items": [ + { + "interface": "ProgrammableNFT", + "id": "AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://madlads.s3.us-west-2.amazonaws.com/json/1983.json", + "files": [], + "metadata": { + "name": "Mad Lads #1983", + "symbol": "MAD", + "token_standard": "ProgrammableNonFungible" + }, + "links": {} + }, + "authorities": [ + { + "address": "2RtGg6fsFiiF1EQzHqbd66AhW7R5bWeQGpTbv2UMkCdW", + "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": "J1S9H3QjnRtBbbuD4HjPV6RpRhwuk4zKbxsnCHuTgh9w" + } + ], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.042, + "basis_points": 420, + "primary_sale_happened": true, + "locked": false + }, + "creators": [ + { + "address": "5XvhfmRjwXkGp3jHGmaKpqeerNYjkuZZBYLVQYdeVcRv", + "share": 0, + "verified": true + }, + { + "address": "2RtGg6fsFiiF1EQzHqbd66AhW7R5bWeQGpTbv2UMkCdW", + "share": 100, + "verified": true + } + ], + "ownership": { + "frozen": true, + "delegated": true, + "delegate": "BPB5idZgbA1DG4XEmnKs62AADRZFf3jY7Kr9mpMGyKPi", + "ownership_model": "single", + "owner": "GqPnSDXwp4JFtKS7YZ2HERgBbYLKpKVYy9TpVunzLRa9" + }, + "mutable": true, + "burnt": false, + "token_info": { + "supply": 1, + "decimals": 0, + "token_program": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "mint_authority": "FAzbjKo66M3tKhkKqegmWFaYr93FB74B1ChEBdFyKcip", + "freeze_authority": "FAzbjKo66M3tKhkKqegmWFaYr93FB74B1ChEBdFyKcip" + } + } + ] +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_by_creator_with_show_fungible.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_by_creator_with_show_fungible.snap new file mode 100644 index 000000000..9481283d0 --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_by_creator_with_show_fungible.snap @@ -0,0 +1,87 @@ +--- +source: integration_tests/tests/integration_tests/show_fungible_flag_tests.rs +expression: response +snapshot_kind: text +--- +{ + "total": 1, + "limit": 1000, + "cursor": "AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM", + "items": [ + { + "interface": "ProgrammableNFT", + "id": "AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://madlads.s3.us-west-2.amazonaws.com/json/1983.json", + "files": [], + "metadata": { + "name": "Mad Lads #1983", + "symbol": "MAD", + "token_standard": "ProgrammableNonFungible" + }, + "links": {} + }, + "authorities": [ + { + "address": "2RtGg6fsFiiF1EQzHqbd66AhW7R5bWeQGpTbv2UMkCdW", + "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": "J1S9H3QjnRtBbbuD4HjPV6RpRhwuk4zKbxsnCHuTgh9w" + } + ], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.042, + "basis_points": 420, + "primary_sale_happened": true, + "locked": false + }, + "creators": [ + { + "address": "5XvhfmRjwXkGp3jHGmaKpqeerNYjkuZZBYLVQYdeVcRv", + "share": 0, + "verified": true + }, + { + "address": "2RtGg6fsFiiF1EQzHqbd66AhW7R5bWeQGpTbv2UMkCdW", + "share": 100, + "verified": true + } + ], + "ownership": { + "frozen": true, + "delegated": true, + "delegate": "BPB5idZgbA1DG4XEmnKs62AADRZFf3jY7Kr9mpMGyKPi", + "ownership_model": "single", + "owner": "GqPnSDXwp4JFtKS7YZ2HERgBbYLKpKVYy9TpVunzLRa9" + }, + "mutable": true, + "burnt": false, + "token_info": { + "supply": 1, + "decimals": 0, + "token_program": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "mint_authority": "FAzbjKo66M3tKhkKqegmWFaYr93FB74B1ChEBdFyKcip", + "freeze_authority": "FAzbjKo66M3tKhkKqegmWFaYr93FB74B1ChEBdFyKcip" + } + } + ] +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_by_owner_with_show_fungible.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_by_owner_with_show_fungible.snap new file mode 100644 index 000000000..9481283d0 --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_by_owner_with_show_fungible.snap @@ -0,0 +1,87 @@ +--- +source: integration_tests/tests/integration_tests/show_fungible_flag_tests.rs +expression: response +snapshot_kind: text +--- +{ + "total": 1, + "limit": 1000, + "cursor": "AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM", + "items": [ + { + "interface": "ProgrammableNFT", + "id": "AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://madlads.s3.us-west-2.amazonaws.com/json/1983.json", + "files": [], + "metadata": { + "name": "Mad Lads #1983", + "symbol": "MAD", + "token_standard": "ProgrammableNonFungible" + }, + "links": {} + }, + "authorities": [ + { + "address": "2RtGg6fsFiiF1EQzHqbd66AhW7R5bWeQGpTbv2UMkCdW", + "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": "J1S9H3QjnRtBbbuD4HjPV6RpRhwuk4zKbxsnCHuTgh9w" + } + ], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.042, + "basis_points": 420, + "primary_sale_happened": true, + "locked": false + }, + "creators": [ + { + "address": "5XvhfmRjwXkGp3jHGmaKpqeerNYjkuZZBYLVQYdeVcRv", + "share": 0, + "verified": true + }, + { + "address": "2RtGg6fsFiiF1EQzHqbd66AhW7R5bWeQGpTbv2UMkCdW", + "share": 100, + "verified": true + } + ], + "ownership": { + "frozen": true, + "delegated": true, + "delegate": "BPB5idZgbA1DG4XEmnKs62AADRZFf3jY7Kr9mpMGyKPi", + "ownership_model": "single", + "owner": "GqPnSDXwp4JFtKS7YZ2HERgBbYLKpKVYy9TpVunzLRa9" + }, + "mutable": true, + "burnt": false, + "token_info": { + "supply": 1, + "decimals": 0, + "token_program": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "mint_authority": "FAzbjKo66M3tKhkKqegmWFaYr93FB74B1ChEBdFyKcip", + "freeze_authority": "FAzbjKo66M3tKhkKqegmWFaYr93FB74B1ChEBdFyKcip" + } + } + ] +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_with_show_fungible_scenario_1.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_with_show_fungible_scenario_1.snap new file mode 100644 index 000000000..b0a8c7016 --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_with_show_fungible_scenario_1.snap @@ -0,0 +1,80 @@ +--- +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": true, + "delegated": false, + "delegate": null, + "ownership_model": "single", + "owner": "J1ep1LizHMU3Bf1GKkWePGHU3Qwwzw6FvwW5ySFWdCkn" + }, + "mutable": true, + "burnt": false, + "token_info": { + "supply": 1, + "decimals": 0, + "token_program": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "mint_authority": "EwSfdqoZPBW6JJN1SBkM2pPgpihDVbByuxKdmiXurxYF", + "freeze_authority": "EwSfdqoZPBW6JJN1SBkM2pPgpihDVbByuxKdmiXurxYF" + } +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_with_show_fungible_scenario_2.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_with_show_fungible_scenario_2.snap new file mode 100644 index 000000000..8b1ca31c0 --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_with_show_fungible_scenario_2.snap @@ -0,0 +1,80 @@ +--- +source: integration_tests/tests/integration_tests/show_fungible_flag_tests.rs +expression: response +snapshot_kind: text +--- +{ + "interface": "ProgrammableNFT", + "id": "AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://madlads.s3.us-west-2.amazonaws.com/json/1983.json", + "files": [], + "metadata": { + "name": "Mad Lads #1983", + "symbol": "MAD", + "token_standard": "ProgrammableNonFungible" + }, + "links": {} + }, + "authorities": [ + { + "address": "2RtGg6fsFiiF1EQzHqbd66AhW7R5bWeQGpTbv2UMkCdW", + "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": "J1S9H3QjnRtBbbuD4HjPV6RpRhwuk4zKbxsnCHuTgh9w" + } + ], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.042, + "basis_points": 420, + "primary_sale_happened": true, + "locked": false + }, + "creators": [ + { + "address": "5XvhfmRjwXkGp3jHGmaKpqeerNYjkuZZBYLVQYdeVcRv", + "share": 0, + "verified": true + }, + { + "address": "2RtGg6fsFiiF1EQzHqbd66AhW7R5bWeQGpTbv2UMkCdW", + "share": 100, + "verified": true + } + ], + "ownership": { + "frozen": true, + "delegated": true, + "delegate": "BPB5idZgbA1DG4XEmnKs62AADRZFf3jY7Kr9mpMGyKPi", + "ownership_model": "single", + "owner": "GqPnSDXwp4JFtKS7YZ2HERgBbYLKpKVYy9TpVunzLRa9" + }, + "mutable": true, + "burnt": false, + "token_info": { + "supply": 1, + "decimals": 0, + "token_program": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "mint_authority": "FAzbjKo66M3tKhkKqegmWFaYr93FB74B1ChEBdFyKcip", + "freeze_authority": "FAzbjKo66M3tKhkKqegmWFaYr93FB74B1ChEBdFyKcip" + } +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_with_show_fungible_scenario_3.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_with_show_fungible_scenario_3.snap new file mode 100644 index 000000000..684e91a0b --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_with_show_fungible_scenario_3.snap @@ -0,0 +1,203 @@ +--- +source: integration_tests/tests/integration_tests/show_fungible_flag_tests.rs +expression: response +snapshot_kind: text +--- +{ + "interface": "FungibleToken", + "id": "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://token-metadata.paxos.com/pyusd_metadata/prod/solana/pyusd_metadata.json", + "files": [], + "metadata": { + "name": "PayPal USD", + "symbol": "PYUSD" + }, + "links": {} + }, + "authorities": [], + "compression": { + "eligible": false, + "compressed": false, + "data_hash": "", + "creator_hash": "", + "asset_hash": "", + "tree": "", + "seq": 0, + "leaf_id": 0 + }, + "grouping": [], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.0, + "basis_points": 0, + "primary_sale_happened": false, + "locked": false + }, + "creators": [], + "ownership": { + "frozen": false, + "delegated": false, + "delegate": null, + "ownership_model": "token", + "owner": "" + }, + "mutable": true, + "burnt": false, + "token_info": { + "supply": 177833330159913, + "decimals": 6, + "token_program": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb", + "mint_authority": "22mKJkKjGEQ3rampp5YKaSsaYZ52BUkcnUN6evXGsXzz", + "freeze_authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk" + }, + "mint_extensions": { + "metadata": { + "uri": "https://token-metadata.paxos.com/pyusd_metadata/prod/solana/pyusd_metadata.json", + "mint": "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo", + "name": "PayPal USD", + "symbol": "PYUSD", + "update_authority": "9nEfZqzTP3dfVWmzQy54TzsZqSQqDFVW4PhXdG9vYCVD", + "additional_metadata": [] + }, + "transfer_hook": { + "authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk", + "program_id": null + }, + "metadata_pointer": { + "metadata_address": "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo" + }, + "permanent_delegate": { + "delegate": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk" + }, + "transfer_fee_config": { + "withheld_amount": 0, + "newer_transfer_fee": { + "epoch": 605, + "maximum_fee": 0, + "transfer_fee_basis_points": 0 + }, + "older_transfer_fee": { + "epoch": 605, + "maximum_fee": 0, + "transfer_fee_basis_points": 0 + }, + "withdraw_withheld_authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk", + "transfer_fee_config_authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk" + }, + "mint_close_authority": { + "close_authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk" + }, + "confidential_transfer_mint": { + "authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk", + "auditor_elgamal_pubkey": null, + "auto_approve_new_accounts": false + }, + "confidential_transfer_fee_config": { + "authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk", + "withheld_amount": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "harvest_to_mint_enabled": true, + "withdraw_withheld_authority_elgamal_pubkey": [ + 28, + 55, + 230, + 67, + 59, + 115, + 4, + 221, + 130, + 115, + 122, + 228, + 13, + 155, + 139, + 243, + 196, + 159, + 91, + 14, + 108, + 73, + 168, + 213, + 51, + 40, + 179, + 229, + 6, + 144, + 28, + 87 + ] + } + } +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_with_show_fungible_scenario_4.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_with_show_fungible_scenario_4.snap new file mode 100644 index 000000000..f2605ec84 --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__show_fungible_flag_tests__get_asset_with_show_fungible_scenario_4.snap @@ -0,0 +1,63 @@ +--- +source: integration_tests/tests/integration_tests/show_fungible_flag_tests.rs +expression: response +snapshot_kind: text +--- +{ + "interface": "FungibleToken", + "id": "J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://storage.googleapis.com/token-metadata/JitoSOL.json", + "files": [], + "metadata": { + "name": "Jito Staked SOL", + "symbol": "JitoSOL", + "token_standard": "Fungible" + }, + "links": {} + }, + "authorities": [ + { + "address": "EDGARWktv3nDxRYjufjdbZmryqGXceaFPoPpbUzdpqED", + "scopes": [ + "full" + ] + } + ], + "compression": { + "eligible": false, + "compressed": false, + "data_hash": "", + "creator_hash": "", + "asset_hash": "", + "tree": "", + "seq": 0, + "leaf_id": 0 + }, + "grouping": [], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.0, + "basis_points": 0, + "primary_sale_happened": false, + "locked": false + }, + "creators": [], + "ownership": { + "frozen": false, + "delegated": false, + "delegate": null, + "ownership_model": "token", + "owner": "" + }, + "mutable": true, + "burnt": false, + "token_info": { + "supply": 12434210592536617, + "decimals": 9, + "token_program": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "mint_authority": "6iQKfEyhr3bZMotVkW6beNZz5CPAkiwvgV2CTje9pVSS" + } +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__show_inscription_flag_tests__get_asset_with_show_inscription_scenario_1.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__show_inscription_flag_tests__get_asset_with_show_inscription_scenario_1.snap new file mode 100644 index 000000000..62373341d --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__show_inscription_flag_tests__get_asset_with_show_inscription_scenario_1.snap @@ -0,0 +1,78 @@ +--- +source: integration_tests/tests/integration_tests/show_inscription_flag_tests.rs +expression: response +snapshot_kind: text +--- +{ + "interface": "V1_NFT", + "id": "9FkS3kZV4MoGps14tUSp7iVnizGbxcK4bDEhSoF5oYAZ", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://arweave.net/qJdjeP8XFfYIG6z5pJ-3RsZR2EcbgILX_ot-b2fEC0g", + "files": [], + "metadata": { + "name": "punk2491", + "symbol": "Symbol", + "token_standard": "NonFungible" + }, + "links": {} + }, + "authorities": [ + { + "address": "BVk6Bvxa9v6Y32o7KGPhYV4CU9pmG2K7nAYc7mDejsGM", + "scopes": [ + "full" + ] + } + ], + "compression": { + "eligible": false, + "compressed": false, + "data_hash": "", + "creator_hash": "", + "asset_hash": "", + "tree": "", + "seq": 0, + "leaf_id": 0 + }, + "grouping": [], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.08, + "basis_points": 800, + "primary_sale_happened": false, + "locked": false + }, + "creators": [ + { + "address": "BVk6Bvxa9v6Y32o7KGPhYV4CU9pmG2K7nAYc7mDejsGM", + "share": 100, + "verified": true + } + ], + "ownership": { + "frozen": false, + "delegated": false, + "delegate": null, + "ownership_model": "single", + "owner": "" + }, + "supply": { + "print_max_supply": 0, + "print_current_supply": 0, + "edition_nonce": 252 + }, + "mutable": true, + "burnt": false, + "inscription": { + "authority": "11111111111111111111111111111111", + "root": "9FkS3kZV4MoGps14tUSp7iVnizGbxcK4bDEhSoF5oYAZ", + "inscription_data": "4Q18N6XrfJHgDbRTaHJR328jN9dixCLQAQhDsTsRzg3v", + "content": "image/net/riupjyro3lsvkb_listajh0jdsrsjmnyhusxvznycqw", + "encoding": "base64", + "order": 1733, + "size": 202, + "validation_hash": "7fa0041483b92f5a0448067ecef9beca2192b13bfe86fbd53a0024e84fcea652" + } +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__test_get_assets_with_multiple_same_ids__get_assets_with_multiple_same_ids.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__test_get_assets_with_multiple_same_ids__get_assets_with_multiple_same_ids.snap new file mode 100644 index 000000000..e856e4c02 --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__test_get_assets_with_multiple_same_ids__get_assets_with_multiple_same_ids.snap @@ -0,0 +1,138 @@ +--- +source: integration_tests/tests/integration_tests/test_get_assets_with_multiple_same_ids.rs +expression: response +snapshot_kind: text +--- +[ + { + "interface": "ProgrammableNFT", + "id": "F9Lw3ki3hJ7PF9HQXsBzoY8GyE6sPoEZZdXJBsTTD2rk", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://madlads.s3.us-west-2.amazonaws.com/json/8420.json", + "files": [], + "metadata": { + "name": "Mad Lads #8420", + "symbol": "MAD", + "token_standard": "ProgrammableNonFungible" + }, + "links": {} + }, + "authorities": [ + { + "address": "2RtGg6fsFiiF1EQzHqbd66AhW7R5bWeQGpTbv2UMkCdW", + "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": "J1S9H3QjnRtBbbuD4HjPV6RpRhwuk4zKbxsnCHuTgh9w" + } + ], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.042, + "basis_points": 420, + "primary_sale_happened": true, + "locked": false + }, + "creators": [ + { + "address": "5XvhfmRjwXkGp3jHGmaKpqeerNYjkuZZBYLVQYdeVcRv", + "share": 0, + "verified": true + }, + { + "address": "2RtGg6fsFiiF1EQzHqbd66AhW7R5bWeQGpTbv2UMkCdW", + "share": 100, + "verified": true + } + ], + "ownership": { + "frozen": false, + "delegated": false, + "delegate": null, + "ownership_model": "single", + "owner": "" + }, + "mutable": true, + "burnt": false + }, + { + "interface": "V1_NFT", + "id": "JEKKtnGvjiZ8GtATnMVgadHU41AuTbFkMW8oD2tdyV9X", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://nftstorage.link/ipfs/bafkreidgvjw2atmkw2jzkkfi56arfrzaicrebzw5xwfkz3b67fq5gbvlre", + "files": [], + "metadata": { + "name": "TURTLES", + "symbol": "TURTLES", + "token_standard": "NonFungible" + }, + "links": {} + }, + "authorities": [ + { + "address": "J4tNLYMTegHE9nVjpRM17tf1EYwJnA9Crfn3KytRNcGv", + "scopes": [ + "full" + ] + } + ], + "compression": { + "eligible": false, + "compressed": false, + "data_hash": "", + "creator_hash": "", + "asset_hash": "", + "tree": "", + "seq": 0, + "leaf_id": 0 + }, + "grouping": [], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.0, + "basis_points": 0, + "primary_sale_happened": true, + "locked": false + }, + "creators": [ + { + "address": "J4tNLYMTegHE9nVjpRM17tf1EYwJnA9Crfn3KytRNcGv", + "share": 100, + "verified": true + } + ], + "ownership": { + "frozen": false, + "delegated": false, + "delegate": null, + "ownership_model": "single", + "owner": "" + }, + "supply": { + "print_max_supply": 0, + "print_current_supply": 0, + "edition_nonce": 253 + }, + "mutable": false, + "burnt": false + } +] diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__test_show_collection_metadata_option__get_asset_with_show_collection_metadata_option.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__test_show_collection_metadata_option__get_asset_with_show_collection_metadata_option.snap new file mode 100644 index 000000000..e49fdf0cd --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__test_show_collection_metadata_option__get_asset_with_show_collection_metadata_option.snap @@ -0,0 +1,74 @@ +--- +source: integration_tests/tests/integration_tests/test_show_collection_metadata_option.rs +expression: response +snapshot_kind: text +--- +{ + "interface": "ProgrammableNFT", + "id": "AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://madlads.s3.us-west-2.amazonaws.com/json/1983.json", + "files": [], + "metadata": { + "name": "Mad Lads #1983", + "symbol": "MAD", + "token_standard": "ProgrammableNonFungible" + }, + "links": {} + }, + "authorities": [ + { + "address": "2RtGg6fsFiiF1EQzHqbd66AhW7R5bWeQGpTbv2UMkCdW", + "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": "J1S9H3QjnRtBbbuD4HjPV6RpRhwuk4zKbxsnCHuTgh9w", + "collection_metadata": {} + } + ], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.042, + "basis_points": 420, + "primary_sale_happened": true, + "locked": false + }, + "creators": [ + { + "address": "5XvhfmRjwXkGp3jHGmaKpqeerNYjkuZZBYLVQYdeVcRv", + "share": 0, + "verified": true + }, + { + "address": "2RtGg6fsFiiF1EQzHqbd66AhW7R5bWeQGpTbv2UMkCdW", + "share": 100, + "verified": true + } + ], + "ownership": { + "frozen": true, + "delegated": true, + "delegate": "BPB5idZgbA1DG4XEmnKs62AADRZFf3jY7Kr9mpMGyKPi", + "ownership_model": "single", + "owner": "GqPnSDXwp4JFtKS7YZ2HERgBbYLKpKVYy9TpVunzLRa9" + }, + "mutable": true, + "burnt": false +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__test_show_zero_balance_filter__show_zero_balance_filter_being_disabled.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__test_show_zero_balance_filter__show_zero_balance_filter_being_disabled.snap new file mode 100644 index 000000000..f2a5d1a10 --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__test_show_zero_balance_filter__show_zero_balance_filter_being_disabled.snap @@ -0,0 +1,24 @@ +--- +source: integration_tests/tests/integration_tests/test_show_zero_balance_filter.rs +expression: response +snapshot_kind: text +--- +{ + "total": 1, + "limit": 1000, + "token_accounts": [ + { + "address": "CyqarC6hyNYvb3EDueyeYrnGeAUjCDtMvWrbtdAnA53a", + "mint": "7Y5WQ2e3FummR2DebrqP8caC64QvXzpnhSTNWjNabxWn", + "amount": 1, + "owner": "2oerfxddTpK5hWAmCMYB6fr9WvNrjEH54CHCWK8sAq7g", + "frozen": true, + "delegate": "D98f1ebFe6kfZTcztLo1iPeKAwogbWHAgXzgSpdRDiu7", + "delegated_amount": 1, + "close_authority": null, + "extensions": null + } + ], + "cursor": null, + "errors": [] +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__test_show_zero_balance_filter__show_zero_balance_filter_being_enabled.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__test_show_zero_balance_filter__show_zero_balance_filter_being_enabled.snap new file mode 100644 index 000000000..c628cdebb --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__test_show_zero_balance_filter__show_zero_balance_filter_being_enabled.snap @@ -0,0 +1,35 @@ +--- +source: integration_tests/tests/integration_tests/test_show_zero_balance_filter.rs +expression: response +snapshot_kind: text +--- +{ + "total": 2, + "limit": 1000, + "token_accounts": [ + { + "address": "BE1CkzRjLTXAWcSVCaqzycwXsZ18Yuk3jMDMnPUoHjjS", + "mint": "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN", + "amount": 0, + "owner": "2oerfxddTpK5hWAmCMYB6fr9WvNrjEH54CHCWK8sAq7g", + "frozen": false, + "delegate": null, + "delegated_amount": 0, + "close_authority": null, + "extensions": null + }, + { + "address": "CyqarC6hyNYvb3EDueyeYrnGeAUjCDtMvWrbtdAnA53a", + "mint": "7Y5WQ2e3FummR2DebrqP8caC64QvXzpnhSTNWjNabxWn", + "amount": 1, + "owner": "2oerfxddTpK5hWAmCMYB6fr9WvNrjEH54CHCWK8sAq7g", + "frozen": true, + "delegate": "D98f1ebFe6kfZTcztLo1iPeKAwogbWHAgXzgSpdRDiu7", + "delegated_amount": 1, + "close_authority": null, + "extensions": null + } + ], + "cursor": null, + "errors": [] +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__token_accounts_tests__get_token_accounts_by_mint.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__token_accounts_tests__get_token_accounts_by_mint.snap new file mode 100644 index 000000000..461483ad2 --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__token_accounts_tests__get_token_accounts_by_mint.snap @@ -0,0 +1,24 @@ +--- +source: integration_tests/tests/integration_tests/token_accounts_tests.rs +expression: response +snapshot_kind: text +--- +{ + "total": 1, + "limit": 1000, + "token_accounts": [ + { + "address": "jKLTJu7nE1zLmC2J2xjVVBm4G7vJcKGCGQX36Jrsba2", + "mint": "wKocBVvHQoVaiwWoCs9JYSVye4YZRrv5Cucf7fDqnz1", + "amount": 1000000000000, + "owner": "CeviT1DTQLuicEB7yLeFkkAGmam5GnJssbGb7CML4Tgx", + "frozen": false, + "delegate": null, + "delegated_amount": 0, + "close_authority": null, + "extensions": null + } + ], + "cursor": null, + "errors": [] +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__token_accounts_tests__get_token_accounts_by_owner.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__token_accounts_tests__get_token_accounts_by_owner.snap new file mode 100644 index 000000000..e99e05b5e --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__token_accounts_tests__get_token_accounts_by_owner.snap @@ -0,0 +1,35 @@ +--- +source: integration_tests/tests/integration_tests/token_accounts_tests.rs +expression: response +snapshot_kind: text +--- +{ + "total": 2, + "limit": 1000, + "token_accounts": [ + { + "address": "jKLTJu7nE1zLmC2J2xjVVBm4G7vJcKGCGQX36Jrsba2", + "mint": "wKocBVvHQoVaiwWoCs9JYSVye4YZRrv5Cucf7fDqnz1", + "amount": 1000000000000, + "owner": "CeviT1DTQLuicEB7yLeFkkAGmam5GnJssbGb7CML4Tgx", + "frozen": false, + "delegate": null, + "delegated_amount": 0, + "close_authority": null, + "extensions": null + }, + { + "address": "3Pv9H5UzU8T9BwgutXrcn2wLohS1JUZuk3x8paiRyzui", + "mint": "F3D8Priw3BRecH36BuMubQHrTUn1QxmupLHEmmbZ4LXW", + "amount": 10000, + "owner": "CeviT1DTQLuicEB7yLeFkkAGmam5GnJssbGb7CML4Tgx", + "frozen": false, + "delegate": null, + "delegated_amount": 0, + "close_authority": null, + "extensions": null + } + ], + "cursor": null, + "errors": [] +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__token_extensions_tests__token_extensions_get_asset_scenario1.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__token_extensions_tests__token_extensions_get_asset_scenario1.snap new file mode 100644 index 000000000..3e6f1d5a1 --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__token_extensions_tests__token_extensions_get_asset_scenario1.snap @@ -0,0 +1,53 @@ +--- +source: integration_tests/tests/integration_tests/token_extensions_tests.rs +expression: response +snapshot_kind: text +--- +{ + "interface": "FungibleToken", + "id": "BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y", + "authorities": [], + "compression": { + "eligible": false, + "compressed": false, + "data_hash": "", + "creator_hash": "", + "asset_hash": "", + "tree": "", + "seq": 0, + "leaf_id": 0 + }, + "grouping": [], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.0, + "basis_points": 0, + "primary_sale_happened": false, + "locked": false + }, + "creators": [], + "ownership": { + "frozen": false, + "delegated": false, + "delegate": null, + "ownership_model": "token", + "owner": "" + }, + "mutable": true, + "burnt": false, + "mint_extensions": { + "metadata": { + "uri": "https://acme.com/demo.json", + "mint": "BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y", + "name": "DAS Dev", + "symbol": "DAS", + "update_authority": "Em34oqDQYQZ9b6ycPHD28K47mttrRsdNu1S1pgK6NtPL", + "additional_metadata": [] + }, + "metadata_pointer": { + "authority": "Em34oqDQYQZ9b6ycPHD28K47mttrRsdNu1S1pgK6NtPL", + "metadata_address": "BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y" + } + } +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__token_extensions_tests__token_extensions_get_asset_scenario2.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__token_extensions_tests__token_extensions_get_asset_scenario2.snap new file mode 100644 index 000000000..d56a5b03f --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__token_extensions_tests__token_extensions_get_asset_scenario2.snap @@ -0,0 +1,68 @@ +--- +source: integration_tests/tests/integration_tests/token_extensions_tests.rs +expression: response +snapshot_kind: text +--- +{ + "interface": "FungibleToken", + "id": "HVbpJAQGNpkgBaYBZQBR1t7yFdvaYVp2vCQQfKKEN4tM", + "authorities": [], + "compression": { + "eligible": false, + "compressed": false, + "data_hash": "", + "creator_hash": "", + "asset_hash": "", + "tree": "", + "seq": 0, + "leaf_id": 0 + }, + "grouping": [], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.0, + "basis_points": 0, + "primary_sale_happened": false, + "locked": false + }, + "creators": [], + "ownership": { + "frozen": false, + "delegated": false, + "delegate": null, + "ownership_model": "token", + "owner": "" + }, + "mutable": true, + "burnt": false, + "mint_extensions": { + "metadata": { + "uri": "https://token-metadata.paxos.com/usdp_metadata/prod/solana/usdp_metadata.json", + "mint": "HVbpJAQGNpkgBaYBZQBR1t7yFdvaYVp2vCQQfKKEN4tM", + "name": "Pax Dollar", + "symbol": "USDP", + "update_authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk", + "additional_metadata": [] + }, + "transfer_hook": { + "authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk", + "program_id": null + }, + "metadata_pointer": { + "authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk", + "metadata_address": "HVbpJAQGNpkgBaYBZQBR1t7yFdvaYVp2vCQQfKKEN4tM" + }, + "permanent_delegate": { + "delegate": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk" + }, + "mint_close_authority": { + "close_authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk" + }, + "confidential_transfer_mint": { + "authority": "2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk", + "auditor_elgamal_pubkey": null, + "auto_approve_new_accounts": false + } + } +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__token_type_test__search_asset_with_token_type_all.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__token_type_test__search_asset_with_token_type_all.snap new file mode 100644 index 000000000..6d58cd939 --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__token_type_test__search_asset_with_token_type_all.snap @@ -0,0 +1,148 @@ +--- +source: integration_tests/tests/integration_tests/token_type_test.rs +expression: response +snapshot_kind: text +--- +{ + "total": 2, + "limit": 2, + "page": 1, + "items": [ + { + "interface": "ProgrammableNFT", + "id": "8t77ShMViat27Sjphvi1FVPaGrhFcttPAkEnLCFp49Bo", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://cdn.hellomoon.io/public/silicons/metadata/1466.json", + "files": [], + "metadata": { + "name": "SILICON #1466", + "symbol": "SILI", + "token_standard": "ProgrammableNonFungible" + }, + "links": {} + }, + "authorities": [ + { + "address": "A2QW89tFNDkkdvJv671tdknAyA21u6hvS7HTUyeMWnf3", + "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": "HS1oygRKNBG1nMqjSmaBXSQqQ7apWr14gUU4pW3aDMCP" + } + ], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.05, + "basis_points": 500, + "primary_sale_happened": true, + "locked": false + }, + "creators": [ + { + "address": "8X2e7Lf3wmA9RPHpPH73kmTqqHHyZE9BcED6Y6TWaZCx", + "share": 0, + "verified": true + }, + { + "address": "5bTgyaCCRNCem3DZXxdRREyesduc6adqwks8rRWGXx8D", + "share": 100, + "verified": false + } + ], + "ownership": { + "frozen": true, + "delegated": true, + "delegate": "D98f1ebFe6kfZTcztLo1iPeKAwogbWHAgXzgSpdRDiu7", + "ownership_model": "single", + "owner": "2oerfxddTpK5hWAmCMYB6fr9WvNrjEH54CHCWK8sAq7g" + }, + "mutable": true, + "burnt": false + }, + { + "interface": "ProgrammableNFT", + "id": "42AYryUGNmJMe9ycBXZekkYvdTehgbtECHs7SLu5JJTB", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://cdn.hellomoon.io/public/silicons/metadata/2835.json", + "files": [], + "metadata": { + "name": "SILICON #2835", + "symbol": "SILI", + "token_standard": "ProgrammableNonFungible" + }, + "links": {} + }, + "authorities": [ + { + "address": "A2QW89tFNDkkdvJv671tdknAyA21u6hvS7HTUyeMWnf3", + "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": "HS1oygRKNBG1nMqjSmaBXSQqQ7apWr14gUU4pW3aDMCP" + } + ], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.05, + "basis_points": 500, + "primary_sale_happened": true, + "locked": false + }, + "creators": [ + { + "address": "8X2e7Lf3wmA9RPHpPH73kmTqqHHyZE9BcED6Y6TWaZCx", + "share": 0, + "verified": true + }, + { + "address": "5bTgyaCCRNCem3DZXxdRREyesduc6adqwks8rRWGXx8D", + "share": 100, + "verified": false + } + ], + "ownership": { + "frozen": true, + "delegated": true, + "delegate": "D98f1ebFe6kfZTcztLo1iPeKAwogbWHAgXzgSpdRDiu7", + "ownership_model": "single", + "owner": "2oerfxddTpK5hWAmCMYB6fr9WvNrjEH54CHCWK8sAq7g" + }, + "mutable": true, + "burnt": false + } + ] +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__token_type_test__search_asset_with_token_type_compressed.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__token_type_test__search_asset_with_token_type_compressed.snap new file mode 100644 index 000000000..59c7dbe8d --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__token_type_test__search_asset_with_token_type_compressed.snap @@ -0,0 +1,80 @@ +--- +source: integration_tests/tests/integration_tests/token_type_test.rs +expression: response +snapshot_kind: text +--- +{ + "total": 1, + "limit": 2, + "page": 1, + "items": [ + { + "interface": "V1_NFT", + "id": "7myVr8fEG52mZ3jAwgz88iQRWsuzuVR2nfH8n2AXnBxE", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://arweave.net/S40vvBVuCvZhAWI3kvk3QreUqVAvR0AaUDObOhB8WIY", + "files": [], + "metadata": { + "name": "Golden Azurite", + "symbol": "OEAs", + "token_standard": "NonFungible" + }, + "links": {} + }, + "authorities": [ + { + "address": "EDAR6p4AUbv9SpD1pDm3gxdSAivdqsHxsf6V9pBc532U", + "scopes": [ + "full" + ] + } + ], + "compression": { + "eligible": false, + "compressed": true, + "data_hash": "B2tu4duCUPequnXh7DxbMnLeLcACHbDCQn3g34s5Cvbx", + "creator_hash": "6UiSCAv4r66MALaqhNE7qdTK84qKk1yJqR4UYtT8qEQ1", + "asset_hash": "8EBnZHUKKB2Vdef34H4L3nxYKkf5RPwCkoHBVLAAM2zN", + "tree": "4r2zZHZvC4Se1KUcCcyCM4ZoFQNGZm2M5FMmUypFocAP", + "seq": 39, + "leaf_id": 5 + }, + "grouping": [ + { + "group_key": "collection", + "group_value": "BwwjnxTHeVWdFieDWmoezta19q1NiwcNNyoon9S38bkM" + } + ], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.05, + "basis_points": 500, + "primary_sale_happened": true, + "locked": false + }, + "creators": [ + { + "address": "4gETqgEwFLkXX9yk6qBszA6LMjC2kRyyERXsAr2rwhwf", + "share": 100, + "verified": false + } + ], + "ownership": { + "frozen": false, + "delegated": false, + "delegate": null, + "ownership_model": "single", + "owner": "53VVFtLzzi3nL2p1QF591PAB8rbcbsirYepwUphtHU9Q" + }, + "supply": { + "print_max_supply": 0, + "print_current_supply": 0, + "edition_nonce": null + }, + "mutable": true, + "burnt": false + } + ] +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__token_type_test__search_asset_with_token_type_fungible.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__token_type_test__search_asset_with_token_type_fungible.snap new file mode 100644 index 000000000..3a0362762 --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__token_type_test__search_asset_with_token_type_fungible.snap @@ -0,0 +1,64 @@ +--- +source: integration_tests/tests/integration_tests/token_type_test.rs +expression: response +snapshot_kind: text +--- +{ + "total": 1, + "limit": 1, + "page": 1, + "items": [ + { + "interface": "FungibleToken", + "id": "7EYnhQoR9YM3N7UoaKRoA44Uy8JeaZV3qyouov87awMs", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://gateway.irys.xyz/P8X64pGutyX5eyTpQmqZr3H4_Lqhm0IYxr5SyzFFNek", + "files": [], + "metadata": { + "name": "Silly Dragon", + "symbol": "SILLY", + "token_standard": "Fungible" + }, + "links": {} + }, + "authorities": [ + { + "address": "38qZKCqcphT5wDrVNJGHYcuenjEtEFPitvrqvMFQkPu7", + "scopes": [ + "full" + ] + } + ], + "compression": { + "eligible": false, + "compressed": false, + "data_hash": "", + "creator_hash": "", + "asset_hash": "", + "tree": "", + "seq": 0, + "leaf_id": 0 + }, + "grouping": [], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.0, + "basis_points": 0, + "primary_sale_happened": true, + "locked": false + }, + "creators": [], + "ownership": { + "frozen": false, + "delegated": false, + "delegate": null, + "ownership_model": "token", + "owner": "" + }, + "mutable": true, + "burnt": false + } + ] +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__token_type_test__search_asset_with_token_type_non_fungible.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__token_type_test__search_asset_with_token_type_non_fungible.snap new file mode 100644 index 000000000..3b14b1809 --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__token_type_test__search_asset_with_token_type_non_fungible.snap @@ -0,0 +1,148 @@ +--- +source: integration_tests/tests/integration_tests/token_type_test.rs +expression: response +snapshot_kind: text +--- +{ + "total": 2, + "limit": 2, + "page": 1, + "items": [ + { + "interface": "ProgrammableNFT", + "id": "AH6VcoSbCGGv8BHeN7K766VUWMcdFRTaXpLvGTLSdAmk", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://cdn.hellomoon.io/public/silicons/metadata/4515.json", + "files": [], + "metadata": { + "name": "SILICON #4515", + "symbol": "SILI", + "token_standard": "ProgrammableNonFungible" + }, + "links": {} + }, + "authorities": [ + { + "address": "A2QW89tFNDkkdvJv671tdknAyA21u6hvS7HTUyeMWnf3", + "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": "HS1oygRKNBG1nMqjSmaBXSQqQ7apWr14gUU4pW3aDMCP" + } + ], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.05, + "basis_points": 500, + "primary_sale_happened": true, + "locked": false + }, + "creators": [ + { + "address": "8X2e7Lf3wmA9RPHpPH73kmTqqHHyZE9BcED6Y6TWaZCx", + "share": 0, + "verified": true + }, + { + "address": "5bTgyaCCRNCem3DZXxdRREyesduc6adqwks8rRWGXx8D", + "share": 100, + "verified": false + } + ], + "ownership": { + "frozen": true, + "delegated": true, + "delegate": "D98f1ebFe6kfZTcztLo1iPeKAwogbWHAgXzgSpdRDiu7", + "ownership_model": "single", + "owner": "2oerfxddTpK5hWAmCMYB6fr9WvNrjEH54CHCWK8sAq7g" + }, + "mutable": true, + "burnt": false + }, + { + "interface": "ProgrammableNFT", + "id": "8t77ShMViat27Sjphvi1FVPaGrhFcttPAkEnLCFp49Bo", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://cdn.hellomoon.io/public/silicons/metadata/1466.json", + "files": [], + "metadata": { + "name": "SILICON #1466", + "symbol": "SILI", + "token_standard": "ProgrammableNonFungible" + }, + "links": {} + }, + "authorities": [ + { + "address": "A2QW89tFNDkkdvJv671tdknAyA21u6hvS7HTUyeMWnf3", + "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": "HS1oygRKNBG1nMqjSmaBXSQqQ7apWr14gUU4pW3aDMCP" + } + ], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.05, + "basis_points": 500, + "primary_sale_happened": true, + "locked": false + }, + "creators": [ + { + "address": "8X2e7Lf3wmA9RPHpPH73kmTqqHHyZE9BcED6Y6TWaZCx", + "share": 0, + "verified": true + }, + { + "address": "5bTgyaCCRNCem3DZXxdRREyesduc6adqwks8rRWGXx8D", + "share": 100, + "verified": false + } + ], + "ownership": { + "frozen": true, + "delegated": true, + "delegate": "D98f1ebFe6kfZTcztLo1iPeKAwogbWHAgXzgSpdRDiu7", + "ownership_model": "single", + "owner": "2oerfxddTpK5hWAmCMYB6fr9WvNrjEH54CHCWK8sAq7g" + }, + "mutable": true, + "burnt": false + } + ] +} diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__token_type_test__search_asset_with_token_type_regular_nft.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__token_type_test__search_asset_with_token_type_regular_nft.snap new file mode 100644 index 000000000..d8ee5ff5b --- /dev/null +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__token_type_test__search_asset_with_token_type_regular_nft.snap @@ -0,0 +1,148 @@ +--- +source: integration_tests/tests/integration_tests/token_type_test.rs +expression: response +snapshot_kind: text +--- +{ + "total": 2, + "limit": 2, + "page": 1, + "items": [ + { + "interface": "ProgrammableNFT", + "id": "42AYryUGNmJMe9ycBXZekkYvdTehgbtECHs7SLu5JJTB", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://cdn.hellomoon.io/public/silicons/metadata/2835.json", + "files": [], + "metadata": { + "name": "SILICON #2835", + "symbol": "SILI", + "token_standard": "ProgrammableNonFungible" + }, + "links": {} + }, + "authorities": [ + { + "address": "A2QW89tFNDkkdvJv671tdknAyA21u6hvS7HTUyeMWnf3", + "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": "HS1oygRKNBG1nMqjSmaBXSQqQ7apWr14gUU4pW3aDMCP" + } + ], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.05, + "basis_points": 500, + "primary_sale_happened": true, + "locked": false + }, + "creators": [ + { + "address": "8X2e7Lf3wmA9RPHpPH73kmTqqHHyZE9BcED6Y6TWaZCx", + "share": 0, + "verified": true + }, + { + "address": "5bTgyaCCRNCem3DZXxdRREyesduc6adqwks8rRWGXx8D", + "share": 100, + "verified": false + } + ], + "ownership": { + "frozen": true, + "delegated": true, + "delegate": "D98f1ebFe6kfZTcztLo1iPeKAwogbWHAgXzgSpdRDiu7", + "ownership_model": "single", + "owner": "2oerfxddTpK5hWAmCMYB6fr9WvNrjEH54CHCWK8sAq7g" + }, + "mutable": true, + "burnt": false + }, + { + "interface": "ProgrammableNFT", + "id": "2w81QrLYTwSDkNwXgCqKAwrC1Tu6R9mh9BHcxys2Bup2", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://cdn.hellomoon.io/public/silicons/metadata/4685.json", + "files": [], + "metadata": { + "name": "SILICON #4685", + "symbol": "SILI", + "token_standard": "ProgrammableNonFungible" + }, + "links": {} + }, + "authorities": [ + { + "address": "A2QW89tFNDkkdvJv671tdknAyA21u6hvS7HTUyeMWnf3", + "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": "HS1oygRKNBG1nMqjSmaBXSQqQ7apWr14gUU4pW3aDMCP" + } + ], + "royalty": { + "royalty_model": "creators", + "target": null, + "percent": 0.05, + "basis_points": 500, + "primary_sale_happened": true, + "locked": false + }, + "creators": [ + { + "address": "8X2e7Lf3wmA9RPHpPH73kmTqqHHyZE9BcED6Y6TWaZCx", + "share": 0, + "verified": true + }, + { + "address": "5bTgyaCCRNCem3DZXxdRREyesduc6adqwks8rRWGXx8D", + "share": 100, + "verified": false + } + ], + "ownership": { + "frozen": true, + "delegated": true, + "delegate": "D98f1ebFe6kfZTcztLo1iPeKAwogbWHAgXzgSpdRDiu7", + "ownership_model": "single", + "owner": "2oerfxddTpK5hWAmCMYB6fr9WvNrjEH54CHCWK8sAq7g" + }, + "mutable": true, + "burnt": false + } + ] +} diff --git a/integration_tests/tests/integration_tests/test_get_assets_with_multiple_same_ids.rs b/integration_tests/tests/integration_tests/test_get_assets_with_multiple_same_ids.rs new file mode 100644 index 000000000..aebb1c8c2 --- /dev/null +++ b/integration_tests/tests/integration_tests/test_get_assets_with_multiple_same_ids.rs @@ -0,0 +1,42 @@ +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_assets_with_multiple_same_ids() { + let name = trim_test_name(function_name!()); + let setup = TestSetup::new(name.clone()).await; + + let seeds: Vec = seed_accounts([ + "F9Lw3ki3hJ7PF9HQXsBzoY8GyE6sPoEZZdXJBsTTD2rk", + "DZAZ3mGuq7nCYGzUyw4MiA74ysr15EfqLpzCzX2cRVng", + "JEKKtnGvjiZ8GtATnMVgadHU41AuTbFkMW8oD2tdyV9X", + "2ecGsTKbj7FecLwxTHaodZRFwza7m7LamqDG4YjczZMj", + ]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "ids": [ + "F9Lw3ki3hJ7PF9HQXsBzoY8GyE6sPoEZZdXJBsTTD2rk", + "F9Lw3ki3hJ7PF9HQXsBzoY8GyE6sPoEZZdXJBsTTD2rk", + "JEKKtnGvjiZ8GtATnMVgadHU41AuTbFkMW8oD2tdyV9X", + "JEKKtnGvjiZ8GtATnMVgadHU41AuTbFkMW8oD2tdyV9X" + ] + } + "#; + + let request: api::GetAssets = serde_json::from_str(request).unwrap(); + let response = setup.das_api.get_assets(request).await.unwrap(); + insta::assert_json_snapshot!(name, response); +} diff --git a/integration_tests/tests/integration_tests/test_show_collection_metadata_option.rs b/integration_tests/tests/integration_tests/test_show_collection_metadata_option.rs new file mode 100644 index 000000000..688448f51 --- /dev/null +++ b/integration_tests/tests/integration_tests/test_show_collection_metadata_option.rs @@ -0,0 +1,50 @@ +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_collection_metadata_option() { + let name = trim_test_name(function_name!()); + + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { + network: Some(Network::Mainnet), + }, + ) + .await; + + let seeds: Vec = seed_accounts([ + "AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM", + "7fXKY9tPpvYsdbSNyesUqo27WYC6ZsBEULdtngGHqLCK", + "8Xv3SpX94HHf32Apg4TeSeS3i2p6wuXeE8FBZr168Hti", + ]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "id": "AH6wj7T8Ke5nbukjtcobjjs1CDWUcQxndtnLkKAdrSrM", + "displayOptions" : { + "showCollectionMetadata": 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); +} diff --git a/integration_tests/tests/integration_tests/test_show_zero_balance_filter.rs b/integration_tests/tests/integration_tests/test_show_zero_balance_filter.rs new file mode 100644 index 000000000..e19f18d71 --- /dev/null +++ b/integration_tests/tests/integration_tests/test_show_zero_balance_filter.rs @@ -0,0 +1,83 @@ +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_show_zero_balance_filter_being_enabled() { + let name = trim_test_name(function_name!()); + + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { + network: Some(Network::Mainnet), + }, + ) + .await; + + let seeds: Vec = seed_accounts([ + "BE1CkzRjLTXAWcSVCaqzycwXsZ18Yuk3jMDMnPUoHjjS", + "CyqarC6hyNYvb3EDueyeYrnGeAUjCDtMvWrbtdAnA53a", + ]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "ownerAddress":"2oerfxddTpK5hWAmCMYB6fr9WvNrjEH54CHCWK8sAq7g", + "displayOptions": { + "showZeroBalance": true + } + } + "#; + + let request: api::GetTokenAccounts = serde_json::from_str(request).unwrap(); + let response = setup.das_api.get_token_accounts(request).await.unwrap(); + + insta::assert_json_snapshot!(name, response); +} + +#[tokio::test] +#[serial] +#[named] +async fn test_show_zero_balance_filter_being_disabled() { + let name = trim_test_name(function_name!()); + + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { + network: Some(Network::Mainnet), + }, + ) + .await; + + let seeds: Vec = seed_accounts([ + "BE1CkzRjLTXAWcSVCaqzycwXsZ18Yuk3jMDMnPUoHjjS", + "CyqarC6hyNYvb3EDueyeYrnGeAUjCDtMvWrbtdAnA53a", + ]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "ownerAddress":"2oerfxddTpK5hWAmCMYB6fr9WvNrjEH54CHCWK8sAq7g", + "displayOptions": { + "showZeroBalance": false + } + } + "#; + + let request: api::GetTokenAccounts = serde_json::from_str(request).unwrap(); + let response = setup.das_api.get_token_accounts(request).await.unwrap(); + + insta::assert_json_snapshot!(name, response); +} diff --git a/integration_tests/tests/integration_tests/token_accounts_tests.rs b/integration_tests/tests/integration_tests/token_accounts_tests.rs new file mode 100644 index 000000000..8a465e914 --- /dev/null +++ b/integration_tests/tests/integration_tests/token_accounts_tests.rs @@ -0,0 +1,74 @@ +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_token_accounts_by_mint() { + let name = trim_test_name(function_name!()); + + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { + network: Some(Network::Devnet), + }, + ) + .await; + + let seeds: Vec = seed_accounts(["jKLTJu7nE1zLmC2J2xjVVBm4G7vJcKGCGQX36Jrsba2"]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "mintAddress":"wKocBVvHQoVaiwWoCs9JYSVye4YZRrv5Cucf7fDqnz1" + } + "#; + + let request: api::GetTokenAccounts = serde_json::from_str(request).unwrap(); + let response = setup.das_api.get_token_accounts(request).await.unwrap(); + + insta::assert_json_snapshot!(name, response); +} + +#[tokio::test] +#[serial] +#[named] +async fn test_get_token_accounts_by_owner() { + let name = trim_test_name(function_name!()); + + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { + network: Some(Network::Devnet), + }, + ) + .await; + + let seeds: Vec = seed_accounts([ + "jKLTJu7nE1zLmC2J2xjVVBm4G7vJcKGCGQX36Jrsba2", + "3Pv9H5UzU8T9BwgutXrcn2wLohS1JUZuk3x8paiRyzui", + ]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "ownerAddress":"CeviT1DTQLuicEB7yLeFkkAGmam5GnJssbGb7CML4Tgx" + } + "#; + + let request: api::GetTokenAccounts = serde_json::from_str(request).unwrap(); + let response = setup.das_api.get_token_accounts(request).await.unwrap(); + + insta::assert_json_snapshot!(name, response); +} diff --git a/integration_tests/tests/integration_tests/token_type_test.rs b/integration_tests/tests/integration_tests/token_type_test.rs new file mode 100644 index 000000000..260d92567 --- /dev/null +++ b/integration_tests/tests/integration_tests/token_type_test.rs @@ -0,0 +1,185 @@ +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_search_asset_with_token_type_regular_nft() { + let name = trim_test_name(function_name!()); + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { + network: Some(Network::Mainnet), + }, + ) + .await; + + let seeds: Vec = seed_nfts([ + "42AYryUGNmJMe9ycBXZekkYvdTehgbtECHs7SLu5JJTB", + "2w81QrLYTwSDkNwXgCqKAwrC1Tu6R9mh9BHcxys2Bup2", + ]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "ownerAddress": "2oerfxddTpK5hWAmCMYB6fr9WvNrjEH54CHCWK8sAq7g", + "page": 1, + "limit": 2, + "tokenType": "Nft" + } + "#; + + let request: api::SearchAssets = serde_json::from_str(request).unwrap(); + let response = setup.das_api.search_assets(request).await.unwrap(); + insta::assert_json_snapshot!(name, response); +} + +#[tokio::test] +#[serial] +#[named] +async fn test_search_asset_with_token_type_non_fungible() { + let name = trim_test_name(function_name!()); + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { + network: Some(Network::Mainnet), + }, + ) + .await; + + let seeds: Vec = seed_nfts([ + "AH6VcoSbCGGv8BHeN7K766VUWMcdFRTaXpLvGTLSdAmk", + "8t77ShMViat27Sjphvi1FVPaGrhFcttPAkEnLCFp49Bo", + ]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "ownerAddress": "2oerfxddTpK5hWAmCMYB6fr9WvNrjEH54CHCWK8sAq7g", + "page": 1, + "limit": 2, + "tokenType": "NonFungible" + } + "#; + + let request: api::SearchAssets = serde_json::from_str(request).unwrap(); + let response = setup.das_api.search_assets(request).await.unwrap(); + insta::assert_json_snapshot!(name, response); +} + +#[tokio::test] +#[serial] +#[named] +async fn test_search_asset_with_token_type_compressed() { + let name = trim_test_name(function_name!()); + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { + network: Some(Network::Mainnet), + }, + ) + .await; + + let seeds: Vec = seed_txns([ + "4nKDSvw2kGpccZWLEPnfdP7J1SEexQFRP3xWc9NBtQ1qQeGu3bu5WnAdpcLbjQ4iyX6BQ5QGF69wevE8ZeeY5poA", + "4URwUGBjbsF7UBUYdSC546tnBy7nD67txsso8D9CR9kGLtbbYh9NkGw15tEp16LLasmJX5VQR4Seh8gDjTrtdpoC", + ]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "ownerAddress": "53VVFtLzzi3nL2p1QF591PAB8rbcbsirYepwUphtHU9Q", + "page": 1, + "limit": 2, + "tokenType": "Compressed" + } + "#; + + let request: api::SearchAssets = serde_json::from_str(request).unwrap(); + let response = setup.das_api.search_assets(request).await.unwrap(); + insta::assert_json_snapshot!(name, response); +} + +#[tokio::test] +#[serial] +#[named] +async fn test_search_asset_with_token_type_all() { + let name = trim_test_name(function_name!()); + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { + network: Some(Network::Mainnet), + }, + ) + .await; + + let seeds: Vec = seed_nfts([ + "42AYryUGNmJMe9ycBXZekkYvdTehgbtECHs7SLu5JJTB", + "8t77ShMViat27Sjphvi1FVPaGrhFcttPAkEnLCFp49Bo", + ]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "ownerAddress": "2oerfxddTpK5hWAmCMYB6fr9WvNrjEH54CHCWK8sAq7g", + "page": 1, + "limit": 2, + "tokenType": "All" + } + "#; + + let request: api::SearchAssets = serde_json::from_str(request).unwrap(); + let response = setup.das_api.search_assets(request).await.unwrap(); + insta::assert_json_snapshot!(name, response); +} + +#[tokio::test] +#[serial] +#[named] +async fn test_search_asset_with_token_type_fungible() { + let name = trim_test_name(function_name!()); + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { + network: Some(Network::Mainnet), + }, + ) + .await; + + let seeds: Vec = seed_accounts([ + "7EYnhQoR9YM3N7UoaKRoA44Uy8JeaZV3qyouov87awMs", + "7BajpcYgnxmWK91RhrfsdB3Tm83PcDwPvMC8ZinvtTY6", + "6BRNfDfdq1nKyU1TQiCEQLWyPtD8EwUH9Kt2ahsbidUx", + ]); + + apply_migrations_and_delete_data(setup.db.clone()).await; + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "ownerAddress": "2oerfxddTpK5hWAmCMYB6fr9WvNrjEH54CHCWK8sAq7g", + "page": 1, + "limit": 1, + "tokenType": "Fungible" + } + "#; + + let request: api::SearchAssets = serde_json::from_str(request).unwrap(); + let response = setup.das_api.search_assets(request).await.unwrap(); + insta::assert_json_snapshot!(name, response); +} diff --git a/metadata_json/src/worker.rs b/metadata_json/src/worker.rs index d72b73eb7..de799f4c1 100644 --- a/metadata_json/src/worker.rs +++ b/metadata_json/src/worker.rs @@ -34,6 +34,7 @@ impl From for Worker { } #[derive(thiserror::Error, Debug)] +#[allow(clippy::large_enum_variant)] pub enum WorkerError { #[error("send error: {0}")] Send(#[from] mpsc::error::SendError), diff --git a/migration/src/lib.rs b/migration/src/lib.rs index 7cee77f5e..211501cd3 100644 --- a/migration/src/lib.rs +++ b/migration/src/lib.rs @@ -38,11 +38,13 @@ mod m20240116_130744_add_update_metadata_ix; mod m20240117_120101_alter_creator_indices; mod m20240124_173104_add_tree_seq_index_to_cl_audits_v2; mod m20240124_181900_add_slot_updated_column_per_update_type; +mod m20240219_115532_add_extensions_column; mod m20240313_120101_add_mpl_core_plugins_columns; mod m20240319_120101_add_mpl_core_enum_vals; mod m20240320_120101_add_mpl_core_info_items; mod m20240520_120101_add_mpl_core_external_plugins_columns; mod m20240718_161232_change_supply_columns_to_numeric; +mod m20241119_060310_add_token_inscription_enum_variant; pub mod model; @@ -90,11 +92,13 @@ impl MigratorTrait for Migrator { Box::new(m20240117_120101_alter_creator_indices::Migration), Box::new(m20240124_173104_add_tree_seq_index_to_cl_audits_v2::Migration), Box::new(m20240124_181900_add_slot_updated_column_per_update_type::Migration), + Box::new(m20240219_115532_add_extensions_column::Migration), Box::new(m20240313_120101_add_mpl_core_plugins_columns::Migration), Box::new(m20240319_120101_add_mpl_core_enum_vals::Migration), Box::new(m20240320_120101_add_mpl_core_info_items::Migration), Box::new(m20240520_120101_add_mpl_core_external_plugins_columns::Migration), Box::new(m20240718_161232_change_supply_columns_to_numeric::Migration), + Box::new(m20241119_060310_add_token_inscription_enum_variant::Migration), ] } } diff --git a/migration/src/m20240219_115532_add_extensions_column.rs b/migration/src/m20240219_115532_add_extensions_column.rs new file mode 100644 index 000000000..d0414ea18 --- /dev/null +++ b/migration/src/m20240219_115532_add_extensions_column.rs @@ -0,0 +1,60 @@ +use sea_orm_migration::{ + prelude::*, + sea_orm::{ConnectionTrait, DatabaseBackend, Statement}, +}; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + let connection = manager.get_connection(); + + connection + .execute(Statement::from_string( + DatabaseBackend::Postgres, + "ALTER TABLE asset ADD COLUMN mint_extensions jsonb;".to_string(), + )) + .await?; + connection + .execute(Statement::from_string( + DatabaseBackend::Postgres, + "ALTER TABLE tokens ADD COLUMN extensions jsonb;".to_string(), + )) + .await?; + connection + .execute(Statement::from_string( + DatabaseBackend::Postgres, + "ALTER TABLE token_accounts ADD COLUMN extensions jsonb;".to_string(), + )) + .await?; + + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + let connection = manager.get_connection(); + + connection + .execute(Statement::from_string( + DatabaseBackend::Postgres, + "ALTER TABLE asset DROP COLUMN mint_extensions;".to_string(), + )) + .await?; + connection + .execute(Statement::from_string( + DatabaseBackend::Postgres, + "ALTER TABLE tokens DROP COLUMN extensions;".to_string(), + )) + .await?; + connection + .execute(Statement::from_string( + DatabaseBackend::Postgres, + "ALTER TABLE token_accounts DROP COLUMN extensions;".to_string(), + )) + .await?; + + Ok(()) + } +} diff --git a/migration/src/m20241119_060310_add_token_inscription_enum_variant.rs b/migration/src/m20241119_060310_add_token_inscription_enum_variant.rs new file mode 100644 index 000000000..1bdd6f8c3 --- /dev/null +++ b/migration/src/m20241119_060310_add_token_inscription_enum_variant.rs @@ -0,0 +1,25 @@ +use sea_orm::{ConnectionTrait, DatabaseBackend, Statement}; +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .get_connection() + .execute(Statement::from_string( + DatabaseBackend::Postgres, + "ALTER TYPE v1_account_attachments ADD VALUE IF NOT EXISTS 'token_inscription';" + .to_string(), + )) + .await?; + + Ok(()) + } + + async fn down(&self, _manager: &SchemaManager) -> Result<(), DbErr> { + Ok(()) + } +} diff --git a/nft_ingester/src/plerkle.rs b/nft_ingester/src/plerkle.rs index bef3d4ff6..446f558b1 100644 --- a/nft_ingester/src/plerkle.rs +++ b/nft_ingester/src/plerkle.rs @@ -17,7 +17,7 @@ pub enum PlerkleDeserializerError { pub struct PlerkleAccountInfo<'a>(pub plerkle_serialization::AccountInfo<'a>); -impl<'a> TryFrom> for AccountInfo { +impl TryFrom> for AccountInfo { type Error = PlerkleDeserializerError; fn try_from(value: PlerkleAccountInfo) -> Result { diff --git a/program_transformers/Cargo.toml b/program_transformers/Cargo.toml index da0848ced..4262824a5 100644 --- a/program_transformers/Cargo.toml +++ b/program_transformers/Cargo.toml @@ -30,6 +30,7 @@ sqlx = { workspace = true } thiserror = { workspace = true } tokio = { workspace = true, features = ["time"] } tracing = { workspace = true } +spl-token-2022 = {workspace = true, features = ["no-entrypoint"]} [lints] workspace = true diff --git a/program_transformers/src/asset_upserts.rs b/program_transformers/src/asset_upserts.rs index a8e155031..9ba7a80b8 100644 --- a/program_transformers/src/asset_upserts.rs +++ b/program_transformers/src/asset_upserts.rs @@ -44,65 +44,38 @@ pub async fn upsert_assets_token_account_columns, pub supply: Decimal, - pub supply_mint: Option>, - pub slot_updated_mint_account: u64, + pub slot_updated_mint_account: i64, + pub extensions: Option, } pub async fn upsert_assets_mint_account_columns( columns: AssetMintAccountColumns, txn_or_conn: &T, ) -> Result<(), DbErr> { - let owner_type = if columns.supply == Decimal::from(1) { - OwnerType::Single - } else { - OwnerType::Token - }; - let active_model = asset::ActiveModel { - id: Set(columns.mint), + id: Set(columns.mint.clone()), supply: Set(columns.supply), - supply_mint: Set(columns.supply_mint), - slot_updated_mint_account: Set(Some(columns.slot_updated_mint_account as i64)), - owner_type: Set(owner_type), + supply_mint: Set(Some(columns.mint.clone())), + slot_updated_mint_account: Set(Some(columns.slot_updated_mint_account)), + slot_updated: Set(Some(columns.slot_updated_mint_account)), + mint_extensions: Set(columns.extensions), + asset_data: Set(Some(columns.mint.clone())), + // assume every token is a fungible token when mint account is created + specification_asset_class: Set(Some(SpecificationAssetClass::FungibleToken)), + // // assume multiple ownership as we set asset class to fungible token + owner_type: Set(OwnerType::Token), ..Default::default() }; asset::Entity::insert(active_model) @@ -145,7 +118,9 @@ pub async fn upsert_assets_mint_account_columns, pub specification_asset_class: Option, + pub owner_type: OwnerType, pub royalty_amount: i32, pub asset_data: Option>, pub slot_updated_metadata_account: u64, @@ -218,6 +194,7 @@ pub async fn upsert_assets_metadata_account_columns( txn: &T, id: Vec, - creators: &Vec, + creators: &[Creator], slot_updated: i64, seq: i64, ) -> ProgramTransformerResult<()> diff --git a/program_transformers/src/lib.rs b/program_transformers/src/lib.rs index 0b75b5180..dab2fa0d8 100644 --- a/program_transformers/src/lib.rs +++ b/program_transformers/src/lib.rs @@ -4,6 +4,7 @@ use { error::{ProgramTransformerError, ProgramTransformerResult}, mpl_core_program::handle_mpl_core_account, token::handle_token_program_account, + token_inscription::handle_token_inscription_program_update, token_metadata::handle_token_metadata_account, }, blockbuster::{ @@ -11,7 +12,8 @@ use { program_handler::ProgramParser, programs::{ bubblegum::BubblegumParser, mpl_core_program::MplCoreParser, - token_account::TokenAccountParser, token_metadata::TokenMetadataParser, + token_account::TokenAccountParser, token_extensions::Token2022AccountParser, + token_inscriptions::TokenInscriptionParser, token_metadata::TokenMetadataParser, ProgramParseResult, }, }, @@ -21,12 +23,14 @@ use { TransactionTrait, }, serde::Deserialize, + serde_json::{Map, Value}, solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey, signature::Signature}, solana_transaction_status::InnerInstructions, sqlx::PgPool, std::collections::{HashMap, HashSet, VecDeque}, + token_extensions::handle_token_extensions_program_account, tokio::time::{sleep, Duration}, - tracing::{debug, error, info}, + tracing::{debug, error}, }; mod asset_upserts; @@ -34,6 +38,8 @@ pub mod bubblegum; pub mod error; mod mpl_core_program; mod token; +mod token_extensions; +mod token_inscription; mod token_metadata; #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] @@ -62,15 +68,19 @@ pub struct ProgramTransformer { impl ProgramTransformer { pub fn new(pool: PgPool, download_metadata_notifier: DownloadMetadataNotifier) -> Self { - let mut parsers: HashMap> = HashMap::with_capacity(4); + let mut parsers: HashMap> = HashMap::with_capacity(5); let bgum = BubblegumParser {}; let token_metadata = TokenMetadataParser {}; let token = TokenAccountParser {}; let mpl_core = MplCoreParser {}; + let token_inscription = TokenInscriptionParser {}; + let token_extensions = Token2022AccountParser {}; parsers.insert(bgum.key(), Box::new(bgum)); parsers.insert(token_metadata.key(), Box::new(token_metadata)); parsers.insert(token.key(), Box::new(token)); parsers.insert(mpl_core.key(), Box::new(mpl_core)); + parsers.insert(token_inscription.key(), Box::new(token_inscription)); + parsers.insert(token_extensions.key(), Box::new(token_extensions)); let hs = parsers.iter().fold(HashSet::new(), |mut acc, (k, _)| { acc.insert(*k); acc @@ -104,7 +114,6 @@ impl ProgramTransformer { &self, tx_info: &TransactionInfo, ) -> ProgramTransformerResult<()> { - info!("Handling Transaction: {:?}", tx_info.signature); let instructions = self.break_transaction(tx_info); let mut not_impl = 0; let ixlen = instructions.len(); @@ -212,6 +221,9 @@ impl ProgramTransformer { ) .await } + ProgramParseResult::TokenExtensionsProgramAccount(parsing_result) => { + handle_token_extensions_program_account(account_info, parsing_result, &db).await + } ProgramParseResult::MplCore(parsing_result) => { handle_mpl_core_account( account_info, @@ -221,6 +233,9 @@ impl ProgramTransformer { ) .await } + ProgramParseResult::TokenInscriptionAccount(parsing_result) => { + handle_token_inscription_program_update(account_info, parsing_result, &db).await + } _ => Err(ProgramTransformerError::NotImplemented), }?; } @@ -260,3 +275,27 @@ fn record_metric(metric_name: &str, success: bool, retries: u32) { cadence_macros::statsd_count!(metric_name, 1, "success" => success, "retry_count" => retry_count); } } + +pub fn filter_non_null_fields(value: Value) -> Option { + match value { + Value::Null => None, + 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)) + } + } + } + _ => Some(value), + } +} diff --git a/program_transformers/src/mpl_core_program/v1_asset.rs b/program_transformers/src/mpl_core_program/v1_asset.rs index 211f6dd72..28798bce0 100644 --- a/program_transformers/src/mpl_core_program/v1_asset.rs +++ b/program_transformers/src/mpl_core_program/v1_asset.rs @@ -1,5 +1,10 @@ use { crate::{ + asset_upserts::{ + upsert_assets_metadata_account_columns, upsert_assets_mint_account_columns, + upsert_assets_token_account_columns, AssetMetadataAccountColumns, + AssetMintAccountColumns, AssetTokenAccountColumns, + }, error::{ProgramTransformerError, ProgramTransformerResult}, find_model_with_retry, DownloadMetadataInfo, }, @@ -12,7 +17,6 @@ use { asset, asset_authority, asset_creators, asset_data, asset_grouping, sea_orm_active_enums::{ ChainMutability, Mutability, OwnerType, SpecificationAssetClass, - SpecificationVersions, }, }, json::ChainDataV1, @@ -388,6 +392,41 @@ pub async fn save_v1_asset( None }; + upsert_assets_metadata_account_columns( + AssetMetadataAccountColumns { + mint: id_vec.clone(), + owner_type: ownership_type.clone(), + specification_asset_class: Some(class.clone()), + royalty_amount: royalty_amount as i32, + asset_data: Some(id_vec.clone()), + slot_updated_metadata_account: slot, + mpl_core_plugins: Some(plugins_json.clone()), + mpl_core_unknown_plugins: unknown_plugins_json.clone(), + mpl_core_collection_num_minted: asset.num_minted.map(|val| val as i32), + mpl_core_collection_current_size: asset.current_size.map(|val| val as i32), + mpl_core_plugins_json_version: Some(1), + mpl_core_external_plugins: Some(external_plugins_json.clone()), + mpl_core_unknown_external_plugins: unknown_external_plugins_json.clone(), + }, + &txn, + ) + .await?; + + let supply = Decimal::from(1); + + // Note: these need to be separate for Token Metadata but here could be one upsert. + upsert_assets_mint_account_columns( + AssetMintAccountColumns { + mint: id_vec.clone(), + supply, + slot_updated_mint_account: slot as i64, + extensions: None, + }, + &txn, + ) + .await?; + + // Get transfer delegate from `TransferDelegate` plugin if available. let transfer_delegate = asset .plugins @@ -411,263 +450,18 @@ pub async fn save_v1_asset( }) .unwrap_or(false); - let asset_model = asset::ActiveModel { - id: ActiveValue::Set(id_vec.clone()), - owner_type: ActiveValue::Set(ownership_type), - supply: ActiveValue::Set(Decimal::from(1)), - supply_mint: ActiveValue::Set(None), - slot_updated_mint_account: ActiveValue::Set(Some(slot as i64)), - specification_version: ActiveValue::Set(Some(SpecificationVersions::V1)), - specification_asset_class: ActiveValue::Set(Some(class)), - royalty_amount: ActiveValue::Set(royalty_amount as i32), - asset_data: ActiveValue::Set(Some(id_vec.clone())), - slot_updated_metadata_account: ActiveValue::Set(Some(slot as i64)), - mpl_core_plugins: ActiveValue::Set(Some(plugins_json)), - mpl_core_unknown_plugins: ActiveValue::Set(unknown_plugins_json), - mpl_core_collection_num_minted: ActiveValue::Set(asset.num_minted.map(|val| val as i32)), - mpl_core_collection_current_size: ActiveValue::Set( - asset.current_size.map(|val| val as i32), - ), - mpl_core_plugins_json_version: ActiveValue::Set(Some(1)), - mpl_core_external_plugins: ActiveValue::Set(Some(external_plugins_json)), - mpl_core_unknown_external_plugins: ActiveValue::Set(unknown_external_plugins_json), - owner: ActiveValue::Set(owner), - frozen: ActiveValue::Set(frozen), - delegate: ActiveValue::Set(transfer_delegate.clone()), - slot_updated_token_account: ActiveValue::Set(Some(slot_i)), - ..Default::default() - }; - - asset::Entity::insert(asset_model) - .on_conflict( - OnConflict::columns([asset::Column::Id]) - .update_columns([ - asset::Column::OwnerType, - asset::Column::Supply, - asset::Column::SupplyMint, - asset::Column::SlotUpdatedMintAccount, - asset::Column::SpecificationVersion, - asset::Column::SpecificationAssetClass, - asset::Column::RoyaltyAmount, - asset::Column::AssetData, - asset::Column::SlotUpdatedMetadataAccount, - asset::Column::MplCorePlugins, - asset::Column::MplCoreUnknownPlugins, - asset::Column::MplCoreCollectionNumMinted, - asset::Column::MplCoreCollectionCurrentSize, - asset::Column::MplCorePluginsJsonVersion, - asset::Column::MplCoreExternalPlugins, - asset::Column::MplCoreUnknownExternalPlugins, - asset::Column::Owner, - asset::Column::Frozen, - asset::Column::Delegate, - asset::Column::SlotUpdatedTokenAccount, - ]) - .action_cond_where( - Condition::any() - .add( - Condition::all() - .add( - Condition::any() - .add( - Expr::tbl( - Alias::new("excluded"), - asset::Column::OwnerType, - ) - .ne(Expr::tbl(asset::Entity, asset::Column::OwnerType)), - ) - .add( - Expr::tbl( - Alias::new("excluded"), - asset::Column::Supply, - ) - .ne(Expr::tbl(asset::Entity, asset::Column::Supply)), - ) - .add( - Expr::tbl( - Alias::new("excluded"), - asset::Column::SupplyMint, - ) - .ne( - Expr::tbl(asset::Entity, asset::Column::SupplyMint), - ), - ) - .add( - Expr::tbl( - Alias::new("excluded"), - asset::Column::SlotUpdatedMintAccount, - ) - .ne( - Expr::tbl( - asset::Entity, - asset::Column::SlotUpdatedMintAccount, - ), - ), - ) - .add( - Expr::tbl( - Alias::new("excluded"), - asset::Column::SpecificationVersion, - ) - .ne( - Expr::tbl( - asset::Entity, - asset::Column::SpecificationVersion, - ), - ), - ) - .add( - Expr::tbl( - Alias::new("excluded"), - asset::Column::SpecificationAssetClass, - ) - .ne( - Expr::tbl( - asset::Entity, - asset::Column::SpecificationAssetClass, - ), - ), - ) - .add( - Expr::tbl( - Alias::new("excluded"), - asset::Column::RoyaltyAmount, - ) - .ne( - Expr::tbl( - asset::Entity, - asset::Column::RoyaltyAmount, - ), - ), - ) - .add( - Expr::tbl( - Alias::new("excluded"), - asset::Column::AssetData, - ) - .ne(Expr::tbl(asset::Entity, asset::Column::AssetData)), - ) - .add( - Expr::tbl( - Alias::new("excluded"), - asset::Column::MplCorePlugins, - ) - .ne( - Expr::tbl( - asset::Entity, - asset::Column::MplCorePlugins, - ), - ), - ) - .add( - Expr::tbl( - Alias::new("excluded"), - asset::Column::MplCoreUnknownPlugins, - ) - .ne( - Expr::tbl( - asset::Entity, - asset::Column::MplCoreUnknownPlugins, - ), - ), - ) - .add( - Expr::tbl( - Alias::new("excluded"), - asset::Column::MplCoreCollectionNumMinted, - ) - .ne( - Expr::tbl( - asset::Entity, - asset::Column::MplCoreCollectionNumMinted, - ), - ), - ) - .add( - Expr::tbl( - Alias::new("excluded"), - asset::Column::MplCoreCollectionCurrentSize, - ) - .ne( - Expr::tbl( - asset::Entity, - asset::Column::MplCoreCollectionCurrentSize, - ), - ), - ) - .add( - Expr::tbl( - Alias::new("excluded"), - asset::Column::MplCorePluginsJsonVersion, - ) - .ne( - Expr::tbl( - asset::Entity, - asset::Column::MplCorePluginsJsonVersion, - ), - ), - ) - .add( - Expr::tbl( - Alias::new("excluded"), - asset::Column::MplCoreExternalPlugins, - ) - .ne( - Expr::tbl( - asset::Entity, - asset::Column::MplCoreExternalPlugins, - ), - ), - ) - .add( - Expr::tbl( - Alias::new("excluded"), - asset::Column::MplCoreUnknownExternalPlugins, - ) - .ne( - Expr::tbl( - asset::Entity, - asset::Column::MplCoreUnknownExternalPlugins, - ), - ), - ) - .add( - Expr::tbl(Alias::new("excluded"), asset::Column::Owner) - .ne(Expr::tbl(asset::Entity, asset::Column::Owner)), - ) - .add( - Expr::tbl( - Alias::new("excluded"), - asset::Column::Frozen, - ) - .ne(Expr::tbl(asset::Entity, asset::Column::Frozen)), - ) - .add( - Expr::tbl( - Alias::new("excluded"), - asset::Column::Delegate, - ) - .ne(Expr::tbl(asset::Entity, asset::Column::Delegate)), - ), - ) - .add( - Expr::tbl( - asset::Entity, - asset::Column::SlotUpdatedMetadataAccount, - ) - .lte(slot as i64), - ), - ) - .add( - Expr::tbl(asset::Entity, asset::Column::SlotUpdatedMetadataAccount) - .is_null(), - ), - ) - .to_owned(), - ) - .exec_without_returning(&txn) - .await?; - + upsert_assets_token_account_columns( + AssetTokenAccountColumns { + mint: id_vec.clone(), + owner, + frozen, + // Note use transfer delegate for the existing delegate field. + delegate: transfer_delegate.clone(), + slot_updated_token_account: Some(slot_i), + }, + &txn, + ) + .await?; //----------------------- // asset_grouping table //----------------------- diff --git a/program_transformers/src/token/mod.rs b/program_transformers/src/token/mod.rs index f712c149c..67c76187a 100644 --- a/program_transformers/src/token/mod.rs +++ b/program_transformers/src/token/mod.rs @@ -8,7 +8,10 @@ use { AccountInfo, DownloadMetadataNotifier, }, blockbuster::programs::token_account::TokenProgramAccount, - digital_asset_types::dao::{token_accounts, tokens}, + digital_asset_types::dao::{ + token_accounts, + tokens::{self, IsNonFungible}, + }, sea_orm::{ entity::ActiveValue, sea_query::query::OnConflict, @@ -27,6 +30,7 @@ pub async fn handle_token_program_account<'a, 'b>( ) -> ProgramTransformerResult<()> { let account_key = account_info.pubkey.to_bytes().to_vec(); let account_owner = account_info.owner.to_bytes().to_vec(); + let slot = account_info.slot as i64; match &parsing_result { TokenProgramAccount::TokenAccount(ta) => { let mint = ta.mint.to_bytes().to_vec(); @@ -44,9 +48,10 @@ pub async fn handle_token_program_account<'a, 'b>( frozen: ActiveValue::Set(frozen), delegated_amount: ActiveValue::Set(ta.delegated_amount as i64), token_program: ActiveValue::Set(account_owner.clone()), - slot_updated: ActiveValue::Set(account_info.slot as i64), + slot_updated: ActiveValue::Set(slot), amount: ActiveValue::Set(ta.amount as i64), close_authority: ActiveValue::Set(None), + extensions: ActiveValue::Set(None), }; let txn = db.begin().await?; @@ -176,20 +181,23 @@ pub async fn handle_token_program_account<'a, 'b>( .exec_without_returning(&txn) .await?; - if ta.amount == 1 { + let token = tokens::Entity::find_by_id(mint.clone()).one(db).await?; + + let is_non_fungible = token.map(|t| t.is_non_fungible()).unwrap_or(false); + + if is_non_fungible { upsert_assets_token_account_columns( AssetTokenAccountColumns { mint: mint.clone(), owner: Some(owner.clone()), frozen, delegate, - slot_updated_token_account: Some(account_info.slot as i64), + slot_updated_token_account: Some(slot), }, &txn, ) .await?; } - txn.commit().await?; Ok(()) } @@ -212,6 +220,7 @@ pub async fn handle_token_program_account<'a, 'b>( extension_data: ActiveValue::Set(None), mint_authority: ActiveValue::Set(mint_auth), freeze_authority: ActiveValue::Set(freeze_auth), + extensions: ActiveValue::Set(None), }; let txn = db.begin().await?; @@ -307,16 +316,15 @@ pub async fn handle_token_program_account<'a, 'b>( upsert_assets_mint_account_columns( AssetMintAccountColumns { mint: account_key.clone(), - supply_mint: Some(account_key), supply: m.supply.into(), - slot_updated_mint_account: account_info.slot, + slot_updated_mint_account: slot, + extensions: None, }, &txn, ) .await?; txn.commit().await?; - Ok(()) } } diff --git a/program_transformers/src/token_extensions/mod.rs b/program_transformers/src/token_extensions/mod.rs new file mode 100644 index 000000000..64e79e509 --- /dev/null +++ b/program_transformers/src/token_extensions/mod.rs @@ -0,0 +1,487 @@ +use { + crate::{ + asset_upserts::{ + upsert_assets_mint_account_columns, upsert_assets_token_account_columns, + AssetMintAccountColumns, AssetTokenAccountColumns, + }, + error::{ProgramTransformerError, ProgramTransformerResult}, + filter_non_null_fields, AccountInfo, + }, + blockbuster::programs::token_extensions::{ + extension::ShadowMetadata, MintAccount, TokenAccount, TokenExtensionsProgramAccount, + }, + digital_asset_types::dao::{ + asset, asset_data, + sea_orm_active_enums::ChainMutability, + token_accounts, + tokens::{self, IsNonFungible as IsNonFungibleModel}, + }, + sea_orm::{ + entity::ActiveValue, + query::QueryTrait, + sea_query::{query::OnConflict, Alias, Expr}, + Condition, ConnectionTrait, DatabaseConnection, DatabaseTransaction, DbBackend, DbErr, + EntityTrait, Set, Statement, TransactionTrait, + }, + serde_json::Value, + solana_sdk::program_option::COption, + spl_token_2022::state::AccountState, +}; + +pub async fn handle_token_extensions_program_account<'a, 'b, 'c>( + account_info: &'a AccountInfo, + parsing_result: &'b TokenExtensionsProgramAccount, + db: &'c DatabaseConnection, +) -> ProgramTransformerResult<()> { + let account_key = account_info.pubkey.to_bytes().to_vec(); + let account_owner = account_info.owner.to_bytes().to_vec(); + let slot = account_info.slot as i64; + match parsing_result { + TokenExtensionsProgramAccount::TokenAccount(ta) => { + let TokenAccount { + account, + extensions, + } = ta; + let ta = account; + + let extensions: Option = if extensions.is_some() { + filter_non_null_fields( + serde_json::to_value(extensions.clone()) + .map_err(|e| ProgramTransformerError::SerializatonError(e.to_string()))?, + ) + } else { + None + }; + + let mint = ta.mint.to_bytes().to_vec(); + let delegate: Option> = match ta.delegate { + COption::Some(d) => Some(d.to_bytes().to_vec()), + COption::None => None, + }; + let frozen = matches!(ta.state, AccountState::Frozen); + let owner = ta.owner.to_bytes().to_vec(); + let model = token_accounts::ActiveModel { + pubkey: ActiveValue::Set(account_key.clone()), + mint: ActiveValue::Set(mint.clone()), + delegate: ActiveValue::Set(delegate.clone()), + owner: ActiveValue::Set(owner.clone()), + frozen: ActiveValue::Set(frozen), + delegated_amount: ActiveValue::Set(ta.delegated_amount as i64), + token_program: ActiveValue::Set(account_owner.clone()), + slot_updated: ActiveValue::Set(slot), + amount: ActiveValue::Set(ta.amount as i64), + close_authority: ActiveValue::Set(None), + extensions: ActiveValue::Set(extensions.clone()), + }; + + let txn = db.begin().await?; + + let set_lock_timeout = "SET LOCAL lock_timeout = '100ms';"; + let set_local_app_name = + "SET LOCAL application_name = 'das::program_transformers::token_extensions::token_account';"; + let set_lock_timeout_stmt = + Statement::from_string(txn.get_database_backend(), set_lock_timeout.to_string()); + let set_local_app_name_stmt = + Statement::from_string(txn.get_database_backend(), set_local_app_name.to_string()); + txn.execute(set_lock_timeout_stmt).await?; + txn.execute(set_local_app_name_stmt).await?; + + token_accounts::Entity::insert(model) + .on_conflict( + OnConflict::columns([token_accounts::Column::Pubkey]) + .update_columns([ + token_accounts::Column::Mint, + token_accounts::Column::DelegatedAmount, + token_accounts::Column::Delegate, + token_accounts::Column::Amount, + token_accounts::Column::Frozen, + token_accounts::Column::TokenProgram, + token_accounts::Column::Owner, + token_accounts::Column::SlotUpdated, + token_accounts::Column::Extensions, + ]) + .action_cond_where( + Condition::all() + .add( + Condition::any() + .add( + Expr::tbl( + Alias::new("excluded"), + token_accounts::Column::Mint, + ) + .ne( + Expr::tbl( + token_accounts::Entity, + token_accounts::Column::Mint, + ), + ), + ) + .add( + Expr::tbl( + Alias::new("excluded"), + token_accounts::Column::DelegatedAmount, + ) + .ne( + Expr::tbl( + token_accounts::Entity, + token_accounts::Column::DelegatedAmount, + ), + ), + ) + .add( + Expr::tbl( + Alias::new("excluded"), + token_accounts::Column::Delegate, + ) + .ne( + Expr::tbl( + token_accounts::Entity, + token_accounts::Column::Delegate, + ), + ), + ) + .add( + Expr::tbl( + Alias::new("excluded"), + token_accounts::Column::Amount, + ) + .ne( + Expr::tbl( + token_accounts::Entity, + token_accounts::Column::Amount, + ), + ), + ) + .add( + Expr::tbl( + Alias::new("excluded"), + token_accounts::Column::Frozen, + ) + .ne( + Expr::tbl( + token_accounts::Entity, + token_accounts::Column::Frozen, + ), + ), + ) + .add( + Expr::tbl( + Alias::new("excluded"), + token_accounts::Column::TokenProgram, + ) + .ne( + Expr::tbl( + token_accounts::Entity, + token_accounts::Column::TokenProgram, + ), + ), + ) + .add( + Expr::tbl( + Alias::new("excluded"), + token_accounts::Column::Owner, + ) + .ne( + Expr::tbl( + token_accounts::Entity, + token_accounts::Column::Owner, + ), + ), + ) + .add( + Expr::tbl( + Alias::new("excluded"), + token_accounts::Column::Extensions, + ) + .ne( + Expr::tbl( + token_accounts::Entity, + token_accounts::Column::Extensions, + ), + ), + ), + ) + .add( + Expr::tbl( + token_accounts::Entity, + token_accounts::Column::SlotUpdated, + ) + .lte(account_info.slot as i64), + ), + ) + .to_owned(), + ) + .exec_without_returning(&txn) + .await?; + + let token = tokens::Entity::find_by_id(mint.clone()).one(db).await?; + + let is_non_fungible = token.map(|t| t.is_non_fungible()).unwrap_or(false); + + if is_non_fungible { + upsert_assets_token_account_columns( + AssetTokenAccountColumns { + mint: mint.clone(), + owner: Some(owner.clone()), + frozen, + delegate, + slot_updated_token_account: Some(slot), + }, + &txn, + ) + .await?; + } + txn.commit().await?; + Ok(()) + } + TokenExtensionsProgramAccount::MintAccount(m) => { + let MintAccount { + account, + extensions, + } = m; + + let mint_extensions: Option = if extensions.is_some() { + filter_non_null_fields( + serde_json::to_value(extensions.clone()) + .map_err(|e| ProgramTransformerError::SerializatonError(e.to_string()))?, + ) + } else { + None + }; + + let m = account; + let freeze_auth: Option> = match m.freeze_authority { + COption::Some(d) => Some(d.to_bytes().to_vec()), + COption::None => None, + }; + let mint_auth: Option> = match m.mint_authority { + COption::Some(d) => Some(d.to_bytes().to_vec()), + COption::None => None, + }; + let model = tokens::ActiveModel { + mint: ActiveValue::Set(account_key.clone()), + token_program: ActiveValue::Set(account_owner), + slot_updated: ActiveValue::Set(slot), + supply: ActiveValue::Set(m.supply.into()), + decimals: ActiveValue::Set(m.decimals as i32), + close_authority: ActiveValue::Set(None), + extension_data: ActiveValue::Set(None), + mint_authority: ActiveValue::Set(mint_auth), + freeze_authority: ActiveValue::Set(freeze_auth), + extensions: ActiveValue::Set(mint_extensions.clone()), + }; + + let txn = db.begin().await?; + + let set_lock_timeout = "SET LOCAL lock_timeout = '100ms';"; + let set_local_app_name = + "SET LOCAL application_name = 'das::program_transformers::token_extensions::mint';"; + let set_lock_timeout_stmt = + Statement::from_string(txn.get_database_backend(), set_lock_timeout.to_string()); + let set_local_app_name_stmt = + Statement::from_string(txn.get_database_backend(), set_local_app_name.to_string()); + txn.execute(set_lock_timeout_stmt).await?; + txn.execute(set_local_app_name_stmt).await?; + + tokens::Entity::insert(model) + .on_conflict( + OnConflict::columns([tokens::Column::Mint]) + .update_columns([ + tokens::Column::Supply, + tokens::Column::TokenProgram, + tokens::Column::MintAuthority, + tokens::Column::SlotUpdated, + tokens::Column::Decimals, + tokens::Column::FreezeAuthority, + tokens::Column::Extensions, + ]) + .action_cond_where( + Condition::all() + .add( + Condition::any() + .add( + Expr::tbl( + Alias::new("excluded"), + tokens::Column::Supply, + ) + .ne(Expr::tbl(tokens::Entity, tokens::Column::Supply)), + ) + .add( + Expr::tbl( + Alias::new("excluded"), + tokens::Column::TokenProgram, + ) + .ne( + Expr::tbl( + tokens::Entity, + tokens::Column::TokenProgram, + ), + ), + ) + .add( + Expr::tbl( + Alias::new("excluded"), + tokens::Column::MintAuthority, + ) + .ne( + Expr::tbl( + tokens::Entity, + tokens::Column::MintAuthority, + ), + ), + ) + .add( + Expr::tbl( + Alias::new("excluded"), + tokens::Column::Decimals, + ) + .ne( + Expr::tbl(tokens::Entity, tokens::Column::Decimals), + ), + ) + .add( + Expr::tbl( + Alias::new("excluded"), + tokens::Column::FreezeAuthority, + ) + .ne( + Expr::tbl( + tokens::Entity, + tokens::Column::FreezeAuthority, + ), + ), + ) + .add( + Expr::tbl( + Alias::new("excluded"), + tokens::Column::Extensions, + ) + .ne( + Expr::tbl( + tokens::Entity, + tokens::Column::Extensions, + ), + ), + ), + ) + .add( + Expr::tbl(tokens::Entity, tokens::Column::SlotUpdated) + .lte(account_info.slot as i64), + ), + ) + .to_owned(), + ) + .exec_without_returning(&txn) + .await?; + + upsert_assets_mint_account_columns( + AssetMintAccountColumns { + mint: account_key.clone(), + supply: m.supply.into(), + slot_updated_mint_account: slot, + extensions: mint_extensions.clone(), + }, + &txn, + ) + .await?; + + txn.commit().await?; + + if let Some(metadata) = &extensions.metadata { + upsert_asset_data(metadata, account_key.clone(), slot, db).await?; + } + + Ok(()) + } + _ => Err(ProgramTransformerError::NotImplemented), + } +} + +async fn upsert_asset_data( + metadata: &ShadowMetadata, + key_bytes: Vec, + slot: i64, + db: &DatabaseConnection, +) -> ProgramTransformerResult<()> { + let metadata_json = serde_json::to_value(metadata.clone()) + .map_err(|e| ProgramTransformerError::SerializatonError(e.to_string()))?; + let asset_data_model = asset_data::ActiveModel { + metadata_url: ActiveValue::Set(metadata.uri.clone()), + metadata: ActiveValue::Set(Value::String("processing".to_string())), + id: ActiveValue::Set(key_bytes.clone()), + chain_data_mutability: ActiveValue::Set(ChainMutability::Mutable), + chain_data: ActiveValue::Set(metadata_json), + slot_updated: ActiveValue::Set(slot), + base_info_seq: ActiveValue::Set(Some(0)), + raw_name: ActiveValue::Set(Some(metadata.name.clone().into_bytes().to_vec())), + raw_symbol: ActiveValue::Set(Some(metadata.symbol.clone().into_bytes().to_vec())), + ..Default::default() + }; + let mut asset_data_query = asset_data::Entity::insert(asset_data_model) + .on_conflict( + OnConflict::columns([asset_data::Column::Id]) + .update_columns([ + asset_data::Column::ChainDataMutability, + asset_data::Column::ChainData, + asset_data::Column::MetadataUrl, + asset_data::Column::SlotUpdated, + asset_data::Column::BaseInfoSeq, + asset_data::Column::RawName, + asset_data::Column::RawSymbol, + ]) + .to_owned(), + ) + .build(DbBackend::Postgres); + asset_data_query.sql = format!( + "{} WHERE excluded.slot_updated >= asset_data.slot_updated", + asset_data_query.sql + ); + db.execute(asset_data_query).await?; + + let txn = db.begin().await?; + upsert_assets_metadata_cols( + AssetMetadataAccountCols { + mint: key_bytes.clone(), + slot_updated_metadata_account: slot, + }, + &txn, + ) + .await?; + + txn.commit().await?; + + Ok(()) +} + +struct AssetMetadataAccountCols { + mint: Vec, + slot_updated_metadata_account: i64, +} + +async fn upsert_assets_metadata_cols( + metadata: AssetMetadataAccountCols, + db: &DatabaseTransaction, +) -> Result<(), DbErr> { + let asset = asset::ActiveModel { + id: ActiveValue::Set(metadata.mint.clone()), + slot_updated_metadata_account: Set(Some(metadata.slot_updated_metadata_account)), + ..Default::default() + }; + + let mut asset_query = asset::Entity::insert(asset) + .on_conflict( + OnConflict::columns([asset::Column::Id]) + .update_columns([asset::Column::SlotUpdatedMetadataAccount]) + .to_owned(), + ) + .build(DbBackend::Postgres); + + asset_query.sql = format!( + "{} WHERE excluded.slot_updated_metadata_account >= asset.slot_updated_metadata_account OR asset.slot_updated_metadata_account IS NULL", + asset_query.sql + ); + + db.execute(asset_query).await?; + + Ok(()) +} diff --git a/program_transformers/src/token_inscription/mod.rs b/program_transformers/src/token_inscription/mod.rs new file mode 100644 index 000000000..957275fc8 --- /dev/null +++ b/program_transformers/src/token_inscription/mod.rs @@ -0,0 +1,59 @@ +use std::str::FromStr; + +use crate::AccountInfo; +use blockbuster::programs::token_inscriptions::TokenInscriptionAccount; +use digital_asset_types::dao::asset_v1_account_attachments; +use digital_asset_types::dao::sea_orm_active_enums::V1AccountAttachments; +use sea_orm::sea_query::OnConflict; +use sea_orm::{ + ActiveValue, ConnectionTrait, DatabaseConnection, DbBackend, EntityTrait, QueryTrait, +}; +use solana_sdk::pubkey::Pubkey; + +use crate::error::{ProgramTransformerError, ProgramTransformerResult}; + +pub async fn handle_token_inscription_program_update<'a, 'b>( + account_info: &AccountInfo, + parsing_result: &'a TokenInscriptionAccount, + db: &'b DatabaseConnection, +) -> ProgramTransformerResult<()> { + let account_key = account_info.pubkey.to_bytes().to_vec(); + + let TokenInscriptionAccount { data } = parsing_result; + + let ser = serde_json::to_value(data) + .map_err(|e| ProgramTransformerError::SerializatonError(e.to_string()))?; + + let asset_id = Pubkey::from_str(&data.root) + .map_err(|e| ProgramTransformerError::ParsingError(e.to_string()))? + .to_bytes() + .to_vec(); + + let model = asset_v1_account_attachments::ActiveModel { + id: ActiveValue::Set(account_key), + asset_id: ActiveValue::Set(Some(asset_id)), + data: ActiveValue::Set(Some(ser)), + slot_updated: ActiveValue::Set(account_info.slot as i64), + initialized: ActiveValue::Set(true), + attachment_type: ActiveValue::Set(V1AccountAttachments::TokenInscription), + }; + + let mut query = asset_v1_account_attachments::Entity::insert(model) + .on_conflict( + OnConflict::columns([asset_v1_account_attachments::Column::Id]) + .update_columns([ + asset_v1_account_attachments::Column::Data, + asset_v1_account_attachments::Column::SlotUpdated, + ]) + .to_owned(), + ) + .build(DbBackend::Postgres); + + query.sql = format!( + "{} WHERE excluded.slot_updated > asset_v1_account_attachments.slot_updated", + query.sql + ); + db.execute(query).await?; + + Ok(()) +} diff --git a/program_transformers/src/token_metadata/master_edition.rs b/program_transformers/src/token_metadata/master_edition.rs index df8872dfd..cdb823e6c 100644 --- a/program_transformers/src/token_metadata/master_edition.rs +++ b/program_transformers/src/token_metadata/master_edition.rs @@ -1,7 +1,7 @@ use { crate::error::{ProgramTransformerError, ProgramTransformerResult}, blockbuster::token_metadata::{ - accounts::{DeprecatedMasterEditionV1, MasterEdition}, + accounts::{DeprecatedMasterEditionV1, Edition, MasterEdition}, types::Key, }, digital_asset_types::dao::{ @@ -121,3 +121,69 @@ pub async fn save_master_edition( Ok(()) } + +pub async fn save_edition( + id: Pubkey, + slot: u64, + e_data: &Edition, + txn: &DatabaseTransaction, +) -> ProgramTransformerResult<()> { + let id_bytes = id.to_bytes().to_vec(); + + let ser = serde_json::to_value(e_data) + .map_err(|e| ProgramTransformerError::SerializatonError(e.to_string()))?; + + let model = asset_v1_account_attachments::ActiveModel { + id: ActiveValue::Set(id_bytes), + attachment_type: ActiveValue::Set(V1AccountAttachments::Edition), + data: ActiveValue::Set(Some(ser)), + slot_updated: ActiveValue::Set(slot as i64), + ..Default::default() + }; + asset_v1_account_attachments::Entity::insert(model) + .on_conflict( + OnConflict::columns([asset_v1_account_attachments::Column::Id]) + .update_columns([ + asset_v1_account_attachments::Column::AttachmentType, + asset_v1_account_attachments::Column::Data, + asset_v1_account_attachments::Column::SlotUpdated, + ]) + .action_cond_where( + Condition::all() + .add( + Condition::any() + .add( + Expr::tbl( + Alias::new("excluded"), + asset_v1_account_attachments::Column::AttachmentType, + ) + .ne(Expr::tbl( + asset_v1_account_attachments::Entity, + asset_v1_account_attachments::Column::AttachmentType, + )), + ) + .add( + Expr::tbl( + Alias::new("excluded"), + asset_v1_account_attachments::Column::Data, + ) + .ne(Expr::tbl( + asset_v1_account_attachments::Entity, + asset_v1_account_attachments::Column::Data, + )), + ), + ) + .add( + Expr::tbl( + asset_v1_account_attachments::Entity, + asset_v1_account_attachments::Column::SlotUpdated, + ) + .lte(slot as i64), + ), + ) + .to_owned(), + ) + .exec_without_returning(txn) + .await?; + Ok(()) +} diff --git a/program_transformers/src/token_metadata/mod.rs b/program_transformers/src/token_metadata/mod.rs index cbeb94171..bf0710560 100644 --- a/program_transformers/src/token_metadata/mod.rs +++ b/program_transformers/src/token_metadata/mod.rs @@ -7,7 +7,11 @@ use { }, AccountInfo, DownloadMetadataNotifier, }, - blockbuster::programs::token_metadata::{TokenMetadataAccountData, TokenMetadataAccountState}, + blockbuster::{ + programs::token_metadata::{TokenMetadataAccountData, TokenMetadataAccountState}, + token_metadata::types::TokenStandard, + }, + master_edition::save_edition, sea_orm::{DatabaseConnection, TransactionTrait}, }; @@ -45,9 +49,32 @@ pub async fn handle_token_metadata_account<'a, 'b>( txn.commit().await?; Ok(()) } + TokenMetadataAccountData::EditionV1(e) => { + let txn = db.begin().await?; + save_edition(account_info.pubkey, account_info.slot, e, &txn).await?; + txn.commit().await?; + Ok(()) + } + // TokenMetadataAccountData::EditionMarker(_) => {} // TokenMetadataAccountData::UseAuthorityRecord(_) => {} // TokenMetadataAccountData::CollectionAuthorityRecord(_) => {} _ => Err(ProgramTransformerError::NotImplemented), } } + +pub trait IsNonFungibeFromTokenStandard { + fn is_non_fungible(&self) -> bool; +} + +impl IsNonFungibeFromTokenStandard for TokenStandard { + fn is_non_fungible(&self) -> bool { + matches!( + self, + TokenStandard::NonFungible + | TokenStandard::NonFungibleEdition + | TokenStandard::ProgrammableNonFungible + | TokenStandard::ProgrammableNonFungibleEdition + ) + } +} diff --git a/program_transformers/src/token_metadata/v1_asset.rs b/program_transformers/src/token_metadata/v1_asset.rs index d500ac2cd..b2c82bc88 100644 --- a/program_transformers/src/token_metadata/v1_asset.rs +++ b/program_transformers/src/token_metadata/v1_asset.rs @@ -1,8 +1,13 @@ use { + super::IsNonFungibeFromTokenStandard, crate::{ - asset_upserts::{upsert_assets_metadata_account_columns, AssetMetadataAccountColumns}, + asset_upserts::{ + upsert_assets_metadata_account_columns, upsert_assets_mint_account_columns, + upsert_assets_token_account_columns, AssetMetadataAccountColumns, + AssetMintAccountColumns, AssetTokenAccountColumns, + }, error::{ProgramTransformerError, ProgramTransformerResult}, - DownloadMetadataInfo, + find_model_with_retry, DownloadMetadataInfo, }, blockbuster::token_metadata::{ accounts::{MasterEdition, Metadata}, @@ -13,25 +18,30 @@ use { asset, asset_authority, asset_creators, asset_data, asset_grouping, asset_v1_account_attachments, sea_orm_active_enums::{ - ChainMutability, Mutability, SpecificationAssetClass, SpecificationVersions, - V1AccountAttachments, + ChainMutability, Mutability, OwnerType, SpecificationAssetClass, + SpecificationVersions, V1AccountAttachments, }, + token_accounts, + tokens::{self}, }, json::ChainDataV1, }, sea_orm::{ entity::{ActiveValue, EntityTrait}, - query::JsonValue, + query::{JsonValue, QueryTrait}, sea_query::{query::OnConflict, Alias, Expr}, - Condition, ConnectionTrait, Statement, TransactionTrait, + ColumnTrait, Condition, ConnectionTrait, DbBackend, DbErr, Order, QueryFilter, QueryOrder, + Statement, TransactionTrait, }, solana_sdk::pubkey, + solana_sdk::pubkey::Pubkey, + sqlx::types::Decimal, tracing::warn, }; pub async fn burn_v1_asset( conn: &T, - id: pubkey::Pubkey, + id: Pubkey, slot: u64, ) -> ProgramTransformerResult<()> { let slot_i = slot as i64; @@ -63,6 +73,85 @@ pub async fn burn_v1_asset( } static WSOL_PUBKEY: pubkey::Pubkey = pubkey!("So11111111111111111111111111111111111111112"); +const RETRY_INTERVALS: &[u64] = &[0, 5, 10]; + +pub async fn index_and_fetch_mint_data( + conn: &T, + mint_pubkey_vec: Vec, +) -> ProgramTransformerResult> { + // Gets the token and token account for the mint to populate the asset. + // This is required when the token and token account are indexed, but not the metadata account. + // If the metadata account is indexed, then the token and ta ingester will update the asset with the correct data. + let token: Option = find_model_with_retry( + conn, + "token", + &tokens::Entity::find_by_id(mint_pubkey_vec.clone()), + RETRY_INTERVALS, + ) + .await?; + + if let Some(token) = token { + upsert_assets_mint_account_columns( + AssetMintAccountColumns { + mint: mint_pubkey_vec.clone(), + supply: token.supply, + slot_updated_mint_account: token.slot_updated, + extensions: token.extensions.clone(), + }, + conn, + ) + .await + .map_err(|db_err| ProgramTransformerError::AssetIndexError(db_err.to_string()))?; + Ok(Some(token)) + } else { + warn!( + target: "Mint not found", + "Mint not found in 'tokens' table for mint {}", + bs58::encode(&mint_pubkey_vec).into_string() + ); + Ok(None) + } +} + +async fn index_token_account_data( + conn: &T, + mint_pubkey_vec: Vec, +) -> ProgramTransformerResult<()> { + let token_account: Option = find_model_with_retry( + conn, + "token_accounts", + &token_accounts::Entity::find() + .filter(token_accounts::Column::Mint.eq(mint_pubkey_vec.clone())) + .filter(token_accounts::Column::Amount.gt(0)) + .order_by(token_accounts::Column::SlotUpdated, Order::Desc), + RETRY_INTERVALS, + ) + .await + .map_err(|e: DbErr| ProgramTransformerError::DatabaseError(e.to_string()))?; + + if let Some(token_account) = token_account { + upsert_assets_token_account_columns( + AssetTokenAccountColumns { + mint: mint_pubkey_vec.clone(), + owner: Some(token_account.owner), + delegate: token_account.delegate, + frozen: token_account.frozen, + slot_updated_token_account: Some(token_account.slot_updated), + }, + conn, + ) + .await + .map_err(|db_err| ProgramTransformerError::AssetIndexError(db_err.to_string()))?; + } else { + warn!( + target: "Account not found", + "Token acc not found in 'token-accounts' table for mint {}", + bs58::encode(&mint_pubkey_vec).into_string() + ); + } + + Ok(()) +} pub async fn save_v1_asset( conn: &T, @@ -91,6 +180,12 @@ pub async fn save_v1_asset( } _ => SpecificationAssetClass::Unknown, }; + let mut ownership_type = match class { + SpecificationAssetClass::FungibleAsset => OwnerType::Token, + SpecificationAssetClass::FungibleToken => OwnerType::Token, + SpecificationAssetClass::Unknown => OwnerType::Unknown, + _ => OwnerType::Single, + }; // Wrapped Solana is a special token that has supply 0 (infinite). // It's a fungible token with a metadata account, but without any token standard, meaning the code above will misabel it as an NFT. @@ -98,6 +193,32 @@ pub async fn save_v1_asset( class = SpecificationAssetClass::FungibleToken; } + let token: Option = + index_and_fetch_mint_data(conn, mint_pubkey_vec.clone()).await?; + + // get supply of token, default to 1 since most cases will be NFTs. Token mint ingester will properly set supply if token_result is None + let supply = token.map(|t| t.supply).unwrap_or_else(|| Decimal::from(1)); + // Map unknown ownership types based on the supply. + if ownership_type == OwnerType::Unknown { + ownership_type = match supply { + s if s == Decimal::from(1) => OwnerType::Single, + s if s > Decimal::from(1) => OwnerType::Token, + _ => OwnerType::Unknown, + }; + }; + + //Map specification asset class based on the supply. + if class == SpecificationAssetClass::Unknown { + class = match supply { + s if s > Decimal::from(1) => SpecificationAssetClass::FungibleToken, + _ => SpecificationAssetClass::Unknown, + }; + }; + + if (ownership_type == OwnerType::Single) | (ownership_type == OwnerType::Unknown) { + index_token_account_data(conn, mint_pubkey_vec.clone()).await?; + } + let name = metadata.name.clone().into_bytes(); let symbol = metadata.symbol.clone().into_bytes(); let mut chain_data = ChainDataV1 { @@ -248,6 +369,7 @@ pub async fn save_v1_asset( AssetMetadataAccountColumns { mint: mint_pubkey_vec.clone(), specification_asset_class: Some(class), + owner_type: ownership_type, royalty_amount: metadata.seller_fee_basis_points as i32, asset_data: Some(mint_pubkey_vec.clone()), slot_updated_metadata_account: slot_i as u64, @@ -481,6 +603,11 @@ pub async fn save_v1_asset( } txn.commit().await?; + // If the asset is a non-fungible token, then we need to insert to the asset_v1_account_attachments table + if let Some(true) = metadata.token_standard.map(|t| t.is_non_fungible()) { + upsert_asset_v1_account_attachments(conn, &mint_pubkey, slot).await?; + } + if uri.is_empty() { warn!( "URI is empty for mint {}. Skipping background task.", @@ -495,3 +622,31 @@ pub async fn save_v1_asset( slot_i, ))) } + +async fn upsert_asset_v1_account_attachments( + conn: &T, + mint_pubkey: &Pubkey, + slot: u64, +) -> ProgramTransformerResult<()> { + let edition_pubkey = MasterEdition::find_pda(mint_pubkey).0; + let mint_pubkey_vec = mint_pubkey.to_bytes().to_vec(); + let attachment = asset_v1_account_attachments::ActiveModel { + id: ActiveValue::Set(edition_pubkey.to_bytes().to_vec()), + asset_id: ActiveValue::Set(Some(mint_pubkey_vec.clone())), + slot_updated: ActiveValue::Set(slot as i64), + // by default, the attachment type is MasterEditionV1 + attachment_type: ActiveValue::Set(V1AccountAttachments::MasterEditionV1), + ..Default::default() + }; + let query = asset_v1_account_attachments::Entity::insert(attachment) + .on_conflict( + OnConflict::columns([asset_v1_account_attachments::Column::Id]) + .update_columns([asset_v1_account_attachments::Column::AssetId]) + .to_owned(), + ) + .build(DbBackend::Postgres); + + conn.execute(query).await?; + + Ok(()) +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index eb84afdfc..0e844ec24 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.75.0" +channel = "1.83" components = ["clippy", "rustfmt"] targets = [] profile = "minimal" diff --git a/solana-test-validator-geyser-config/accountsdb-plugin-config.json b/solana-test-validator-geyser-config/accountsdb-plugin-config.json index 3925d085a..34a6adce8 100644 --- a/solana-test-validator-geyser-config/accountsdb-plugin-config.json +++ b/solana-test-validator-geyser-config/accountsdb-plugin-config.json @@ -4,19 +4,18 @@ "metrics_port": 8125, "metrics_uri": "graphite", "env": "dev", - "accounts_selector" : { - "owners" : [ + "accounts_selector": { + "owners": [ "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s", "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb", "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", "BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY", - "CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d" + "CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d", + "inscokhJarcjaEs59QbQ7hYjrKz25LEPRfCbP8EmdUp" ] }, - "transaction_selector" : { - "mentions" : [ - "BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY" - ] + "transaction_selector": { + "mentions": ["BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY"] } } diff --git a/tools/txn_forwarder/src/lib.rs b/tools/txn_forwarder/src/lib.rs index c496ab19d..fb385f19d 100644 --- a/tools/txn_forwarder/src/lib.rs +++ b/tools/txn_forwarder/src/lib.rs @@ -27,6 +27,7 @@ use { }; #[derive(Debug, thiserror::Error)] +#[allow(clippy::large_enum_variant)] pub enum FindSignaturesError { #[error("Failed to fetch signatures: {0}")] Fetch(#[from] ClientError),