diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 5e6bebb7..2e436593 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -136,4 +136,6 @@ jobs: DATABASE_TEST_URL: "postgres://postgres:postgres@127.0.0.1:5432/postgres" DEVNET_RPC_URL: ${{ secrets.SOLANA_DEVNET_RPC_URL }} MAINNET_RPC_URL: ${{ secrets.SOLANA_MAINNET_RPC_URL }} + ECLIPSE_DEVNET_RPC_URL: ${{ secrets.SOLANA_ECLIPSE_DEVNET_RPC_URL }} + ECLIPSE_MAINNET_RPC_URL: ${{ secrets.SOLANA_ECLIPSE_MAINNET_RPC_URL }} run: cargo test --features integration_tests -- --nocapture \ No newline at end of file diff --git a/integration_tests/src/account_update_tests.rs b/integration_tests/src/account_update_tests.rs index 904efb6b..1d03b1a3 100644 --- a/integration_tests/src/account_update_tests.rs +++ b/integration_tests/src/account_update_tests.rs @@ -172,7 +172,7 @@ async fn test_account_updates() { setup.clean_up_data_bases().await; - index_nft(&setup, mint).await; + index_nft_accounts(&setup, get_nft_accounts(&setup, mint).await).await; let response = setup.das_api.get_asset(request.clone(), mutexed_tasks.clone()).await.unwrap(); @@ -217,7 +217,7 @@ async fn test_account_updates() { for named_update in named_updates.clone() { setup.clean_up_data_bases().await; - index_nft(&setup, mint).await; + index_nft_accounts(&setup, get_nft_accounts(&setup, mint).await).await; let other_named_updates = named_updates .clone() diff --git a/integration_tests/src/common.rs b/integration_tests/src/common.rs index 2cc02e99..a0f4ac32 100644 --- a/integration_tests/src/common.rs +++ b/integration_tests/src/common.rs @@ -117,6 +117,8 @@ impl TestSetup { let rpc_url = match opts.network.unwrap_or_default() { Network::Mainnet => std::env::var("MAINNET_RPC_URL").unwrap(), Network::Devnet => std::env::var("DEVNET_RPC_URL").unwrap(), + Network::EclipseMainnet => std::env::var("ECLIPSE_MAINNET_RPC_URL").unwrap(), + Network::EclipseDevnet => std::env::var("ECLIPSE_DEVNET_RPC_URL").unwrap(), }; let client = Arc::new(RpcClient::new(rpc_url.to_string())); @@ -537,6 +539,8 @@ pub enum Network { #[default] Mainnet, Devnet, + EclipseMainnet, + EclipseDevnet, } #[derive(Clone, Copy, Debug)] @@ -553,7 +557,7 @@ pub async fn index_seed_events(setup: &TestSetup, events: Vec<&SeedEvent>) { index_and_sync_account_with_ordered_slot(setup, *account).await; }, SeedEvent::Nft(mint) => { - index_nft(setup, *mint).await; + index_nft_accounts(setup, get_nft_accounts(setup, *mint).await).await; }, SeedEvent::Signature(sig) => { index_transaction(setup, *sig).await; @@ -688,10 +692,6 @@ async fn index_token_mint(setup: &TestSetup, mint: Pubkey) { } } -pub async fn index_nft(setup: &TestSetup, mint: Pubkey) { - index_nft_accounts(setup, get_nft_accounts(setup, mint).await).await; -} - pub async fn index_nft_accounts(setup: &TestSetup, nft_accounts: NftAccounts) { for account in [nft_accounts.mint, nft_accounts.metadata, nft_accounts.token] { index_account(setup, account).await; diff --git a/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/2TQDwULQDdpisGssKZeRw2qcCTiZnsAmi6cnR89YYxSg b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/2TQDwULQDdpisGssKZeRw2qcCTiZnsAmi6cnR89YYxSg new file mode 100644 index 00000000..b9f542f0 Binary files /dev/null and b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/2TQDwULQDdpisGssKZeRw2qcCTiZnsAmi6cnR89YYxSg differ diff --git a/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/44vjE7bDpwA2nFp5KbjWHjG2RHBWi5z1pP5ehY9t6p8V b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/44vjE7bDpwA2nFp5KbjWHjG2RHBWi5z1pP5ehY9t6p8V new file mode 100644 index 00000000..6f27a1b3 Binary files /dev/null and b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/44vjE7bDpwA2nFp5KbjWHjG2RHBWi5z1pP5ehY9t6p8V differ diff --git a/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/4pRQs1xZdASeL65PHTa1C8GnYCWtX18Lx98ofJB3SZNC b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/4pRQs1xZdASeL65PHTa1C8GnYCWtX18Lx98ofJB3SZNC new file mode 100644 index 00000000..2f9bffb2 Binary files /dev/null and b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/4pRQs1xZdASeL65PHTa1C8GnYCWtX18Lx98ofJB3SZNC differ diff --git a/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/5ok1Zv557DAnichMsWE4cfURYbr1D2yWfcaqehydHo9R b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/5ok1Zv557DAnichMsWE4cfURYbr1D2yWfcaqehydHo9R new file mode 100644 index 00000000..1d18365c Binary files /dev/null and b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/5ok1Zv557DAnichMsWE4cfURYbr1D2yWfcaqehydHo9R differ diff --git a/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/75peBtH5MwfA5t9uhr51AYL7MR5DbPJ5xQ7wizzvowUH b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/75peBtH5MwfA5t9uhr51AYL7MR5DbPJ5xQ7wizzvowUH new file mode 100644 index 00000000..dc499a14 Binary files /dev/null and b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/75peBtH5MwfA5t9uhr51AYL7MR5DbPJ5xQ7wizzvowUH differ diff --git a/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/7ZkXycbrAhVzeB9ngnjcCdjk5bxTJYzscSZMhRRBx3QB b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/7ZkXycbrAhVzeB9ngnjcCdjk5bxTJYzscSZMhRRBx3QB new file mode 100644 index 00000000..acf64e04 Binary files /dev/null and b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/7ZkXycbrAhVzeB9ngnjcCdjk5bxTJYzscSZMhRRBx3QB differ diff --git a/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/8WKGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1 b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/8WKGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1 new file mode 100644 index 00000000..868f86c5 Binary files /dev/null and b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/8WKGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1 differ diff --git a/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/9qA21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/9qA21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom new file mode 100644 index 00000000..12b0481d Binary files /dev/null and b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/9qA21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom differ diff --git a/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/DvpMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/DvpMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ new file mode 100644 index 00000000..cf8a5a53 Binary files /dev/null and b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/DvpMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ differ diff --git a/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/JCnRA9ALhDYC5SWhBrw19JVWnDxnrGMYTmkfLsLkbpzV b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/JCnRA9ALhDYC5SWhBrw19JVWnDxnrGMYTmkfLsLkbpzV new file mode 100644 index 00000000..84d96ed5 Binary files /dev/null and b/integration_tests/src/data/accounts/requested_non_fungibles_are_non_fungibles/JCnRA9ALhDYC5SWhBrw19JVWnDxnrGMYTmkfLsLkbpzV differ diff --git a/integration_tests/src/data/largest_token_account_ids/75peBtH5MwfA5t9uhr51AYL7MR5DbPJ5xQ7wizzvowUH/75peBtH5MwfA5t9uhr51AYL7MR5DbPJ5xQ7wizzvowUH b/integration_tests/src/data/largest_token_account_ids/75peBtH5MwfA5t9uhr51AYL7MR5DbPJ5xQ7wizzvowUH/75peBtH5MwfA5t9uhr51AYL7MR5DbPJ5xQ7wizzvowUH new file mode 100644 index 00000000..5a1de341 --- /dev/null +++ b/integration_tests/src/data/largest_token_account_ids/75peBtH5MwfA5t9uhr51AYL7MR5DbPJ5xQ7wizzvowUH/75peBtH5MwfA5t9uhr51AYL7MR5DbPJ5xQ7wizzvowUH @@ -0,0 +1 @@ +-do ƲIރ@4z%x \ No newline at end of file diff --git a/integration_tests/src/data/largest_token_account_ids/7ZkXycbrAhVzeB9ngnjcCdjk5bxTJYzscSZMhRRBx3QB/7ZkXycbrAhVzeB9ngnjcCdjk5bxTJYzscSZMhRRBx3QB b/integration_tests/src/data/largest_token_account_ids/7ZkXycbrAhVzeB9ngnjcCdjk5bxTJYzscSZMhRRBx3QB/7ZkXycbrAhVzeB9ngnjcCdjk5bxTJYzscSZMhRRBx3QB new file mode 100644 index 00000000..26672f8f --- /dev/null +++ b/integration_tests/src/data/largest_token_account_ids/7ZkXycbrAhVzeB9ngnjcCdjk5bxTJYzscSZMhRRBx3QB/7ZkXycbrAhVzeB9ngnjcCdjk5bxTJYzscSZMhRRBx3QB @@ -0,0 +1 @@ + dbGOuCޥ;*ҮkұeL \ No newline at end of file diff --git a/integration_tests/src/data/largest_token_account_ids/8WKGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1/8WKGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1 b/integration_tests/src/data/largest_token_account_ids/8WKGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1/8WKGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1 new file mode 100644 index 00000000..22d2672a --- /dev/null +++ b/integration_tests/src/data/largest_token_account_ids/8WKGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1/8WKGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1 @@ -0,0 +1 @@ +kTSV1TVVج!'6 NG0 \ No newline at end of file diff --git a/integration_tests/src/data/largest_token_account_ids/9qA21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom/9qA21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom b/integration_tests/src/data/largest_token_account_ids/9qA21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom/9qA21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom new file mode 100644 index 00000000..464bc29a --- /dev/null +++ b/integration_tests/src/data/largest_token_account_ids/9qA21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom/9qA21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom @@ -0,0 +1 @@ +GhCEـ;l卣S}q \ No newline at end of file diff --git a/integration_tests/src/data/largest_token_account_ids/DvpMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ/DvpMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ b/integration_tests/src/data/largest_token_account_ids/DvpMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ/DvpMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ new file mode 100644 index 00000000..6e14fe6f --- /dev/null +++ b/integration_tests/src/data/largest_token_account_ids/DvpMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ/DvpMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ @@ -0,0 +1 @@ +8%v1YJ */h͛!< \ No newline at end of file diff --git a/integration_tests/src/regular_nft_tests.rs b/integration_tests/src/regular_nft_tests.rs index fbfbe9af..31e5ec85 100644 --- a/integration_tests/src/regular_nft_tests.rs +++ b/integration_tests/src/regular_nft_tests.rs @@ -229,3 +229,51 @@ async fn get_asset_nft_token_22_with_metadata() { insta::assert_json_snapshot!(name, response); } + +#[tokio::test] +#[serial] +#[named] +async fn test_requested_non_fungibles_are_non_fungibles() { + let name = trim_test_name(function_name!()); + let setup = TestSetup::new_with_options( + name.clone(), + TestSetupOptions { network: Some(Network::EclipseMainnet), clear_db: true }, + ) + .await; + + let seeds = seed_token_mints([ + "DvpMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ", + "9qA21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom", + "8WKGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1", + "7ZkXycbrAhVzeB9ngnjcCdjk5bxTJYzscSZMhRRBx3QB", + "75peBtH5MwfA5t9uhr51AYL7MR5DbPJ5xQ7wizzvowUH", + ]); + + index_seed_events(&setup, seeds.iter().collect_vec()).await; + + let request = r#" + { + "limit": 500, + "ownerAddress": "EcxjN4mea6Ah9WSqZhLtSJJCZcxY73Vaz6UVHFZZ5Ttz", + "tokenType": "nonFungible", + "options": { + "showCollectionMetadata": true, + "showGrandTotal": true, + "showInscription": true, + "showNativeBalance": true + } + }"#; + + let mutexed_tasks = Arc::new(Mutex::new(JoinSet::new())); + + let request: SearchAssets = serde_json::from_str(request).unwrap(); + let response = setup.das_api.search_assets(request, mutexed_tasks.clone()).await.unwrap(); + + response["items"].as_array().unwrap().iter().all(|i| { + let interface = i["interface"].as_str().unwrap(); + assert_eq!(interface, "V1_NFT"); + true + }); + + insta::assert_json_snapshot!(name, response); +} diff --git a/integration_tests/src/snapshots/integration_tests__regular_nft_tests__requested_non_fungibles_are_non_fungibles.snap b/integration_tests/src/snapshots/integration_tests__regular_nft_tests__requested_non_fungibles_are_non_fungibles.snap new file mode 100644 index 00000000..300d4ddd --- /dev/null +++ b/integration_tests/src/snapshots/integration_tests__regular_nft_tests__requested_non_fungibles_are_non_fungibles.snap @@ -0,0 +1,458 @@ +--- +source: integration_tests/src/regular_nft_tests.rs +assertion_line: 271 +expression: response +snapshot_kind: text +--- +{ + "total": 5, + "grand_total": 5, + "limit": 500, + "items": [ + { + "interface": "V1_NFT", + "id": "DvpMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://nftstorage.link/ipfs/bafkreigq3rvy636lvj23tid5ioxd4ovtcivfbhhjst5hk7fhziedygew3a", + "files": [], + "metadata": { + "name": "LIBRE", + "symbol": "LIBRE" + }, + "links": {} + }, + "authorities": [ + { + "address": "", + "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": "single", + "owner": "EcxjN4mea6Ah9WSqZhLtSJJCZcxY73Vaz6UVHFZZ5Ttz" + }, + "supply": { + "print_max_supply": 0, + "print_current_supply": 0, + "edition_nonce": null + }, + "mutable": true, + "burnt": false, + "mint_extensions": { + "metadata_pointer": { + "authority": "2jL7yFGXkKE9oi1xHsA45UzV5491PD55AugGJiTbUr9m", + "metadata_address": "DvpMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ" + }, + "metadata": { + "update_authority": "2jL7yFGXkKE9oi1xHsA45UzV5491PD55AugGJiTbUr9m", + "mint": "DvpMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ", + "name": "LIBRE", + "symbol": "LIBRE", + "uri": "https://nftstorage.link/ipfs/bafkreigq3rvy636lvj23tid5ioxd4ovtcivfbhhjst5hk7fhziedygew3a", + "additional_metadata": [] + }, + "group_member_pointer": { + "authority": "2jL7yFGXkKE9oi1xHsA45UzV5491PD55AugGJiTbUr9m", + "member_address": "DvpMQyF8sT6hPBewQf6VrVESw6L1zewPyNit1CSt1tDJ" + } + }, + "token_info": { + "supply": 1, + "decimals": 0, + "token_program": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb", + "freeze_authority": "2jL7yFGXkKE9oi1xHsA45UzV5491PD55AugGJiTbUr9m" + } + }, + { + "interface": "V1_NFT", + "id": "9qA21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://api.akord.com/files/5d0e6fa5-01dc-4893-a2d7-64be4d576449", + "files": [], + "metadata": { + "name": "backpack.eclipse", + "symbol": "SN" + }, + "links": {} + }, + "authorities": [ + { + "address": "", + "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": "single", + "owner": "EcxjN4mea6Ah9WSqZhLtSJJCZcxY73Vaz6UVHFZZ5Ttz" + }, + "supply": { + "print_max_supply": 0, + "print_current_supply": 0, + "edition_nonce": null + }, + "mutable": true, + "burnt": false, + "mint_extensions": { + "metadata_pointer": { + "authority": "6qVNPWh4Qhr6pBVZQMNpxwn477rg5LUkjBFuG5KpZvJc", + "metadata_address": "9qA21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom" + }, + "metadata": { + "update_authority": "6qVNPWh4Qhr6pBVZQMNpxwn477rg5LUkjBFuG5KpZvJc", + "mint": "9qA21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom", + "name": "backpack.eclipse", + "symbol": "SN", + "uri": "https://api.akord.com/files/5d0e6fa5-01dc-4893-a2d7-64be4d576449", + "additional_metadata": [] + }, + "group_member_pointer": { + "authority": "6qVNPWh4Qhr6pBVZQMNpxwn477rg5LUkjBFuG5KpZvJc", + "member_address": "9qA21TR9QTsQeR5sP6L2PytjgxXcVRSyqUY5vRcUogom" + } + }, + "token_info": { + "supply": 1, + "decimals": 0, + "token_program": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" + } + }, + { + "interface": "V1_NFT", + "id": "8WKGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://nftstorage.link/ipfs/bafkreigq3rvy636lvj23tid5ioxd4ovtcivfbhhjst5hk7fhziedygew3a", + "files": [], + "metadata": { + "name": "LIBRE", + "symbol": "LIBRE" + }, + "links": {} + }, + "authorities": [ + { + "address": "", + "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": "single", + "owner": "EcxjN4mea6Ah9WSqZhLtSJJCZcxY73Vaz6UVHFZZ5Ttz" + }, + "supply": { + "print_max_supply": 0, + "print_current_supply": 0, + "edition_nonce": null + }, + "mutable": true, + "burnt": false, + "mint_extensions": { + "metadata_pointer": { + "authority": "2jL7yFGXkKE9oi1xHsA45UzV5491PD55AugGJiTbUr9m", + "metadata_address": "8WKGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1" + }, + "metadata": { + "update_authority": "2jL7yFGXkKE9oi1xHsA45UzV5491PD55AugGJiTbUr9m", + "mint": "8WKGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1", + "name": "LIBRE", + "symbol": "LIBRE", + "uri": "https://nftstorage.link/ipfs/bafkreigq3rvy636lvj23tid5ioxd4ovtcivfbhhjst5hk7fhziedygew3a", + "additional_metadata": [] + }, + "group_member_pointer": { + "authority": "2jL7yFGXkKE9oi1xHsA45UzV5491PD55AugGJiTbUr9m", + "member_address": "8WKGo1z9k3PjTsQw5GDQmvAbKwuRGtb4APkCneH8AVY1" + } + }, + "token_info": { + "supply": 1, + "decimals": 0, + "token_program": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb", + "freeze_authority": "2jL7yFGXkKE9oi1xHsA45UzV5491PD55AugGJiTbUr9m" + } + }, + { + "interface": "V1_NFT", + "id": "7ZkXycbrAhVzeB9ngnjcCdjk5bxTJYzscSZMhRRBx3QB", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "ipfs://QmTmNdx3cNT4wv5yyi7ajvPLZTVia6QzWzg1AAkKtauqqs", + "files": [], + "metadata": { + "name": "Path of Discovery", + "symbol": "POD" + }, + "links": {} + }, + "authorities": [ + { + "address": "", + "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": "single", + "owner": "EcxjN4mea6Ah9WSqZhLtSJJCZcxY73Vaz6UVHFZZ5Ttz" + }, + "supply": { + "print_max_supply": 0, + "print_current_supply": 0, + "edition_nonce": null + }, + "mutable": true, + "burnt": false, + "mint_extensions": { + "metadata_pointer": { + "authority": "6wBjjwmWAZzuzAYt9N7EbhPsthE6m2LStNAxZUbViqQb", + "metadata_address": "7ZkXycbrAhVzeB9ngnjcCdjk5bxTJYzscSZMhRRBx3QB" + }, + "metadata": { + "update_authority": "6wBjjwmWAZzuzAYt9N7EbhPsthE6m2LStNAxZUbViqQb", + "mint": "7ZkXycbrAhVzeB9ngnjcCdjk5bxTJYzscSZMhRRBx3QB", + "name": "Path of Discovery", + "symbol": "POD", + "uri": "ipfs://QmTmNdx3cNT4wv5yyi7ajvPLZTVia6QzWzg1AAkKtauqqs", + "additional_metadata": [ + [ + "royalty_basis_points", + "5000" + ], + [ + "AsSKqK7CkxFUf3KaoQzzr8ZLPm5fFguUtVE5QwGALQQn", + "100" + ] + ] + }, + "group_member_pointer": { + "authority": "6wBjjwmWAZzuzAYt9N7EbhPsthE6m2LStNAxZUbViqQb", + "member_address": "7ZkXycbrAhVzeB9ngnjcCdjk5bxTJYzscSZMhRRBx3QB" + } + }, + "token_info": { + "supply": 1, + "decimals": 0, + "token_program": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb", + "freeze_authority": "6wBjjwmWAZzuzAYt9N7EbhPsthE6m2LStNAxZUbViqQb" + } + }, + { + "interface": "V1_NFT", + "id": "75peBtH5MwfA5t9uhr51AYL7MR5DbPJ5xQ7wizzvowUH", + "content": { + "$schema": "https://schema.metaplex.com/nft1.0.json", + "json_uri": "https://s3.filebase.com/eclipsedomains/eclipse-item.json", + "files": [], + "metadata": { + "name": "backpack.eclipse", + "symbol": "ED" + }, + "links": {} + }, + "authorities": [ + { + "address": "", + "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": "single", + "owner": "EcxjN4mea6Ah9WSqZhLtSJJCZcxY73Vaz6UVHFZZ5Ttz" + }, + "supply": { + "print_max_supply": 0, + "print_current_supply": 0, + "edition_nonce": null + }, + "mutable": true, + "burnt": false, + "mint_extensions": { + "permanent_delegate": { + "delegate": "8JGNPBnUFHyjtzF8h9orj7fWNRLJBbvJZvZB2nwjE4Zo" + }, + "metadata_pointer": { + "authority": "8JGNPBnUFHyjtzF8h9orj7fWNRLJBbvJZvZB2nwjE4Zo", + "metadata_address": "75peBtH5MwfA5t9uhr51AYL7MR5DbPJ5xQ7wizzvowUH" + }, + "metadata": { + "update_authority": "8JGNPBnUFHyjtzF8h9orj7fWNRLJBbvJZvZB2nwjE4Zo", + "mint": "75peBtH5MwfA5t9uhr51AYL7MR5DbPJ5xQ7wizzvowUH", + "name": "backpack.eclipse", + "symbol": "ED", + "uri": "https://s3.filebase.com/eclipsedomains/eclipse-item.json", + "additional_metadata": [ + [ + "royalty_basis_points", + "500" + ], + [ + "FBepPeUcmFupjK7rWonB5gKtjT16AbExnhSVC1bBPAqf", + "100" + ], + [ + "expiration_date", + "1765018176" + ], + [ + "domain", + "backpack.eclipse" + ], + [ + "extension", + "eclipse" + ], + [ + "length", + "8" + ], + [ + "created_at", + "1733482176" + ], + [ + "updated_at", + "1735340757" + ] + ] + }, + "group_member_pointer": { + "authority": "8JGNPBnUFHyjtzF8h9orj7fWNRLJBbvJZvZB2nwjE4Zo", + "member_address": "EdmnsgHGEeeBoGEhtK4th6L3ebmfzfR9Lvw9oi9t4nnL" + } + }, + "token_info": { + "supply": 1, + "decimals": 0, + "token_program": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb", + "freeze_authority": "8JGNPBnUFHyjtzF8h9orj7fWNRLJBbvJZvZB2nwjE4Zo" + } + } + ], + "cursor": "75peBtH5MwfA5t9uhr51AYL7MR5DbPJ5xQ7wizzvowUH" +} diff --git a/nft_ingester/tests/api_tests.rs b/nft_ingester/tests/api_tests.rs index e81d3323..c57844d1 100644 --- a/nft_ingester/tests/api_tests.rs +++ b/nft_ingester/tests/api_tests.rs @@ -3717,4 +3717,178 @@ mod tests { NATIVE_MINT_PUBKEY.to_string(), ) } + + #[tokio::test] + #[tracing_test::traced_test] + async fn test_static_details_transition_from_fungible_into_nft() { + // Given Fungible Metadata + // When updated comes + // Then it should be recorded as fungible + + let cnt = 0; + let cli = Cli::default(); + let (env, _) = setup::TestEnvironment::create(&cli, cnt, SLOT_UPDATED).await; + let api = nft_ingester::api::api_impl::DasApi::< + MaybeProofChecker, + JsonWorker, + JsonWorker, + MockAccountBalanceGetter, + RaydiumTokenPriceFetcher, + Storage, + >::new( + env.pg_env.client.clone(), + env.rocks_env.storage.clone(), + Arc::new(ApiMetricsConfig::new()), + None, + None, + 50, + None, + None, + JsonMiddlewareConfig::default(), + Arc::new(MockAccountBalanceGetter::new()), + None, + Arc::new(RaydiumTokenPriceFetcher::default()), + NATIVE_MINT_PUBKEY.to_string(), + ); + let tasks = JoinSet::new(); + let mutexed_tasks = Arc::new(Mutex::new(tasks)); + + let token_updates_processor = + TokenAccountsProcessor::new(Arc::new(IngesterMetricsConfig::new())); + let mplx_updates_processor = + MplxAccountsProcessor::new(Arc::new(IngesterMetricsConfig::new())); + + let token_key = Pubkey::new_unique(); + let mint_key = Pubkey::new_unique(); + let owner_key = Pubkey::new_unique(); + + let mint_auth_key = Pubkey::new_unique(); + + let token_acc = TokenAccount { + pubkey: token_key, + mint: mint_key, + delegate: None, + owner: owner_key, + extensions: None, + frozen: false, + delegated_amount: 0, + slot_updated: 1, + amount: 1, + write_version: 1, + }; + + let mint_acc = Mint { + pubkey: mint_key, + slot_updated: 1, + supply: 10, + decimals: 0, + mint_authority: Some(mint_auth_key), + freeze_authority: None, + token_program: Default::default(), + extensions: None, + write_version: 1, + }; + + let metadata = MetadataInfo { + metadata: Metadata { + key: Key::MetadataV1, + update_authority: Pubkey::new_unique(), + mint: mint_key, + name: "".to_string(), + symbol: "".to_string(), + uri: "".to_string(), + seller_fee_basis_points: 0, + creators: None, + primary_sale_happened: false, + is_mutable: true, + edition_nonce: None, + token_standard: Some(mpl_token_metadata::types::TokenStandard::Fungible), + collection: None, + uses: None, + collection_details: None, + programmable_config: None, + }, + slot_updated: 1, + write_version: 1, + lamports: 1, + executable: false, + metadata_owner: None, + rent_epoch: 0, + }; + let offchain_data = OffChainData { + url: Some("https://ping-pong".to_string()), + metadata: Some("{\"msg\": \"hallo\"}".to_string()), + ..Default::default() + }; + + env.rocks_env + .storage + .asset_offchain_data + .put(offchain_data.url.clone().unwrap(), offchain_data.clone()) + .unwrap(); + + let mut batch_storage = BatchSaveStorage::new( + env.rocks_env.storage.clone(), + 10, + Arc::new(IngesterMetricsConfig::new()), + ); + token_updates_processor + .transform_and_save_mint_account(&mut batch_storage, &mint_acc) + .unwrap(); + token_updates_processor + .transform_and_save_token_account(&mut batch_storage, token_acc.pubkey, &token_acc) + .unwrap(); + + mplx_updates_processor + .transform_and_store_metadata_account(&mut batch_storage, mint_key, &metadata) + .unwrap(); + batch_storage.flush().unwrap(); + + let payload = GetAsset { + id: mint_key.to_string(), + options: Options { show_unverified_collections: true, ..Default::default() }, + }; + let response = api.get_asset(payload.clone(), mutexed_tasks.clone()).await.unwrap(); + + assert_eq!(response["interface"], "FungibleToken".to_string()); + + // Given record that respects fungible metadata + // When updated comes with NFT metadata + // Then it should transfer to NFT + + let metadata = MetadataInfo { + metadata: Metadata { + token_standard: Some(mpl_token_metadata::types::TokenStandard::NonFungible), + ..metadata.metadata + }, + ..metadata + }; + + mplx_updates_processor + .transform_and_store_metadata_account(&mut batch_storage, mint_key, &metadata) + .unwrap(); + batch_storage.flush().unwrap(); + let response = api.get_asset(payload.clone(), mutexed_tasks.clone()).await.unwrap(); + + assert_eq!(response["interface"], "V1_NFT".to_string()); + + // Given record that respects NFT metadata + // When updated comes with fungible metadata + // Then it should stay as NFT + let metadata = MetadataInfo { + metadata: Metadata { + token_standard: Some(mpl_token_metadata::types::TokenStandard::Fungible), + ..metadata.metadata + }, + ..metadata + }; + + mplx_updates_processor + .transform_and_store_metadata_account(&mut batch_storage, mint_key, &metadata) + .unwrap(); + batch_storage.flush().unwrap(); + let response = api.get_asset(payload.clone(), mutexed_tasks.clone()).await.unwrap(); + + assert_eq!(response["interface"], "V1_NFT".to_string()); + } }