|
1 |
| -use std::collections::HashMap; |
| 1 | +use std::{collections::HashMap, str::FromStr, sync::Arc}; |
2 | 2 |
|
3 | 3 | use entities::{
|
4 |
| - api_req_params::{GetAsset, GetAssetBatch, GetAssetsByGroup, SearchAssets}, |
5 |
| - enums::{AssetType, AssetType::Fungible}, |
| 4 | + api_req_params::{GetAsset, GetAssetBatch, GetAssetsByGroup, GetNftEditions, SearchAssets}, |
| 5 | + enums::{AssetType, AssetType::Fungible, TokenMetadataEdition}, |
| 6 | + models::{EditionMetadata, EditionV1, MasterEdition}, |
6 | 7 | };
|
7 | 8 | use function_name::named;
|
8 | 9 | use itertools::Itertools;
|
| 10 | +use metrics_utils::IngesterMetricsConfig; |
9 | 11 | use nft_ingester::{
|
10 | 12 | api::dapi::response::AssetList,
|
11 | 13 | consts::RAYDIUM_API_HOST,
|
| 14 | + processors::account_based::mplx_updates_processor::MplxAccountsProcessor, |
12 | 15 | raydium_price_fetcher::{RaydiumTokenPriceFetcher, CACHE_TTL},
|
13 | 16 | scheduler::{update_fungible_token_static_details, Scheduler},
|
14 | 17 | };
|
| 18 | +use rocks_db::batch_savers::BatchSaveStorage; |
15 | 19 | use serial_test::serial;
|
| 20 | +use solana_sdk::pubkey::Pubkey; |
16 | 21 | use tokio_util::sync::CancellationToken;
|
17 | 22 | use AssetType::NonFungible;
|
18 | 23 |
|
@@ -1149,3 +1154,233 @@ async fn test_update_fungible_token_static_details_job() {
|
1149 | 1154 |
|
1150 | 1155 | insta::assert_json_snapshot!(name, response);
|
1151 | 1156 | }
|
| 1157 | + |
| 1158 | +#[named] |
| 1159 | +#[serial] |
| 1160 | +#[tokio::test(flavor = "multi_thread")] |
| 1161 | +#[tracing_test::traced_test] |
| 1162 | +async fn test_get_master_editions() { |
| 1163 | + let name = trim_test_name(function_name!()); |
| 1164 | + let first_mint_master_edition = |
| 1165 | + Pubkey::from_str("Ey2Qb8kLctbchQsMnhZs5DjY32To2QtPuXNwWvk4NosL").unwrap(); |
| 1166 | + let second_mint_edition = |
| 1167 | + Pubkey::from_str("GJvFDcBWf6aDncd1TBzx2ou1rgLFYaMBdbYLBa9oTAEw").unwrap(); |
| 1168 | + let third_mint_edition = |
| 1169 | + Pubkey::from_str("9yQecKKYSHxez7fFjJkUvkz42TLmkoXzhyZxEf2pw8pz").unwrap(); |
| 1170 | + let fourth_mint_edition = |
| 1171 | + Pubkey::from_str("7AeRUkukNCpWFtxK2QBZr1PymzPde6qtQYND6CajrE2B").unwrap(); |
| 1172 | + let supply = 123; |
| 1173 | + let max_supply = 10000; |
| 1174 | + |
| 1175 | + let setup = TestSetup::new_with_options( |
| 1176 | + name.clone(), |
| 1177 | + TestSetupOptions { |
| 1178 | + network: Some(Network::Mainnet), |
| 1179 | + clear_db: true, |
| 1180 | + well_known_fungible_accounts: HashMap::new(), |
| 1181 | + }, |
| 1182 | + ) |
| 1183 | + .await; |
| 1184 | + |
| 1185 | + let seeds: Vec<SeedEvent> = seed_nfts([ |
| 1186 | + first_mint_master_edition.to_string(), // Master Edition |
| 1187 | + second_mint_edition.to_string(), |
| 1188 | + third_mint_edition.to_string(), |
| 1189 | + fourth_mint_edition.to_string(), |
| 1190 | + ]); |
| 1191 | + index_seed_events(&setup, seeds.iter().collect_vec()).await; |
| 1192 | + |
| 1193 | + let first_mint_master_edition_to_save = EditionMetadata { |
| 1194 | + edition: TokenMetadataEdition::MasterEdition { |
| 1195 | + 0: MasterEdition { |
| 1196 | + key: first_mint_master_edition, |
| 1197 | + supply, |
| 1198 | + max_supply: Some(max_supply), |
| 1199 | + write_version: 1, |
| 1200 | + }, |
| 1201 | + }, |
| 1202 | + write_version: 1, |
| 1203 | + slot_updated: 1, |
| 1204 | + }; |
| 1205 | + let second_mint_edition_to_save = |
| 1206 | + create_edition_metadata(second_mint_edition, first_mint_master_edition, 1); |
| 1207 | + let third_mint_edition_to_save = |
| 1208 | + create_edition_metadata(third_mint_edition, first_mint_master_edition, 2); |
| 1209 | + let fourth_mint_edition_to_save = |
| 1210 | + create_edition_metadata(fourth_mint_edition, first_mint_master_edition, 3); |
| 1211 | + |
| 1212 | + let mut batch_storage = |
| 1213 | + BatchSaveStorage::new(setup.rocks_db, 10, Arc::new(IngesterMetricsConfig::new())); |
| 1214 | + let mplx_accs_parser = MplxAccountsProcessor::new(Arc::new(IngesterMetricsConfig::new())); |
| 1215 | + |
| 1216 | + mplx_accs_parser |
| 1217 | + .transform_and_store_edition_account( |
| 1218 | + &mut batch_storage, |
| 1219 | + first_mint_master_edition, |
| 1220 | + &first_mint_master_edition_to_save.edition, |
| 1221 | + ) |
| 1222 | + .unwrap(); |
| 1223 | + mplx_accs_parser |
| 1224 | + .transform_and_store_edition_account( |
| 1225 | + &mut batch_storage, |
| 1226 | + second_mint_edition, |
| 1227 | + &second_mint_edition_to_save.edition, |
| 1228 | + ) |
| 1229 | + .unwrap(); |
| 1230 | + mplx_accs_parser |
| 1231 | + .transform_and_store_edition_account( |
| 1232 | + &mut batch_storage, |
| 1233 | + third_mint_edition, |
| 1234 | + &third_mint_edition_to_save.edition, |
| 1235 | + ) |
| 1236 | + .unwrap(); |
| 1237 | + mplx_accs_parser |
| 1238 | + .transform_and_store_edition_account( |
| 1239 | + &mut batch_storage, |
| 1240 | + fourth_mint_edition, |
| 1241 | + &fourth_mint_edition_to_save.edition, |
| 1242 | + ) |
| 1243 | + .unwrap(); |
| 1244 | + |
| 1245 | + batch_storage.flush().unwrap(); |
| 1246 | + |
| 1247 | + let request = r#" |
| 1248 | + { |
| 1249 | + "page": 1, |
| 1250 | + "limit": 100, |
| 1251 | + "mint": "Ey2Qb8kLctbchQsMnhZs5DjY32To2QtPuXNwWvk4NosL" |
| 1252 | + }"#; |
| 1253 | + let request: GetNftEditions = serde_json::from_str(request).unwrap(); |
| 1254 | + let response = setup.das_api.get_nft_editions(request).await.unwrap(); |
| 1255 | + |
| 1256 | + assert_eq!(response["page"], 1); |
| 1257 | + assert_eq!(response["total"], 3); |
| 1258 | + assert_eq!(response["limit"], 100); |
| 1259 | + assert_eq!(response["supply"], supply); |
| 1260 | + assert_eq!(response["max_supply"], max_supply); |
| 1261 | + assert_eq!(response["editions"].as_array().unwrap().len(), 3); |
| 1262 | + assert_eq!(response["editions"].as_array().unwrap()[0]["edition"], 1); |
| 1263 | + assert_eq!(response["editions"].as_array().unwrap()[1]["edition"], 2); |
| 1264 | + assert_eq!(response["editions"].as_array().unwrap()[2]["edition"], 3); |
| 1265 | + insta::assert_json_snapshot!(format!("{}_all_items_in_sorted_order", name), response); |
| 1266 | + |
| 1267 | + let request = r#" |
| 1268 | + { |
| 1269 | + "page": 1, |
| 1270 | + "limit": 2, |
| 1271 | + "mint": "Ey2Qb8kLctbchQsMnhZs5DjY32To2QtPuXNwWvk4NosL" |
| 1272 | + }"#; |
| 1273 | + let request: GetNftEditions = serde_json::from_str(request).unwrap(); |
| 1274 | + let response = setup.das_api.get_nft_editions(request).await.unwrap(); |
| 1275 | + |
| 1276 | + assert_eq!(response["page"], 1); |
| 1277 | + assert_eq!(response["total"], 2); |
| 1278 | + assert_eq!(response["limit"], 2); |
| 1279 | + assert_eq!(response["supply"], supply); |
| 1280 | + assert_eq!(response["max_supply"], max_supply); |
| 1281 | + assert_eq!(response["editions"].as_array().unwrap().len(), 2); |
| 1282 | + assert_eq!(response["editions"].as_array().unwrap()[0]["edition"], 1); |
| 1283 | + assert_eq!(response["editions"].as_array().unwrap()[1]["edition"], 2); |
| 1284 | + insta::assert_json_snapshot!(format!("{}_few_items_in_sorted_order", name), response); |
| 1285 | + |
| 1286 | + let request = r#" |
| 1287 | + { |
| 1288 | + "page": 1, |
| 1289 | + "limit": 1, |
| 1290 | + "mint": "Ey2Qb8kLctbchQsMnhZs5DjY32To2QtPuXNwWvk4NosL" |
| 1291 | + }"#; |
| 1292 | + let request: GetNftEditions = serde_json::from_str(request).unwrap(); |
| 1293 | + let response = setup.das_api.get_nft_editions(request).await.unwrap(); |
| 1294 | + |
| 1295 | + assert_eq!(response["page"], 1); |
| 1296 | + assert_eq!(response["total"], 1); |
| 1297 | + assert_eq!(response["limit"], 1); |
| 1298 | + assert_eq!(response["supply"], supply); |
| 1299 | + assert_eq!(response["max_supply"], max_supply); |
| 1300 | + assert_eq!(response["editions"].as_array().unwrap().len(), 1); |
| 1301 | + assert_eq!(response["editions"].as_array().unwrap()[0]["edition"], 1); |
| 1302 | + insta::assert_json_snapshot!(format!("{}_first_page", name), response); |
| 1303 | + |
| 1304 | + let request = r#" |
| 1305 | + { |
| 1306 | + "page": 2, |
| 1307 | + "limit": 1, |
| 1308 | + "mint": "Ey2Qb8kLctbchQsMnhZs5DjY32To2QtPuXNwWvk4NosL" |
| 1309 | + }"#; |
| 1310 | + let request: GetNftEditions = serde_json::from_str(request).unwrap(); |
| 1311 | + let response = setup.das_api.get_nft_editions(request).await.unwrap(); |
| 1312 | + |
| 1313 | + assert_eq!(response["page"], 2); |
| 1314 | + assert_eq!(response["total"], 1); |
| 1315 | + assert_eq!(response["limit"], 1); |
| 1316 | + assert_eq!(response["supply"], supply); |
| 1317 | + assert_eq!(response["max_supply"], max_supply); |
| 1318 | + assert_eq!(response["editions"].as_array().unwrap().len(), 1); |
| 1319 | + assert_eq!(response["editions"].as_array().unwrap()[0]["edition"], 2); |
| 1320 | + insta::assert_json_snapshot!(format!("{}_second_page", name), response); |
| 1321 | + |
| 1322 | + let request = r#" |
| 1323 | + { |
| 1324 | + "page": 50, |
| 1325 | + "limit": 1, |
| 1326 | + "mint": "Ey2Qb8kLctbchQsMnhZs5DjY32To2QtPuXNwWvk4NosL" |
| 1327 | + }"#; |
| 1328 | + let request: GetNftEditions = serde_json::from_str(request).unwrap(); |
| 1329 | + let response = setup.das_api.get_nft_editions(request).await.unwrap(); |
| 1330 | + |
| 1331 | + assert_eq!(response["page"], 50); |
| 1332 | + assert_eq!(response["total"], 0); |
| 1333 | + assert_eq!(response["limit"], 1); |
| 1334 | + assert_eq!(response["supply"], supply); |
| 1335 | + assert_eq!(response["max_supply"], max_supply); |
| 1336 | + assert_eq!(response["editions"].as_array().unwrap().len(), 0); |
| 1337 | + insta::assert_json_snapshot!(format!("{}_page_out_of_range", name), response); |
| 1338 | + |
| 1339 | + let request = r#" |
| 1340 | + { |
| 1341 | + "after": "1", |
| 1342 | + "limit": 100, |
| 1343 | + "mint": "Ey2Qb8kLctbchQsMnhZs5DjY32To2QtPuXNwWvk4NosL" |
| 1344 | + }"#; |
| 1345 | + let request: GetNftEditions = serde_json::from_str(request).unwrap(); |
| 1346 | + let response = setup.das_api.get_nft_editions(request).await.unwrap(); |
| 1347 | + |
| 1348 | + assert_eq!(response["after"], "1"); |
| 1349 | + assert_eq!(response["total"], 2); |
| 1350 | + assert_eq!(response["limit"], 100); |
| 1351 | + assert_eq!(response["supply"], supply); |
| 1352 | + assert_eq!(response["max_supply"], max_supply); |
| 1353 | + assert_eq!(response["editions"].as_array().unwrap().len(), 2); |
| 1354 | + assert_eq!(response["editions"].as_array().unwrap()[0]["edition"], 2); |
| 1355 | + assert_eq!(response["editions"].as_array().unwrap()[1]["edition"], 3); |
| 1356 | + insta::assert_json_snapshot!(format!("{}_page_after_first", name), response); |
| 1357 | + |
| 1358 | + let request = r#" |
| 1359 | + { |
| 1360 | + "before": "3", |
| 1361 | + "limit": 100, |
| 1362 | + "mint": "Ey2Qb8kLctbchQsMnhZs5DjY32To2QtPuXNwWvk4NosL" |
| 1363 | + }"#; |
| 1364 | + let request: GetNftEditions = serde_json::from_str(request).unwrap(); |
| 1365 | + let response = setup.das_api.get_nft_editions(request).await.unwrap(); |
| 1366 | + |
| 1367 | + assert_eq!(response["before"], "3"); |
| 1368 | + assert_eq!(response["total"], 2); |
| 1369 | + assert_eq!(response["limit"], 100); |
| 1370 | + assert_eq!(response["supply"], supply); |
| 1371 | + assert_eq!(response["max_supply"], max_supply); |
| 1372 | + assert_eq!(response["editions"].as_array().unwrap().len(), 2); |
| 1373 | + assert_eq!(response["editions"].as_array().unwrap()[0]["edition"], 1); |
| 1374 | + assert_eq!(response["editions"].as_array().unwrap()[1]["edition"], 2); |
| 1375 | + insta::assert_json_snapshot!(format!("{}_page_before_third", name), response); |
| 1376 | +} |
| 1377 | + |
| 1378 | +fn create_edition_metadata(key: Pubkey, parent: Pubkey, edition: u64) -> EditionMetadata { |
| 1379 | + EditionMetadata { |
| 1380 | + edition: TokenMetadataEdition::EditionV1 { |
| 1381 | + 0: EditionV1 { key, parent, edition, write_version: 1 }, |
| 1382 | + }, |
| 1383 | + write_version: 1, |
| 1384 | + slot_updated: 1, |
| 1385 | + } |
| 1386 | +} |
0 commit comments