From c30056f6a3f6e92d058d2aaff83ba02c58e4a4ad Mon Sep 17 00:00:00 2001 From: Michael Danenberg <56533526+danenbm@users.noreply.github.com> Date: Wed, 2 Jul 2025 13:49:38 -0700 Subject: [PATCH 1/9] Fix docker build --- Api.Dockerfile | 2 +- Builder.Dockerfile | 4 ++-- Ingest.Dockerfile | 2 +- Load.Dockerfile | 2 +- Migrator.Dockerfile | 2 +- Proxy.Dockerfile | 4 ++-- metaplex-rpc-proxy/src/lib.rs | 4 ++++ rust-toolchain.toml | 2 +- 8 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Api.Dockerfile b/Api.Dockerfile index c0e61f6f5..dee9c4a60 100644 --- a/Api.Dockerfile +++ b/Api.Dockerfile @@ -1,5 +1,5 @@ FROM das-api/builder AS files -FROM rust:1.81-slim-bullseye +FROM rust:1.82-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 5d932fc52..f17f0c66c 100644 --- a/Builder.Dockerfile +++ b/Builder.Dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.81-bullseye AS builder +FROM rust:1.82-bullseye AS builder RUN apt-get update -y && \ apt-get install -y build-essential make git @@ -21,6 +21,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.81-slim-bullseye as final +FROM rust:1.82-slim-bullseye as final COPY --from=builder /rust/bins /das/ CMD echo "Built the DAS API bins!" diff --git a/Ingest.Dockerfile b/Ingest.Dockerfile index f93087b83..66a4105f3 100644 --- a/Ingest.Dockerfile +++ b/Ingest.Dockerfile @@ -1,5 +1,5 @@ FROM das-api/builder AS files -FROM rust:1.81-slim-bullseye +FROM rust:1.82-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 37b68e493..d87e21bdc 100644 --- a/Load.Dockerfile +++ b/Load.Dockerfile @@ -1,5 +1,5 @@ FROM das-api/builder AS files -FROM rust:1.81-slim-bullseye +FROM rust:1.82-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 cc04e83e1..034e75df8 100644 --- a/Migrator.Dockerfile +++ b/Migrator.Dockerfile @@ -1,6 +1,6 @@ FROM das-api/builder AS files -FROM rust:1.81-bullseye +FROM rust:1.82-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 4fa1f8737..2f0176ff4 100644 --- a/Proxy.Dockerfile +++ b/Proxy.Dockerfile @@ -1,5 +1,5 @@ -FROM rust:1.81-bullseye AS builder -RUN cargo install wasm-pack +FROM rust:1.82-bullseye AS builder +RUN cargo install wasm-pack --version 0.13.1 RUN mkdir /rust COPY ./Cargo.toml /rust diff --git a/metaplex-rpc-proxy/src/lib.rs b/metaplex-rpc-proxy/src/lib.rs index 24f60437e..665ad6376 100644 --- a/metaplex-rpc-proxy/src/lib.rs +++ b/metaplex-rpc-proxy/src/lib.rs @@ -5,6 +5,10 @@ use proxy_wasm::types::*; use regex::{Regex, RegexBuilder}; use std::time::Duration; +// Workaround: forces wasm-bindgen to include required intrinsics for proxy-wasm build. +#[allow(unused_imports)] +use wasm_bindgen::JsValue; + proxy_wasm::main! {{ proxy_wasm::set_log_level(LogLevel::Trace); proxy_wasm::set_root_context(|_| -> Box { Box::new(Root) }); diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 071ff5b32..86cda942f 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.81.0" +channel = "1.82.0" components = ["clippy", "rustfmt"] targets = [] profile = "minimal" From d78b0085217256fe3b9fd199fcf525bed5ed6569 Mon Sep 17 00:00:00 2001 From: Michael Danenberg <56533526+danenbm@users.noreply.github.com> Date: Wed, 2 Jul 2025 13:56:20 -0700 Subject: [PATCH 2/9] Fix clippy error --- tools/txn_forwarder/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/txn_forwarder/src/lib.rs b/tools/txn_forwarder/src/lib.rs index c496ab19d..89f7b8e8e 100644 --- a/tools/txn_forwarder/src/lib.rs +++ b/tools/txn_forwarder/src/lib.rs @@ -26,6 +26,7 @@ use { tokio_stream::wrappers::LinesStream, }; +#[allow(clippy::large_enum_variant)] #[derive(Debug, thiserror::Error)] pub enum FindSignaturesError { #[error("Failed to fetch signatures: {0}")] From 8f24a94cf3d2afbd4904be00b8f962dcadfc3e85 Mon Sep 17 00:00:00 2001 From: Michael Danenberg <56533526+danenbm@users.noreply.github.com> Date: Wed, 2 Jul 2025 13:59:45 -0700 Subject: [PATCH 3/9] Add category to RPC response for content, if present --- digital_asset_types/src/dapi/common/asset.rs | 4 +++- digital_asset_types/src/rpc/asset.rs | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/digital_asset_types/src/dapi/common/asset.rs b/digital_asset_types/src/dapi/common/asset.rs index e6ba7ccc5..a9d1ef792 100644 --- a/digital_asset_types/src/dapi/common/asset.rs +++ b/digital_asset_types/src/dapi/common/asset.rs @@ -211,7 +211,8 @@ pub fn v1_content_from_json(asset_data: &asset_data::Model) -> Result = HashMap::new(); if let Some(files) = selector("$.properties.files[*]") .ok() @@ -280,6 +281,7 @@ pub fn v1_content_from_json(asset_data: &asset_data::Model) -> Result, + #[serde(skip_serializing_if = "Option::is_none")] + pub category: Option, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] From cf3c327ab0b987a8aea7471d96bdedc5c3665191 Mon Sep 17 00:00:00 2001 From: Michael Danenberg <56533526+danenbm@users.noreply.github.com> Date: Wed, 2 Jul 2025 15:04:47 -0700 Subject: [PATCH 4/9] Add BubblegumV2 specification asset class enum value --- migration/src/lib.rs | 2 ++ ...50702_120101_add_bubblegum_v2_enum_vals.rs | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 migration/src/m20250702_120101_add_bubblegum_v2_enum_vals.rs diff --git a/migration/src/lib.rs b/migration/src/lib.rs index 3385cd855..c2dd490e7 100644 --- a/migration/src/lib.rs +++ b/migration/src/lib.rs @@ -50,6 +50,7 @@ mod m20250313_105132_drop_idx_token_accounts_owner_and_idx_ta_mint; mod m20250313_105206_add_idx_ta_owner_amount_and_idx_ta_mint_amount; mod m20250321_120101_add_bgum_leaf_schema_v2_items; mod m20250327_120101_add_bubblegum_v2_ixs_to_enum; +mod m20250702_120101_add_bubblegum_v2_enum_vals; pub mod model; @@ -109,6 +110,7 @@ impl MigratorTrait for Migrator { Box::new(m20250313_105206_add_idx_ta_owner_amount_and_idx_ta_mint_amount::Migration), Box::new(m20250321_120101_add_bgum_leaf_schema_v2_items::Migration), Box::new(m20250327_120101_add_bubblegum_v2_ixs_to_enum::Migration), + Box::new(m20250702_120101_add_bubblegum_v2_enum_vals::Migration), ] } } diff --git a/migration/src/m20250702_120101_add_bubblegum_v2_enum_vals.rs b/migration/src/m20250702_120101_add_bubblegum_v2_enum_vals.rs new file mode 100644 index 000000000..5c1f6beef --- /dev/null +++ b/migration/src/m20250702_120101_add_bubblegum_v2_enum_vals.rs @@ -0,0 +1,27 @@ +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> { + manager + .get_connection() + .execute(Statement::from_string( + DatabaseBackend::Postgres, + "ALTER TYPE specification_asset_class ADD VALUE IF NOT EXISTS 'MPL_BUBBLEGUM_V2';" + .to_string(), + )) + .await?; + + Ok(()) + } + + async fn down(&self, _manager: &SchemaManager) -> Result<(), DbErr> { + Ok(()) + } +} From 050fe9c55929b84c202bde35c9b51d6974ef0b59 Mon Sep 17 00:00:00 2001 From: Michael Danenberg <56533526+danenbm@users.noreply.github.com> Date: Wed, 2 Jul 2025 15:13:31 -0700 Subject: [PATCH 5/9] Regenerate SeaORM active enums --- .../src/dao/generated/sea_orm_active_enums.rs | 174 +++++++++--------- 1 file changed, 88 insertions(+), 86 deletions(-) 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 8eafbeee4..dd6d1e336 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 @@ -3,6 +3,80 @@ use sea_orm::entity::prelude::*; use serde::{Deserialize, Serialize}; +#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] +#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "task_status")] +pub enum TaskStatus { + #[sea_orm(string_value = "failed")] + Failed, + #[sea_orm(string_value = "pending")] + Pending, + #[sea_orm(string_value = "running")] + Running, + #[sea_orm(string_value = "success")] + Success, +} +#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] +#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "mutability")] +pub enum Mutability { + #[sea_orm(string_value = "immutable")] + Immutable, + #[sea_orm(string_value = "mutable")] + Mutable, + #[sea_orm(string_value = "unknown")] + Unknown, +} +#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] +#[sea_orm( + rs_type = "String", + db_type = "Enum", + enum_name = "specification_versions" +)] +pub enum SpecificationVersions { + #[sea_orm(string_value = "unknown")] + Unknown, + #[sea_orm(string_value = "v0")] + V0, + #[sea_orm(string_value = "v1")] + V1, + #[sea_orm(string_value = "v2")] + V2, +} +#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] +#[sea_orm( + rs_type = "String", + db_type = "Enum", + enum_name = "v1_account_attachments" +)] +pub enum V1AccountAttachments { + #[sea_orm(string_value = "edition")] + Edition, + #[sea_orm(string_value = "edition_marker")] + EditionMarker, + #[sea_orm(string_value = "master_edition_v1")] + MasterEditionV1, + #[sea_orm(string_value = "master_edition_v2")] + MasterEditionV2, + #[sea_orm(string_value = "token_inscription")] + TokenInscription, + #[sea_orm(string_value = "unknown")] + Unknown, +} +#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] +#[sea_orm( + rs_type = "String", + db_type = "Enum", + enum_name = "royalty_target_type" +)] +pub enum RoyaltyTargetType { + #[sea_orm(string_value = "creators")] + Creators, + #[sea_orm(string_value = "fanout")] + Fanout, + #[sea_orm(string_value = "single")] + Single, + #[sea_orm(string_value = "unknown")] + Unknown, +} #[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] #[sea_orm( rs_type = "String", @@ -16,6 +90,8 @@ pub enum SpecificationAssetClass { FungibleToken, #[sea_orm(string_value = "IDENTITY_NFT")] IdentityNft, + #[sea_orm(string_value = "MPL_BUBBLEGUM_V2")] + MplBubblegumV2, #[sea_orm(string_value = "MPL_CORE_ASSET")] MplCoreAsset, #[sea_orm(string_value = "MPL_CORE_COLLECTION")] @@ -36,46 +112,14 @@ pub enum SpecificationAssetClass { Unknown, } #[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] -#[sea_orm( - rs_type = "String", - db_type = "Enum", - enum_name = "royalty_target_type" -)] -pub enum RoyaltyTargetType { - #[sea_orm(string_value = "creators")] - Creators, - #[sea_orm(string_value = "fanout")] - Fanout, - #[sea_orm(string_value = "single")] - Single, - #[sea_orm(string_value = "unknown")] - Unknown, -} -#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] -#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "owner_type")] -pub enum OwnerType { - #[sea_orm(string_value = "single")] - Single, - #[sea_orm(string_value = "token")] - Token, - #[sea_orm(string_value = "unknown")] - Unknown, -} -#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] -#[sea_orm( - rs_type = "String", - db_type = "Enum", - enum_name = "specification_versions" -)] -pub enum SpecificationVersions { +#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "chain_mutability")] +pub enum ChainMutability { + #[sea_orm(string_value = "immutable")] + Immutable, + #[sea_orm(string_value = "mutable")] + Mutable, #[sea_orm(string_value = "unknown")] Unknown, - #[sea_orm(string_value = "v0")] - V0, - #[sea_orm(string_value = "v1")] - V1, - #[sea_orm(string_value = "v2")] - V2, } #[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] #[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "instruction")] @@ -142,54 +186,12 @@ pub enum Instruction { VerifyCreatorV2, } #[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] -#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "mutability")] -pub enum Mutability { - #[sea_orm(string_value = "immutable")] - Immutable, - #[sea_orm(string_value = "mutable")] - Mutable, - #[sea_orm(string_value = "unknown")] - Unknown, -} -#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] -#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "task_status")] -pub enum TaskStatus { - #[sea_orm(string_value = "failed")] - Failed, - #[sea_orm(string_value = "pending")] - Pending, - #[sea_orm(string_value = "running")] - Running, - #[sea_orm(string_value = "success")] - Success, -} -#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] -#[sea_orm( - rs_type = "String", - db_type = "Enum", - enum_name = "v1_account_attachments" -)] -pub enum V1AccountAttachments { - #[sea_orm(string_value = "edition")] - Edition, - #[sea_orm(string_value = "edition_marker")] - EditionMarker, - #[sea_orm(string_value = "master_edition_v1")] - MasterEditionV1, - #[sea_orm(string_value = "master_edition_v2")] - MasterEditionV2, - #[sea_orm(string_value = "token_inscription")] - TokenInscription, - #[sea_orm(string_value = "unknown")] - Unknown, -} -#[derive(Debug, Clone, PartialEq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] -#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "chain_mutability")] -pub enum ChainMutability { - #[sea_orm(string_value = "immutable")] - Immutable, - #[sea_orm(string_value = "mutable")] - Mutable, +#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "owner_type")] +pub enum OwnerType { + #[sea_orm(string_value = "single")] + Single, + #[sea_orm(string_value = "token")] + Token, #[sea_orm(string_value = "unknown")] Unknown, } From b42ffd572dd39a51e5d74693f6166d351febade0 Mon Sep 17 00:00:00 2001 From: Michael Danenberg <56533526+danenbm@users.noreply.github.com> Date: Wed, 2 Jul 2025 16:23:38 -0700 Subject: [PATCH 6/9] Use BubblegumV2 interface --- blockbuster/src/programs/bubblegum/mod.rs | 2 +- digital_asset_types/src/dapi/common/asset.rs | 13 ++++++- digital_asset_types/src/rpc/asset.rs | 35 +++++++++++-------- program_transformers/src/bubblegum/mint.rs | 11 ++++-- .../src/bubblegum/update_metadata.rs | 11 ++++-- 5 files changed, 52 insertions(+), 20 deletions(-) diff --git a/blockbuster/src/programs/bubblegum/mod.rs b/blockbuster/src/programs/bubblegum/mod.rs index 364bd4c1d..4c9a8b5fd 100644 --- a/blockbuster/src/programs/bubblegum/mod.rs +++ b/blockbuster/src/programs/bubblegum/mod.rs @@ -16,7 +16,7 @@ use mpl_bubblegum::{ types::{BubblegumEventType, MetadataArgs, UpdateArgs}, }; pub use mpl_bubblegum::{ - types::{LeafSchema, UseMethod}, + types::{LeafSchema, UseMethod, Version}, InstructionName, LeafSchemaEvent, ID, }; use solana_sdk::pubkey::Pubkey; diff --git a/digital_asset_types/src/dapi/common/asset.rs b/digital_asset_types/src/dapi/common/asset.rs index a9d1ef792..47371640c 100644 --- a/digital_asset_types/src/dapi/common/asset.rs +++ b/digital_asset_types/src/dapi/common/asset.rs @@ -382,7 +382,16 @@ pub fn asset_to_rpc(asset: FullAsset, options: &Options) -> Result Result Some(Supply { edition_nonce, print_current_supply: 0, diff --git a/digital_asset_types/src/rpc/asset.rs b/digital_asset_types/src/rpc/asset.rs index ff6cd75e5..1cbb2dd53 100644 --- a/digital_asset_types/src/rpc/asset.rs +++ b/digital_asset_types/src/rpc/asset.rs @@ -47,6 +47,8 @@ pub enum Interface { MplCoreAsset, #[serde(rename = "MplCoreCollection")] MplCoreCollection, + #[serde(rename = "MplBubblegumV2")] + MplBubblegumV2, #[default] #[serde(rename = "Custom")] Custom, @@ -55,20 +57,21 @@ pub enum Interface { impl From<(Option<&SpecificationVersions>, &SpecificationAssetClass)> for Interface { fn from(i: (Option<&SpecificationVersions>, &SpecificationAssetClass)) -> Self { match i { + (_, SpecificationAssetClass::FungibleAsset) => Interface::FungibleAsset, + (_, SpecificationAssetClass::FungibleToken) => Interface::FungibleToken, + (_, SpecificationAssetClass::MplBubblegumV2) => Interface::MplBubblegumV2, + (_, SpecificationAssetClass::MplCoreAsset) => Interface::MplCoreAsset, + (_, SpecificationAssetClass::MplCoreCollection) => Interface::MplCoreCollection, + (Some(SpecificationVersions::V0), SpecificationAssetClass::Nft) => { + Interface::LEGACY_NFT + } (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, } } @@ -78,16 +81,20 @@ impl From for (SpecificationVersions, SpecificationAssetClass) { fn from(interface: Interface) -> (SpecificationVersions, SpecificationAssetClass) { match interface { Interface::V1NFT => (SpecificationVersions::V1, SpecificationAssetClass::Nft), - Interface::LEGACY_NFT => (SpecificationVersions::V0, SpecificationAssetClass::Nft), - Interface::ProgrammableNFT => ( - SpecificationVersions::V1, - SpecificationAssetClass::ProgrammableNft, - ), Interface::V1PRINT => (SpecificationVersions::V1, SpecificationAssetClass::Print), + Interface::LEGACY_NFT => (SpecificationVersions::V0, SpecificationAssetClass::Nft), Interface::FungibleAsset => ( SpecificationVersions::V1, SpecificationAssetClass::FungibleAsset, ), + Interface::FungibleToken => ( + SpecificationVersions::V1, + SpecificationAssetClass::FungibleToken, + ), + Interface::ProgrammableNFT => ( + SpecificationVersions::V1, + SpecificationAssetClass::ProgrammableNft, + ), Interface::MplCoreAsset => ( SpecificationVersions::V1, SpecificationAssetClass::MplCoreAsset, @@ -96,9 +103,9 @@ impl From for (SpecificationVersions, SpecificationAssetClass) { SpecificationVersions::V1, SpecificationAssetClass::MplCoreCollection, ), - Interface::FungibleToken => ( + Interface::MplBubblegumV2 => ( SpecificationVersions::V1, - SpecificationAssetClass::FungibleToken, + SpecificationAssetClass::MplBubblegumV2, ), _ => (SpecificationVersions::V1, SpecificationAssetClass::Unknown), } diff --git a/program_transformers/src/bubblegum/mint.rs b/program_transformers/src/bubblegum/mint.rs index 004dfd6be..c378e7f7a 100644 --- a/program_transformers/src/bubblegum/mint.rs +++ b/program_transformers/src/bubblegum/mint.rs @@ -15,7 +15,7 @@ use { }, blockbuster::{ instruction::InstructionBundle, - programs::bubblegum::{BubblegumInstruction, Payload}, + programs::bubblegum::{BubblegumInstruction, Payload, Version}, token_metadata::types::{TokenStandard, Uses}, }, digital_asset_types::{ @@ -109,13 +109,20 @@ where Some(leaf.delegate.to_bytes().to_vec()) }; + // BubblegumV2 now gets its own `SpecificationAssetClass` and `Interface`. + let specification_asset_class = if matches!(le.version, Version::V2) { + SpecificationAssetClass::MplBubblegumV2 + } else { + SpecificationAssetClass::Nft + }; + // Upsert `asset` table base info and `asset_creators` table. upsert_asset_base_info( &multi_txn, id_bytes.to_vec(), OwnerType::Single, SpecificationVersions::V1, - SpecificationAssetClass::Nft, + specification_asset_class, RoyaltyTargetType::Creators, None, metadata.seller_fee_basis_points as i32, diff --git a/program_transformers/src/bubblegum/update_metadata.rs b/program_transformers/src/bubblegum/update_metadata.rs index dfd0f8636..067bb082e 100644 --- a/program_transformers/src/bubblegum/update_metadata.rs +++ b/program_transformers/src/bubblegum/update_metadata.rs @@ -13,7 +13,7 @@ use { }, blockbuster::{ instruction::InstructionBundle, - programs::bubblegum::{BubblegumInstruction, Payload}, + programs::bubblegum::{BubblegumInstruction, Payload, Version}, token_metadata::types::{TokenStandard, Uses}, }, digital_asset_types::{ @@ -144,12 +144,19 @@ where ¤t_metadata.creators }; + // BubblegumV2 now gets its own `SpecificationAssetClass` and `Interface`. + let specification_asset_class = if matches!(le.version, Version::V2) { + SpecificationAssetClass::MplBubblegumV2 + } else { + SpecificationAssetClass::Nft + }; + upsert_asset_base_info( &multi_txn, id_bytes.to_vec(), OwnerType::Single, SpecificationVersions::V1, - SpecificationAssetClass::Nft, + specification_asset_class, RoyaltyTargetType::Creators, None, seller_fee_basis_points as i32, From f9784d2376d78d7a37b970e0a19b1620409a5b69 Mon Sep 17 00:00:00 2001 From: Michael Danenberg <56533526+danenbm@users.noreply.github.com> Date: Wed, 2 Jul 2025 16:41:58 -0700 Subject: [PATCH 7/9] Update integration test results --- ...schema__add_asset_to_collection_using_set_collection_v2.snap | 2 +- ..._leaf_schema__change_collection_using_set_collection_v2.snap | 2 +- ...ests__cnft_tests_v2_leaf_schema__delegate_and_freeze_v2.snap | 2 +- ...tegration_tests__cnft_tests_v2_leaf_schema__delegate_v2.snap | 2 +- ...integration_tests__cnft_tests_v2_leaf_schema__freeze_v2.snap | 2 +- ...ests_v2_leaf_schema__freeze_v2_using_permanent_delegate.snap | 2 +- ...s__cnft_tests_v2_leaf_schema__mint_v2_not_to_collection.snap | 2 +- ...nft_tests_v2_leaf_schema__mint_v2_to_collection_burn_v2.snap | 2 +- ...__cnft_tests_v2_leaf_schema__mint_v2_to_collection_only.snap | 2 +- ...tests_v2_leaf_schema__mint_v2_to_collection_transfer_v2.snap | 2 +- ...n_tests__cnft_tests_v2_leaf_schema__mint_v2_transfer_v2.snap | 2 +- ..._schema__remove_from_collection_using_set_collection_v2.snap | 2 +- ...sts__cnft_tests_v2_leaf_schema__set_non_transferable_v2.snap | 2 +- ...on_tests__cnft_tests_v2_leaf_schema__thaw_and_revoke_v2.snap | 2 +- ...n_tests__cnft_tests_v2_leaf_schema__unverify_creator_v2.snap | 2 +- ...sts_v2_leaf_schema__update_metadata_v2_new_name_new_uri.snap | 2 +- ...ion_tests__cnft_tests_v2_leaf_schema__verify_creator_v2.snap | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__add_asset_to_collection_using_set_collection_v2.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__add_asset_to_collection_using_set_collection_v2.snap index 77785b16b..ec50b926f 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__add_asset_to_collection_using_set_collection_v2.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__add_asset_to_collection_using_set_collection_v2.snap @@ -4,7 +4,7 @@ assertion_line: 33 expression: response --- { - "interface": "V1_NFT", + "interface": "MplBubblegumV2", "id": "5fADezYRRBaiLcRrSMC5Wsqj4mpd4BJkJvjTTQBWaB5T", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__change_collection_using_set_collection_v2.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__change_collection_using_set_collection_v2.snap index 95485c338..be5231fbe 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__change_collection_using_set_collection_v2.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__change_collection_using_set_collection_v2.snap @@ -4,7 +4,7 @@ assertion_line: 33 expression: response --- { - "interface": "V1_NFT", + "interface": "MplBubblegumV2", "id": "7xNZ8rh4zH9EoACqEWymt5FSwgjbkDM1uFQ6MSB6kwc8", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__delegate_and_freeze_v2.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__delegate_and_freeze_v2.snap index dcb273481..38abc609f 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__delegate_and_freeze_v2.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__delegate_and_freeze_v2.snap @@ -4,7 +4,7 @@ assertion_line: 33 expression: response --- { - "interface": "V1_NFT", + "interface": "MplBubblegumV2", "id": "5ryKjZ554B9aSKWyEH4kprdjQSvRk3ioAVPgsxRqcDAf", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__delegate_v2.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__delegate_v2.snap index bab869a64..d460255cb 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__delegate_v2.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__delegate_v2.snap @@ -4,7 +4,7 @@ assertion_line: 33 expression: response --- { - "interface": "V1_NFT", + "interface": "MplBubblegumV2", "id": "6F3Dv73qYxay78WtGMqjB4voY7E8GSmYvbq8nDNroAeC", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__freeze_v2.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__freeze_v2.snap index 2d0d1fc51..31be39036 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__freeze_v2.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__freeze_v2.snap @@ -4,7 +4,7 @@ assertion_line: 33 expression: response --- { - "interface": "V1_NFT", + "interface": "MplBubblegumV2", "id": "4ynkSgr8S9pq3a2ynNHVfJbAcBrBxJUFkRCkwmjEc3TS", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__freeze_v2_using_permanent_delegate.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__freeze_v2_using_permanent_delegate.snap index c98949c29..7c234e8c5 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__freeze_v2_using_permanent_delegate.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__freeze_v2_using_permanent_delegate.snap @@ -4,7 +4,7 @@ assertion_line: 33 expression: response --- { - "interface": "V1_NFT", + "interface": "MplBubblegumV2", "id": "9j8QfKwJvzjiHwcRyi1TCK7sZgm8iEBpGn8sRyGF5Wy8", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__mint_v2_not_to_collection.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__mint_v2_not_to_collection.snap index 19bfe0754..b8c087fce 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__mint_v2_not_to_collection.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__mint_v2_not_to_collection.snap @@ -4,7 +4,7 @@ assertion_line: 33 expression: response --- { - "interface": "V1_NFT", + "interface": "MplBubblegumV2", "id": "8FD8ZTQtPzPzADnSUs1sb3vb54MxQ29mJkcEDTGzDANA", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__mint_v2_to_collection_burn_v2.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__mint_v2_to_collection_burn_v2.snap index 1a1d89986..7eee657ca 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__mint_v2_to_collection_burn_v2.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__mint_v2_to_collection_burn_v2.snap @@ -4,7 +4,7 @@ assertion_line: 33 expression: response --- { - "interface": "V1_NFT", + "interface": "MplBubblegumV2", "id": "FJDXSjkTpx7zZm3mcxzFzHPJ4EMLzgU9DaMtMvHPY6em", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__mint_v2_to_collection_only.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__mint_v2_to_collection_only.snap index 2289c37c0..e55823001 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__mint_v2_to_collection_only.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__mint_v2_to_collection_only.snap @@ -4,7 +4,7 @@ assertion_line: 33 expression: response --- { - "interface": "V1_NFT", + "interface": "MplBubblegumV2", "id": "HGu4vJMLCboGNNVnH6UXrQZKVVXBX4xMZFxfmFgQD9pG", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__mint_v2_to_collection_transfer_v2.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__mint_v2_to_collection_transfer_v2.snap index af7541252..1d4ac0bed 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__mint_v2_to_collection_transfer_v2.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__mint_v2_to_collection_transfer_v2.snap @@ -4,7 +4,7 @@ assertion_line: 33 expression: response --- { - "interface": "V1_NFT", + "interface": "MplBubblegumV2", "id": "86c2p9hZJTPWmFRKz1znX3yx9E8vhESk9wr9soTMET8Y", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__mint_v2_transfer_v2.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__mint_v2_transfer_v2.snap index b402b67aa..517269c1c 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__mint_v2_transfer_v2.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__mint_v2_transfer_v2.snap @@ -4,7 +4,7 @@ assertion_line: 33 expression: response --- { - "interface": "V1_NFT", + "interface": "MplBubblegumV2", "id": "H98ZTBg5XdWRxt35XDznbX2Z1m7nCYeYqoBTdi5qAQBg", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__remove_from_collection_using_set_collection_v2.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__remove_from_collection_using_set_collection_v2.snap index a20f06734..8c6f5c4ee 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__remove_from_collection_using_set_collection_v2.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__remove_from_collection_using_set_collection_v2.snap @@ -4,7 +4,7 @@ assertion_line: 33 expression: response --- { - "interface": "V1_NFT", + "interface": "MplBubblegumV2", "id": "HN6V2risGpYADNKyRoceBwgrUJDnSm6h21uSTLbLVaPY", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__set_non_transferable_v2.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__set_non_transferable_v2.snap index 52ee23ccd..f3fb59ca3 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__set_non_transferable_v2.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__set_non_transferable_v2.snap @@ -4,7 +4,7 @@ assertion_line: 33 expression: response --- { - "interface": "V1_NFT", + "interface": "MplBubblegumV2", "id": "9JZWk34GEsxNWRF6XRxL6LYDhs5W7AuUVX2VHo9UV7ds", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__thaw_and_revoke_v2.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__thaw_and_revoke_v2.snap index 3edeb843e..d230871ed 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__thaw_and_revoke_v2.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__thaw_and_revoke_v2.snap @@ -4,7 +4,7 @@ assertion_line: 33 expression: response --- { - "interface": "V1_NFT", + "interface": "MplBubblegumV2", "id": "J1iH8MiPeW6rFZP8hjM8PEXFAwaKpcHyb5mgsB1pji5r", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__unverify_creator_v2.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__unverify_creator_v2.snap index b4c3b5ee3..ee55c3dc1 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__unverify_creator_v2.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__unverify_creator_v2.snap @@ -4,7 +4,7 @@ assertion_line: 33 expression: response --- { - "interface": "V1_NFT", + "interface": "MplBubblegumV2", "id": "Eoz1EtUHHpNPXU8UHM5dP93npGWzLx6uh19ExexhMwBm", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__update_metadata_v2_new_name_new_uri.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__update_metadata_v2_new_name_new_uri.snap index ce3f37891..c8e78d2da 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__update_metadata_v2_new_name_new_uri.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__update_metadata_v2_new_name_new_uri.snap @@ -4,7 +4,7 @@ assertion_line: 33 expression: response --- { - "interface": "V1_NFT", + "interface": "MplBubblegumV2", "id": "38pabFkaBAVUBwPotd1Wync8ECDbVe8iZLxJyDgZG8jo", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__verify_creator_v2.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__verify_creator_v2.snap index d4efa4909..c4ff0b46f 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__verify_creator_v2.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__cnft_tests_v2_leaf_schema__verify_creator_v2.snap @@ -4,7 +4,7 @@ assertion_line: 33 expression: response --- { - "interface": "V1_NFT", + "interface": "MplBubblegumV2", "id": "7zKon1FrkcHr8cQnEmch9fWn6mfNgihxQz7kqqTVtDE2", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", From fc0579886c2730632cac33d64e3e83b466658eae Mon Sep 17 00:00:00 2001 From: Michael Danenberg <56533526+danenbm@users.noreply.github.com> Date: Tue, 1 Jul 2025 23:12:40 -0700 Subject: [PATCH 8/9] Only update assets in mpl-core collection if auth changed --- prepare-local-docker-env.sh | 14 +++++++------ .../src/mpl_core_program/v1_asset.rs | 20 ++++++++++++++++++- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/prepare-local-docker-env.sh b/prepare-local-docker-env.sh index 01214ace5..909a67349 100755 --- a/prepare-local-docker-env.sh +++ b/prepare-local-docker-env.sh @@ -9,18 +9,20 @@ SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) # go to parent folder cd $(dirname $(dirname $SCRIPT_DIR)) -EXTERNAL_ID_MAINNET=("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s" \ +EXTERNAL_ID_MAINNET=( \ +"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" \ +"BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY" \ "cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK" \ +"CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d" \ +"mcmt6YrQEMKw8Mw43FmpRLmf7BqRnFMKmAcbxE3xkAW" \ +"metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s" \ +"mnoopTCrg4p8ry25e4bcWA9XZjbNjMTfgYVGGEdRsf3" \ "noopb9bkMVfRPU8AsbpTUg8AQkHtKwMYZiFUjNRtMmV" \ -"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" \ "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" \ "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" \ ) -EXTERNAL_ID_DEVNET=("BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY" \ -"mcmt6YrQEMKw8Mw43FmpRLmf7BqRnFMKmAcbxE3xkAW" \ -"mnoopTCrg4p8ry25e4bcWA9XZjbNjMTfgYVGGEdRsf3" \ -) +EXTERNAL_ID_DEVNET=() RPC_MAINNET="https://api.mainnet-beta.solana.com" RPC_DEVNET="https://api.devnet.solana.com" diff --git a/program_transformers/src/mpl_core_program/v1_asset.rs b/program_transformers/src/mpl_core_program/v1_asset.rs index 943f7b99b..49a77244f 100644 --- a/program_transformers/src/mpl_core_program/v1_asset.rs +++ b/program_transformers/src/mpl_core_program/v1_asset.rs @@ -104,6 +104,23 @@ pub async fn save_v1_asset( UpdateAuthority::None => Pubkey::default().to_bytes().to_vec(), }; + // If we are looking at a collection, see if there's an existing record and if so check + // if the authority changed. + let collection_authority_changed = match account_data { + MplCoreAccountData::Collection(_) => { + let existing_record = asset_authority::Entity::find() + .filter(asset_authority::Column::AssetId.eq(id_vec.clone())) + .one(conn) + .await + .map_err(|db_err| ProgramTransformerError::AssetIndexError(db_err.to_string()))?; + + existing_record + .map(|record| record.authority != update_authority) + .unwrap_or(false) + } + _ => false, + }; + let slot_i = slot as i64; let txn = conn.begin().await?; @@ -135,7 +152,8 @@ pub async fn save_v1_asset( .await .map_err(|db_err| ProgramTransformerError::AssetIndexError(db_err.to_string()))?; - if matches!(account_data, MplCoreAccountData::Collection(_)) { + // Only update assets in a collection if the collection authority changed. + if collection_authority_changed { update_group_asset_authorities(conn, id_vec.clone(), update_authority.clone(), slot_i) .await?; } From de7acc70f6aeb7db2fdd5ef33eb77ced301f86d9 Mon Sep 17 00:00:00 2001 From: Michael Danenberg <56533526+danenbm@users.noreply.github.com> Date: Tue, 1 Jul 2025 23:49:21 -0700 Subject: [PATCH 9/9] Default to updating all assets if collection not found --- .../src/mpl_core_program/v1_asset.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/program_transformers/src/mpl_core_program/v1_asset.rs b/program_transformers/src/mpl_core_program/v1_asset.rs index 49a77244f..a7d3c0285 100644 --- a/program_transformers/src/mpl_core_program/v1_asset.rs +++ b/program_transformers/src/mpl_core_program/v1_asset.rs @@ -104,8 +104,8 @@ pub async fn save_v1_asset( UpdateAuthority::None => Pubkey::default().to_bytes().to_vec(), }; - // If we are looking at a collection, see if there's an existing record and if so check - // if the authority changed. + // If this is a collection, check if there's an existing authority record. + // If found, determine whether the authority has changed. let collection_authority_changed = match account_data { MplCoreAccountData::Collection(_) => { let existing_record = asset_authority::Entity::find() @@ -114,9 +114,15 @@ pub async fn save_v1_asset( .await .map_err(|db_err| ProgramTransformerError::AssetIndexError(db_err.to_string()))?; + // We need to update all assets in the collection if: + // 1. The collection is found and its authority has changed. + // 2. The collection is not found. + // + // Case 2 requires us to attempt to update all assets in a collection because assets + // can be indexed before the collection itself. existing_record .map(|record| record.authority != update_authority) - .unwrap_or(false) + .unwrap_or(true) } _ => false, };