diff --git a/consumer/src/backend.rs b/consumer/src/backend.rs index bdff7dc..08d32a4 100644 --- a/consumer/src/backend.rs +++ b/consumer/src/backend.rs @@ -37,8 +37,10 @@ pub struct MintMetaplexAddresses { #[derive(Clone)] pub struct MintCompressedMintV1Addresses { - pub owner: Pubkey, - pub recipient: Pubkey, + pub merkle_tree: Pubkey, + pub tree_authority: Pubkey, + pub tree_delegate: Pubkey, + pub leaf_owner: Pubkey, } #[derive(Clone)] diff --git a/consumer/src/events.rs b/consumer/src/events.rs index 637c664..967b279 100644 --- a/consumer/src/events.rs +++ b/consumer/src/events.rs @@ -1,4 +1,3 @@ -use anchor_lang::Event; use holaplex_hub_nfts_solana_core::{ db, proto::{ @@ -12,9 +11,9 @@ use holaplex_hub_nfts_solana_core::{ SolanaTransactionFailureReason, TransferMetaplexAssetTransaction, }, sea_orm::{DbErr, Set}, - Collection, CollectionMint, Services, + Collection, CollectionMint, CompressionLeaf, Services, }; -use holaplex_hub_nfts_solana_entity::{collection_mints, collections}; +use holaplex_hub_nfts_solana_entity::{collection_mints, collections, compression_leafs}; use hub_core::{ chrono::Utc, prelude::*, @@ -30,7 +29,7 @@ use crate::{ CollectionBackend, MasterEditionAddresses, MintBackend, MintEditionAddresses, MintMetaplexAddresses, TransferBackend, }, - solana::{EditionRef, Solana, UncompressedRef}, + solana::{CompressedRef, EditionRef, Solana, UncompressedRef}, }; #[derive(Debug, thiserror::Error)] @@ -330,7 +329,7 @@ impl Processor { self.process_nft( EventKind::MintToCollection, &key, - self.mint_to_collection(&UncompressedRef(self.solana()), &key, payload), + self.mint_to_collection(&key, payload), ) .await }, @@ -595,11 +594,8 @@ impl Processor { Ok(tx.into()) } - async fn mint_to_collection< - B: MintBackend, - >( + async fn mint_to_collection( &self, - backend: &B, key: &SolanaNftEventKey, payload: MintMetaplexMetadataTransaction, ) -> ProcessResult { @@ -609,6 +605,31 @@ impl Processor { .await? .ok_or(ProcessorErrorKind::RecordNotFound)?; + if payload.compressed { + let backend = &CompressedRef(self.solana()); + + let tx = backend + .mint(&collection, payload) + .map_err(ProcessorErrorKind::Solana)?; + + let compression_leaf = compression_leafs::Model { + id, + collection_id: collection.id, + merkle_tree: tx.addresses.merkle_tree.to_string(), + tree_authority: tx.addresses.tree_authority.to_string(), + tree_delegate: tx.addresses.tree_delegate.to_string(), + leaf_owner: tx.addresses.leaf_owner.to_string(), + created_at: Utc::now().naive_utc(), + ..Default::default() + }; + + CompressionLeaf::create(&self.db, compression_leaf).await?; + + return Ok(tx.into()); + } + + let backend = &UncompressedRef(self.solana()); + let tx = backend .mint(&collection, payload) .map_err(ProcessorErrorKind::Solana)?; @@ -616,10 +637,11 @@ impl Processor { let collection_mint = collection_mints::Model { id, collection_id: collection.id, - mint: tx.addresses.mint.to_string(), owner: tx.addresses.recipient.to_string(), - associated_token_account: Some(tx.addresses.associated_token_account.to_string()), + mint: tx.addresses.mint.to_string(), created_at: Utc::now().naive_utc(), + associated_token_account: tx.addresses.associated_token_account.to_string(), + ..Default::default() }; CollectionMint::create(&self.db, collection_mint).await?; @@ -648,7 +670,7 @@ impl Processor { collection_id: collection.id, mint: tx.addresses.mint.to_string(), owner: tx.addresses.recipient.to_string(), - associated_token_account: Some(tx.addresses.associated_token_account.to_string()), + associated_token_account: tx.addresses.associated_token_account.to_string(), created_at: Utc::now().naive_utc(), }; @@ -764,7 +786,7 @@ impl Processor { collection_mint.mint = Set(mint.to_string()); collection_mint.owner = Set(recipient.to_string()); - collection_mint.associated_token_account = Set(Some(associated_token_account.to_string())); + collection_mint.associated_token_account = Set(associated_token_account.to_string()); CollectionMint::update(&self.db, collection_mint).await?; @@ -803,7 +825,7 @@ impl Processor { collection_mint.mint = Set(mint.to_string()); collection_mint.owner = Set(recipient.to_string()); - collection_mint.associated_token_account = Set(Some(associated_token_account.to_string())); + collection_mint.associated_token_account = Set(associated_token_account.to_string()); CollectionMint::update(&self.db, collection_mint).await?; diff --git a/consumer/src/solana.rs b/consumer/src/solana.rs index 695df69..b6c2959 100644 --- a/consumer/src/solana.rs +++ b/consumer/src/solana.rs @@ -53,7 +53,6 @@ pub struct SolanaArgs { #[arg(long, env)] pub digital_asset_api_endpoint: String, - // TODO: remove these #[arg(long, env)] pub tree_authority: Pubkey, #[arg(long, env)] @@ -280,7 +279,7 @@ impl<'a> CollectionBackend for UncompressedRef<'a> { true, None, None, - None, + Some(mpl_token_metadata::state::CollectionDetails::V1 { size: 0 }), ); let create_master_edition_ins = mpl_token_metadata::instruction::create_master_edition_v3( mpl_token_metadata::ID, @@ -668,7 +667,8 @@ impl<'a> MintBackend MintBackend MintBackend MintBackend MintBackend None, ); - let verify_collection = mpl_token_metadata::instruction::verify_collection( + let verify_collection = mpl_token_metadata::instruction::verify_sized_collection_item( mpl_token_metadata::ID, metadata, owner, @@ -886,8 +891,8 @@ impl<'a> MintBackend serialized_message, signatures_or_signers_public_keys: vec![ payer.to_string(), - owner.to_string(), mint_signature.to_string(), + owner.to_string(), ], addresses: MintMetaplexAddresses { update_authority: owner, diff --git a/core/src/collection_mints.rs b/core/src/collection_mints.rs index f80e40d..7b5e059 100644 --- a/core/src/collection_mints.rs +++ b/core/src/collection_mints.rs @@ -33,7 +33,7 @@ impl CollectionMint { let mut active_model: ActiveModel = model.clone().into(); active_model.owner = Set(owner); - active_model.associated_token_account = Set(Some(ata)); + active_model.associated_token_account = Set(ata); active_model.update(conn).await } diff --git a/core/src/compression_leafs.rs b/core/src/compression_leafs.rs new file mode 100644 index 0000000..5637aff --- /dev/null +++ b/core/src/compression_leafs.rs @@ -0,0 +1,28 @@ +use holaplex_hub_nfts_solana_entity::compression_leafs::{ActiveModel, Column, Entity, Model}; +use sea_orm::prelude::*; + +use crate::db::Connection; + +pub struct CompressionLeaf; + +impl CompressionLeaf { + pub async fn create(db: &Connection, model: Model) -> Result { + let conn = db.get(); + + let active_model: ActiveModel = model.into(); + + active_model.insert(conn).await + } + + pub async fn find_by_id(db: &Connection, id: Uuid) -> Result, DbErr> { + let conn = db.get(); + + Entity::find().filter(Column::Id.eq(id)).one(conn).await + } + + pub async fn update(db: &Connection, model: ActiveModel) -> Result { + let conn = db.get(); + + model.update(conn).await + } +} diff --git a/core/src/lib.rs b/core/src/lib.rs index 60868de..ab34488 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -4,10 +4,12 @@ mod collection_mints; mod collections; +mod compression_leafs; pub mod db; pub use collection_mints::CollectionMint; pub use collections::Collection; +pub use compression_leafs::CompressionLeaf; use hub_core::{consumer::RecvError, prelude::*}; use proto::{NftEventKey, SolanaNftEventKey, TreasuryEventKey}; pub use sea_orm; diff --git a/entity/src/collection_mints.rs b/entity/src/collection_mints.rs index c835d14..3d7dd38 100644 --- a/entity/src/collection_mints.rs +++ b/entity/src/collection_mints.rs @@ -13,8 +13,8 @@ pub struct Model { pub mint: String, #[sea_orm(column_type = "Text")] pub owner: String, - #[sea_orm(column_type = "Text", nullable)] - pub associated_token_account: Option, + #[sea_orm(column_type = "Text")] + pub associated_token_account: String, pub created_at: DateTime, } diff --git a/entity/src/compression_leafs.rs b/entity/src/compression_leafs.rs new file mode 100644 index 0000000..5bf28bd --- /dev/null +++ b/entity/src/compression_leafs.rs @@ -0,0 +1,27 @@ +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.5 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, Default, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "compression_leafs")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + pub collection_id: Uuid, + #[sea_orm(column_type = "Text")] + pub merkle_tree: String, + #[sea_orm(column_type = "Text")] + pub tree_authority: String, + #[sea_orm(column_type = "Text")] + pub tree_delegate: String, + #[sea_orm(column_type = "Text")] + pub leaf_owner: String, + #[sea_orm(column_type = "Text", nullable)] + pub asset_id: Option, + pub created_at: DateTime, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/entity/src/lib.rs b/entity/src/lib.rs index 517860e..04ce5b9 100644 --- a/entity/src/lib.rs +++ b/entity/src/lib.rs @@ -1,4 +1,5 @@ pub mod collection_mints; pub mod collections; +pub mod compression_leafs; pub mod prelude; diff --git a/entity/src/mod.rs b/entity/src/mod.rs index da3ad48..6690f3a 100644 --- a/entity/src/mod.rs +++ b/entity/src/mod.rs @@ -4,4 +4,5 @@ pub mod prelude; pub mod collection_mints; pub mod editions; -pub mod certified_collections; \ No newline at end of file +pub mod certified_collections; +pub mod compression_leafs; \ No newline at end of file diff --git a/entity/src/prelude.rs b/entity/src/prelude.rs index ab991bc..be23938 100644 --- a/entity/src/prelude.rs +++ b/entity/src/prelude.rs @@ -1,3 +1,6 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.5 -pub use super::{collection_mints::Entity as CollectionMints, collections::Entity as Collections}; +pub use super::{ + collection_mints::Entity as CollectionMints, collections::Entity as Collections, + compression_leafs::Entity as CompressionLeafs, +}; diff --git a/migration/src/lib.rs b/migration/src/lib.rs index 0c13847..4593dd6 100644 --- a/migration/src/lib.rs +++ b/migration/src/lib.rs @@ -4,6 +4,7 @@ mod m20230529_134752_create_collections_table; mod m20230530_131917_create_collection_mints_table; mod m20230614_132203_make_associated_token_account_nullable_on_collection_mints; mod m20230616_091724_backfill_associated_token_account_on_collection_mints; +mod m20230725_143421_add_compression_leafs_table; pub struct Migrator; @@ -15,6 +16,7 @@ impl MigratorTrait for Migrator { Box::new(m20230530_131917_create_collection_mints_table::Migration), Box::new(m20230614_132203_make_associated_token_account_nullable_on_collection_mints::Migration), Box::new(m20230616_091724_backfill_associated_token_account_on_collection_mints::Migration), + Box::new(m20230725_143421_add_compression_leafs_table::Migration), ] } } diff --git a/migration/src/m20230725_143421_add_compression_leafs_table.rs b/migration/src/m20230725_143421_add_compression_leafs_table.rs new file mode 100644 index 0000000..4bddcc6 --- /dev/null +++ b/migration/src/m20230725_143421_add_compression_leafs_table.rs @@ -0,0 +1,76 @@ +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 + .create_table( + Table::create() + .table(CompressionLeafs::Table) + .if_not_exists() + .col( + ColumnDef::new(CompressionLeafs::Id) + .uuid() + .not_null() + .primary_key(), + ) + .col( + ColumnDef::new(CompressionLeafs::CollectionId) + .uuid() + .not_null(), + ) + .col( + ColumnDef::new(CompressionLeafs::MerkleTree) + .text() + .not_null(), + ) + .col( + ColumnDef::new(CompressionLeafs::TreeAuthority) + .text() + .not_null(), + ) + .col( + ColumnDef::new(CompressionLeafs::TreeDelegate) + .text() + .not_null(), + ) + .col( + ColumnDef::new(CompressionLeafs::LeafOwner) + .text() + .not_null(), + ) + .col(ColumnDef::new(CompressionLeafs::AssetId).text()) + .col( + ColumnDef::new(CompressionLeafs::CreatedAt) + .timestamp() + .not_null() + .extra("default now()".to_string()), + ) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop().table(CompressionLeafs::Table).to_owned()) + .await + } +} + +/// Learn more at https://docs.rs/sea-query#iden +#[derive(Iden)] +enum CompressionLeafs { + Table, + Id, + MerkleTree, + TreeAuthority, + TreeDelegate, + LeafOwner, + AssetId, + CollectionId, + CreatedAt, +}