From 259c56f68609a42fced2a88657c66610f598ac61 Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Mon, 16 Oct 2023 15:58:51 +0500 Subject: [PATCH] mutation for batched random queued mints --- api/proto.lock | 16 +-- api/proto.toml | 14 +-- api/src/mutations/mint.rs | 201 +++++++++++++++++++++++++++++++++++++- 3 files changed, 215 insertions(+), 16 deletions(-) diff --git a/api/proto.lock b/api/proto.lock index 2fbdf20..4c4d14f 100644 --- a/api/proto.lock +++ b/api/proto.lock @@ -1,27 +1,27 @@ [[schemas]] subject = "customer" -version = 2 +version = 1 sha512 = "d75800df0d4744c6b0f4d9a9952d3bfd0bb6b24a8babd19104cc11b54a525f85551b3c7375d69aeabbcf629cd826aa0bc6b0c0467add20716c504f5e856ce1c5" [[schemas]] subject = "nfts" -version = 30 -sha512 = "bee70bd6f0f18a8049f93bceb9c4b500b49352f9d19d55d5a411da92cbd786c88bec47f73e1ef6946ceefc7de8e558f704bf8187be9d9f4e49bd102baec29327" +version = 1 +sha512 = "449574f8551ab8c17824af9e08b1658ad1b26ac80340230ddf02e7a1e0979d8a47025913a6598799cf83dd1a9cda87697ee87a13f404ebb52c95ea0084205767" [[schemas]] subject = "organization" -version = 5 +version = 1 sha512 = "9fb28ac73d9712292297394a5fa53a7dae9deba6847353582987ba749859301c23c05fd49d2ce84a1640f8864c5c04d59fa38907700b280000e5c4afc96654bf" [[schemas]] subject = "polygon_nfts" -version = 6 +version = 1 sha512 = "c5ddf43d2958ec690ee2261d0ff9808b67ce810d2fc4b6077f96f561929a920f03509fc8bd7adbda219250eb019f5f7be8a3f51c554f665ea1881f7a973ef2a6" [[schemas]] subject = "solana_nfts" -version = 11 -sha512 = "967fefde938a0f6ce05194e4fca15673e681caac54d8aeec114c5d38418632b9696dbaf5362345a15114e5abb49de55d0af8b9edcc0f2c91f9ef1ccc4ff55d68" +version = 1 +sha512 = "c1b1f3af0097d52622e7b8628fd6085fa4cced9e91883fff309de370f4ff55f8a58c388e5eee69d1755b113e39c772f113ff6220d8a7dc435b79bc51e121473e" [[schemas]] subject = "timestamp" @@ -30,5 +30,5 @@ sha512 = "d167e0a143c813073eef8597f0b237e5a8eaf32abbf709724e8071b2dd73ce0438b82f [[schemas]] subject = "treasury" -version = 23 +version = 1 sha512 = "0e4d77999767d5971122e720c1cee7a57c3e47ce69f58a582f1762d8e65e031ea3bd9024cfc21bd7da5db6e38a71657151c58cdfa21d9ff643fb2fc657105cf5" diff --git a/api/proto.toml b/api/proto.toml index 44a45d7..c05a453 100644 --- a/api/proto.toml +++ b/api/proto.toml @@ -1,11 +1,11 @@ [registry] -endpoint = "https://schemas.holaplex.tools" +endpoint = "http://localhost:8081" [schemas] -organization = 5 -nfts = 30 -customer = 2 -treasury = 23 -solana_nfts = 11 -polygon_nfts = 6 +organization = 1 +nfts = 1 +customer = 1 +treasury = 1 +solana_nfts = 1 +polygon_nfts = 1 timestamp = 1 \ No newline at end of file diff --git a/api/src/mutations/mint.rs b/api/src/mutations/mint.rs index 7af2012..579deee 100644 --- a/api/src/mutations/mint.rs +++ b/api/src/mutations/mint.rs @@ -39,7 +39,8 @@ use crate::{ objects::{CollectionMint, Creator, MetadataJsonInput}, proto::{ self, nft_events::Event as NftEvent, CreationStatus as NftCreationStatus, MetaplexMetadata, - MintCollectionCreation, MintCreation, NftEventKey, NftEvents, RetryUpdateSolanaMintPayload, + MintCollectionCreation, MintCreation, MintOpenDropTransaction, NftEventKey, NftEvents, + RetryUpdateSolanaMintPayload, SolanaMintOpenDropBatchedPayload, }, Actions, AppContext, OrganizationId, UserID, }; @@ -1291,6 +1292,190 @@ impl Mutation { collection_mint: mint.into(), }) } + + async fn mint_random_queued_to_drop_batched( + &self, + ctx: &Context<'_>, + input: MintRandomQueuedBatchedInput, + ) -> Result { + let AppContext { + db, + user_id, + organization_id, + balance, + .. + } = ctx.data::()?; + let credits = ctx.data::>()?; + let conn = db.get(); + let nfts_producer = ctx.data::>()?; + + let UserID(id) = user_id; + let OrganizationId(org) = organization_id; + + let user_id = id.ok_or(Error::new("X-USER-ID header not found"))?; + let org_id = org.ok_or(Error::new("X-ORGANIZATION-ID header not found"))?; + let balance = balance + .0 + .ok_or(Error::new("X-CREDIT-BALANCE header not found"))?; + + let batch_size = input.recipients.len(); + + if batch_size == 0 { + return Err(Error::new("No recipients provided")); + } + + if batch_size > 250 { + return Err(Error::new("Batch size cannot be greater than 250")); + } + + let drop = drops::Entity::find_by_id(input.drop) + .one(conn) + .await? + .ok_or(Error::new("drop not found"))?; + + let mints = CollectionMints::find() + .filter(collection_mints::Column::CollectionId.eq(drop.collection_id)) + .filter(collection_mints::Column::CreationStatus.eq(CreationStatus::Queued)) + .order_by(SimpleExpr::FunctionCall(Func::random()), Order::Asc) + .limit(Some(batch_size.try_into()?)) + .all(conn) + .await?; + + if mints.len() != batch_size { + return Err(Error::new("Not enough mints found for the drop")); + } + + let collection = collections::Entity::find_by_id(drop.collection_id) + .one(conn) + .await? + .ok_or(Error::new("collection not found"))?; + + let project_id = collection.project_id; + let blockchain = collection.blockchain; + + if blockchain != BlockchainEnum::Solana { + return Err(Error::new("Only Solana is supported at this time")); + } + + let owner_address = fetch_owner(conn, project_id, blockchain).await?; + + let action = if input.compressed { + Actions::MintCompressed + } else { + Actions::Mint + }; + + let event_key = NftEventKey { + id: collection.id.to_string(), + user_id: user_id.to_string(), + project_id: project_id.to_string(), + }; + + let mut transactions = Vec::new(); + + for (mint, recipient) in mints.clone().into_iter().zip(input.recipients.into_iter()) { + let metadata_json = metadata_jsons::Entity::find_by_id(mint.id) + .one(conn) + .await? + .ok_or(Error::new("metadata json not found"))?; + + let metadata_uri = metadata_json + .uri + .ok_or(Error::new("No metadata json uri found"))?; + + let creators = mint_creators::Entity::find_by_collection_mint_id(mint.id) + .all(conn) + .await?; + + let TransactionId(deduction_id) = credits + .submit_pending_deduction( + org_id, + user_id, + action, + collection.blockchain.into(), + balance, + ) + .await?; + + let tx = conn.begin().await?; + + let mut collection_am = collections::ActiveModel::from(collection.clone()); + collection_am.total_mints = Set(collection.total_mints.add(1)); + collection_am.update(&tx).await?; + + let mut mint_am: collection_mints::ActiveModel = mint.into(); + + mint_am.creation_status = Set(CreationStatus::Pending); + mint_am.credits_deduction_id = Set(Some(deduction_id)); + mint_am.compressed = Set(Some(input.compressed)); + mint_am.owner = Set(Some(recipient.clone())); + mint_am.seller_fee_basis_points = Set(collection.seller_fee_basis_points); + + let mint = mint_am.update(&tx).await?; + + let mint_history_am = mint_histories::ActiveModel { + mint_id: Set(mint.id), + wallet: Set(recipient.clone()), + collection_id: Set(collection.id), + tx_signature: Set(None), + status: Set(CreationStatus::Pending), + created_at: Set(Utc::now().into()), + ..Default::default() + }; + + mint_history_am.insert(&tx).await?; + + tx.commit().await?; + + nfts_producer + .send( + Some(&NftEvents { + event: Some(NftEvent::DropMinted(MintCreation { + drop_id: drop.id.to_string(), + status: NftCreationStatus::InProgress as i32, + })), + }), + Some(&NftEventKey { + id: mint.id.to_string(), + project_id: drop.project_id.to_string(), + user_id: user_id.to_string(), + }), + ) + .await?; + + transactions.push(MintOpenDropTransaction { + recipient_address: recipient, + metadata: Some(MetaplexMetadata { + owner_address: owner_address.clone(), + name: metadata_json.name, + symbol: metadata_json.symbol, + metadata_uri, + seller_fee_basis_points: mint.seller_fee_basis_points.into(), + creators: creators.into_iter().map(Into::into).collect(), + }), + mint_id: mint.id.to_string(), + }); + } + + nfts_producer + .send( + Some(&NftEvents { + event: Some(NftEvent::SolanaMintOpenDropBatched( + SolanaMintOpenDropBatchedPayload { + collection_id: collection.id.to_string(), + compressed: input.compressed, + mint_open_drop_transactions: transactions, + }, + )), + }), + Some(&event_key), + ) + .await?; + + Ok(MintRandomQueuedBatchedPayload { + collection_mints: mints.into_iter().map(Into::into).collect(), + }) + } } fn validate_compress(blockchain: BlockchainEnum, compressed: bool) -> Result<(), Error> { @@ -1475,3 +1660,17 @@ pub struct MintRandomQueuedInput { recipient: String, compressed: bool, } + +/// Represents input data for `mint_random_queued_batched` mutation +#[derive(Debug, Clone, InputObject)] +pub struct MintRandomQueuedBatchedInput { + drop: Uuid, + recipients: Vec, + compressed: bool, +} + +/// Represents payload data for `mint_random_queued_batched` mutation +#[derive(Debug, Clone, SimpleObject)] +pub struct MintRandomQueuedBatchedPayload { + collection_mints: Vec, +}