From 650cfbd80b2b2e555f011850524a472c060a7958 Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Tue, 1 Aug 2023 04:54:07 +0500 Subject: [PATCH 01/28] update collection mint --- api/proto.lock | 18 ++-- api/proto.toml | 14 ++-- api/src/blockchains/mod.rs | 1 + api/src/blockchains/solana.rs | 18 +++- api/src/mutations/mint.rs | 152 +++++++++++++++++++++++++++++++++- 5 files changed, 182 insertions(+), 21 deletions(-) diff --git a/api/proto.lock b/api/proto.lock index b8d9326..efb19fe 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 = 22 -sha512 = "c9920f6a5792b067396c88e40b9bd2adfcb55b582734aff924a67a9d5841a5e2839fc734c1bbff66f402f9a9d8852ca5fef1339aaaa3d5b05aa7868ddfa375c1" +version = 1 +sha512 = "c4032c35d77a78090c17d230dfae7955577a6172bc60921c4821e76690c89d3f858d2b358ca41e34fc25468f430107d4c1552e4529dc48db61e4f5545a6ef82c" [[schemas]] subject = "organization" -version = 5 +version = 1 sha512 = "9fb28ac73d9712292297394a5fa53a7dae9deba6847353582987ba749859301c23c05fd49d2ce84a1640f8864c5c04d59fa38907700b280000e5c4afc96654bf" [[schemas]] subject = "polygon_nfts" -version = 6 +version = 1 sha512 = "c5ddf43d2958ec690ee2261d0ff9808b67ce810d2fc4b6077f96f561929a920f03509fc8bd7adbda219250eb019f5f7be8a3f51c554f665ea1881f7a973ef2a6" [[schemas]] subject = "solana_nfts" -version = 7 -sha512 = "73570b9e58f91a06901ba6455986ce1a0d3675e33860d2447160d711a8cebcfb78cfc714fb08644ad83495dc8612b0b123203561af6d93d29ffb0256725047ba" +version = 1 +sha512 = "2a57c4200577f8a6efa36e2c045a5bd3eb0dba11466659a80dd82f5422db4ac119f529d391805d14449b0ffac6048ae789727075882f9b0496dac710e32f4ff5" [[schemas]] subject = "timestamp" @@ -30,5 +30,5 @@ sha512 = "d167e0a143c813073eef8597f0b237e5a8eaf32abbf709724e8071b2dd73ce0438b82f [[schemas]] subject = "treasury" -version = 17 -sha512 = "c4caa4f7d032686dff56840909254f5bbb21c12b5e01cf890443dbe4d9806be637e5bbd09a66176152ecd42687fd7bc7008b50f00aec46ff941f4eb04bee25f2" +version = 1 +sha512 = "f3ff35aeb4bfa3a76b4cb985c4f2fc4b3dab1d0bb1585d4d720ff2c1087a879b56531efd3ecdebbb0968fae23371ec03aa944eec0ed07c0a3db7d66aa2074e2e" diff --git a/api/proto.toml b/api/proto.toml index ee4b436..51e4a35 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 = 22 -customer = 2 -treasury = 17 -solana_nfts = 7 -polygon_nfts = 6 +organization = 1 +nfts = 1 +customer = 1 +treasury = 1 +solana_nfts = 1 +polygon_nfts = 1 timestamp = 1 diff --git a/api/src/blockchains/mod.rs b/api/src/blockchains/mod.rs index 13690d5..b6edc00 100644 --- a/api/src/blockchains/mod.rs +++ b/api/src/blockchains/mod.rs @@ -31,6 +31,7 @@ pub trait CollectionEvent { async fn update_collection(&self, key: NftEventKey, payload: B) -> Result<()>; async fn mint_to_collection(&self, key: NftEventKey, payload: C) -> Result<()>; async fn retry_mint_to_collection(&self, key: NftEventKey, payload: C) -> Result<()>; + async fn update_collection_mint(&self, key: NftEventKey, payload: C) -> Result<()>; } #[async_trait::async_trait] diff --git a/api/src/blockchains/solana.rs b/api/src/blockchains/solana.rs index 6d65e49..e8dc0ea 100644 --- a/api/src/blockchains/solana.rs +++ b/api/src/blockchains/solana.rs @@ -5,12 +5,12 @@ use crate::proto::{ nft_events::Event::{ SolanaCreateCollection, SolanaCreateDrop, SolanaMintDrop, SolanaMintToCollection, SolanaRetryCreateCollection, SolanaRetryDrop, SolanaRetryMintDrop, - SolanaRetryMintToCollection, SolanaTransferAsset, SolanaUpdateCollection, SolanaUpdateDrop, + SolanaRetryMintToCollection, SolanaTransferAsset, SolanaUpdateCollection, + SolanaUpdateCollectionMint, SolanaUpdateDrop, }, MetaplexMasterEditionTransaction, MintMetaplexEditionTransaction, MintMetaplexMetadataTransaction, NftEventKey, NftEvents, TransferMetaplexAssetTransaction, }; - #[derive(Clone)] pub struct Solana { producer: Producer, @@ -212,4 +212,18 @@ impl Ok(()) } + + async fn update_collection_mint( + &self, + key: NftEventKey, + payload: MintMetaplexMetadataTransaction, + ) -> Result<()> { + let event = NftEvents { + event: Some(SolanaUpdateCollectionMint(payload)), + }; + + self.producer.send(Some(&event), Some(&key)).await?; + + Ok(()) + } } diff --git a/api/src/mutations/mint.rs b/api/src/mutations/mint.rs index 277df84..89b60b1 100644 --- a/api/src/mutations/mint.rs +++ b/api/src/mutations/mint.rs @@ -2,7 +2,7 @@ use std::ops::Add; use async_graphql::{Context, Error, InputObject, Object, Result, SimpleObject}; use hub_core::{chrono::Utc, credits::CreditsClient, producer::Producer}; -use sea_orm::{prelude::*, JoinType, QuerySelect, Set}; +use sea_orm::{prelude::*, JoinType, QuerySelect, Set, TransactionTrait}; use super::collection::{ fetch_owner, validate_creators, validate_json, validate_solana_creator_verification, @@ -11,8 +11,8 @@ use crate::{ blockchains::{polygon::Polygon, solana::Solana, CollectionEvent, DropEvent}, db::Connection, entities::{ - collection_mints, collections, drops, mint_creators, mint_histories, - prelude::{Collections, Drops}, + collection_mints, collections, drops, metadata_jsons, mint_creators, mint_histories, + prelude::{CollectionMints, Collections, Drops}, project_wallets, sea_orm_active_enums::{Blockchain as BlockchainEnum, CreationStatus}, }, @@ -486,6 +486,139 @@ impl Mutation { }) } + pub async fn update_collection_mint( + &self, + ctx: &Context<'_>, + input: UpdateCollectionMint, + ) -> Result { + let AppContext { + db, + user_id, + organization_id, + balance, + .. + } = ctx.data::()?; + let credits = ctx.data::>()?; + let conn = db.get(); + let solana = ctx.data::()?; + let nft_storage = 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 balance = balance + .0 + .ok_or(Error::new("X-CREDIT-BALANCE header not found"))?; + + let creators = input.creators; + + let (mint, collection) = CollectionMints::find() + .find_also_related(Collections) + .filter(collection_mints::Column::Id.eq(input.mint)) + .one(conn) + .await? + .ok_or(Error::new("Mint not found"))?; + + if mint.creation_status != CreationStatus::Created { + return Err(Error::new("Mint not created")); + } + + let collection = collection.ok_or(Error::new("Collection not found"))?; + let blockchain = collection.blockchain; + + validate_creators(blockchain, &creators)?; + validate_json(blockchain, &input.metadata_json)?; + + let seller_fee_basis_points = input.seller_fee_basis_points.unwrap_or_default(); + + let owner_address = fetch_owner(conn, collection.project_id, collection.blockchain).await?; + + if collection.blockchain == BlockchainEnum::Solana { + validate_solana_creator_verification(&owner_address, &creators)?; + } + + let creators_am = creators + .clone() + .into_iter() + .map(|creator| { + Ok(mint_creators::ActiveModel { + collection_mint_id: Set(mint.id), + address: Set(creator.address), + verified: Set(creator.verified.unwrap_or_default()), + share: Set(creator.share.try_into()?), + }) + }) + .collect::>>()?; + + conn.transaction::<_, (), DbErr>(|txn| { + Box::pin(async move { + mint_creators::Entity::delete_many() + .filter(mint_creators::Column::CollectionMintId.eq(mint.id)) + .exec(txn) + .await?; + + mint_creators::Entity::insert_many(creators_am) + .exec(txn) + .await?; + + let metadata_json_model = metadata_jsons::Entity::find() + .filter(metadata_jsons::Column::Id.eq(mint.id)) + .one(txn) + .await? + .ok_or(DbErr::RecordNotFound("Metadata Json not found".to_string()))?; + + metadata_json_model.delete(txn).await?; + + Ok(()) + }) + }) + .await?; + + let metadata_json = MetadataJson::new(input.metadata_json) + .upload(nft_storage) + .await? + .save(mint.id, db) + .await?; + + match collection.blockchain { + BlockchainEnum::Solana => { + solana + .event() + .update_collection_mint( + NftEventKey { + id: mint.id.to_string(), + project_id: collection.project_id.to_string(), + user_id: user_id.to_string(), + }, + proto::MintMetaplexMetadataTransaction { + metadata: Some(MetaplexMetadata { + owner_address, + name: metadata_json.name, + symbol: metadata_json.symbol, + metadata_uri: metadata_json.uri, + seller_fee_basis_points: seller_fee_basis_points.into(), + creators: creators + .into_iter() + .map(TryFrom::try_from) + .collect::>()?, + }), + collection_id: collection.id.to_string(), + ..Default::default() + }, + ) + .await?; + }, + BlockchainEnum::Ethereum | BlockchainEnum::Polygon => { + return Err(Error::new("blockchain not supported as this time")); + }, + }; + + Ok(UpdateCollectionMintPayload { + collection_mint: mint.into(), + }) + } + pub async fn retry_mint_to_collection( &self, ctx: &Context<'_>, @@ -723,11 +856,24 @@ pub struct MintToCollectionInput { compressed: Option, } +#[derive(Debug, Clone, InputObject)] +pub struct UpdateCollectionMint { + mint: Uuid, + metadata_json: MetadataJsonInput, + seller_fee_basis_points: Option, + creators: Vec, +} + #[derive(Debug, Clone, SimpleObject)] pub struct MintToCollectionPayload { collection_mint: collection_mints::CollectionMint, } +#[derive(Debug, Clone, SimpleObject)] +pub struct UpdateCollectionMintPayload { + collection_mint: collection_mints::CollectionMint, +} + #[derive(Debug, Clone, InputObject)] pub struct RetryMintToCollectionInput { id: Uuid, From b28d8cdc3f5d66bb8dbfaf3416a333f277a9dbc2 Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Mon, 7 Aug 2023 19:53:53 +0500 Subject: [PATCH 02/28] Save into update histories table --- Cargo.lock | 698 +++++++++--------- api/Cargo.toml | 2 +- api/proto.lock | 14 +- api/proto.toml | 16 +- api/src/blockchains/mod.rs | 8 +- api/src/blockchains/solana.rs | 9 +- api/src/entities/mod.rs | 1 + api/src/entities/prelude.rs | 2 +- api/src/entities/update_histories.rs | 24 + api/src/events.rs | 37 +- api/src/lib.rs | 2 + api/src/mutations/mint.rs | 48 +- migration/src/lib.rs | 2 + ...m20230807_090847_create_histories_table.rs | 64 ++ 14 files changed, 554 insertions(+), 373 deletions(-) create mode 100644 api/src/entities/update_histories.rs create mode 100644 migration/src/m20230807_090847_create_histories_table.rs diff --git a/Cargo.lock b/Cargo.lock index 66f4940..93c3321 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,9 +14,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" dependencies = [ "gimli", ] @@ -67,9 +67,9 @@ checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" [[package]] name = "allocator-api2" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56fc6cf8dc8c4158eed8649f9b8b0ea1518eb62b544fe9490d66fa0b349eafe9" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" [[package]] name = "android-tzdata" @@ -122,7 +122,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -132,14 +132,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" dependencies = [ "backtrace", ] @@ -306,7 +306,7 @@ dependencies = [ "futures-util", "handlebars", "http", - "indexmap", + "indexmap 1.9.3", "log", "lru", "mime", @@ -372,7 +372,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d461325bfb04058070712296601dfe5e5bd6cdff84780a0a8c569ffb15c87eb3" dependencies = [ "bytes 1.4.0", - "indexmap", + "indexmap 1.9.3", "serde", "serde_json", ] @@ -396,18 +396,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -438,9 +438,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" dependencies = [ "addr2line", "cc", @@ -503,6 +503,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" + [[package]] name = "bitmaps" version = "2.1.0" @@ -532,7 +538,7 @@ checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" dependencies = [ "arrayref", "arrayvec", - "constant_time_eq", + "constant_time_eq 0.2.6", ] [[package]] @@ -543,20 +549,20 @@ checksum = "6637f448b9e61dfadbdcbae9a885fadee1f3eaffb1f8d3c1965d3ade8bdfd44f" dependencies = [ "arrayref", "arrayvec", - "constant_time_eq", + "constant_time_eq 0.2.6", ] [[package]] name = "blake3" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "729b71f35bd3fa1a4c86b85d32c8b9069ea7fe14f7a53cfabb65f62d4265b888" +checksum = "199c42ab6972d92c9f8995f086273d25c42fc0f7b2a1fcefba465c1352d25ba5" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if", - "constant_time_eq", + "constant_time_eq 0.3.0", "digest 0.10.7", ] @@ -578,29 +584,63 @@ dependencies = [ "generic-array", ] +[[package]] +name = "borsh" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" +dependencies = [ + "borsh-derive 0.9.3", + "hashbrown 0.11.2", +] + [[package]] name = "borsh" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" dependencies = [ - "borsh-derive", + "borsh-derive 0.10.3", "hashbrown 0.13.2", ] +[[package]] +name = "borsh-derive" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" +dependencies = [ + "borsh-derive-internal 0.9.3", + "borsh-schema-derive-internal 0.9.3", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + [[package]] name = "borsh-derive" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", + "borsh-derive-internal 0.10.3", + "borsh-schema-derive-internal 0.10.3", "proc-macro-crate 0.1.5", "proc-macro2", "syn 1.0.109", ] +[[package]] +name = "borsh-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "borsh-derive-internal" version = "0.10.3" @@ -612,6 +652,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "borsh-schema-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "borsh-schema-derive-internal" version = "0.10.3" @@ -684,7 +735,7 @@ checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -710,11 +761,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.79" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" dependencies = [ "jobserver", + "libc", ] [[package]] @@ -759,10 +811,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "atty", - "bitflags", + "bitflags 1.3.2", "clap_derive 3.2.25", "clap_lex 0.2.4", - "indexmap", + "indexmap 1.9.3", "once_cell", "strsim", "termcolor", @@ -771,24 +823,23 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.5" +version = "4.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2686c4115cb0810d9a984776e197823d08ec94f176549a89a9efded477c456dc" +checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" dependencies = [ "clap_builder", - "clap_derive 4.3.2", + "clap_derive 4.3.12", "once_cell", ] [[package]] name = "clap_builder" -version = "4.3.5" +version = "4.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e53afce1efce6ed1f633cf0e57612fe51db54a1ee4fd8f8503d078fe02d69ae" +checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" dependencies = [ "anstream", "anstyle", - "bitflags", "clap_lex 0.5.0", "once_cell", "strsim", @@ -809,14 +860,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.3.2" +version = "4.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" +checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -866,6 +917,12 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + [[package]] name = "core-foundation" version = "0.9.3" @@ -893,9 +950,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -1020,12 +1077,12 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.1" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ - "darling_core 0.20.1", - "darling_macro 0.20.1", + "darling_core 0.20.3", + "darling_macro 0.20.3", ] [[package]] @@ -1044,16 +1101,16 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.1" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -1069,13 +1126,13 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.1" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ - "darling_core 0.20.1", + "darling_core 0.20.3", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -1104,6 +1161,15 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "deranged" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929" +dependencies = [ + "serde", +] + [[package]] name = "derivative" version = "2.2.0" @@ -1181,9 +1247,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "encoding_rs" @@ -1194,15 +1260,21 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" dependencies = [ "errno-dragonfly", "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1232,12 +1304,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "1.9.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" [[package]] name = "feature-probe" @@ -1354,7 +1423,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -1450,9 +1519,9 @@ checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" [[package]] name = "h2" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" dependencies = [ "bytes 1.4.0", "fnv", @@ -1460,7 +1529,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -1481,6 +1550,15 @@ dependencies = [ "thiserror", ] +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash 0.7.6", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -1525,7 +1603,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" dependencies = [ "base64 0.13.1", - "bitflags", + "bitflags 1.3.2", "bytes 1.4.0", "headers-core", "http", @@ -1572,18 +1650,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "hex" @@ -1635,14 +1704,14 @@ dependencies = [ [[package]] name = "holaplex-hub-core" -version = "0.3.1" -source = "git+https://github.com/holaplex/hub-core?branch=stable#64b4ace7aa493d2fa0ab8d1e2a132f0dec98029a" +version = "0.3.2" +source = "git+https://github.com/holaplex/hub-core?branch=stable#35052639f5fccd17107585814ca4d743f3f28213" dependencies = [ "anyhow", "async-trait", "chrono", "cid", - "clap 4.3.5", + "clap 4.3.19", "dotenv", "futures-util", "holaplex-hub-core-schemas", @@ -1659,7 +1728,7 @@ dependencies = [ "strum", "thiserror", "tokio", - "toml 0.7.4", + "toml 0.7.6", "tracing", "tracing-loki", "tracing-subscriber", @@ -1670,7 +1739,7 @@ dependencies = [ [[package]] name = "holaplex-hub-core-build" version = "0.2.1" -source = "git+https://github.com/holaplex/hub-core?branch=stable#64b4ace7aa493d2fa0ab8d1e2a132f0dec98029a" +source = "git+https://github.com/holaplex/hub-core?branch=stable#35052639f5fccd17107585814ca4d743f3f28213" dependencies = [ "anyhow", "dotenv", @@ -1689,7 +1758,7 @@ dependencies = [ [[package]] name = "holaplex-hub-core-schemas" version = "0.3.1" -source = "git+https://github.com/holaplex/hub-core?branch=stable#64b4ace7aa493d2fa0ab8d1e2a132f0dec98029a" +source = "git+https://github.com/holaplex/hub-core?branch=stable#35052639f5fccd17107585814ca4d743f3f28213" dependencies = [ "holaplex-hub-core-build", "prost", @@ -1762,9 +1831,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.26" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes 1.4.0", "futures-channel", @@ -1864,41 +1933,39 @@ dependencies = [ ] [[package]] -name = "instant" -version = "0.1.12" +name = "indexmap" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ - "cfg-if", + "equivalent", + "hashbrown 0.14.0", ] [[package]] -name = "io-lifetimes" -version = "1.0.11" +name = "instant" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "hermit-abi 0.3.1", - "libc", - "windows-sys 0.48.0", + "cfg-if", ] [[package]] name = "ipnet" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "is-terminal" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", + "hermit-abi 0.3.2", "rustix", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1912,9 +1979,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jobserver" @@ -1951,9 +2018,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.146" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libsecp256k1" @@ -2005,9 +2072,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.9" +version = "1.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ee889ecc9568871456d42f603d6a0ce59ff328d291063a45cbdf0036baf6db" +checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" dependencies = [ "cc", "libc", @@ -2017,9 +2084,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.3.8" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" [[package]] name = "lock_api" @@ -2068,7 +2135,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "regex-automata", + "regex-automata 0.1.10", ] [[package]] @@ -2126,9 +2193,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", ] @@ -2141,7 +2208,7 @@ checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -2282,20 +2349,20 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi 0.3.2", "libc", ] @@ -2322,9 +2389,9 @@ dependencies = [ [[package]] name = "object" -version = "0.30.4" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" dependencies = [ "memchr", ] @@ -2343,11 +2410,11 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.55" +version = "0.10.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +checksum = "729b745ad4a5575dd06a3e1af1414bd330ee561c01b3899eb584baeaa8def17e" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "foreign-types", "libc", @@ -2364,7 +2431,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -2375,9 +2442,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.90" +version = "0.9.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +checksum = "866b5f16f90776b9bb8dc1e1802ac6f0513de3a7a7465867bfbc563dc737faac" dependencies = [ "cc", "libc", @@ -2392,7 +2459,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ae859aa07428ca9a929b936690f8b12dc5f11dd8c6992a18ca93919f28bc177" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -2480,9 +2547,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pbkdf2" @@ -2501,9 +2568,9 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.6.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16833386b02953ca926d19f64af613b9bf742c48dcd5e09b32fbfc9740bf84e2" +checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a" dependencies = [ "thiserror", "ucd-trie", @@ -2511,9 +2578,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.6.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7763190f9406839f99e5197afee8c9e759969f7dbfa40ad3b8dbee8757b745b5" +checksum = "666d00490d4ac815001da55838c500eafb0320019bbaa44444137c48b443a853" dependencies = [ "pest", "pest_generator", @@ -2521,22 +2588,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.6.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "249061b22e99973da1f5f5f1410284419e283bb60b79255bf5f42a94b66a2e00" +checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] name = "pest_meta" -version = "2.6.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "457c310cfc9cf3f22bc58901cc7f0d3410ac5d6298e432a4f9a6138565cb6df6" +checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48" dependencies = [ "once_cell", "pest", @@ -2550,7 +2617,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" dependencies = [ "fixedbitset", - "indexmap", + "indexmap 1.9.3", ] [[package]] @@ -2575,9 +2642,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "2c516611246607d0c04186886dbb3a754368ef82c79e9827a802c6d836dd111c" [[package]] name = "pin-utils" @@ -2593,9 +2660,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "poem" -version = "1.3.56" +version = "1.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a56df40b79ebdccf7986b337f9b0e51ac55cd5e9d21fb20b6aa7c7d49741854" +checksum = "f0d92c532a37a9e98c0e9a0411e6852b8acccf9ec07d5e6e450b01cbf947d90b" dependencies = [ "anyhow", "async-trait", @@ -2627,14 +2694,14 @@ dependencies = [ [[package]] name = "poem-derive" -version = "1.3.56" +version = "1.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1701f977a2d650a03df42c053686ea0efdb83554f34c7b026b89383c0a1b7846" +checksum = "f5dd58846a1f582215370384c3090c62c9ef188e9d798ffc67ea90d0a1a8a3b8" dependencies = [ "proc-macro-crate 1.1.3", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.28", ] [[package]] @@ -2698,9 +2765,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] @@ -2781,9 +2848,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.28" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" dependencies = [ "proc-macro2", ] @@ -2935,7 +3002,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -2944,7 +3011,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -2960,13 +3027,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.4" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.2", + "regex-automata 0.3.6", + "regex-syntax 0.7.4", ] [[package]] @@ -2978,6 +3046,17 @@ dependencies = [ "regex-syntax 0.6.29", ] +[[package]] +name = "regex-automata" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.4", +] + [[package]] name = "regex-syntax" version = "0.6.29" @@ -2986,9 +3065,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "rend" @@ -3092,13 +3171,12 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.30.0" +version = "1.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0446843641c69436765a35a5a77088e28c2e6a12da93e84aa3ab1cd4aa5a042" +checksum = "4a2ab0025103a60ecaaf3abf24db1db240a4e1c15837090d2c32f625ac98abea" dependencies = [ "arrayvec", - "borsh", - "bytecheck", + "borsh 0.10.3", "byteorder", "bytes 1.4.0", "num-traits", @@ -3131,16 +3209,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.20" +version = "0.38.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" +checksum = "172891ebdceb05aa0005f533a6cbfca599ddd7d966f6f5d4d9b2e70478e70399" dependencies = [ - "bitflags", + "bitflags 2.3.3", "errno", - "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -3157,24 +3234,24 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ "base64 0.21.2", ] [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "sasl2-sys" @@ -3190,18 +3267,18 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys 0.42.0", + "windows-sys", ] [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" @@ -3235,7 +3312,7 @@ dependencies = [ "serde_json", "sqlx", "thiserror", - "time 0.3.22", + "time 0.3.25", "tracing", "url", "uuid", @@ -3296,7 +3373,7 @@ dependencies = [ "rust_decimal", "sea-query-derive", "serde_json", - "time 0.3.22", + "time 0.3.25", "uuid", ] @@ -3311,7 +3388,7 @@ dependencies = [ "sea-query", "serde_json", "sqlx", - "time 0.3.22", + "time 0.3.25", "uuid", ] @@ -3381,11 +3458,11 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "security-framework" -version = "2.9.1" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", @@ -3394,9 +3471,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" dependencies = [ "core-foundation-sys", "libc", @@ -3404,44 +3481,44 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" [[package]] name = "serde" -version = "1.0.164" +version = "1.0.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.9" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" +checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] name = "serde_json" -version = "1.0.97" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf3bf93142acad5821c99197022e170842cdbc1c30482b98750c688c640842a" +checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" dependencies = [ "itoa", "ryu", @@ -3450,9 +3527,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" dependencies = [ "serde", ] @@ -3478,11 +3555,11 @@ dependencies = [ "base64 0.13.1", "chrono", "hex", - "indexmap", + "indexmap 1.9.3", "serde", "serde_json", "serde_with_macros", - "time 0.3.22", + "time 0.3.25", ] [[package]] @@ -3491,10 +3568,10 @@ version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" dependencies = [ - "darling 0.20.1", + "darling 0.20.3", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -3588,9 +3665,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "snap" @@ -3610,9 +3687,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.16.1" +version = "1.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eea8be57163366de9ffee3652cd42ea02fd5cca672408722f1426eb0d234a330" +checksum = "bee2b96d4150d9ebf55e903014bc332ac64c642837d7f1e6f7b911d709331380" dependencies = [ "ahash 0.8.3", "blake3", @@ -3643,21 +3720,21 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.16.1" +version = "1.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4121f91307234cec8c8d8cd2d7ec171881c07db2222335e8c840d555ebe89cc" +checksum = "942534eb972f955ed186175495654cabece6261a8ac3211e5791440d40a1ed96" dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] name = "solana-program" -version = "1.16.1" +version = "1.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ac28d05adeff2212cdec76dfacc6eb631d69d065b1b83c063a1fab505d5e62" +checksum = "2f81c59ed0b65b403cc5db459dd1214dfab89ccd3ce20aadf98102b072d08562" dependencies = [ "ark-bn254", "ark-ec", @@ -3666,9 +3743,10 @@ dependencies = [ "array-bytes", "base64 0.21.2", "bincode", - "bitflags", + "bitflags 1.3.2", "blake3", - "borsh", + "borsh 0.10.3", + "borsh 0.9.3", "bs58", "bv", "bytemuck", @@ -3709,15 +3787,15 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.16.1" +version = "1.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa991e6d6ae7c57ef9fc56f964b22f3bae6ba6c144ccb07b0fe07e06a3efc47c" +checksum = "2e7d686e405694cd6510cd77bb87d0eeda64ad3df08d3293278ba47ca78b8e5e" dependencies = [ "bs58", "proc-macro2", "quote", "rustversion", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -3762,7 +3840,7 @@ dependencies = [ "ahash 0.7.6", "atoi", "base64 0.13.1", - "bitflags", + "bitflags 1.3.2", "byteorder", "bytes 1.4.0", "chrono", @@ -3780,7 +3858,7 @@ dependencies = [ "hex", "hkdf", "hmac 0.12.1", - "indexmap", + "indexmap 1.9.3", "itoa", "libc", "log", @@ -3803,7 +3881,7 @@ dependencies = [ "sqlx-rt", "stringprep", "thiserror", - "time 0.3.22", + "time 0.3.25", "tokio-stream", "url", "uuid", @@ -3862,9 +3940,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "stringprep" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" +checksum = "db3737bde7edce97102e0e2b15365bf7a20bfdb5f60f4f9e8d7004258a51a8da" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -3917,9 +3995,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" dependencies = [ "proc-macro2", "quote", @@ -3946,16 +4024,15 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.6.0" +version = "3.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651" dependencies = [ - "autocfg", "cfg-if", "fastrand", "redox_syscall 0.3.5", "rustix", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -3975,22 +4052,22 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -4016,10 +4093,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.22" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" +checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea" dependencies = [ + "deranged", "itoa", "serde", "time-core", @@ -4034,9 +4112,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd" dependencies = [ "time-core", ] @@ -4077,11 +4155,12 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.2" +version = "1.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" dependencies = [ "autocfg", + "backtrace", "bytes 1.4.0", "libc", "mio", @@ -4090,7 +4169,7 @@ dependencies = [ "pin-project-lite", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -4101,7 +4180,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -4138,9 +4217,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd" +checksum = "ec509ac96e9a0c43427c74f003127d953a265737636129424288d27cb5c4b12c" dependencies = [ "futures-util", "log", @@ -4169,15 +4248,15 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ - "indexmap", + "indexmap 1.9.3", "serde", ] [[package]] name = "toml" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" dependencies = [ "serde", "serde_spanned", @@ -4187,20 +4266,20 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.10" +version = "0.19.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ - "indexmap", + "indexmap 2.0.0", "serde", "serde_spanned", "toml_datetime", @@ -4228,13 +4307,13 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8803eee176538f94ae9a14b55b2804eb7e1441f8210b1c31290b3bccdccff73b" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] @@ -4260,9 +4339,9 @@ dependencies = [ [[package]] name = "tracing-loki" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dd4fccab2576134d2aa57a1457f93e6612e8afea2a170f392fd1c081e249998" +checksum = "49bbc87d08020d7c2a9f4bb0b7d10da5381d3867f8ae57fcc54621b34567e963" dependencies = [ "loki-api", "reqwest", @@ -4315,13 +4394,13 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "tungstenite" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" +checksum = "15fba1a6d6bb030745759a9a2a588bfe8490fc8b4751a277db3a0be1c9ebbf67" dependencies = [ - "base64 0.13.1", "byteorder", "bytes 1.4.0", + "data-encoding", "http", "httparse", "log", @@ -4340,9 +4419,9 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "ucd-trie" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "uncased" @@ -4361,9 +4440,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-normalization" @@ -4430,9 +4509,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.3.4" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa2982af2eec27de306107c027578ff7f423d65f7250e40ce0fea8f45248b81" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" dependencies = [ "getrandom 0.2.10", "serde", @@ -4504,7 +4583,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", "wasm-bindgen-shared", ] @@ -4538,7 +4617,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4604,9 +4683,9 @@ dependencies = [ [[package]] name = "whoami" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c70234412ca409cc04e864e89523cb0fc37f5e1344ebed5a3ebf4192b6b9f68" +checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" dependencies = [ "wasm-bindgen", "web-sys", @@ -4652,21 +4731,6 @@ dependencies = [ "windows-targets", ] -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -4678,97 +4742,55 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - [[package]] name = "windows_aarch64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - [[package]] name = "windows_i686_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - [[package]] name = "windows_i686_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - [[package]] name = "windows_x86_64_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - [[package]] name = "windows_x86_64_msvc" version = "0.48.0" @@ -4777,9 +4799,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.7" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +checksum = "acaaa1190073b2b101e15083c38ee8ec891b5e05cbee516521e94ec008f61e64" dependencies = [ "memchr", ] @@ -4819,7 +4841,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.28", ] [[package]] diff --git a/api/Cargo.toml b/api/Cargo.toml index d9eac55..561dc35 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -42,7 +42,7 @@ strum = { version = "0.24.1", features = ["derive"] } [dependencies.hub-core] package = "holaplex-hub-core" -version = "0.3.1" +version = "0.3.2" git = "https://github.com/holaplex/hub-core" branch = "stable" features = ["kafka", "credits", "asset_proxy"] diff --git a/api/proto.lock b/api/proto.lock index efb19fe..a6b1ace 100644 --- a/api/proto.lock +++ b/api/proto.lock @@ -1,26 +1,26 @@ [[schemas]] subject = "customer" -version = 1 +version = 2 sha512 = "d75800df0d4744c6b0f4d9a9952d3bfd0bb6b24a8babd19104cc11b54a525f85551b3c7375d69aeabbcf629cd826aa0bc6b0c0467add20716c504f5e856ce1c5" [[schemas]] subject = "nfts" -version = 1 -sha512 = "c4032c35d77a78090c17d230dfae7955577a6172bc60921c4821e76690c89d3f858d2b358ca41e34fc25468f430107d4c1552e4529dc48db61e4f5545a6ef82c" +version = 24 +sha512 = "e4be4beae6db9911bd5a5ab9d807dc9b0c027dba67bfb5c114cf805edba9f67c758769a7dd9d69d0f692e567fc35001d69d00b9aa59a92b9ef004aba79fbc6b9" [[schemas]] subject = "organization" -version = 1 +version = 5 sha512 = "9fb28ac73d9712292297394a5fa53a7dae9deba6847353582987ba749859301c23c05fd49d2ce84a1640f8864c5c04d59fa38907700b280000e5c4afc96654bf" [[schemas]] subject = "polygon_nfts" -version = 1 +version = 6 sha512 = "c5ddf43d2958ec690ee2261d0ff9808b67ce810d2fc4b6077f96f561929a920f03509fc8bd7adbda219250eb019f5f7be8a3f51c554f665ea1881f7a973ef2a6" [[schemas]] subject = "solana_nfts" -version = 1 +version = 8 sha512 = "2a57c4200577f8a6efa36e2c045a5bd3eb0dba11466659a80dd82f5422db4ac119f529d391805d14449b0ffac6048ae789727075882f9b0496dac710e32f4ff5" [[schemas]] @@ -30,5 +30,5 @@ sha512 = "d167e0a143c813073eef8597f0b237e5a8eaf32abbf709724e8071b2dd73ce0438b82f [[schemas]] subject = "treasury" -version = 1 +version = 20 sha512 = "f3ff35aeb4bfa3a76b4cb985c4f2fc4b3dab1d0bb1585d4d720ff2c1087a879b56531efd3ecdebbb0968fae23371ec03aa944eec0ed07c0a3db7d66aa2074e2e" diff --git a/api/proto.toml b/api/proto.toml index 51e4a35..94ef3db 100644 --- a/api/proto.toml +++ b/api/proto.toml @@ -1,11 +1,11 @@ [registry] -endpoint = "http://localhost:8081" +endpoint = "https://schemas.holaplex.tools" [schemas] -organization = 1 -nfts = 1 -customer = 1 -treasury = 1 -solana_nfts = 1 -polygon_nfts = 1 -timestamp = 1 +organization = 5 +nfts = 24 +customer = 2 +treasury = 20 +solana_nfts = 8 +polygon_nfts = 6 +timestamp = 1 \ No newline at end of file diff --git a/api/src/blockchains/mod.rs b/api/src/blockchains/mod.rs index b6edc00..ef66c4b 100644 --- a/api/src/blockchains/mod.rs +++ b/api/src/blockchains/mod.rs @@ -3,7 +3,7 @@ pub mod solana; use hub_core::anyhow::Result; -use crate::proto::NftEventKey; +use crate::proto::{NftEventKey, UpdateSolanaMintPayload}; /// Represents a response from a transaction on the blockchain. This struct /// provides the serialized message and the signatures of the signed message. @@ -31,7 +31,11 @@ pub trait CollectionEvent { async fn update_collection(&self, key: NftEventKey, payload: B) -> Result<()>; async fn mint_to_collection(&self, key: NftEventKey, payload: C) -> Result<()>; async fn retry_mint_to_collection(&self, key: NftEventKey, payload: C) -> Result<()>; - async fn update_collection_mint(&self, key: NftEventKey, payload: C) -> Result<()>; + async fn update_collection_mint( + &self, + key: NftEventKey, + payload: UpdateSolanaMintPayload, + ) -> Result<()>; } #[async_trait::async_trait] diff --git a/api/src/blockchains/solana.rs b/api/src/blockchains/solana.rs index e8dc0ea..7e6238c 100644 --- a/api/src/blockchains/solana.rs +++ b/api/src/blockchains/solana.rs @@ -5,11 +5,12 @@ use crate::proto::{ nft_events::Event::{ SolanaCreateCollection, SolanaCreateDrop, SolanaMintDrop, SolanaMintToCollection, SolanaRetryCreateCollection, SolanaRetryDrop, SolanaRetryMintDrop, - SolanaRetryMintToCollection, SolanaTransferAsset, SolanaUpdateCollection, - SolanaUpdateCollectionMint, SolanaUpdateDrop, + SolanaRetryMintToCollection, SolanaTransferAsset, SolanaUpdateCollection, SolanaUpdateDrop, + SolanaUpdatedCollectionMint, }, MetaplexMasterEditionTransaction, MintMetaplexEditionTransaction, MintMetaplexMetadataTransaction, NftEventKey, NftEvents, TransferMetaplexAssetTransaction, + UpdateSolanaMintPayload, }; #[derive(Clone)] pub struct Solana { @@ -216,10 +217,10 @@ impl async fn update_collection_mint( &self, key: NftEventKey, - payload: MintMetaplexMetadataTransaction, + payload: UpdateSolanaMintPayload, ) -> Result<()> { let event = NftEvents { - event: Some(SolanaUpdateCollectionMint(payload)), + event: Some(SolanaUpdatedCollectionMint(payload)), }; self.producer.send(Some(&event), Some(&key)).await?; diff --git a/api/src/entities/mod.rs b/api/src/entities/mod.rs index 1973251..f1b87a3 100644 --- a/api/src/entities/mod.rs +++ b/api/src/entities/mod.rs @@ -17,3 +17,4 @@ pub mod nft_transfers; pub mod project_wallets; pub mod sea_orm_active_enums; pub mod transfer_charges; +pub mod update_histories; diff --git a/api/src/entities/prelude.rs b/api/src/entities/prelude.rs index 5b4f708..63461d0 100644 --- a/api/src/entities/prelude.rs +++ b/api/src/entities/prelude.rs @@ -7,5 +7,5 @@ pub use super::{ metadata_json_files::Entity as MetadataJsonFiles, metadata_jsons::Entity as MetadataJsons, mint_creators::Entity as MintCreators, mint_histories::Entity as MintHistory, nft_transfers::Entity as NftTransfers, project_wallets::Entity as ProjectWallets, - transfer_charges::Entity as TransferCharges, + transfer_charges::Entity as TransferCharges, update_histories::Entity as UpdateHistories, }; diff --git a/api/src/entities/update_histories.rs b/api/src/entities/update_histories.rs new file mode 100644 index 0000000..1f0ba20 --- /dev/null +++ b/api/src/entities/update_histories.rs @@ -0,0 +1,24 @@ +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3 + +use sea_orm::entity::prelude::*; + +use super::sea_orm_active_enums::CreationStatus; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "update_histories")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + pub mint_id: Uuid, + #[sea_orm(column_type = "Text", nullable)] + pub txn_signature: Option, + pub status: CreationStatus, + pub credit_deduction_id: Uuid, + pub created_by: Uuid, + pub created_at: DateTime, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/api/src/events.rs b/api/src/events.rs index 29b5652..5e98e03 100644 --- a/api/src/events.rs +++ b/api/src/events.rs @@ -16,10 +16,10 @@ use crate::{ collection_creators, collection_mints, collections, customer_wallets, drops, metadata_json_attributes, metadata_json_files, metadata_jsons, mint_creators, mint_histories, nft_transfers, - prelude::{CollectionMints, Collections, Drops, MintHistory}, + prelude::{CollectionMints, Collections, Drops, MintHistory, UpdateHistories}, project_wallets, sea_orm_active_enums::{Blockchain, CreationStatus}, - transfer_charges, + transfer_charges, update_histories, }, proto::{ nft_events::Event as NftEvent, @@ -62,6 +62,12 @@ enum TransferResult { Failure, } +#[derive(Clone)] +enum UpdateResult { + Success(String), + Failure, +} + impl Processor { #[must_use] pub fn new( @@ -134,6 +140,10 @@ impl Processor { self.minted_to_collection(id, MintResult::Success(payload.into())) .await }, + Some(SolanaNftsEvent::UpdateCollectionMintSubmitted(payload)) => { + self.mint_updated(id, UpdateResult::Success(payload.signature)) + .await + }, Some(SolanaNftsEvent::TransferAssetSubmitted( SolanaCompletedTransferTransaction { signature }, )) => { @@ -161,6 +171,9 @@ impl Processor { Some(SolanaNftsEvent::RetryMintDropFailed(_)) => { self.drop_minted(id, MintResult::Failure).await }, + Some(SolanaNftsEvent::UpdateCollectionMintFailed(_)) => { + self.mint_updated(id, UpdateResult::Failure).await + }, Some(SolanaNftsEvent::UpdateMintOwner(e)) => self.update_mint_owner(id, e).await, Some(SolanaNftsEvent::ImportedExternalCollection(e)) => { self.index_collection(id, project_id, user_id, e).await @@ -168,6 +181,7 @@ impl Processor { Some(SolanaNftsEvent::ImportedExternalMint(e)) => { self.index_mint(id, user_id, e).await }, + None | Some(_) => Ok(()), }, Services::Polygon(_, e) => match e.event { @@ -726,6 +740,25 @@ impl Processor { Ok(()) } + + async fn mint_updated(&self, id: String, payload: UpdateResult) -> Result<()> { + let update_history = UpdateHistories::find_by_id(id.parse()?) + .one(self.db.get()) + .await? + .context("Update history record not found")?; + let mut update_history: update_histories::ActiveModel = update_history.into(); + + if let UpdateResult::Success(signature) = payload { + update_history.txn_signature = Set(Some(signature)); + update_history.status = Set(CreationStatus::Created); + } else { + update_history.status = Set(CreationStatus::Failed); + } + + update_history.update(self.db.get()).await?; + + Ok(()) + } } impl TryFrom for Blockchain { diff --git a/api/src/lib.rs b/api/src/lib.rs index d3ec7cd..84c5bc6 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -203,6 +203,7 @@ pub enum Actions { MintCompressed, CreateCollection, RetryCollection, + UpdateMint, } impl From for hub_core::credits::Action { @@ -217,6 +218,7 @@ impl From for hub_core::credits::Action { Actions::MintCompressed => hub_core::credits::Action::MintCompressed, Actions::CreateCollection => hub_core::credits::Action::CreateCollection, Actions::RetryCollection => hub_core::credits::Action::RetryCollection, + Actions::UpdateMint => hub_core::credits::Action::UpdateMint, } } } diff --git a/api/src/mutations/mint.rs b/api/src/mutations/mint.rs index 89b60b1..eff9cd9 100644 --- a/api/src/mutations/mint.rs +++ b/api/src/mutations/mint.rs @@ -1,7 +1,11 @@ use std::ops::Add; use async_graphql::{Context, Error, InputObject, Object, Result, SimpleObject}; -use hub_core::{chrono::Utc, credits::CreditsClient, producer::Producer}; +use hub_core::{ + chrono::Utc, + credits::{Blockchain, CreditsClient}, + producer::Producer, +}; use sea_orm::{prelude::*, JoinType, QuerySelect, Set, TransactionTrait}; use super::collection::{ @@ -15,6 +19,7 @@ use crate::{ prelude::{CollectionMints, Collections, Drops}, project_wallets, sea_orm_active_enums::{Blockchain as BlockchainEnum, CreationStatus}, + update_histories, }, metadata_json::MetadataJson, objects::{Creator, MetadataJsonInput}, @@ -486,11 +491,11 @@ impl Mutation { }) } - pub async fn update_collection_mint( + pub async fn update_mint( &self, ctx: &Context<'_>, - input: UpdateCollectionMint, - ) -> Result { + input: UpdateMintInput, + ) -> Result { let AppContext { db, user_id, @@ -510,6 +515,7 @@ impl Mutation { let balance = balance .0 .ok_or(Error::new("X-CREDIT-BALANCE header not found"))?; + let org_id = org.ok_or(Error::new("X-ORGANIZATION-ID header not found"))?; let creators = input.creators; @@ -551,6 +557,17 @@ impl Mutation { }) .collect::>>()?; + let deduction_id = credits + .submit_pending_deduction( + org_id, + user_id, + Actions::UpdateMint, + Blockchain::Solana, + balance, + ) + .await? + .ok_or(Error::new("Organization does not have enough credits"))?; + conn.transaction::<_, (), DbErr>(|txn| { Box::pin(async move { mint_creators::Entity::delete_many() @@ -581,17 +598,28 @@ impl Mutation { .save(mint.id, db) .await?; + let mint_history_am = update_histories::ActiveModel { + mint_id: Set(mint.id), + txn_signature: Set(None), + credit_deduction_id: Set(deduction_id.0), + created_by: Set(user_id), + status: Set(CreationStatus::Pending), + ..Default::default() + }; + + let mint_history = mint_history_am.insert(db.get()).await?; + match collection.blockchain { BlockchainEnum::Solana => { solana .event() .update_collection_mint( NftEventKey { - id: mint.id.to_string(), + id: mint_history.id.to_string(), project_id: collection.project_id.to_string(), user_id: user_id.to_string(), }, - proto::MintMetaplexMetadataTransaction { + proto::UpdateSolanaMintPayload { metadata: Some(MetaplexMetadata { owner_address, name: metadata_json.name, @@ -604,7 +632,7 @@ impl Mutation { .collect::>()?, }), collection_id: collection.id.to_string(), - ..Default::default() + mint_id: mint.id.to_string(), }, ) .await?; @@ -614,7 +642,7 @@ impl Mutation { }, }; - Ok(UpdateCollectionMintPayload { + Ok(UpdateMintPayload { collection_mint: mint.into(), }) } @@ -857,7 +885,7 @@ pub struct MintToCollectionInput { } #[derive(Debug, Clone, InputObject)] -pub struct UpdateCollectionMint { +pub struct UpdateMintInput { mint: Uuid, metadata_json: MetadataJsonInput, seller_fee_basis_points: Option, @@ -870,7 +898,7 @@ pub struct MintToCollectionPayload { } #[derive(Debug, Clone, SimpleObject)] -pub struct UpdateCollectionMintPayload { +pub struct UpdateMintPayload { collection_mint: collection_mints::CollectionMint, } diff --git a/migration/src/lib.rs b/migration/src/lib.rs index f17946f..f065357 100644 --- a/migration/src/lib.rs +++ b/migration/src/lib.rs @@ -50,6 +50,7 @@ mod m20230713_163043_add_column_compressed_to_collection_mints; mod m20230718_111347_add_created_at_and_created_by_columns_to_collections; mod m20230725_135946_rename_purchases_to_mint_histories; mod m20230725_144506_drop_solana_collections_table; +mod m20230807_090847_create_histories_table; pub struct Migrator; @@ -107,6 +108,7 @@ impl MigratorTrait for Migrator { Box::new(m20230718_111347_add_created_at_and_created_by_columns_to_collections::Migration), Box::new(m20230725_135946_rename_purchases_to_mint_histories::Migration), Box::new(m20230725_144506_drop_solana_collections_table::Migration), + Box::new(m20230807_090847_create_histories_table::Migration), ] } } diff --git a/migration/src/m20230807_090847_create_histories_table.rs b/migration/src/m20230807_090847_create_histories_table.rs new file mode 100644 index 0000000..6e0ac8d --- /dev/null +++ b/migration/src/m20230807_090847_create_histories_table.rs @@ -0,0 +1,64 @@ +use sea_orm_migration::prelude::*; + +use crate::m20230214_212301_create_collections_table::CreationStatus; + +#[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(UpdateHistories::Table) + .if_not_exists() + .col( + ColumnDef::new(UpdateHistories::Id) + .uuid() + .not_null() + .primary_key() + .extra("default gen_random_uuid()".to_string()), + ) + .col(ColumnDef::new(UpdateHistories::MintId).uuid().not_null()) + .col(ColumnDef::new(UpdateHistories::TxnSignature).text()) + .col( + ColumnDef::new(UpdateHistories::Status) + .custom(CreationStatus::Type) + .not_null(), + ) + .col( + ColumnDef::new(UpdateHistories::CreditDeductionId) + .uuid() + .not_null(), + ) + .col(ColumnDef::new(UpdateHistories::CreatedBy).uuid().not_null()) + .col( + ColumnDef::new(UpdateHistories::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(UpdateHistories::Table).to_owned()) + .await + } +} + +#[derive(Iden)] +pub enum UpdateHistories { + Table, + Id, + MintId, + TxnSignature, + Status, + CreditDeductionId, + CreatedBy, + CreatedAt, +} From 3e5823596296eec315a854d937921620f87976c7 Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Tue, 8 Aug 2023 03:18:35 +0500 Subject: [PATCH 03/28] Increment total_mints when indexing mints using update statement --- api/src/events.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/api/src/events.rs b/api/src/events.rs index b973759..3424290 100644 --- a/api/src/events.rs +++ b/api/src/events.rs @@ -6,8 +6,9 @@ use hub_core::{ uuid::Uuid, }; use sea_orm::{ - ActiveModelTrait, ColumnTrait, EntityTrait, JoinType, QueryFilter, QuerySelect, RelationTrait, - Set, TransactionTrait, + sea_query::{Expr, SimpleExpr}, + ActiveModelTrait, ColumnTrait, DbErr, EntityTrait, JoinType, QueryFilter, QuerySelect, + RelationTrait, Set, TransactionTrait, }; use crate::{ @@ -324,15 +325,18 @@ impl Processor { index_attributes(&self.db, json_model.id, attributes).await?; index_files(&self.db, json_model.id, files).await?; - let collection = Collections::find_by_id(collection_id.parse()?) - .one(self.db.get()) - .await - .context("failed to load collection from db")? - .context("collection not found in db")?; - let mut collection_am: collections::ActiveModel = collection.clone().into(); + let collection_id = Uuid::from_str(&collection_id)?; + + collections::Entity::update_many() + .col_expr( + collections::Column::TotalMints, + >::into(Expr::col(collections::Column::TotalMints)) + .add(SimpleExpr::Value(1.into())), + ) + .filter(collections::Column::Id.eq(collection_id)) + .exec(self.db.get()) + .await?; - collection_am.total_mints = Set(collection.total_mints + 1); - collection_am.update(self.db.get()).await?; Ok(()) } From f49eef011e8297aff2327bb36f4701cbdfb33a79 Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Wed, 9 Aug 2023 00:17:32 +0500 Subject: [PATCH 04/28] support retry update mint --- api/proto.lock | 12 ++-- api/proto.toml | 6 +- api/src/blockchains/mod.rs | 9 ++- api/src/blockchains/solana.rs | 23 ++++-- api/src/entities/collection_mints.rs | 8 +++ api/src/entities/update_histories.rs | 17 ++++- api/src/events.rs | 12 ++-- api/src/mutations/mint.rs | 71 +++++++++++++++++-- credits.toml | 4 ++ ...m20230807_090847_create_histories_table.rs | 13 +++- 10 files changed, 151 insertions(+), 24 deletions(-) diff --git a/api/proto.lock b/api/proto.lock index a6b1ace..355201e 100644 --- a/api/proto.lock +++ b/api/proto.lock @@ -5,8 +5,8 @@ sha512 = "d75800df0d4744c6b0f4d9a9952d3bfd0bb6b24a8babd19104cc11b54a525f85551b3c [[schemas]] subject = "nfts" -version = 24 -sha512 = "e4be4beae6db9911bd5a5ab9d807dc9b0c027dba67bfb5c114cf805edba9f67c758769a7dd9d69d0f692e567fc35001d69d00b9aa59a92b9ef004aba79fbc6b9" +version = 25 +sha512 = "90dadff6bc75b59bb79d9ed2a65d582923f9ce66b5915c020306571bb446d68ff6648543386838510a60081d7cbb14f43fa2ae22c4c8ecd85874bee4323dd26a" [[schemas]] subject = "organization" @@ -20,8 +20,8 @@ sha512 = "c5ddf43d2958ec690ee2261d0ff9808b67ce810d2fc4b6077f96f561929a920f03509f [[schemas]] subject = "solana_nfts" -version = 8 -sha512 = "2a57c4200577f8a6efa36e2c045a5bd3eb0dba11466659a80dd82f5422db4ac119f529d391805d14449b0ffac6048ae789727075882f9b0496dac710e32f4ff5" +version = 9 +sha512 = "312a84e8ae8b9222c7ec2b307d036dae0bd8dac4363e813c2fcffd5d7fba8741bd802953b1ec0a96baf57a7ce852debb724fcccf3b0bd8a27a9e4cc60344a56f" [[schemas]] subject = "timestamp" @@ -30,5 +30,5 @@ sha512 = "d167e0a143c813073eef8597f0b237e5a8eaf32abbf709724e8071b2dd73ce0438b82f [[schemas]] subject = "treasury" -version = 20 -sha512 = "f3ff35aeb4bfa3a76b4cb985c4f2fc4b3dab1d0bb1585d4d720ff2c1087a879b56531efd3ecdebbb0968fae23371ec03aa944eec0ed07c0a3db7d66aa2074e2e" +version = 21 +sha512 = "734cff313b8b4854b9a4c03cfd6f95f07b1fd86f8678393ab466443d9da4d6e7c9fc400bdbcc718d83e6c7711857941d4b6dc0ea5d1d926f05a7859a65a15509" diff --git a/api/proto.toml b/api/proto.toml index 94ef3db..151c09b 100644 --- a/api/proto.toml +++ b/api/proto.toml @@ -3,9 +3,9 @@ endpoint = "https://schemas.holaplex.tools" [schemas] organization = 5 -nfts = 24 +nfts = 25 customer = 2 -treasury = 20 -solana_nfts = 8 +treasury = 21 +solana_nfts = 9 polygon_nfts = 6 timestamp = 1 \ No newline at end of file diff --git a/api/src/blockchains/mod.rs b/api/src/blockchains/mod.rs index ef66c4b..2b1da4e 100644 --- a/api/src/blockchains/mod.rs +++ b/api/src/blockchains/mod.rs @@ -1,9 +1,11 @@ pub mod polygon; pub mod solana; +use std::marker::PhantomData; + use hub_core::anyhow::Result; -use crate::proto::{NftEventKey, UpdateSolanaMintPayload}; +use crate::proto::{NftEventKey, RetryUpdateSolanaMintPayload, UpdateSolanaMintPayload}; /// Represents a response from a transaction on the blockchain. This struct /// provides the serialized message and the signatures of the signed message. @@ -36,6 +38,11 @@ pub trait CollectionEvent { key: NftEventKey, payload: UpdateSolanaMintPayload, ) -> Result<()>; + async fn retry_update_mint( + &self, + key: NftEventKey, + payload: RetryUpdateSolanaMintPayload, + ) -> Result<()>; } #[async_trait::async_trait] diff --git a/api/src/blockchains/solana.rs b/api/src/blockchains/solana.rs index 7e6238c..f8d87fb 100644 --- a/api/src/blockchains/solana.rs +++ b/api/src/blockchains/solana.rs @@ -1,3 +1,5 @@ +use std::marker::PhantomData; + use hub_core::{anyhow::Result, producer::Producer}; use super::{CollectionEvent, DropEvent, TransferEvent}; @@ -5,12 +7,12 @@ use crate::proto::{ nft_events::Event::{ SolanaCreateCollection, SolanaCreateDrop, SolanaMintDrop, SolanaMintToCollection, SolanaRetryCreateCollection, SolanaRetryDrop, SolanaRetryMintDrop, - SolanaRetryMintToCollection, SolanaTransferAsset, SolanaUpdateCollection, SolanaUpdateDrop, - SolanaUpdatedCollectionMint, + SolanaRetryMintToCollection, SolanaRetryUpdatedCollectionMint, SolanaTransferAsset, + SolanaUpdateCollection, SolanaUpdateDrop, SolanaUpdatedCollectionMint, }, MetaplexMasterEditionTransaction, MintMetaplexEditionTransaction, - MintMetaplexMetadataTransaction, NftEventKey, NftEvents, TransferMetaplexAssetTransaction, - UpdateSolanaMintPayload, + MintMetaplexMetadataTransaction, NftEventKey, NftEvents, RetryUpdateSolanaMintPayload, + TransferMetaplexAssetTransaction, UpdateSolanaMintPayload, }; #[derive(Clone)] pub struct Solana { @@ -227,4 +229,17 @@ impl Ok(()) } + + async fn retry_update_mint( + &self, + key: NftEventKey, + payload: RetryUpdateSolanaMintPayload, + ) -> Result<()> { + let event = NftEvents { + event: Some(SolanaRetryUpdatedCollectionMint(payload)), + }; + + self.producer.send(Some(&event), Some(&key)).await?; + Ok(()) + } } diff --git a/api/src/entities/collection_mints.rs b/api/src/entities/collection_mints.rs index 3f15c6a..dd7445d 100644 --- a/api/src/entities/collection_mints.rs +++ b/api/src/entities/collection_mints.rs @@ -146,6 +146,8 @@ pub enum Relation { MintHistories, #[sea_orm(has_many = "super::nft_transfers::Entity")] NftTransfers, + #[sea_orm(has_many = "super::update_histories::Entity")] + UpdateHistories, } impl Related for Entity { @@ -172,6 +174,12 @@ impl Related for Entity { } } +impl Related for Entity { + fn to() -> RelationDef { + Relation::UpdateHistories.def() + } +} + impl ActiveModelBehavior for ActiveModel {} impl Entity { diff --git a/api/src/entities/update_histories.rs b/api/src/entities/update_histories.rs index 1f0ba20..6fcd682 100644 --- a/api/src/entities/update_histories.rs +++ b/api/src/entities/update_histories.rs @@ -19,6 +19,21 @@ pub struct Model { } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation {} +pub enum Relation { + #[sea_orm( + belongs_to = "super::collection_mints::Entity", + from = "Column::MintId", + to = "super::collection_mints::Column::Id", + on_update = "Cascade", + on_delete = "Cascade" + )] + CollectionMints, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::CollectionMints.def() + } +} impl ActiveModelBehavior for ActiveModel {} diff --git a/api/src/events.rs b/api/src/events.rs index 3d995b8..8b1a1de 100644 --- a/api/src/events.rs +++ b/api/src/events.rs @@ -140,7 +140,10 @@ impl Processor { self.minted_to_collection(id, MintResult::Success(payload.into())) .await }, - Some(SolanaNftsEvent::UpdateCollectionMintSubmitted(payload)) => { + Some( + SolanaNftsEvent::UpdateCollectionMintSubmitted(payload) + | SolanaNftsEvent::RetryUpdateMintSubmitted(payload), + ) => { self.mint_updated(id, UpdateResult::Success(payload.signature)) .await }, @@ -171,9 +174,10 @@ impl Processor { Some(SolanaNftsEvent::RetryMintDropFailed(_)) => { self.drop_minted(id, MintResult::Failure).await }, - Some(SolanaNftsEvent::UpdateCollectionMintFailed(_)) => { - self.mint_updated(id, UpdateResult::Failure).await - }, + Some( + SolanaNftsEvent::UpdateCollectionMintFailed(_) + | SolanaNftsEvent::RetryUpdateMintFailed(_), + ) => self.mint_updated(id, UpdateResult::Failure).await, Some(SolanaNftsEvent::UpdateMintOwner(e)) => self.update_mint_owner(id, e).await, Some(SolanaNftsEvent::ImportedExternalCollection(e)) => { self.index_collection(id, project_id, user_id, e).await diff --git a/api/src/mutations/mint.rs b/api/src/mutations/mint.rs index fd1d2b5..10ecf54 100644 --- a/api/src/mutations/mint.rs +++ b/api/src/mutations/mint.rs @@ -25,7 +25,7 @@ use crate::{ objects::{Creator, MetadataJsonInput}, proto::{ self, nft_events::Event as NftEvent, CreationStatus as NftCreationStatus, MetaplexMetadata, - MintCollectionCreation, MintCreation, NftEventKey, NftEvents, + MintCollectionCreation, MintCreation, NftEventKey, NftEvents, RetryUpdateSolanaMintPayload, }, Actions, AppContext, NftStorageClient, OrganizationId, UserID, }; @@ -600,7 +600,7 @@ impl Mutation { .save(mint.id, db) .await?; - let mint_history_am = update_histories::ActiveModel { + let update_history_am = update_histories::ActiveModel { mint_id: Set(mint.id), txn_signature: Set(None), credit_deduction_id: Set(deduction_id.0), @@ -609,7 +609,7 @@ impl Mutation { ..Default::default() }; - let mint_history = mint_history_am.insert(db.get()).await?; + let update_history = update_history_am.insert(db.get()).await?; match collection.blockchain { BlockchainEnum::Solana => { @@ -617,7 +617,7 @@ impl Mutation { .event() .update_collection_mint( NftEventKey { - id: mint_history.id.to_string(), + id: update_history.id.to_string(), project_id: collection.project_id.to_string(), user_id: user_id.to_string(), }, @@ -649,6 +649,59 @@ impl Mutation { }) } + pub async fn retry_update_mint( + &self, + ctx: &Context<'_>, + input: RetryUpdateMintInput, + ) -> Result { + let AppContext { db, user_id, .. } = ctx.data::()?; + + let conn = db.get(); + let solana = ctx.data::()?; + + let UserID(id) = user_id; + let user_id = id.ok_or(Error::new("X-USER-ID header not found"))?; + + let (update_history, collection) = update_histories::Entity::find_by_id(input.revision_id) + .inner_join(CollectionMints) + .join( + JoinType::InnerJoin, + collection_mints::Relation::Collections.def(), + ) + .select_also(Collections) + .one(conn) + .await? + .ok_or(Error::new("Update history not found"))?; + + let collection = collection.ok_or(Error::new("Collection not found"))?; + + match collection.blockchain { + BlockchainEnum::Solana => { + solana + .event() + .retry_update_mint( + NftEventKey { + id: update_history.id.to_string(), + project_id: collection.project_id.to_string(), + user_id: user_id.to_string(), + }, + RetryUpdateSolanaMintPayload { + mint_id: update_history.mint_id.to_string(), + collection_id: collection.id.to_string(), + }, + ) + .await?; + }, + BlockchainEnum::Ethereum | BlockchainEnum::Polygon => { + return Err(Error::new("blockchain not supported as this time")); + }, + }; + + Ok(RetryUpdateMintPayload { + status: CreationStatus::Pending, + }) + } + // Retries a mint which failed by passing its ID. pub async fn retry_mint_to_collection( &self, @@ -930,3 +983,13 @@ pub struct RetryMintToCollectionPayload { /// The retried minted NFT collection_mint: collection_mints::CollectionMint, } + +#[derive(Debug, Clone, InputObject)] +pub struct RetryUpdateMintInput { + revision_id: Uuid, +} + +#[derive(Debug, Clone, SimpleObject)] +pub struct RetryUpdateMintPayload { + status: CreationStatus, +} diff --git a/credits.toml b/credits.toml index 2eb9c0e..13a3810 100644 --- a/credits.toml +++ b/credits.toml @@ -36,4 +36,8 @@ polygon = 0 [RetryCollection] solana = 0 +polygon = 0 + +[UpdateMint] +solana = 0 polygon = 0 \ No newline at end of file diff --git a/migration/src/m20230807_090847_create_histories_table.rs b/migration/src/m20230807_090847_create_histories_table.rs index 6e0ac8d..5a5fcc4 100644 --- a/migration/src/m20230807_090847_create_histories_table.rs +++ b/migration/src/m20230807_090847_create_histories_table.rs @@ -1,6 +1,9 @@ use sea_orm_migration::prelude::*; -use crate::m20230214_212301_create_collections_table::CreationStatus; +use crate::{ + m20230214_212301_create_collections_table::CreationStatus, + m20230220_223223_create_collection_mints_table::CollectionMints, +}; #[derive(DeriveMigrationName)] pub struct Migration; @@ -39,6 +42,14 @@ impl MigrationTrait for Migration { .not_null() .extra("default now()".to_string()), ) + .foreign_key( + ForeignKey::create() + .name("fk-update_histories_mint_id") + .from(UpdateHistories::Table, UpdateHistories::MintId) + .to(CollectionMints::Table, CollectionMints::Id) + .on_delete(ForeignKeyAction::Cascade) + .on_update(ForeignKeyAction::Cascade), + ) .to_owned(), ) .await From 7daf023fc5bb4e353beaa3caeb840c29b629e2b7 Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Wed, 9 Aug 2023 00:37:05 +0500 Subject: [PATCH 05/28] reset status to pending on retry and confirm credit deduction --- api/src/blockchains/mod.rs | 2 -- api/src/blockchains/solana.rs | 2 -- api/src/events.rs | 14 +++++++++----- api/src/mutations/mint.rs | 8 ++++++++ 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/api/src/blockchains/mod.rs b/api/src/blockchains/mod.rs index 2b1da4e..294c46b 100644 --- a/api/src/blockchains/mod.rs +++ b/api/src/blockchains/mod.rs @@ -1,8 +1,6 @@ pub mod polygon; pub mod solana; -use std::marker::PhantomData; - use hub_core::anyhow::Result; use crate::proto::{NftEventKey, RetryUpdateSolanaMintPayload, UpdateSolanaMintPayload}; diff --git a/api/src/blockchains/solana.rs b/api/src/blockchains/solana.rs index f8d87fb..d5326fa 100644 --- a/api/src/blockchains/solana.rs +++ b/api/src/blockchains/solana.rs @@ -1,5 +1,3 @@ -use std::marker::PhantomData; - use hub_core::{anyhow::Result, producer::Producer}; use super::{CollectionEvent, DropEvent, TransferEvent}; diff --git a/api/src/events.rs b/api/src/events.rs index 8b1a1de..553a4db 100644 --- a/api/src/events.rs +++ b/api/src/events.rs @@ -750,16 +750,20 @@ impl Processor { .one(self.db.get()) .await? .context("Update history record not found")?; - let mut update_history: update_histories::ActiveModel = update_history.into(); + let mut update_history_am: update_histories::ActiveModel = update_history.clone().into(); if let UpdateResult::Success(signature) = payload { - update_history.txn_signature = Set(Some(signature)); - update_history.status = Set(CreationStatus::Created); + update_history_am.txn_signature = Set(Some(signature)); + update_history_am.status = Set(CreationStatus::Created); + + self.credits + .confirm_deduction(TransactionId(update_history.credit_deduction_id)) + .await?; } else { - update_history.status = Set(CreationStatus::Failed); + update_history_am.status = Set(CreationStatus::Failed); } - update_history.update(self.db.get()).await?; + update_history_am.update(self.db.get()).await?; Ok(()) } diff --git a/api/src/mutations/mint.rs b/api/src/mutations/mint.rs index 10ecf54..b1adcfe 100644 --- a/api/src/mutations/mint.rs +++ b/api/src/mutations/mint.rs @@ -673,6 +673,14 @@ impl Mutation { .await? .ok_or(Error::new("Update history not found"))?; + if update_history.status == CreationStatus::Created { + return Err(Error::new("Mint already updated")); + } + + let mut update_history_am = update_histories::ActiveModel::from(update_history.clone()); + update_history_am.status = Set(CreationStatus::Pending); + update_history_am.update(db.get()).await?; + let collection = collection.ok_or(Error::new("Collection not found"))?; match collection.blockchain { From dfaf604ae9500e6bdbdcc879309815bd6dad6b01 Mon Sep 17 00:00:00 2001 From: Kyle Espinola Date: Wed, 9 Aug 2023 13:10:32 +0200 Subject: [PATCH 06/28] fix: prevent creating zombie objects due to insufficient credits by checking the credits immediately after input validations --- Cargo.lock | 8 +- api/Cargo.toml | 2 +- api/src/events.rs | 4 +- api/src/mutations/collection.rs | 121 ++++++--------------- api/src/mutations/drop.rs | 134 +++++++----------------- api/src/mutations/mint.rs | 180 ++++++++++---------------------- api/src/mutations/transfer.rs | 76 ++++---------- 7 files changed, 151 insertions(+), 374 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 66f4940..ebd9ace 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1635,8 +1635,8 @@ dependencies = [ [[package]] name = "holaplex-hub-core" -version = "0.3.1" -source = "git+https://github.com/holaplex/hub-core?branch=stable#64b4ace7aa493d2fa0ab8d1e2a132f0dec98029a" +version = "0.4.0" +source = "git+https://github.com/holaplex/hub-core?branch=stable#97576b2a5ec65446b8c416c64d190a309f4d269b" dependencies = [ "anyhow", "async-trait", @@ -1670,7 +1670,7 @@ dependencies = [ [[package]] name = "holaplex-hub-core-build" version = "0.2.1" -source = "git+https://github.com/holaplex/hub-core?branch=stable#64b4ace7aa493d2fa0ab8d1e2a132f0dec98029a" +source = "git+https://github.com/holaplex/hub-core?branch=stable#97576b2a5ec65446b8c416c64d190a309f4d269b" dependencies = [ "anyhow", "dotenv", @@ -1689,7 +1689,7 @@ dependencies = [ [[package]] name = "holaplex-hub-core-schemas" version = "0.3.1" -source = "git+https://github.com/holaplex/hub-core?branch=stable#64b4ace7aa493d2fa0ab8d1e2a132f0dec98029a" +source = "git+https://github.com/holaplex/hub-core?branch=stable#97576b2a5ec65446b8c416c64d190a309f4d269b" dependencies = [ "holaplex-hub-core-build", "prost", diff --git a/api/Cargo.toml b/api/Cargo.toml index d9eac55..3ff2b6b 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -42,7 +42,7 @@ strum = { version = "0.24.1", features = ["derive"] } [dependencies.hub-core] package = "holaplex-hub-core" -version = "0.3.1" +version = "0.4.0" git = "https://github.com/holaplex/hub-core" branch = "stable" features = ["kafka", "credits", "asset_proxy"] diff --git a/api/src/events.rs b/api/src/events.rs index 3424290..c7bb961 100644 --- a/api/src/events.rs +++ b/api/src/events.rs @@ -7,8 +7,8 @@ use hub_core::{ }; use sea_orm::{ sea_query::{Expr, SimpleExpr}, - ActiveModelTrait, ColumnTrait, DbErr, EntityTrait, JoinType, QueryFilter, QuerySelect, - RelationTrait, Set, TransactionTrait, + ActiveModelTrait, ColumnTrait, EntityTrait, JoinType, QueryFilter, QuerySelect, RelationTrait, + Set, TransactionTrait, }; use crate::{ diff --git a/api/src/mutations/collection.rs b/api/src/mutations/collection.rs index ef047f8..6be647b 100644 --- a/api/src/mutations/collection.rs +++ b/api/src/mutations/collection.rs @@ -1,7 +1,10 @@ use std::str::FromStr; use async_graphql::{Context, Error, InputObject, Object, Result, SimpleObject}; -use hub_core::{credits::CreditsClient, producer::Producer}; +use hub_core::{ + credits::{CreditsClient, DeductionErrorKind, TransactionId}, + producer::Producer, +}; use reqwest::Url; use sea_orm::{prelude::*, ModelTrait, Set, TransactionTrait}; use serde::{Deserialize, Serialize}; @@ -10,7 +13,6 @@ use solana_program::pubkey::Pubkey; use crate::{ blockchains::{polygon::Polygon, solana::Solana, CollectionEvent}, collection::Collection, - db::Connection, entities::{ collection_creators, collection_mints, collections, metadata_jsons, prelude::{CollectionCreators, CollectionMints, Collections, MetadataJsons}, @@ -24,7 +26,7 @@ use crate::{ CreationStatus as NftCreationStatus, Creator as ProtoCreator, MasterEdition, MetaplexMasterEditionTransaction, NftEventKey, NftEvents, }, - Actions, AppContext, NftStorageClient, OrganizationId, UserID, + Actions, AppContext, NftStorageClient, UserID, }; #[derive(Default)] @@ -58,7 +60,6 @@ impl Mutation { let conn = db.get(); let credits = ctx.data::>()?; let solana = ctx.data::()?; - let _polygon = ctx.data::()?; let nft_storage = ctx.data::()?; let nfts_producer = ctx.data::>()?; @@ -70,6 +71,30 @@ impl Mutation { validate_solana_creator_verification(&owner_address, &input.creators)?; } + let TransactionId(credits_deduction_id) = credits + .submit_pending_deduction( + org_id, + user_id, + Actions::CreateCollection, + input.blockchain.into(), + balance, + ) + .await + .map_err(|e| match e.kind() { + DeductionErrorKind::InsufficientBalance { available, cost } => Error::new(format!( + "insufficient balance: available: {available}, cost: {cost}" + )), + DeductionErrorKind::MissingItem => Error::new(format!( + "{:?} is not supported by the blockchain {} at this time", + e.item(), + e.blockchain() + )), + DeductionErrorKind::InvalidCost(_) => Error::new("invalid cost"), + DeductionErrorKind::Send(_) => { + Error::new("unable to send credit deduction request") + }, + })?; + let collection_am = collections::ActiveModel { blockchain: Set(input.blockchain), supply: Set(Some(0)), @@ -77,6 +102,7 @@ impl Mutation { project_id: Set(input.project), created_by: Set(user_id), seller_fee_basis_points: Set(0), + credits_deduction_id: Set(Some(credits_deduction_id)), ..Default::default() }; @@ -123,16 +149,6 @@ impl Mutation { }, }; - submit_pending_deduction(credits, db, DeductionParams { - user_id, - org_id, - balance, - collection: collection.id, - blockchain: input.blockchain, - action: Actions::CreateCollection, - }) - .await?; - nfts_producer .send( Some(&NftEvents { @@ -159,23 +175,11 @@ impl Mutation { ctx: &Context<'_>, input: RetryCollectionInput, ) -> Result { - let AppContext { - db, - user_id, - organization_id, - balance, - .. - } = ctx.data::()?; + let AppContext { db, user_id, .. } = ctx.data::()?; let UserID(id) = user_id; - let OrganizationId(org) = organization_id; let conn = db.get(); let solana = ctx.data::()?; - let credits = ctx.data::>()?; 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-ORGANIZATION-BALANCE header not found"))?; let collection = Collections::find() .filter(collections::Column::Id.eq(input.id)) .one(db.get()) @@ -232,16 +236,6 @@ impl Mutation { }, }; - submit_pending_deduction(credits, db, DeductionParams { - balance, - user_id, - org_id, - collection: collection.id, - blockchain: collection.blockchain, - action: Actions::RetryCollection, - }) - .await?; - Ok(CreateCollectionPayload { collection: collection.into(), }) @@ -456,59 +450,6 @@ impl Mutation { } } -struct DeductionParams { - balance: u64, - user_id: Uuid, - org_id: Uuid, - collection: Uuid, - blockchain: BlockchainEnum, - action: Actions, -} - -async fn submit_pending_deduction( - credits: &CreditsClient, - db: &Connection, - params: DeductionParams, -) -> Result<()> { - let DeductionParams { - balance, - user_id, - org_id, - collection, - blockchain, - action, - } = params; - - let collection_model = Collections::find() - .filter(collections::Column::Id.eq(collection)) - .one(db.get()) - .await? - .ok_or(Error::new("drop not found"))?; - - if collection_model.credits_deduction_id.is_some() { - return Ok(()); - } - - let id = match blockchain { - BlockchainEnum::Solana => { - credits - .submit_pending_deduction(org_id, user_id, action, blockchain.into(), balance) - .await? - }, - BlockchainEnum::Ethereum | BlockchainEnum::Polygon => { - return Err(Error::new("blockchain not supported yet")); - }, - }; - - let deduction_id = id.ok_or(Error::new("Organization does not have enough credits"))?; - - let mut collection_am: collections::ActiveModel = collection_model.into(); - collection_am.credits_deduction_id = Set(Some(deduction_id.0)); - collection_am.update(db.get()).await?; - - Ok(()) -} - pub async fn fetch_owner( conn: &DatabaseConnection, project: Uuid, diff --git a/api/src/mutations/drop.rs b/api/src/mutations/drop.rs index 586c683..294f903 100644 --- a/api/src/mutations/drop.rs +++ b/api/src/mutations/drop.rs @@ -1,5 +1,9 @@ use async_graphql::{Context, Error, InputObject, Object, Result, SimpleObject}; -use hub_core::{chrono::Utc, credits::CreditsClient, producer::Producer}; +use hub_core::{ + chrono::Utc, + credits::{CreditsClient, DeductionErrorKind, TransactionId}, + producer::Producer, +}; use sea_orm::{prelude::*, JoinType, ModelTrait, QuerySelect, Set, TransactionTrait}; use serde::{Deserialize, Serialize}; @@ -7,7 +11,6 @@ use super::collection::{validate_creators, validate_json, validate_solana_creato use crate::{ blockchains::{polygon::Polygon, solana::Solana, DropEvent}, collection::Collection, - db::Connection, entities::{ collection_creators, collections, drops, metadata_jsons, prelude::{CollectionCreators, Collections, Drops, MetadataJsons}, @@ -20,7 +23,7 @@ use crate::{ self, nft_events::Event as NftEvent, CreationStatus as NftCreationStatus, EditionInfo, NftEventKey, NftEvents, }, - Actions, AppContext, NftStorageClient, OrganizationId, UserID, + Actions, AppContext, NftStorageClient, UserID, }; #[derive(Default)] @@ -67,6 +70,31 @@ impl Mutation { validate_solana_creator_verification(&owner_address, &input.creators)?; } + let TransactionId(credits_deduction_id) = credits + .submit_pending_deduction( + org_id, + user_id, + Actions::CreateDrop, + input.blockchain.into(), + balance, + ) + .await + .map_err(|e| match e.kind() { + DeductionErrorKind::InsufficientBalance { available, cost } => Error::new(format!( + "insufficient balance: available: {}, cost: {}", + available, cost + )), + DeductionErrorKind::MissingItem => Error::new(format!( + "{:?} is not supported by the blockchain {} at this time", + e.item(), + e.blockchain() + )), + DeductionErrorKind::InvalidCost(_) => Error::new("invalid cost"), + DeductionErrorKind::Send(_) => { + Error::new("unable to send credit deduction request") + }, + })?; + let seller_fee_basis_points = input.seller_fee_basis_points.unwrap_or_default(); let collection_am = collections::ActiveModel { @@ -76,6 +104,7 @@ impl Mutation { seller_fee_basis_points: Set(seller_fee_basis_points.try_into()?), created_by: Set(user_id), project_id: Set(input.project), + credits_deduction_id: Set(Some(credits_deduction_id)), ..Default::default() }; @@ -99,6 +128,7 @@ impl Mutation { price: Set(input.price.unwrap_or_default().try_into()?), created_by: Set(user_id), created_at: Set(Utc::now().into()), + credits_deduction_id: Set(Some(credits_deduction_id)), ..Default::default() }; @@ -157,16 +187,6 @@ impl Mutation { }, }; - submit_pending_deduction(credits, db, DeductionParams { - user_id, - org_id, - balance, - drop: drop_model.id, - blockchain: input.blockchain, - action: Actions::CreateDrop, - }) - .await?; - nfts_producer .send( Some(&NftEvents { @@ -199,27 +219,15 @@ impl Mutation { ctx: &Context<'_>, input: RetryDropInput, ) -> Result { - let AppContext { - db, - user_id, - organization_id, - balance, - .. - } = ctx.data::()?; + let AppContext { db, user_id, .. } = ctx.data::()?; let UserID(id) = user_id; - let OrganizationId(org) = organization_id; let conn = db.get(); let solana = ctx.data::()?; let polygon = ctx.data::()?; - let credits = ctx.data::>()?; 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-ORGANIZATION-BALANCE header not found"))?; let (drop, collection) = Drops::find_by_id(input.drop) .find_also_related(Collections) - .one(db.get()) + .one(conn) .await? .ok_or(Error::new("drop not found"))?; @@ -294,16 +302,6 @@ impl Mutation { drop_am.creation_status = Set(CreationStatus::Pending); let drop = drop_am.update(conn).await?; - submit_pending_deduction(credits, db, DeductionParams { - balance, - user_id, - org_id, - drop: drop.id, - blockchain: collection.blockchain, - action: Actions::RetryDrop, - }) - .await?; - Ok(CreateDropPayload { drop: Drop::new(drop, collection), }) @@ -608,68 +606,6 @@ impl Mutation { } } -struct DeductionParams { - balance: u64, - user_id: Uuid, - org_id: Uuid, - drop: Uuid, - blockchain: BlockchainEnum, - action: Actions, -} - -async fn submit_pending_deduction( - credits: &CreditsClient, - db: &Connection, - params: DeductionParams, -) -> Result<()> { - let DeductionParams { - balance, - user_id, - org_id, - drop, - blockchain, - action, - } = params; - let conn = db.get(); - - let (drop_model, collection) = Drops::find() - .join(JoinType::InnerJoin, drops::Relation::Collections.def()) - .select_also(Collections) - .filter(drops::Column::Id.eq(drop)) - .one(conn) - .await? - .ok_or(Error::new("drop not found"))?; - - let collection = collection.ok_or(Error::new("collection not found"))?; - - if drop_model.credits_deduction_id.is_some() { - return Ok(()); - } - - let id = match blockchain { - BlockchainEnum::Solana | BlockchainEnum::Polygon => { - credits - .submit_pending_deduction(org_id, user_id, action, blockchain.into(), balance) - .await? - }, - BlockchainEnum::Ethereum => { - return Err(Error::new("blockchain not supported yet")); - }, - }; - - let deduction_id = id.ok_or(Error::new("Organization does not have enough credits"))?; - - let mut drop: drops::ActiveModel = drop_model.into(); - let mut collection: collections::ActiveModel = collection.into(); - drop.credits_deduction_id = Set(Some(deduction_id.0)); - collection.credits_deduction_id = Set(Some(deduction_id.0)); - - collection.update(conn).await?; - drop.update(conn).await?; - - Ok(()) -} - async fn fetch_owner( conn: &DatabaseConnection, project: Uuid, diff --git a/api/src/mutations/mint.rs b/api/src/mutations/mint.rs index e689db2..63e2c4c 100644 --- a/api/src/mutations/mint.rs +++ b/api/src/mutations/mint.rs @@ -1,7 +1,11 @@ use std::ops::Add; use async_graphql::{Context, Error, InputObject, Object, Result, SimpleObject}; -use hub_core::{chrono::Utc, credits::CreditsClient, producer::Producer}; +use hub_core::{ + chrono::Utc, + credits::{CreditsClient, DeductionErrorKind, TransactionId}, + producer::Producer, +}; use sea_orm::{prelude::*, JoinType, QuerySelect, Set}; use super::collection::{ @@ -9,7 +13,6 @@ use super::collection::{ }; use crate::{ blockchains::{polygon::Polygon, solana::Solana, CollectionEvent, DropEvent}, - db::Connection, entities::{ collection_mints, collections, drops, mint_creators, mint_histories, prelude::{Collections, Drops}, @@ -97,6 +100,26 @@ impl Mutation { )))? .wallet_address; + let TransactionId(credits_deduction_id) = credits + .submit_pending_deduction( + org_id, + user_id, + Actions::MintEdition, + collection.blockchain.into(), + balance, + ) + .await + .map_err(|e| match e.kind() { + DeductionErrorKind::InsufficientBalance { available, cost } => Error::new(format!( + "insufficient balance: available: {available}, cost: {cost}" + )), + DeductionErrorKind::MissingItem => Error::new("action not supported at this time"), + DeductionErrorKind::InvalidCost(_) => Error::new("invalid cost"), + DeductionErrorKind::Send(_) => { + Error::new("unable to send credit deduction request") + }, + })?; + // insert a collection mint record into database let collection_mint_active_model = collection_mints::ActiveModel { collection_id: Set(collection.id), @@ -105,6 +128,7 @@ impl Mutation { seller_fee_basis_points: Set(collection.seller_fee_basis_points), created_by: Set(user_id), edition: Set(edition), + credits_deduction_id: Set(Some(credits_deduction_id)), ..Default::default() }; @@ -164,16 +188,6 @@ impl Mutation { purchase_am.insert(conn).await?; - submit_pending_deduction(credits, db, DeductionParams { - balance, - user_id, - org_id, - mint: collection_mint_model.id, - blockchain: collection.blockchain, - action: Actions::MintEdition, - }) - .await?; - nfts_producer .send( Some(&NftEvents { @@ -203,26 +217,13 @@ impl Mutation { ctx: &Context<'_>, input: RetryMintEditionInput, ) -> Result { - let AppContext { - db, - user_id, - organization_id, - balance, - .. - } = ctx.data::()?; - let credits = ctx.data::>()?; + let AppContext { db, user_id, .. } = ctx.data::()?; let conn = db.get(); let solana = ctx.data::()?; let polygon = 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-ORGANIZATION-BALANCE header not found"))?; let (collection_mint_model, drop) = collection_mints::Entity::find() .join( @@ -306,16 +307,6 @@ impl Mutation { mint_am.creation_status = Set(CreationStatus::Pending); let collection_mint_model = mint_am.update(conn).await?; - submit_pending_deduction(credits, db, DeductionParams { - balance, - user_id, - org_id, - mint: collection_mint_model.id, - blockchain: collection.blockchain, - action: Actions::RetryMint, - }) - .await?; - Ok(RetryMintEditionPayload { collection_mint: collection_mint_model.into(), }) @@ -374,6 +365,33 @@ impl Mutation { validate_solana_creator_verification(&owner_address, &creators)?; } + let action = if compressed { + Actions::MintCompressed + } else { + Actions::Mint + }; + + let TransactionId(credits_deduction_id) = credits + .submit_pending_deduction( + org_id, + user_id, + action, + collection.blockchain.into(), + balance, + ) + .await + .map_err(|e| match e.kind() { + DeductionErrorKind::InsufficientBalance { available, cost } => Error::new(format!( + "insufficient balance: available: {}, cost: {}", + available, cost + )), + DeductionErrorKind::MissingItem => Error::new("action not supported at this time"), + DeductionErrorKind::InvalidCost(_) => Error::new("invalid cost"), + DeductionErrorKind::Send(_) => { + Error::new("unable to send credit deduction request") + }, + })?; + // insert a collection mint record into database let collection_mint_active_model = collection_mints::ActiveModel { collection_id: Set(collection.id), @@ -382,6 +400,7 @@ impl Mutation { seller_fee_basis_points: Set(collection.seller_fee_basis_points), created_by: Set(user_id), compressed: Set(compressed), + credits_deduction_id: Set(Some(credits_deduction_id)), ..Default::default() }; @@ -453,20 +472,6 @@ impl Mutation { mint_history_am.insert(conn).await?; - submit_pending_deduction(credits, db, DeductionParams { - balance, - user_id, - org_id, - mint: collection_mint_model.id, - blockchain: collection.blockchain, - action: if compressed { - Actions::MintCompressed - } else { - Actions::Mint - }, - }) - .await?; - nfts_producer .send( Some(&NftEvents { @@ -494,25 +499,13 @@ impl Mutation { ctx: &Context<'_>, input: RetryMintEditionInput, ) -> Result { - let AppContext { - db, - user_id, - organization_id, - balance, - .. - } = ctx.data::()?; - let credits = ctx.data::>()?; + let AppContext { db, user_id, .. } = ctx.data::()?; let conn = db.get(); let solana = 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-ORGANIZATION-BALANCE header not found"))?; let (collection_mint_model, collection) = collection_mints::Entity::find_by_id_with_collection(input.id) @@ -572,73 +565,12 @@ impl Mutation { }, }; - submit_pending_deduction(credits, db, DeductionParams { - balance, - user_id, - org_id, - mint: collection_mint_model.id, - blockchain: collection.blockchain, - action: Actions::RetryMint, - }) - .await?; - Ok(RetryMintEditionPayload { collection_mint: collection_mint_model.into(), }) } } -struct DeductionParams { - balance: u64, - user_id: Uuid, - org_id: Uuid, - mint: Uuid, - blockchain: BlockchainEnum, - action: Actions, -} -async fn submit_pending_deduction( - credits: &CreditsClient, - db: &Connection, - params: DeductionParams, -) -> Result<()> { - let DeductionParams { - balance, - user_id, - org_id, - mint, - blockchain, - action, - } = params; - - let mint_model = collection_mints::Entity::find_by_id(mint) - .one(db.get()) - .await? - .ok_or(Error::new("drop not found"))?; - - if mint_model.credits_deduction_id.is_some() { - return Ok(()); - } - - let id = match blockchain { - BlockchainEnum::Solana | BlockchainEnum::Polygon => { - credits - .submit_pending_deduction(org_id, user_id, action, blockchain.into(), balance) - .await? - }, - BlockchainEnum::Ethereum => { - return Err(Error::new("blockchain not supported yet")); - }, - }; - - let deduction_id = id.ok_or(Error::new("Organization does not have enough credits"))?; - - let mut mint: collection_mints::ActiveModel = mint_model.into(); - mint.credits_deduction_id = Set(Some(deduction_id.0)); - mint.update(db.get()).await?; - - Ok(()) -} - fn validate_compress(blockchain: BlockchainEnum, compressed: bool) -> Result<(), Error> { if blockchain != BlockchainEnum::Solana && compressed { return Err(Error::new("compression is only supported on Solana")); diff --git a/api/src/mutations/transfer.rs b/api/src/mutations/transfer.rs index 949c22b..138db2a 100644 --- a/api/src/mutations/transfer.rs +++ b/api/src/mutations/transfer.rs @@ -1,12 +1,11 @@ use async_graphql::{Context, Error, InputObject, Object, Result, SimpleObject}; -use hub_core::credits::CreditsClient; +use hub_core::credits::{CreditsClient, DeductionErrorKind, TransactionId}; use sea_orm::{prelude::*, Set}; use serde::{Deserialize, Serialize}; use super::collection::{validate_evm_address, validate_solana_address}; use crate::{ blockchains::{polygon::Polygon, solana::Solana, TransferEvent}, - db::Connection, entities::{ collection_mints::{self, CollectionMint}, prelude::CustomerWallets, @@ -71,7 +70,28 @@ impl Mutation { .await? .ok_or(Error::new("Sender wallet is not managed by HUB"))?; + let TransactionId(credits_deduction_id) = credits + .submit_pending_deduction( + org_id, + user_id, + Actions::TransferAsset, + collection.blockchain.into(), + balance, + ) + .await + .map_err(|e| match e.kind() { + DeductionErrorKind::InsufficientBalance { available, cost } => Error::new(format!( + "insufficient balance: available: {available}, cost: {cost}" + )), + DeductionErrorKind::MissingItem => Error::new("action not supported at this time"), + DeductionErrorKind::InvalidCost(_) => Error::new("invalid cost"), + DeductionErrorKind::Send(_) => { + Error::new("unable to send credit deduction request") + }, + })?; + let transfer_charges_am = transfer_charges::ActiveModel { + credits_deduction_id: Set(Some(credits_deduction_id)), ..Default::default() }; @@ -115,64 +135,12 @@ impl Mutation { }, }; - submit_pending_deduction( - credits, - db, - balance, - org_id, - user_id, - transfer_charge_model.id, - collection.blockchain, - ) - .await?; - Ok(TransferAssetPayload { mint: collection_mint_model.into(), }) } } -async fn submit_pending_deduction( - credits: &CreditsClient, - db: &Connection, - balance: u64, - org_id: Uuid, - user_id: Uuid, - transfer_id: Uuid, - blockchain: Blockchain, -) -> Result<()> { - let id = match blockchain { - Blockchain::Solana | Blockchain::Polygon => { - credits - .submit_pending_deduction( - org_id, - user_id, - Actions::TransferAsset, - blockchain.into(), - balance, - ) - .await? - }, - Blockchain::Ethereum => { - return Err(Error::new("blockchain not supported yet")); - }, - }; - - let deduction_id = id.ok_or(Error::new("Organization does not have enough credits"))?; - - let transfer_charge_model = transfer_charges::Entity::find() - .filter(transfer_charges::Column::Id.eq(transfer_id)) - .one(db.get()) - .await? - .ok_or(Error::new("transfer charge not found"))?; - - let mut transfer_charge: transfer_charges::ActiveModel = transfer_charge_model.into(); - transfer_charge.credits_deduction_id = Set(Some(deduction_id.0)); - transfer_charge.update(db.get()).await?; - - Ok(()) -} - #[derive(Debug, Clone, Serialize, Deserialize, InputObject)] pub struct TransferAssetInput { pub id: Uuid, From 11dea01e34776c0a9c39be4f64bb0fca7b38e485 Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Wed, 9 Aug 2023 19:02:30 +0500 Subject: [PATCH 07/28] Update histories field for collection mint --- api/src/dataloaders/mod.rs | 2 ++ api/src/dataloaders/update_histories.rs | 45 +++++++++++++++++++++++++ api/src/entities/collection_mints.rs | 14 ++++++++ api/src/entities/update_histories.rs | 5 +-- api/src/lib.rs | 6 +++- 5 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 api/src/dataloaders/update_histories.rs diff --git a/api/src/dataloaders/mod.rs b/api/src/dataloaders/mod.rs index bd73092..f53329b 100644 --- a/api/src/dataloaders/mod.rs +++ b/api/src/dataloaders/mod.rs @@ -9,6 +9,7 @@ mod metadata_json; mod mint_histories; mod project_collection; mod project_collections; +mod update_histories; pub use collection::Loader as CollectionLoader; pub use collection_drop::Loader as CollectionDropLoader; @@ -28,3 +29,4 @@ pub use mint_histories::{ }; pub use project_collection::ProjectCollectionLoader; pub use project_collections::ProjectCollectionsLoader; +pub use update_histories::UpdateMintHistoryLoader; diff --git a/api/src/dataloaders/update_histories.rs b/api/src/dataloaders/update_histories.rs new file mode 100644 index 0000000..aa0e458 --- /dev/null +++ b/api/src/dataloaders/update_histories.rs @@ -0,0 +1,45 @@ +use std::collections::HashMap; + +use async_graphql::{dataloader::Loader as DataLoader, FieldError, Result}; +use poem::async_trait; +use sea_orm::{prelude::*, Order, QueryOrder}; + +use crate::{db::Connection, entities::update_histories}; + +#[derive(Debug, Clone)] +pub struct UpdateMintHistoryLoader { + pub db: Connection, +} + +impl UpdateMintHistoryLoader { + #[must_use] + pub fn new(db: Connection) -> Self { + Self { db } + } +} + +#[async_trait] +impl DataLoader for UpdateMintHistoryLoader { + type Error = FieldError; + type Value = Vec; + + async fn load(&self, keys: &[Uuid]) -> Result, Self::Error> { + let conn = self.db.get(); + let update_histories = update_histories::Entity::find() + .filter(update_histories::Column::MintId.is_in(keys.iter().map(ToOwned::to_owned))) + .order_by(update_histories::Column::CreatedAt, Order::Desc) + .all(conn) + .await?; + + Ok(update_histories + .into_iter() + .fold(HashMap::new(), |mut acc, history| { + acc.entry(history.mint_id).or_insert_with(Vec::new); + + acc.entry(history.mint_id) + .and_modify(|update_histories| update_histories.push(history.into())); + + acc + })) + } +} diff --git a/api/src/entities/collection_mints.rs b/api/src/entities/collection_mints.rs index dd7445d..c96a417 100644 --- a/api/src/entities/collection_mints.rs +++ b/api/src/entities/collection_mints.rs @@ -6,6 +6,7 @@ use sea_orm::{entity::prelude::*, JoinType, QuerySelect, SelectTwo}; use super::{ collections, sea_orm_active_enums::{Blockchain, CreationStatus}, + update_histories, }; use crate::{ objects::{Collection, MetadataJson}, @@ -94,6 +95,19 @@ impl CollectionMint { Blockchain::Ethereum => Err(Error::new("Ethereum not supported")), } } + + /// The update history of the mint. + async fn update_histories( + &self, + ctx: &Context<'_>, + ) -> Result>> { + let AppContext { + update_mint_history_loader, + .. + } = ctx.data::()?; + + update_mint_history_loader.load_one(self.id).await + } } impl From for CollectionMint { diff --git a/api/src/entities/update_histories.rs b/api/src/entities/update_histories.rs index 6fcd682..b0f8cea 100644 --- a/api/src/entities/update_histories.rs +++ b/api/src/entities/update_histories.rs @@ -1,11 +1,12 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3 - +use async_graphql::{Result, SimpleObject}; use sea_orm::entity::prelude::*; use super::sea_orm_active_enums::CreationStatus; -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, SimpleObject)] #[sea_orm(table_name = "update_histories")] +#[graphql(concrete(name = "UpdateHistory", params()))] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: Uuid, diff --git a/api/src/lib.rs b/api/src/lib.rs index c2dc845..3020a60 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -26,6 +26,7 @@ use dataloaders::{ CollectionMintsLoader, CollectionMintsOwnerLoader, CreatorsLoader, DropLoader, DropMintHistoryLoader, HoldersLoader, MetadataJsonAttributesLoader, MetadataJsonLoader, MinterMintHistoryLoader, ProjectCollectionLoader, ProjectCollectionsLoader, ProjectDropsLoader, + UpdateMintHistoryLoader, }; use db::Connection; use hub_core::{ @@ -281,6 +282,7 @@ pub struct AppContext { collection_mint_history_loader: DataLoader, drop_mint_history_loader: DataLoader, minter_mint_history_loader: DataLoader, + update_mint_history_loader: DataLoader, } impl AppContext { @@ -319,7 +321,8 @@ impl AppContext { DataLoader::new(CollectionMintLoader::new(db.clone()), tokio::spawn); let minter_mint_history_loader = DataLoader::new(MinterMintHistoryLoader::new(db.clone()), tokio::spawn); - + let update_mint_history_loader = + DataLoader::new(UpdateMintHistoryLoader::new(db.clone()), tokio::spawn); Self { db, user_id, @@ -341,6 +344,7 @@ impl AppContext { collection_mint_history_loader, drop_mint_history_loader, minter_mint_history_loader, + update_mint_history_loader, } } } From dca078cd04fb4a6545f7afd15f4c2c3accf52a50 Mon Sep 17 00:00:00 2001 From: Kyle Espinola Date: Wed, 9 Aug 2023 16:09:24 +0200 Subject: [PATCH 08/28] refactor: add back sending credit line item for retry actions --- api/src/mutations/collection.rs | 43 ++++++++++++++++++-- api/src/mutations/drop.rs | 43 ++++++++++++++++++-- api/src/mutations/mint.rs | 69 ++++++++++++++++++++++++++++++++- 3 files changed, 145 insertions(+), 10 deletions(-) diff --git a/api/src/mutations/collection.rs b/api/src/mutations/collection.rs index 6be647b..2992479 100644 --- a/api/src/mutations/collection.rs +++ b/api/src/mutations/collection.rs @@ -26,7 +26,7 @@ use crate::{ CreationStatus as NftCreationStatus, Creator as ProtoCreator, MasterEdition, MetaplexMasterEditionTransaction, NftEventKey, NftEvents, }, - Actions, AppContext, NftStorageClient, UserID, + Actions, AppContext, NftStorageClient, }; #[derive(Default)] @@ -175,11 +175,26 @@ impl Mutation { ctx: &Context<'_>, input: RetryCollectionInput, ) -> Result { - let AppContext { db, user_id, .. } = ctx.data::()?; - let UserID(id) = user_id; + let AppContext { + db, + user_id, + organization_id, + balance, + .. + } = ctx.data::()?; + + let user_id = user_id.0.ok_or(Error::new("X-USER-ID header not found"))?; + let org_id = organization_id + .0 + .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 conn = db.get(); + let credits = ctx.data::>()?; let solana = ctx.data::()?; - let user_id = id.ok_or(Error::new("X-USER-ID header not found"))?; + let collection = Collections::find() .filter(collections::Column::Id.eq(input.id)) .one(db.get()) @@ -201,6 +216,26 @@ impl Mutation { let owner_address = fetch_owner(conn, collection.project_id, collection.blockchain).await?; + let TransactionId(_) = credits + .submit_pending_deduction( + org_id, + user_id, + Actions::RetryCollection, + collection.blockchain.into(), + balance, + ) + .await + .map_err(|e| match e.kind() { + DeductionErrorKind::InsufficientBalance { available, cost } => Error::new(format!( + "insufficient balance: available: {available}, cost: {cost}" + )), + DeductionErrorKind::MissingItem => Error::new("action not supported at this time"), + DeductionErrorKind::InvalidCost(_) => Error::new("invalid cost"), + DeductionErrorKind::Send(_) => { + Error::new("unable to send credit deduction request") + }, + })?; + let event_key = NftEventKey { id: collection.id.to_string(), user_id: user_id.to_string(), diff --git a/api/src/mutations/drop.rs b/api/src/mutations/drop.rs index 294f903..ac94b75 100644 --- a/api/src/mutations/drop.rs +++ b/api/src/mutations/drop.rs @@ -23,7 +23,7 @@ use crate::{ self, nft_events::Event as NftEvent, CreationStatus as NftCreationStatus, EditionInfo, NftEventKey, NftEvents, }, - Actions, AppContext, NftStorageClient, UserID, + Actions, AppContext, NftStorageClient, }; #[derive(Default)] @@ -219,12 +219,27 @@ impl Mutation { ctx: &Context<'_>, input: RetryDropInput, ) -> Result { - let AppContext { db, user_id, .. } = ctx.data::()?; - let UserID(id) = user_id; + let AppContext { + db, + user_id, + organization_id, + balance, + .. + } = ctx.data::()?; + + let user_id = user_id.0.ok_or(Error::new("X-USER-ID header not found"))?; + let org_id = organization_id + .0 + .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 conn = db.get(); + let credits = ctx.data::>()?; let solana = ctx.data::()?; let polygon = ctx.data::()?; - let user_id = id.ok_or(Error::new("X-USER-ID header not found"))?; + let (drop, collection) = Drops::find_by_id(input.drop) .find_also_related(Collections) .one(conn) @@ -248,6 +263,26 @@ impl Mutation { let owner_address = fetch_owner(conn, drop.project_id, collection.blockchain).await?; + let TransactionId(_) = credits + .submit_pending_deduction( + org_id, + user_id, + Actions::RetryDrop, + collection.blockchain.into(), + balance, + ) + .await + .map_err(|e| match e.kind() { + DeductionErrorKind::InsufficientBalance { available, cost } => Error::new(format!( + "insufficient balance: available: {available}, cost: {cost}" + )), + DeductionErrorKind::MissingItem => Error::new("action not supported at this time"), + DeductionErrorKind::InvalidCost(_) => Error::new("invalid cost"), + DeductionErrorKind::Send(_) => { + Error::new("unable to send credit deduction request") + }, + })?; + let event_key = NftEventKey { id: collection.id.to_string(), user_id: user_id.to_string(), diff --git a/api/src/mutations/mint.rs b/api/src/mutations/mint.rs index 63e2c4c..e394c84 100644 --- a/api/src/mutations/mint.rs +++ b/api/src/mutations/mint.rs @@ -217,13 +217,26 @@ impl Mutation { ctx: &Context<'_>, input: RetryMintEditionInput, ) -> Result { - let AppContext { db, user_id, .. } = ctx.data::()?; + let AppContext { + db, + user_id, + organization_id, + balance, + .. + } = ctx.data::()?; + let credits = ctx.data::>()?; let conn = db.get(); let solana = ctx.data::()?; let polygon = 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 (collection_mint_model, drop) = collection_mints::Entity::find() .join( @@ -270,6 +283,26 @@ impl Mutation { )))? .wallet_address; + let TransactionId(_) = credits + .submit_pending_deduction( + org_id, + user_id, + Actions::RetryMint, + collection.blockchain.into(), + balance, + ) + .await + .map_err(|e| match e.kind() { + DeductionErrorKind::InsufficientBalance { available, cost } => Error::new(format!( + "insufficient balance: available: {available}, cost: {cost}" + )), + DeductionErrorKind::MissingItem => Error::new("action not supported at this time"), + DeductionErrorKind::InvalidCost(_) => Error::new("invalid cost"), + DeductionErrorKind::Send(_) => { + Error::new("unable to send credit deduction request") + }, + })?; + let event_key = NftEventKey { id: collection_mint_model.id.to_string(), user_id: user_id.to_string(), @@ -499,13 +532,25 @@ impl Mutation { ctx: &Context<'_>, input: RetryMintEditionInput, ) -> Result { - let AppContext { db, user_id, .. } = ctx.data::()?; + let AppContext { + db, + user_id, + organization_id, + balance, + .. + } = ctx.data::()?; + let credits = ctx.data::>()?; let conn = db.get(); let solana = 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 (collection_mint_model, collection) = collection_mints::Entity::find_by_id_with_collection(input.id) @@ -539,6 +584,26 @@ impl Mutation { .all(conn) .await?; + let TransactionId(_) = credits + .submit_pending_deduction( + org_id, + user_id, + Actions::RetryMint, + collection.blockchain.into(), + balance, + ) + .await + .map_err(|e| match e.kind() { + DeductionErrorKind::InsufficientBalance { available, cost } => Error::new(format!( + "insufficient balance: available: {available}, cost: {cost}" + )), + DeductionErrorKind::MissingItem => Error::new("action not supported at this time"), + DeductionErrorKind::InvalidCost(_) => Error::new("invalid cost"), + DeductionErrorKind::Send(_) => { + Error::new("unable to send credit deduction request") + }, + })?; + match collection.blockchain { BlockchainEnum::Solana => { solana From 52276337a8523c7a11c2d5b9c5b1f58eea478ed3 Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Wed, 9 Aug 2023 19:10:05 +0500 Subject: [PATCH 09/28] Update rust toolchain to 1.71.0 --- .github/workflows/apollo_release.yml | 2 +- .github/workflows/cargo.yml | 2 +- .github/workflows/cargo_test.yml | 2 +- Dockerfile | 2 +- rust-toolchain.toml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/apollo_release.yml b/.github/workflows/apollo_release.yml index b12ec14..114f99c 100644 --- a/.github/workflows/apollo_release.yml +++ b/.github/workflows/apollo_release.yml @@ -38,7 +38,7 @@ jobs: - uses: actions-rs/toolchain@v1 with: - toolchain: 1.69.0 + toolchain: 1.71.0 override: true components: cargo, rustc diff --git a/.github/workflows/cargo.yml b/.github/workflows/cargo.yml index c81a6c9..b70bd85 100644 --- a/.github/workflows/cargo.yml +++ b/.github/workflows/cargo.yml @@ -38,7 +38,7 @@ jobs: - name: Install latest nightly uses: actions-rs/toolchain@v1 with: - toolchain: 1.69.0 + toolchain: 1.71.0 override: true components: rustfmt, clippy diff --git a/.github/workflows/cargo_test.yml b/.github/workflows/cargo_test.yml index 8b41a8b..7e72828 100644 --- a/.github/workflows/cargo_test.yml +++ b/.github/workflows/cargo_test.yml @@ -49,7 +49,7 @@ jobs: - uses: actions-rs/toolchain@v1 with: - toolchain: 1.69.0 + toolchain: 1.71.0 override: true components: cargo, rustc diff --git a/Dockerfile b/Dockerfile index b074c58..03947df 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.69.0-bullseye as chef +FROM rust:1.71.0-bullseye as chef RUN cargo install cargo-chef --locked WORKDIR /app diff --git a/rust-toolchain.toml b/rust-toolchain.toml index f5dd4b4..db8508b 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.69.0" +channel = "1.71.0" components = [ "cargo", "clippy", From 3d7abeff6f1f274b5041a066171a57ac20b72ad5 Mon Sep 17 00:00:00 2001 From: Kyle Espinola Date: Wed, 9 Aug 2023 20:27:08 +0200 Subject: [PATCH 10/28] refactor: update to hub-core 0.4.1 to eliminate map_err --- Cargo.lock | 8 +++--- api/Cargo.toml | 2 +- api/src/mutations/collection.rs | 28 ++----------------- api/src/mutations/drop.rs | 29 ++----------------- api/src/mutations/mint.rs | 49 +++------------------------------ api/src/mutations/transfer.rs | 12 +------- 6 files changed, 14 insertions(+), 114 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ebd9ace..f074b66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1635,8 +1635,8 @@ dependencies = [ [[package]] name = "holaplex-hub-core" -version = "0.4.0" -source = "git+https://github.com/holaplex/hub-core?branch=stable#97576b2a5ec65446b8c416c64d190a309f4d269b" +version = "0.4.1" +source = "git+https://github.com/holaplex/hub-core?branch=stable#b4980ed55425e025945ca9960a33e7062a75ab06" dependencies = [ "anyhow", "async-trait", @@ -1670,7 +1670,7 @@ dependencies = [ [[package]] name = "holaplex-hub-core-build" version = "0.2.1" -source = "git+https://github.com/holaplex/hub-core?branch=stable#97576b2a5ec65446b8c416c64d190a309f4d269b" +source = "git+https://github.com/holaplex/hub-core?branch=stable#b4980ed55425e025945ca9960a33e7062a75ab06" dependencies = [ "anyhow", "dotenv", @@ -1689,7 +1689,7 @@ dependencies = [ [[package]] name = "holaplex-hub-core-schemas" version = "0.3.1" -source = "git+https://github.com/holaplex/hub-core?branch=stable#97576b2a5ec65446b8c416c64d190a309f4d269b" +source = "git+https://github.com/holaplex/hub-core?branch=stable#b4980ed55425e025945ca9960a33e7062a75ab06" dependencies = [ "holaplex-hub-core-build", "prost", diff --git a/api/Cargo.toml b/api/Cargo.toml index 3ff2b6b..348e4f0 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -42,7 +42,7 @@ strum = { version = "0.24.1", features = ["derive"] } [dependencies.hub-core] package = "holaplex-hub-core" -version = "0.4.0" +version = "0.4.1" git = "https://github.com/holaplex/hub-core" branch = "stable" features = ["kafka", "credits", "asset_proxy"] diff --git a/api/src/mutations/collection.rs b/api/src/mutations/collection.rs index 2992479..e4d302f 100644 --- a/api/src/mutations/collection.rs +++ b/api/src/mutations/collection.rs @@ -79,21 +79,7 @@ impl Mutation { input.blockchain.into(), balance, ) - .await - .map_err(|e| match e.kind() { - DeductionErrorKind::InsufficientBalance { available, cost } => Error::new(format!( - "insufficient balance: available: {available}, cost: {cost}" - )), - DeductionErrorKind::MissingItem => Error::new(format!( - "{:?} is not supported by the blockchain {} at this time", - e.item(), - e.blockchain() - )), - DeductionErrorKind::InvalidCost(_) => Error::new("invalid cost"), - DeductionErrorKind::Send(_) => { - Error::new("unable to send credit deduction request") - }, - })?; + .await?; let collection_am = collections::ActiveModel { blockchain: Set(input.blockchain), @@ -224,17 +210,7 @@ impl Mutation { collection.blockchain.into(), balance, ) - .await - .map_err(|e| match e.kind() { - DeductionErrorKind::InsufficientBalance { available, cost } => Error::new(format!( - "insufficient balance: available: {available}, cost: {cost}" - )), - DeductionErrorKind::MissingItem => Error::new("action not supported at this time"), - DeductionErrorKind::InvalidCost(_) => Error::new("invalid cost"), - DeductionErrorKind::Send(_) => { - Error::new("unable to send credit deduction request") - }, - })?; + .await?; let event_key = NftEventKey { id: collection.id.to_string(), diff --git a/api/src/mutations/drop.rs b/api/src/mutations/drop.rs index ac94b75..a99e5f0 100644 --- a/api/src/mutations/drop.rs +++ b/api/src/mutations/drop.rs @@ -78,22 +78,7 @@ impl Mutation { input.blockchain.into(), balance, ) - .await - .map_err(|e| match e.kind() { - DeductionErrorKind::InsufficientBalance { available, cost } => Error::new(format!( - "insufficient balance: available: {}, cost: {}", - available, cost - )), - DeductionErrorKind::MissingItem => Error::new(format!( - "{:?} is not supported by the blockchain {} at this time", - e.item(), - e.blockchain() - )), - DeductionErrorKind::InvalidCost(_) => Error::new("invalid cost"), - DeductionErrorKind::Send(_) => { - Error::new("unable to send credit deduction request") - }, - })?; + .await?; let seller_fee_basis_points = input.seller_fee_basis_points.unwrap_or_default(); @@ -271,17 +256,7 @@ impl Mutation { collection.blockchain.into(), balance, ) - .await - .map_err(|e| match e.kind() { - DeductionErrorKind::InsufficientBalance { available, cost } => Error::new(format!( - "insufficient balance: available: {available}, cost: {cost}" - )), - DeductionErrorKind::MissingItem => Error::new("action not supported at this time"), - DeductionErrorKind::InvalidCost(_) => Error::new("invalid cost"), - DeductionErrorKind::Send(_) => { - Error::new("unable to send credit deduction request") - }, - })?; + .await?; let event_key = NftEventKey { id: collection.id.to_string(), diff --git a/api/src/mutations/mint.rs b/api/src/mutations/mint.rs index e394c84..a237e9e 100644 --- a/api/src/mutations/mint.rs +++ b/api/src/mutations/mint.rs @@ -108,17 +108,7 @@ impl Mutation { collection.blockchain.into(), balance, ) - .await - .map_err(|e| match e.kind() { - DeductionErrorKind::InsufficientBalance { available, cost } => Error::new(format!( - "insufficient balance: available: {available}, cost: {cost}" - )), - DeductionErrorKind::MissingItem => Error::new("action not supported at this time"), - DeductionErrorKind::InvalidCost(_) => Error::new("invalid cost"), - DeductionErrorKind::Send(_) => { - Error::new("unable to send credit deduction request") - }, - })?; + .await?; // insert a collection mint record into database let collection_mint_active_model = collection_mints::ActiveModel { @@ -291,17 +281,7 @@ impl Mutation { collection.blockchain.into(), balance, ) - .await - .map_err(|e| match e.kind() { - DeductionErrorKind::InsufficientBalance { available, cost } => Error::new(format!( - "insufficient balance: available: {available}, cost: {cost}" - )), - DeductionErrorKind::MissingItem => Error::new("action not supported at this time"), - DeductionErrorKind::InvalidCost(_) => Error::new("invalid cost"), - DeductionErrorKind::Send(_) => { - Error::new("unable to send credit deduction request") - }, - })?; + .await?; let event_key = NftEventKey { id: collection_mint_model.id.to_string(), @@ -412,18 +392,7 @@ impl Mutation { collection.blockchain.into(), balance, ) - .await - .map_err(|e| match e.kind() { - DeductionErrorKind::InsufficientBalance { available, cost } => Error::new(format!( - "insufficient balance: available: {}, cost: {}", - available, cost - )), - DeductionErrorKind::MissingItem => Error::new("action not supported at this time"), - DeductionErrorKind::InvalidCost(_) => Error::new("invalid cost"), - DeductionErrorKind::Send(_) => { - Error::new("unable to send credit deduction request") - }, - })?; + .await?; // insert a collection mint record into database let collection_mint_active_model = collection_mints::ActiveModel { @@ -592,17 +561,7 @@ impl Mutation { collection.blockchain.into(), balance, ) - .await - .map_err(|e| match e.kind() { - DeductionErrorKind::InsufficientBalance { available, cost } => Error::new(format!( - "insufficient balance: available: {available}, cost: {cost}" - )), - DeductionErrorKind::MissingItem => Error::new("action not supported at this time"), - DeductionErrorKind::InvalidCost(_) => Error::new("invalid cost"), - DeductionErrorKind::Send(_) => { - Error::new("unable to send credit deduction request") - }, - })?; + .await?; match collection.blockchain { BlockchainEnum::Solana => { diff --git a/api/src/mutations/transfer.rs b/api/src/mutations/transfer.rs index 138db2a..b08d15c 100644 --- a/api/src/mutations/transfer.rs +++ b/api/src/mutations/transfer.rs @@ -78,17 +78,7 @@ impl Mutation { collection.blockchain.into(), balance, ) - .await - .map_err(|e| match e.kind() { - DeductionErrorKind::InsufficientBalance { available, cost } => Error::new(format!( - "insufficient balance: available: {available}, cost: {cost}" - )), - DeductionErrorKind::MissingItem => Error::new("action not supported at this time"), - DeductionErrorKind::InvalidCost(_) => Error::new("invalid cost"), - DeductionErrorKind::Send(_) => { - Error::new("unable to send credit deduction request") - }, - })?; + .await?; let transfer_charges_am = transfer_charges::ActiveModel { credits_deduction_id: Set(Some(credits_deduction_id)), From 004d3c19501379c76fb90e50df90aadaa1b9fd57 Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Thu, 10 Aug 2023 17:14:23 +0500 Subject: [PATCH 11/28] Emit SolanaMintUpdated event --- api/proto.lock | 4 ++-- api/proto.toml | 2 +- api/src/events.rs | 32 ++++++++++++++++++++++++++++---- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/api/proto.lock b/api/proto.lock index 355201e..2246705 100644 --- a/api/proto.lock +++ b/api/proto.lock @@ -5,8 +5,8 @@ sha512 = "d75800df0d4744c6b0f4d9a9952d3bfd0bb6b24a8babd19104cc11b54a525f85551b3c [[schemas]] subject = "nfts" -version = 25 -sha512 = "90dadff6bc75b59bb79d9ed2a65d582923f9ce66b5915c020306571bb446d68ff6648543386838510a60081d7cbb14f43fa2ae22c4c8ecd85874bee4323dd26a" +version = 26 +sha512 = "8191626dbd6e222f24914589a77855e5f0f5122b7adc655ef7e84af0d9ef104715408db97cdf7843882aaa65cfcacc436a01e01b336f6758b0863ec5e007b709" [[schemas]] subject = "organization" diff --git a/api/proto.toml b/api/proto.toml index 151c09b..7a0b3f9 100644 --- a/api/proto.toml +++ b/api/proto.toml @@ -3,7 +3,7 @@ endpoint = "https://schemas.holaplex.tools" [schemas] organization = 5 -nfts = 25 +nfts = 26 customer = 2 treasury = 21 solana_nfts = 9 diff --git a/api/src/events.rs b/api/src/events.rs index 18d44c9..720d034 100644 --- a/api/src/events.rs +++ b/api/src/events.rs @@ -33,7 +33,8 @@ use crate::{ Attribute, CreationStatus as NftCreationStatus, DropCreation, File, Metadata, MintCollectionCreation, MintCreation, MintOwnershipUpdate, MintedTokensOwnershipUpdate, NftEventKey, NftEvents, SolanaCollectionPayload, SolanaCompletedMintTransaction, - SolanaCompletedTransferTransaction, SolanaMintPayload, SolanaNftEventKey, TreasuryEventKey, + SolanaCompletedTransferTransaction, SolanaMintPayload, SolanaNftEventKey, + SolanaUpdatedMintPayload, TreasuryEventKey, }, Actions, Services, }; @@ -145,7 +146,7 @@ impl Processor { SolanaNftsEvent::UpdateCollectionMintSubmitted(payload) | SolanaNftsEvent::RetryUpdateMintSubmitted(payload), ) => { - self.mint_updated(id, UpdateResult::Success(payload.signature)) + self.mint_updated(id, project_id, UpdateResult::Success(payload.signature)) .await }, Some(SolanaNftsEvent::TransferAssetSubmitted( @@ -178,7 +179,10 @@ impl Processor { Some( SolanaNftsEvent::UpdateCollectionMintFailed(_) | SolanaNftsEvent::RetryUpdateMintFailed(_), - ) => self.mint_updated(id, UpdateResult::Failure).await, + ) => { + self.mint_updated(id, project_id, UpdateResult::Failure) + .await + }, Some(SolanaNftsEvent::UpdateMintOwner(e)) => self.update_mint_owner(id, e).await, Some(SolanaNftsEvent::ImportedExternalCollection(e)) => { self.index_collection(id, project_id, user_id, e).await @@ -749,7 +753,12 @@ impl Processor { Ok(()) } - async fn mint_updated(&self, id: String, payload: UpdateResult) -> Result<()> { + async fn mint_updated( + &self, + id: String, + project_id: String, + payload: UpdateResult, + ) -> Result<()> { let update_history = UpdateHistories::find_by_id(id.parse()?) .one(self.db.get()) .await? @@ -763,6 +772,21 @@ impl Processor { self.credits .confirm_deduction(TransactionId(update_history.credit_deduction_id)) .await?; + + self.producer + .send( + Some(&NftEvents { + event: Some(NftEvent::SolanaMintUpdated(SolanaUpdatedMintPayload { + mint_id: update_history.mint_id.to_string(), + })), + }), + Some(&NftEventKey { + id, + project_id, + user_id: update_history.created_by.to_string(), + }), + ) + .await?; } else { update_history_am.status = Set(CreationStatus::Failed); } From 0fb8458b438969cf3696f46af6eff07c5c4c50ae Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Fri, 11 Aug 2023 05:26:07 +0500 Subject: [PATCH 12/28] rename Update Mint input mint field to id --- api/src/mutations/mint.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/api/src/mutations/mint.rs b/api/src/mutations/mint.rs index 19f5890..92e3399 100644 --- a/api/src/mutations/mint.rs +++ b/api/src/mutations/mint.rs @@ -526,7 +526,7 @@ impl Mutation { let (mint, collection) = CollectionMints::find() .find_also_related(Collections) - .filter(collection_mints::Column::Id.eq(input.mint)) + .filter(collection_mints::Column::Id.eq(input.id)) .one(conn) .await? .ok_or(Error::new("Mint not found"))?; @@ -911,9 +911,15 @@ pub struct MintToCollectionInput { #[derive(Debug, Clone, InputObject)] pub struct UpdateMintInput { - mint: Uuid, + /// The ID of the mint to be updated + id: Uuid, + /// The metadata of the mint metadata_json: MetadataJsonInput, + /// The optional seller fee basis points seller_fee_basis_points: Option, + /// The creators to be assigned to the NFT. + /// For Solana, this can be up to five creators. If the project treasury wallet is set as a creator and verified set to true the creator will be verified on chain. + /// For Polygon, this can be only 1 creator. creators: Vec, } @@ -945,6 +951,7 @@ pub struct RetryMintToCollectionPayload { #[derive(Debug, Clone, InputObject)] pub struct RetryUpdateMintInput { + /// Update History ID revision_id: Uuid, } From 8094c9bab3a1cd22cf6e519eb738c5d570643be7 Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Fri, 11 Aug 2023 07:22:55 +0500 Subject: [PATCH 13/28] use update_history.id as key id for SolanaMintUpdated event --- api/src/events.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/events.rs b/api/src/events.rs index 720d034..8940fc6 100644 --- a/api/src/events.rs +++ b/api/src/events.rs @@ -781,7 +781,7 @@ impl Processor { })), }), Some(&NftEventKey { - id, + id: update_history.id.to_string(), project_id, user_id: update_history.created_by.to_string(), }), From 5ff766048d581f0d586e637a0c09daf1bb2f4187 Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Fri, 11 Aug 2023 07:49:20 +0500 Subject: [PATCH 14/28] Remove SolanaMintUpdated event --- api/src/events.rs | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/api/src/events.rs b/api/src/events.rs index 8940fc6..284ba18 100644 --- a/api/src/events.rs +++ b/api/src/events.rs @@ -146,7 +146,7 @@ impl Processor { SolanaNftsEvent::UpdateCollectionMintSubmitted(payload) | SolanaNftsEvent::RetryUpdateMintSubmitted(payload), ) => { - self.mint_updated(id, project_id, UpdateResult::Success(payload.signature)) + self.mint_updated(id, UpdateResult::Success(payload.signature)) .await }, Some(SolanaNftsEvent::TransferAssetSubmitted( @@ -179,10 +179,7 @@ impl Processor { Some( SolanaNftsEvent::UpdateCollectionMintFailed(_) | SolanaNftsEvent::RetryUpdateMintFailed(_), - ) => { - self.mint_updated(id, project_id, UpdateResult::Failure) - .await - }, + ) => self.mint_updated(id, UpdateResult::Failure).await, Some(SolanaNftsEvent::UpdateMintOwner(e)) => self.update_mint_owner(id, e).await, Some(SolanaNftsEvent::ImportedExternalCollection(e)) => { self.index_collection(id, project_id, user_id, e).await @@ -753,12 +750,7 @@ impl Processor { Ok(()) } - async fn mint_updated( - &self, - id: String, - project_id: String, - payload: UpdateResult, - ) -> Result<()> { + async fn mint_updated(&self, id: String, payload: UpdateResult) -> Result<()> { let update_history = UpdateHistories::find_by_id(id.parse()?) .one(self.db.get()) .await? @@ -772,21 +764,6 @@ impl Processor { self.credits .confirm_deduction(TransactionId(update_history.credit_deduction_id)) .await?; - - self.producer - .send( - Some(&NftEvents { - event: Some(NftEvent::SolanaMintUpdated(SolanaUpdatedMintPayload { - mint_id: update_history.mint_id.to_string(), - })), - }), - Some(&NftEventKey { - id: update_history.id.to_string(), - project_id, - user_id: update_history.created_by.to_string(), - }), - ) - .await?; } else { update_history_am.status = Set(CreationStatus::Failed); } From b23453b17e5df83d8c13a7d751bdd8849a4c76a3 Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Fri, 11 Aug 2023 14:05:13 +0500 Subject: [PATCH 15/28] use blockchain variable for credit deduction in update_mint mutation --- api/src/mutations/mint.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/src/mutations/mint.rs b/api/src/mutations/mint.rs index 92e3399..ad62cae 100644 --- a/api/src/mutations/mint.rs +++ b/api/src/mutations/mint.rs @@ -3,7 +3,7 @@ use std::ops::Add; use async_graphql::{Context, Error, InputObject, Object, Result, SimpleObject}; use hub_core::{ chrono::Utc, - credits::{Blockchain, CreditsClient, TransactionId}, + credits::{CreditsClient, TransactionId}, producer::Producer, }; use sea_orm::{prelude::*, JoinType, QuerySelect, Set, TransactionTrait}; @@ -567,7 +567,7 @@ impl Mutation { org_id, user_id, Actions::UpdateMint, - Blockchain::Solana, + collection.blockchain.into(), balance, ) .await?; From 20b208657b3e2ea5e9152524d76df3d9a8afb126 Mon Sep 17 00:00:00 2001 From: Kyle Espinola Date: Fri, 11 Aug 2023 11:54:45 +0200 Subject: [PATCH 16/28] feat: query mint by ID. move collection and drop queries to root query and mark project field version as deprecated. --- api/src/dataloaders/update_histories.rs | 2 +- api/src/events.rs | 3 +-- api/src/mutations/mint.rs | 6 ++++++ api/src/objects/project.rs | 3 +++ api/src/queries/collection.rs | 20 ++++++++++++++++++++ api/src/queries/drop.rs | 17 +++++++++++++++++ api/src/queries/mint.rs | 20 ++++++++++++++++++++ api/src/queries/mod.rs | 12 +++++++++++- 8 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 api/src/queries/collection.rs create mode 100644 api/src/queries/drop.rs create mode 100644 api/src/queries/mint.rs diff --git a/api/src/dataloaders/update_histories.rs b/api/src/dataloaders/update_histories.rs index aa0e458..30bb18e 100644 --- a/api/src/dataloaders/update_histories.rs +++ b/api/src/dataloaders/update_histories.rs @@ -37,7 +37,7 @@ impl DataLoader for UpdateMintHistoryLoader { acc.entry(history.mint_id).or_insert_with(Vec::new); acc.entry(history.mint_id) - .and_modify(|update_histories| update_histories.push(history.into())); + .and_modify(|update_histories| update_histories.push(history)); acc })) diff --git a/api/src/events.rs b/api/src/events.rs index 284ba18..18d44c9 100644 --- a/api/src/events.rs +++ b/api/src/events.rs @@ -33,8 +33,7 @@ use crate::{ Attribute, CreationStatus as NftCreationStatus, DropCreation, File, Metadata, MintCollectionCreation, MintCreation, MintOwnershipUpdate, MintedTokensOwnershipUpdate, NftEventKey, NftEvents, SolanaCollectionPayload, SolanaCompletedMintTransaction, - SolanaCompletedTransferTransaction, SolanaMintPayload, SolanaNftEventKey, - SolanaUpdatedMintPayload, TreasuryEventKey, + SolanaCompletedTransferTransaction, SolanaMintPayload, SolanaNftEventKey, TreasuryEventKey, }, Actions, Services, }; diff --git a/api/src/mutations/mint.rs b/api/src/mutations/mint.rs index 92e3399..4e4fef5 100644 --- a/api/src/mutations/mint.rs +++ b/api/src/mutations/mint.rs @@ -496,6 +496,9 @@ impl Mutation { }) } + /// This mutation updates a mint. + /// # Errors + /// If the mint cannot be saved to the database or fails to be emitted for submission to the desired blockchain, the mutation will result in an error. pub async fn update_mint( &self, ctx: &Context<'_>, @@ -651,6 +654,9 @@ impl Mutation { }) } + /// This mutation retries updating a mint that failed by providing the ID of the `update_history`. + /// # Errors + /// If the mint cannot be saved to the database or fails to be emitted for submission to the desired blockchain, the mutation will result in an error. pub async fn retry_update_mint( &self, ctx: &Context<'_>, diff --git a/api/src/objects/project.rs b/api/src/objects/project.rs index 85b2e8a..c0d3715 100644 --- a/api/src/objects/project.rs +++ b/api/src/objects/project.rs @@ -25,6 +25,7 @@ impl Project { } /// Look up a drop associated with the project by its ID. + #[graphql(deprecation = "Use `drop` root query field instead")] async fn drop(&self, ctx: &Context<'_>, id: Uuid) -> Result> { let AppContext { drop_loader, .. } = ctx.data::()?; @@ -54,6 +55,8 @@ impl Project { project_collections_loader.load_one(self.id).await } + /// Look up a collection associated with the project by its ID. + #[graphql(deprecation = "Use `collection` root query field instead")] async fn collection(&self, ctx: &Context<'_>, id: Uuid) -> Result> { let AppContext { project_collection_loader, diff --git a/api/src/queries/collection.rs b/api/src/queries/collection.rs new file mode 100644 index 0000000..d3da055 --- /dev/null +++ b/api/src/queries/collection.rs @@ -0,0 +1,20 @@ +use async_graphql::{Context, Object, Result}; +use hub_core::uuid::Uuid; + +use crate::{objects::Collection, AppContext}; + +#[derive(Debug, Clone, Copy, Default)] +pub struct Query; + +#[Object(name = "CollectionQuery")] +impl Query { + /// Look up a `collection` by its ID. + async fn collection(&self, ctx: &Context<'_>, id: Uuid) -> Result> { + let AppContext { + project_collection_loader, + .. + } = ctx.data::()?; + + project_collection_loader.load_one(id).await + } +} diff --git a/api/src/queries/drop.rs b/api/src/queries/drop.rs new file mode 100644 index 0000000..3ebacbd --- /dev/null +++ b/api/src/queries/drop.rs @@ -0,0 +1,17 @@ +use async_graphql::{Context, Object, Result}; +use hub_core::uuid::Uuid; + +use crate::{objects::Drop, AppContext}; + +#[derive(Debug, Clone, Copy, Default)] +pub struct Query; + +#[Object(name = "DropQuery")] +impl Query { + /// Look up a `drop` by its ID. + async fn drop(&self, ctx: &Context<'_>, id: Uuid) -> Result> { + let AppContext { drop_loader, .. } = ctx.data::()?; + + drop_loader.load_one(id).await + } +} diff --git a/api/src/queries/mint.rs b/api/src/queries/mint.rs new file mode 100644 index 0000000..43cb649 --- /dev/null +++ b/api/src/queries/mint.rs @@ -0,0 +1,20 @@ +use async_graphql::{Context, Object, Result}; +use hub_core::uuid::Uuid; + +use crate::{entities::collection_mints::CollectionMint, AppContext}; + +#[derive(Debug, Clone, Copy, Default)] +pub struct Query; + +#[Object(name = "MintQuery")] +impl Query { + /// Look up a `collection_mint` by its ID. + async fn mint(&self, ctx: &Context<'_>, id: Uuid) -> Result> { + let AppContext { + single_collection_mint_loader, + .. + } = ctx.data::()?; + + single_collection_mint_loader.load_one(id).await + } +} diff --git a/api/src/queries/mod.rs b/api/src/queries/mod.rs index 7c5e4e5..88eaa44 100644 --- a/api/src/queries/mod.rs +++ b/api/src/queries/mod.rs @@ -1,9 +1,19 @@ #![allow(clippy::unused_async)] +mod collection; mod customer; +mod drop; +mod mint; mod project; mod wallet; // // Add your other ones here to create a unified Query object #[derive(async_graphql::MergedObject, Default)] -pub struct Query(project::Query, wallet::Query, customer::Query); +pub struct Query( + project::Query, + wallet::Query, + customer::Query, + mint::Query, + collection::Query, + drop::Query, +); From 93aed80f9f58ee71f4823c8621e57d6ed5d9b01c Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Fri, 11 Aug 2023 17:42:16 +0500 Subject: [PATCH 17/28] Lowercase EVM addresses before saving && querying --- api/src/dataloaders/collection_mints.rs | 3 +++ api/src/dataloaders/mint_histories.rs | 14 ++++++++++++++ api/src/entities/collection_creators.rs | 13 +++++++++++-- api/src/entities/collection_mints.rs | 19 +++++++++++++++++-- api/src/entities/collections.rs | 17 ++++++++++++++--- api/src/entities/customer_wallets.rs | 21 +++++++++++++++++---- api/src/entities/mint_creators.rs | 15 ++++++++++++--- api/src/entities/mint_histories.rs | 15 ++++++++++++--- api/src/entities/nft_transfers.rs | 19 ++++++++++++++++--- api/src/entities/project_wallets.rs | 13 +++++++++++-- 10 files changed, 127 insertions(+), 22 deletions(-) diff --git a/api/src/dataloaders/collection_mints.rs b/api/src/dataloaders/collection_mints.rs index 8506810..21e2bc9 100644 --- a/api/src/dataloaders/collection_mints.rs +++ b/api/src/dataloaders/collection_mints.rs @@ -4,6 +4,7 @@ use async_graphql::{dataloader::Loader as DataLoader, FieldError, Result}; use poem::async_trait; use sea_orm::prelude::*; +use super::mint_histories::lowercase_evm_addresses; use crate::{db::Connection, entities::collection_mints}; #[derive(Debug, Clone)] @@ -63,6 +64,8 @@ impl DataLoader for OwnerLoader { type Value = Vec; async fn load(&self, keys: &[String]) -> Result, Self::Error> { + let keys = lowercase_evm_addresses(keys); + let collection_mints = collection_mints::Entity::find() .filter(collection_mints::Column::Owner.is_in(keys.iter().map(ToOwned::to_owned))) .all(self.db.get()) diff --git a/api/src/dataloaders/mint_histories.rs b/api/src/dataloaders/mint_histories.rs index 250d581..a691cec 100644 --- a/api/src/dataloaders/mint_histories.rs +++ b/api/src/dataloaders/mint_histories.rs @@ -115,6 +115,8 @@ impl DataLoader for MinterLoader { type Value = Vec; async fn load(&self, keys: &[String]) -> Result, Self::Error> { + let keys = lowercase_evm_addresses(keys); + let mint_histories = mint_histories::Entity::find() .filter(mint_histories::Column::Wallet.is_in(keys.iter().map(ToOwned::to_owned))) .all(self.db.get()) @@ -133,3 +135,15 @@ impl DataLoader for MinterLoader { })) } } + +pub fn lowercase_evm_addresses(keys: &[String]) -> Vec { + keys.iter() + .map(|key| { + if key.starts_with("0x") { + key.to_lowercase() + } else { + key.clone() + } + }) + .collect::>() +} diff --git a/api/src/entities/collection_creators.rs b/api/src/entities/collection_creators.rs index 67250f3..7277962 100644 --- a/api/src/entities/collection_creators.rs +++ b/api/src/entities/collection_creators.rs @@ -1,7 +1,7 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.0 use async_graphql::SimpleObject; -use sea_orm::entity::prelude::*; +use sea_orm::{entity::prelude::*, Set}; use crate::proto; @@ -52,4 +52,13 @@ impl Related for Entity { } } -impl ActiveModelBehavior for ActiveModel {} +impl ActiveModelBehavior for ActiveModel { + /// Will be triggered before insert / update + fn before_save(mut self, _insert: bool) -> Result { + if self.address.as_ref().starts_with("0x") { + self.address = Set(self.address.as_ref().to_lowercase()); + } + + Ok(self) + } +} diff --git a/api/src/entities/collection_mints.rs b/api/src/entities/collection_mints.rs index c96a417..97de198 100644 --- a/api/src/entities/collection_mints.rs +++ b/api/src/entities/collection_mints.rs @@ -1,7 +1,7 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.0 use async_graphql::{ComplexObject, Context, Error, Result, SimpleObject}; -use sea_orm::{entity::prelude::*, JoinType, QuerySelect, SelectTwo}; +use sea_orm::{entity::prelude::*, JoinType, QuerySelect, SelectTwo, Set}; use super::{ collections, @@ -194,7 +194,22 @@ impl Related for Entity { } } -impl ActiveModelBehavior for ActiveModel {} +impl ActiveModelBehavior for ActiveModel { + /// Will be triggered before insert / update + fn before_save(mut self, _insert: bool) -> Result { + if self.owner.as_ref().starts_with("0x") { + self.owner = Set(self.owner.as_ref().to_lowercase()); + } + + if let Some(a) = self.address.as_ref() { + if a.starts_with("0x") { + self.address = Set(Some(a.to_lowercase())); + } + } + + Ok(self) + } +} impl Entity { pub fn find_by_id_with_collection(id: Uuid) -> SelectTwo { diff --git a/api/src/entities/collections.rs b/api/src/entities/collections.rs index 683db27..297069b 100644 --- a/api/src/entities/collections.rs +++ b/api/src/entities/collections.rs @@ -1,6 +1,6 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.0 -use sea_orm::entity::prelude::*; +use sea_orm::{entity::prelude::*, Set}; use super::sea_orm_active_enums::{Blockchain, CreationStatus}; @@ -25,6 +25,19 @@ pub struct Model { pub created_at: DateTimeWithTimeZone, } +impl ActiveModelBehavior for ActiveModel { + /// Will be triggered before insert / update + fn before_save(mut self, _insert: bool) -> Result { + if let Some(a) = self.address.as_ref() { + if a.starts_with("0x") { + self.address = Set(Some(a.to_lowercase())); + } + } + + Ok(self) + } +} + #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm(has_many = "super::collection_creators::Entity")] @@ -60,5 +73,3 @@ impl Related for Entity { Relation::MintHistories.def() } } - -impl ActiveModelBehavior for ActiveModel {} diff --git a/api/src/entities/customer_wallets.rs b/api/src/entities/customer_wallets.rs index 5145f92..5994887 100644 --- a/api/src/entities/customer_wallets.rs +++ b/api/src/entities/customer_wallets.rs @@ -1,6 +1,6 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3 -use sea_orm::entity::prelude::*; +use sea_orm::{entity::prelude::*, Set}; use super::sea_orm_active_enums::Blockchain; @@ -15,13 +15,26 @@ pub struct Model { pub blockchain: Blockchain, } +impl ActiveModelBehavior for ActiveModel { + /// Will be triggered before insert / update + fn before_save(mut self, _insert: bool) -> Result { + if self.address.as_ref().starts_with("0x") { + self.address = Set(self.address.as_ref().to_lowercase()); + } + + Ok(self) + } +} + #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation {} -impl ActiveModelBehavior for ActiveModel {} - impl Entity { pub fn find_by_address(address: String) -> Select { - Self::find().filter(Column::Address.eq(address)) + if address.starts_with("0x") { + Self::find().filter(Column::Address.like(&address)) + } else { + Self::find().filter(Column::Address.eq(address)) + } } } diff --git a/api/src/entities/mint_creators.rs b/api/src/entities/mint_creators.rs index d04d56d..fd0f53a 100644 --- a/api/src/entities/mint_creators.rs +++ b/api/src/entities/mint_creators.rs @@ -1,7 +1,7 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.5 use async_graphql::SimpleObject; -use sea_orm::entity::prelude::*; +use sea_orm::{entity::prelude::*, Set}; use crate::proto; @@ -16,6 +16,17 @@ pub struct Model { pub share: i32, } +impl ActiveModelBehavior for ActiveModel { + /// Will be triggered before insert / update + fn before_save(mut self, _insert: bool) -> Result { + if self.address.as_ref().starts_with("0x") { + self.address = Set(self.address.as_ref().to_lowercase()); + } + + Ok(self) + } +} + impl From for proto::Creator { fn from( Model { @@ -51,8 +62,6 @@ impl Related for Entity { } } -impl ActiveModelBehavior for ActiveModel {} - impl Entity { pub fn find_by_collection_mint_id(collection_mint_id: Uuid) -> Select { Self::find().filter(Column::CollectionMintId.eq(collection_mint_id)) diff --git a/api/src/entities/mint_histories.rs b/api/src/entities/mint_histories.rs index 0a1cdae..34e10b1 100644 --- a/api/src/entities/mint_histories.rs +++ b/api/src/entities/mint_histories.rs @@ -1,7 +1,7 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3 use async_graphql::{ComplexObject, Context, Result, SimpleObject}; -use sea_orm::entity::prelude::*; +use sea_orm::{entity::prelude::*, Set}; use super::{collection_mints::CollectionMint, sea_orm_active_enums::CreationStatus}; use crate::AppContext; @@ -29,6 +29,17 @@ pub struct Model { pub collection_id: Uuid, } +impl ActiveModelBehavior for ActiveModel { + /// Will be triggered before insert / update + fn before_save(mut self, _insert: bool) -> Result { + if self.wallet.as_ref().starts_with("0x") { + self.wallet = Set(self.wallet.as_ref().to_lowercase()); + } + + Ok(self) + } +} + #[ComplexObject] impl Model { /// The minted NFT. @@ -73,5 +84,3 @@ impl Related for Entity { Relation::Collections.def() } } - -impl ActiveModelBehavior for ActiveModel {} diff --git a/api/src/entities/nft_transfers.rs b/api/src/entities/nft_transfers.rs index 6baf6c5..656bcae 100644 --- a/api/src/entities/nft_transfers.rs +++ b/api/src/entities/nft_transfers.rs @@ -1,6 +1,6 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.0 -use sea_orm::entity::prelude::*; +use sea_orm::{entity::prelude::*, Set}; /// A record of a transfer of an NFT. #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] @@ -21,6 +21,21 @@ pub struct Model { pub created_at: DateTimeWithTimeZone, } +impl ActiveModelBehavior for ActiveModel { + /// Will be triggered before insert / update + fn before_save(mut self, _insert: bool) -> Result { + if self.sender.as_ref().starts_with("0x") { + self.sender = Set(self.sender.as_ref().to_lowercase()); + } + + if self.recipient.as_ref().starts_with("0x") { + self.recipient = Set(self.recipient.as_ref().to_lowercase()); + } + + Ok(self) + } +} + #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm( @@ -38,5 +53,3 @@ impl Related for Entity { Relation::CollectionMints.def() } } - -impl ActiveModelBehavior for ActiveModel {} diff --git a/api/src/entities/project_wallets.rs b/api/src/entities/project_wallets.rs index d7509f1..5f6709c 100644 --- a/api/src/entities/project_wallets.rs +++ b/api/src/entities/project_wallets.rs @@ -1,6 +1,6 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.0 -use sea_orm::entity::prelude::*; +use sea_orm::{entity::prelude::*, Set}; use super::sea_orm_active_enums::Blockchain; @@ -17,4 +17,13 @@ pub struct Model { #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation {} -impl ActiveModelBehavior for ActiveModel {} +impl ActiveModelBehavior for ActiveModel { + /// Will be triggered before insert / update + fn before_save(mut self, _insert: bool) -> Result { + if self.wallet_address.as_ref().starts_with("0x") { + self.wallet_address = Set(self.wallet_address.as_ref().to_lowercase()); + } + + Ok(self) + } +} From afcbabffc62c4531e2c0dc98932e03e24f7f45e8 Mon Sep 17 00:00:00 2001 From: mpw Date: Fri, 11 Aug 2023 11:07:44 -0300 Subject: [PATCH 18/28] use latest buildkit --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bec9e00..843f635 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -42,7 +42,7 @@ jobs: uses: docker/setup-buildx-action@v2 with: driver-opts: image=moby/buildkit:master - version: v0.10.4 + version: v0.12.1 endpoint: ci - uses: aws-actions/configure-aws-credentials@v1 From 6d10b1f014d12f02c0f4c03eb45c87a26e72171b Mon Sep 17 00:00:00 2001 From: mpw Date: Fri, 11 Aug 2023 11:09:20 -0300 Subject: [PATCH 19/28] wops, use buildkit v0.11.2 --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 843f635..72f4d15 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -42,7 +42,7 @@ jobs: uses: docker/setup-buildx-action@v2 with: driver-opts: image=moby/buildkit:master - version: v0.12.1 + version: v0.11.2 endpoint: ci - uses: aws-actions/configure-aws-credentials@v1 From 34bea8c138322052718a5f56e64b7b74f336a7c1 Mon Sep 17 00:00:00 2001 From: Kyle Espinola Date: Mon, 14 Aug 2023 14:40:07 +0200 Subject: [PATCH 20/28] feat: field on collection mint for its mint history, creators, and nft transfers. --- api/src/dataloaders/mint_creators.rs | 46 +++++++++++++++++++++++++ api/src/dataloaders/mint_histories.rs | 36 ++++++++++++++++++-- api/src/dataloaders/mod.rs | 7 +++- api/src/dataloaders/nft_transfers.rs | 48 +++++++++++++++++++++++++++ api/src/entities/collection_mints.rs | 34 ++++++++++++++++++- api/src/entities/mint_creators.rs | 1 + api/src/entities/nft_transfers.rs | 4 ++- api/src/lib.rs | 31 ++++++++++++----- 8 files changed, 193 insertions(+), 14 deletions(-) create mode 100644 api/src/dataloaders/mint_creators.rs create mode 100644 api/src/dataloaders/nft_transfers.rs diff --git a/api/src/dataloaders/mint_creators.rs b/api/src/dataloaders/mint_creators.rs new file mode 100644 index 0000000..a22f11d --- /dev/null +++ b/api/src/dataloaders/mint_creators.rs @@ -0,0 +1,46 @@ +use std::collections::HashMap; + +use async_graphql::{dataloader::Loader as DataLoader, FieldError, Result}; +use poem::async_trait; +use sea_orm::prelude::*; + +use crate::{db::Connection, entities::mint_creators}; + +#[derive(Debug, Clone)] +pub struct Loader { + pub db: Connection, +} + +impl Loader { + #[must_use] + pub fn new(db: Connection) -> Self { + Self { db } + } +} + +#[async_trait] +impl DataLoader for Loader { + type Error = FieldError; + type Value = Vec; + + async fn load(&self, keys: &[Uuid]) -> Result, Self::Error> { + let mint_creators = mint_creators::Entity::find() + .filter( + mint_creators::Column::CollectionMintId.is_in(keys.iter().map(ToOwned::to_owned)), + ) + .all(self.db.get()) + .await?; + + Ok(mint_creators + .into_iter() + .fold(HashMap::new(), |mut acc, mint_creator| { + acc.entry(mint_creator.collection_mint_id) + .or_insert_with(Vec::new); + + acc.entry(mint_creator.collection_mint_id) + .and_modify(|mint_creators| mint_creators.push(mint_creator)); + + acc + })) + } +} diff --git a/api/src/dataloaders/mint_histories.rs b/api/src/dataloaders/mint_histories.rs index 250d581..a59fe60 100644 --- a/api/src/dataloaders/mint_histories.rs +++ b/api/src/dataloaders/mint_histories.rs @@ -10,11 +10,11 @@ use crate::{ }; #[derive(Debug, Clone)] -pub struct CollectionMintHistoryLoader { +pub struct CollectionMintHistoriesLoader { pub db: Connection, } -impl CollectionMintHistoryLoader { +impl CollectionMintHistoriesLoader { #[must_use] pub fn new(db: Connection) -> Self { Self { db } @@ -22,7 +22,7 @@ impl CollectionMintHistoryLoader { } #[async_trait] -impl DataLoader for CollectionMintHistoryLoader { +impl DataLoader for CollectionMintHistoriesLoader { type Error = FieldError; type Value = Vec; @@ -133,3 +133,33 @@ impl DataLoader for MinterLoader { })) } } + +#[derive(Debug, Clone)] +pub struct CollectionMintMintHistoryLoader { + pub db: Connection, +} + +impl CollectionMintMintHistoryLoader { + #[must_use] + pub fn new(db: Connection) -> Self { + Self { db } + } +} + +#[async_trait] +impl DataLoader for CollectionMintMintHistoryLoader { + type Error = FieldError; + type Value = mint_histories::Model; + + async fn load(&self, keys: &[Uuid]) -> Result, Self::Error> { + let mint_histories = mint_histories::Entity::find() + .filter(mint_histories::Column::Id.is_in(keys.iter().map(ToOwned::to_owned))) + .all(self.db.get()) + .await?; + + Ok(mint_histories + .into_iter() + .map(|mint_history| (mint_history.mint_id, mint_history)) + .collect()) + } +} diff --git a/api/src/dataloaders/mod.rs b/api/src/dataloaders/mod.rs index f53329b..2bf0b1e 100644 --- a/api/src/dataloaders/mod.rs +++ b/api/src/dataloaders/mod.rs @@ -6,7 +6,9 @@ mod drop; mod drops; mod holders; mod metadata_json; +mod mint_creators; mod mint_histories; +mod nft_transfers; mod project_collection; mod project_collections; mod update_histories; @@ -24,9 +26,12 @@ pub use holders::Loader as HoldersLoader; pub use metadata_json::{ AttributesLoader as MetadataJsonAttributesLoader, Loader as MetadataJsonLoader, }; +pub use mint_creators::Loader as MintCreatorsLoader; pub use mint_histories::{ - CollectionMintHistoryLoader, DropMintHistoryLoader, MinterLoader as MinterMintHistoryLoader, + CollectionMintHistoriesLoader, CollectionMintMintHistoryLoader, DropMintHistoryLoader, + MinterLoader as MinterMintHistoryLoader, }; +pub use nft_transfers::CollectionMintTransfersLoader; pub use project_collection::ProjectCollectionLoader; pub use project_collections::ProjectCollectionsLoader; pub use update_histories::UpdateMintHistoryLoader; diff --git a/api/src/dataloaders/nft_transfers.rs b/api/src/dataloaders/nft_transfers.rs new file mode 100644 index 0000000..cec96fe --- /dev/null +++ b/api/src/dataloaders/nft_transfers.rs @@ -0,0 +1,48 @@ +use std::collections::HashMap; + +use async_graphql::{dataloader::Loader as DataLoader, FieldError, Result}; +use poem::async_trait; +use sea_orm::{prelude::*, Order, QueryOrder}; + +use crate::{db::Connection, entities::nft_transfers}; + +#[derive(Debug, Clone)] +pub struct CollectionMintTransfersLoader { + pub db: Connection, +} + +impl CollectionMintTransfersLoader { + #[must_use] + pub fn new(db: Connection) -> Self { + Self { db } + } +} + +#[async_trait] +impl DataLoader for CollectionMintTransfersLoader { + type Error = FieldError; + type Value = Vec; + + async fn load(&self, keys: &[Uuid]) -> Result, Self::Error> { + let conn = self.db.get(); + let nft_transfers = nft_transfers::Entity::find() + .filter( + nft_transfers::Column::CollectionMintId.is_in(keys.iter().map(ToOwned::to_owned)), + ) + .order_by(nft_transfers::Column::CreatedAt, Order::Desc) + .all(conn) + .await?; + + Ok(nft_transfers + .into_iter() + .fold(HashMap::new(), |mut acc, nft_transfer| { + acc.entry(nft_transfer.collection_mint_id) + .or_insert_with(Vec::new); + + acc.entry(nft_transfer.collection_mint_id) + .and_modify(|nft_transfers| nft_transfers.push(nft_transfer)); + + acc + })) + } +} diff --git a/api/src/entities/collection_mints.rs b/api/src/entities/collection_mints.rs index c96a417..1f9bb66 100644 --- a/api/src/entities/collection_mints.rs +++ b/api/src/entities/collection_mints.rs @@ -4,7 +4,7 @@ use async_graphql::{ComplexObject, Context, Error, Result, SimpleObject}; use sea_orm::{entity::prelude::*, JoinType, QuerySelect, SelectTwo}; use super::{ - collections, + collections, mint_creators, mint_histories, nft_transfers, sea_orm_active_enums::{Blockchain, CreationStatus}, update_histories, }; @@ -108,6 +108,38 @@ impl CollectionMint { update_mint_history_loader.load_one(self.id).await } + /// The creators of the mint. Includes the creator addresses and their shares. + async fn creators(&self, ctx: &Context<'_>) -> Result>> { + let AppContext { + mint_creators_loader, + .. + } = ctx.data::()?; + + mint_creators_loader.load_one(self.id).await + } + + /// The record of the original mint. + async fn mint_history(&self, ctx: &Context<'_>) -> Result> { + let AppContext { + collection_mint_mint_history_loader, + .. + } = ctx.data::()?; + + collection_mint_mint_history_loader.load_one(self.id).await + } + + /// The history of transfers for the mint. + async fn transfer_histories( + &self, + ctx: &Context<'_>, + ) -> Result>> { + let AppContext { + collection_mint_transfers_loader, + .. + } = ctx.data::()?; + + collection_mint_transfers_loader.load_one(self.id).await + } } impl From for CollectionMint { diff --git a/api/src/entities/mint_creators.rs b/api/src/entities/mint_creators.rs index d04d56d..88db0ce 100644 --- a/api/src/entities/mint_creators.rs +++ b/api/src/entities/mint_creators.rs @@ -7,6 +7,7 @@ use crate::proto; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, SimpleObject)] #[sea_orm(table_name = "mint_creators")] +#[graphql(concrete(name = "MintCreator", params()))] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub collection_mint_id: Uuid, diff --git a/api/src/entities/nft_transfers.rs b/api/src/entities/nft_transfers.rs index 6baf6c5..6485256 100644 --- a/api/src/entities/nft_transfers.rs +++ b/api/src/entities/nft_transfers.rs @@ -1,10 +1,12 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.0 +use async_graphql::SimpleObject; use sea_orm::entity::prelude::*; /// A record of a transfer of an NFT. -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, SimpleObject)] #[sea_orm(table_name = "nft_transfers")] +#[graphql(concrete(name = "NftTransfer", params()))] pub struct Model { /// The ID of the NFT transfer. #[sea_orm(primary_key, auto_increment = false)] diff --git a/api/src/lib.rs b/api/src/lib.rs index 3020a60..800a082 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -22,11 +22,11 @@ use async_graphql::{ }; use blockchains::{polygon::Polygon, solana::Solana}; use dataloaders::{ - CollectionDropLoader, CollectionLoader, CollectionMintHistoryLoader, CollectionMintLoader, - CollectionMintsLoader, CollectionMintsOwnerLoader, CreatorsLoader, DropLoader, - DropMintHistoryLoader, HoldersLoader, MetadataJsonAttributesLoader, MetadataJsonLoader, - MinterMintHistoryLoader, ProjectCollectionLoader, ProjectCollectionsLoader, ProjectDropsLoader, - UpdateMintHistoryLoader, + CollectionDropLoader, CollectionLoader, CollectionMintHistoriesLoader, CollectionMintLoader, + CollectionMintMintHistoryLoader, CollectionMintTransfersLoader, CollectionMintsLoader, + CollectionMintsOwnerLoader, CreatorsLoader, DropLoader, DropMintHistoryLoader, HoldersLoader, + MetadataJsonAttributesLoader, MetadataJsonLoader, MintCreatorsLoader, MinterMintHistoryLoader, + ProjectCollectionLoader, ProjectCollectionsLoader, ProjectDropsLoader, UpdateMintHistoryLoader, }; use db::Connection; use hub_core::{ @@ -279,10 +279,13 @@ pub struct AppContext { drop_loader: DataLoader, creators_loader: DataLoader, holders_loader: DataLoader, - collection_mint_history_loader: DataLoader, + collection_mint_history_loader: DataLoader, drop_mint_history_loader: DataLoader, minter_mint_history_loader: DataLoader, update_mint_history_loader: DataLoader, + mint_creators_loader: DataLoader, + collection_mint_mint_history_loader: DataLoader, + collection_mint_transfers_loader: DataLoader, } impl AppContext { @@ -313,8 +316,8 @@ impl AppContext { let drop_loader = DataLoader::new(DropLoader::new(db.clone()), tokio::spawn); let creators_loader = DataLoader::new(CreatorsLoader::new(db.clone()), tokio::spawn); let holders_loader = DataLoader::new(HoldersLoader::new(db.clone()), tokio::spawn); - let collection_mint_history_loader = - DataLoader::new(CollectionMintHistoryLoader::new(db.clone()), tokio::spawn); + let collection_mint_history_loader: DataLoader = + DataLoader::new(CollectionMintHistoriesLoader::new(db.clone()), tokio::spawn); let drop_mint_history_loader = DataLoader::new(DropMintHistoryLoader::new(db.clone()), tokio::spawn); let single_collection_mint_loader = @@ -323,6 +326,15 @@ impl AppContext { DataLoader::new(MinterMintHistoryLoader::new(db.clone()), tokio::spawn); let update_mint_history_loader = DataLoader::new(UpdateMintHistoryLoader::new(db.clone()), tokio::spawn); + let mint_creators_loader = + DataLoader::new(MintCreatorsLoader::new(db.clone()), tokio::spawn); + let collection_mint_mint_history_loader = DataLoader::new( + CollectionMintMintHistoryLoader::new(db.clone()), + tokio::spawn, + ); + let collection_mint_transfers_loader = + DataLoader::new(CollectionMintTransfersLoader::new(db.clone()), tokio::spawn); + Self { db, user_id, @@ -345,6 +357,9 @@ impl AppContext { drop_mint_history_loader, minter_mint_history_loader, update_mint_history_loader, + mint_creators_loader, + collection_mint_mint_history_loader, + collection_mint_transfers_loader, } } } From 6e50693e445a736ccbe081de66d1cef9f0c48180 Mon Sep 17 00:00:00 2001 From: Kyle Espinola Date: Mon, 14 Aug 2023 16:14:23 +0200 Subject: [PATCH 21/28] fix: fetching mintHistory for the collection mint by selecting by mint id --- api/src/dataloaders/mint_histories.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/dataloaders/mint_histories.rs b/api/src/dataloaders/mint_histories.rs index a59fe60..3198969 100644 --- a/api/src/dataloaders/mint_histories.rs +++ b/api/src/dataloaders/mint_histories.rs @@ -153,7 +153,7 @@ impl DataLoader for CollectionMintMintHistoryLoader { async fn load(&self, keys: &[Uuid]) -> Result, Self::Error> { let mint_histories = mint_histories::Entity::find() - .filter(mint_histories::Column::Id.is_in(keys.iter().map(ToOwned::to_owned))) + .filter(mint_histories::Column::MintId.is_in(keys.iter().map(ToOwned::to_owned))) .all(self.db.get()) .await?; From ec6820585b9d156e8adc36050a119458031f0a8d Mon Sep 17 00:00:00 2001 From: raykast Date: Tue, 15 Aug 2023 11:20:56 -0700 Subject: [PATCH 22/28] Update EVM address code to use hub-core utilities. --- Cargo.lock | 84 ++++++++++++++++++++++--- api/Cargo.toml | 2 +- api/src/dataloaders/collection_mints.rs | 10 +-- api/src/dataloaders/mint_histories.rs | 21 ++----- api/src/dataloaders/update_histories.rs | 2 +- api/src/entities/collection_creators.rs | 11 +--- api/src/entities/collection_mints.rs | 17 +---- api/src/entities/collections.rs | 13 +--- api/src/entities/customer_wallets.rs | 11 +--- api/src/entities/mint_creators.rs | 11 +--- api/src/entities/mint_histories.rs | 11 +--- api/src/entities/nft_transfers.rs | 15 +---- api/src/entities/project_wallets.rs | 11 +--- 13 files changed, 102 insertions(+), 117 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a04ea36..7ebe9ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -436,6 +436,18 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backon" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1a6197b2120bb2185a267f6515038558b019e92b832bb0320e96d66268dcf9" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "pin-project 1.1.3", + "tokio", +] + [[package]] name = "backtrace" version = "0.3.68" @@ -680,6 +692,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" +[[package]] +name = "bs58" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +dependencies = [ + "tinyvec", +] + [[package]] name = "bumpalo" version = "3.13.0" @@ -1302,6 +1323,15 @@ dependencies = [ "ascii_utils", ] +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + [[package]] name = "fastrand" version = "2.0.0" @@ -1471,7 +1501,7 @@ dependencies = [ "bytes 0.5.6", "futures", "memchr", - "pin-project", + "pin-project 0.4.30", ] [[package]] @@ -1704,16 +1734,19 @@ dependencies = [ [[package]] name = "holaplex-hub-core" -version = "0.4.1" -source = "git+https://github.com/holaplex/hub-core?branch=stable#b4980ed55425e025945ca9960a33e7062a75ab06" +version = "0.5.0" +source = "git+https://github.com/holaplex/hub-core?branch=stable#711b8a0c9a1056490dff05acadf5a2b354612f01" dependencies = [ "anyhow", "async-trait", + "backon", + "bs58 0.5.0", "chrono", "cid", "clap 4.3.21", "dotenv", "futures-util", + "holaplex-hub-core-macros", "holaplex-hub-core-schemas", "hostname", "num_cpus", @@ -1739,7 +1772,7 @@ dependencies = [ [[package]] name = "holaplex-hub-core-build" version = "0.2.1" -source = "git+https://github.com/holaplex/hub-core?branch=stable#b4980ed55425e025945ca9960a33e7062a75ab06" +source = "git+https://github.com/holaplex/hub-core?branch=stable#711b8a0c9a1056490dff05acadf5a2b354612f01" dependencies = [ "anyhow", "dotenv", @@ -1755,10 +1788,21 @@ dependencies = [ "url", ] +[[package]] +name = "holaplex-hub-core-macros" +version = "0.1.0" +source = "git+https://github.com/holaplex/hub-core?branch=stable#711b8a0c9a1056490dff05acadf5a2b354612f01" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", + "thiserror", +] + [[package]] name = "holaplex-hub-core-schemas" version = "0.3.1" -source = "git+https://github.com/holaplex/hub-core?branch=stable#b4980ed55425e025945ca9960a33e7062a75ab06" +source = "git+https://github.com/holaplex/hub-core?branch=stable#711b8a0c9a1056490dff05acadf5a2b354612f01" dependencies = [ "holaplex-hub-core-build", "prost", @@ -2626,7 +2670,16 @@ version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ef0f924a5ee7ea9cbcea77529dba45f8a9ba9f622419fe3386ca581a3ae9d5a" dependencies = [ - "pin-project-internal", + "pin-project-internal 0.4.30", +] + +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal 1.1.3", ] [[package]] @@ -2640,6 +2693,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "pin-project-internal" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + [[package]] name = "pin-project-lite" version = "0.2.12" @@ -3704,7 +3768,7 @@ dependencies = [ "ahash 0.8.3", "blake3", "block-buffer 0.10.4", - "bs58", + "bs58 0.4.0", "bv", "byteorder", "cc", @@ -3757,7 +3821,7 @@ dependencies = [ "blake3", "borsh 0.10.3", "borsh 0.9.3", - "bs58", + "bs58 0.4.0", "bv", "bytemuck", "cc", @@ -3801,7 +3865,7 @@ version = "1.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e7d686e405694cd6510cd77bb87d0eeda64ad3df08d3293278ba47ca78b8e5e" dependencies = [ - "bs58", + "bs58 0.4.0", "proc-macro2", "quote", "rustversion", @@ -4039,7 +4103,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651" dependencies = [ "cfg-if", - "fastrand", + "fastrand 2.0.0", "redox_syscall 0.3.5", "rustix", "windows-sys", diff --git a/api/Cargo.toml b/api/Cargo.toml index 348e4f0..a2ca25b 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -42,7 +42,7 @@ strum = { version = "0.24.1", features = ["derive"] } [dependencies.hub-core] package = "holaplex-hub-core" -version = "0.4.1" +version = "0.5.0" git = "https://github.com/holaplex/hub-core" branch = "stable" features = ["kafka", "credits", "asset_proxy"] diff --git a/api/src/dataloaders/collection_mints.rs b/api/src/dataloaders/collection_mints.rs index 21e2bc9..c456f78 100644 --- a/api/src/dataloaders/collection_mints.rs +++ b/api/src/dataloaders/collection_mints.rs @@ -1,10 +1,9 @@ -use std::collections::HashMap; +use std::{borrow::Cow, collections::HashMap}; use async_graphql::{dataloader::Loader as DataLoader, FieldError, Result}; use poem::async_trait; use sea_orm::prelude::*; -use super::mint_histories::lowercase_evm_addresses; use crate::{db::Connection, entities::collection_mints}; #[derive(Debug, Clone)] @@ -64,10 +63,11 @@ impl DataLoader for OwnerLoader { type Value = Vec; async fn load(&self, keys: &[String]) -> Result, Self::Error> { - let keys = lowercase_evm_addresses(keys); - let collection_mints = collection_mints::Entity::find() - .filter(collection_mints::Column::Owner.is_in(keys.iter().map(ToOwned::to_owned))) + .filter( + collection_mints::Column::Owner + .is_in(hub_core::util::downcase_evm_addresses(keys).map(Cow::into_owned)), + ) .all(self.db.get()) .await?; diff --git a/api/src/dataloaders/mint_histories.rs b/api/src/dataloaders/mint_histories.rs index a691cec..6d795af 100644 --- a/api/src/dataloaders/mint_histories.rs +++ b/api/src/dataloaders/mint_histories.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::{borrow::Cow, collections::HashMap}; use async_graphql::{dataloader::Loader as DataLoader, FieldError, Result}; use poem::async_trait; @@ -115,10 +115,11 @@ impl DataLoader for MinterLoader { type Value = Vec; async fn load(&self, keys: &[String]) -> Result, Self::Error> { - let keys = lowercase_evm_addresses(keys); - let mint_histories = mint_histories::Entity::find() - .filter(mint_histories::Column::Wallet.is_in(keys.iter().map(ToOwned::to_owned))) + .filter( + mint_histories::Column::Wallet + .is_in(hub_core::util::downcase_evm_addresses(keys).map(Cow::into_owned)), + ) .all(self.db.get()) .await?; @@ -135,15 +136,3 @@ impl DataLoader for MinterLoader { })) } } - -pub fn lowercase_evm_addresses(keys: &[String]) -> Vec { - keys.iter() - .map(|key| { - if key.starts_with("0x") { - key.to_lowercase() - } else { - key.clone() - } - }) - .collect::>() -} diff --git a/api/src/dataloaders/update_histories.rs b/api/src/dataloaders/update_histories.rs index aa0e458..30bb18e 100644 --- a/api/src/dataloaders/update_histories.rs +++ b/api/src/dataloaders/update_histories.rs @@ -37,7 +37,7 @@ impl DataLoader for UpdateMintHistoryLoader { acc.entry(history.mint_id).or_insert_with(Vec::new); acc.entry(history.mint_id) - .and_modify(|update_histories| update_histories.push(history.into())); + .and_modify(|update_histories| update_histories.push(history)); acc })) diff --git a/api/src/entities/collection_creators.rs b/api/src/entities/collection_creators.rs index 7277962..720ffc3 100644 --- a/api/src/entities/collection_creators.rs +++ b/api/src/entities/collection_creators.rs @@ -1,7 +1,7 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.0 use async_graphql::SimpleObject; -use sea_orm::{entity::prelude::*, Set}; +use sea_orm::entity::prelude::*; use crate::proto; @@ -53,12 +53,5 @@ impl Related for Entity { } impl ActiveModelBehavior for ActiveModel { - /// Will be triggered before insert / update - fn before_save(mut self, _insert: bool) -> Result { - if self.address.as_ref().starts_with("0x") { - self.address = Set(self.address.as_ref().to_lowercase()); - } - - Ok(self) - } + hub_core::before_save_evm_addrs!(address); } diff --git a/api/src/entities/collection_mints.rs b/api/src/entities/collection_mints.rs index 97de198..d13cc4e 100644 --- a/api/src/entities/collection_mints.rs +++ b/api/src/entities/collection_mints.rs @@ -1,7 +1,7 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.0 use async_graphql::{ComplexObject, Context, Error, Result, SimpleObject}; -use sea_orm::{entity::prelude::*, JoinType, QuerySelect, SelectTwo, Set}; +use sea_orm::{entity::prelude::*, JoinType, QuerySelect, SelectTwo}; use super::{ collections, @@ -195,20 +195,7 @@ impl Related for Entity { } impl ActiveModelBehavior for ActiveModel { - /// Will be triggered before insert / update - fn before_save(mut self, _insert: bool) -> Result { - if self.owner.as_ref().starts_with("0x") { - self.owner = Set(self.owner.as_ref().to_lowercase()); - } - - if let Some(a) = self.address.as_ref() { - if a.starts_with("0x") { - self.address = Set(Some(a.to_lowercase())); - } - } - - Ok(self) - } + hub_core::before_save_evm_addrs!(owner, address?); } impl Entity { diff --git a/api/src/entities/collections.rs b/api/src/entities/collections.rs index 297069b..e00687c 100644 --- a/api/src/entities/collections.rs +++ b/api/src/entities/collections.rs @@ -1,6 +1,6 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.0 -use sea_orm::{entity::prelude::*, Set}; +use sea_orm::entity::prelude::*; use super::sea_orm_active_enums::{Blockchain, CreationStatus}; @@ -26,16 +26,7 @@ pub struct Model { } impl ActiveModelBehavior for ActiveModel { - /// Will be triggered before insert / update - fn before_save(mut self, _insert: bool) -> Result { - if let Some(a) = self.address.as_ref() { - if a.starts_with("0x") { - self.address = Set(Some(a.to_lowercase())); - } - } - - Ok(self) - } + hub_core::before_save_evm_addrs!(address?); } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/api/src/entities/customer_wallets.rs b/api/src/entities/customer_wallets.rs index 5994887..75aa235 100644 --- a/api/src/entities/customer_wallets.rs +++ b/api/src/entities/customer_wallets.rs @@ -1,6 +1,6 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3 -use sea_orm::{entity::prelude::*, Set}; +use sea_orm::entity::prelude::*; use super::sea_orm_active_enums::Blockchain; @@ -16,14 +16,7 @@ pub struct Model { } impl ActiveModelBehavior for ActiveModel { - /// Will be triggered before insert / update - fn before_save(mut self, _insert: bool) -> Result { - if self.address.as_ref().starts_with("0x") { - self.address = Set(self.address.as_ref().to_lowercase()); - } - - Ok(self) - } + hub_core::before_save_evm_addrs!(address); } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/api/src/entities/mint_creators.rs b/api/src/entities/mint_creators.rs index fd0f53a..d3536ac 100644 --- a/api/src/entities/mint_creators.rs +++ b/api/src/entities/mint_creators.rs @@ -1,7 +1,7 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.5 use async_graphql::SimpleObject; -use sea_orm::{entity::prelude::*, Set}; +use sea_orm::entity::prelude::*; use crate::proto; @@ -17,14 +17,7 @@ pub struct Model { } impl ActiveModelBehavior for ActiveModel { - /// Will be triggered before insert / update - fn before_save(mut self, _insert: bool) -> Result { - if self.address.as_ref().starts_with("0x") { - self.address = Set(self.address.as_ref().to_lowercase()); - } - - Ok(self) - } + hub_core::before_save_evm_addrs!(address); } impl From for proto::Creator { diff --git a/api/src/entities/mint_histories.rs b/api/src/entities/mint_histories.rs index 34e10b1..435a05a 100644 --- a/api/src/entities/mint_histories.rs +++ b/api/src/entities/mint_histories.rs @@ -1,7 +1,7 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3 use async_graphql::{ComplexObject, Context, Result, SimpleObject}; -use sea_orm::{entity::prelude::*, Set}; +use sea_orm::entity::prelude::*; use super::{collection_mints::CollectionMint, sea_orm_active_enums::CreationStatus}; use crate::AppContext; @@ -30,14 +30,7 @@ pub struct Model { } impl ActiveModelBehavior for ActiveModel { - /// Will be triggered before insert / update - fn before_save(mut self, _insert: bool) -> Result { - if self.wallet.as_ref().starts_with("0x") { - self.wallet = Set(self.wallet.as_ref().to_lowercase()); - } - - Ok(self) - } + hub_core::before_save_evm_addrs!(wallet); } #[ComplexObject] diff --git a/api/src/entities/nft_transfers.rs b/api/src/entities/nft_transfers.rs index 656bcae..00569a5 100644 --- a/api/src/entities/nft_transfers.rs +++ b/api/src/entities/nft_transfers.rs @@ -1,6 +1,6 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.0 -use sea_orm::{entity::prelude::*, Set}; +use sea_orm::entity::prelude::*; /// A record of a transfer of an NFT. #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] @@ -22,18 +22,7 @@ pub struct Model { } impl ActiveModelBehavior for ActiveModel { - /// Will be triggered before insert / update - fn before_save(mut self, _insert: bool) -> Result { - if self.sender.as_ref().starts_with("0x") { - self.sender = Set(self.sender.as_ref().to_lowercase()); - } - - if self.recipient.as_ref().starts_with("0x") { - self.recipient = Set(self.recipient.as_ref().to_lowercase()); - } - - Ok(self) - } + hub_core::before_save_evm_addrs!(sender, recipient); } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/api/src/entities/project_wallets.rs b/api/src/entities/project_wallets.rs index 5f6709c..ddc73c8 100644 --- a/api/src/entities/project_wallets.rs +++ b/api/src/entities/project_wallets.rs @@ -1,6 +1,6 @@ //! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.0 -use sea_orm::{entity::prelude::*, Set}; +use sea_orm::entity::prelude::*; use super::sea_orm_active_enums::Blockchain; @@ -18,12 +18,5 @@ pub struct Model { pub enum Relation {} impl ActiveModelBehavior for ActiveModel { - /// Will be triggered before insert / update - fn before_save(mut self, _insert: bool) -> Result { - if self.wallet_address.as_ref().starts_with("0x") { - self.wallet_address = Set(self.wallet_address.as_ref().to_lowercase()); - } - - Ok(self) - } + hub_core::before_save_evm_addrs!(wallet_address); } From 7fccb684f45267a5b0df82d00534a35a2857a16e Mon Sep 17 00:00:00 2001 From: raykast Date: Wed, 16 Aug 2023 11:38:30 -0700 Subject: [PATCH 23/28] Fix handling of EVM addresses. --- Cargo.lock | 32 ++++++++++++++++++++++------ api/Cargo.toml | 6 +++--- api/src/entities/collection_mints.rs | 2 +- api/src/entities/collections.rs | 2 +- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ebe9ef..f24dead 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1734,8 +1734,8 @@ dependencies = [ [[package]] name = "holaplex-hub-core" -version = "0.5.0" -source = "git+https://github.com/holaplex/hub-core?branch=stable#711b8a0c9a1056490dff05acadf5a2b354612f01" +version = "0.5.1" +source = "git+https://github.com/holaplex/hub-core?branch=master#f436cb38795adec5963f8e6b2eb3b5b1ebbca2cd" dependencies = [ "anyhow", "async-trait", @@ -1756,6 +1756,7 @@ dependencies = [ "rand 0.8.5", "rdkafka", "reqwest", + "sea-orm", "serde_json", "serde_with", "strum", @@ -1769,6 +1770,25 @@ dependencies = [ "uuid", ] +[[package]] +name = "holaplex-hub-core-build" +version = "0.2.1" +source = "git+https://github.com/holaplex/hub-core?branch=master#f436cb38795adec5963f8e6b2eb3b5b1ebbca2cd" +dependencies = [ + "anyhow", + "dotenv", + "futures-util", + "hex", + "prost-build", + "reqwest", + "serde", + "sha2 0.10.7", + "tempfile", + "tokio", + "toml 0.5.11", + "url", +] + [[package]] name = "holaplex-hub-core-build" version = "0.2.1" @@ -1791,7 +1811,7 @@ dependencies = [ [[package]] name = "holaplex-hub-core-macros" version = "0.1.0" -source = "git+https://github.com/holaplex/hub-core?branch=stable#711b8a0c9a1056490dff05acadf5a2b354612f01" +source = "git+https://github.com/holaplex/hub-core?branch=master#f436cb38795adec5963f8e6b2eb3b5b1ebbca2cd" dependencies = [ "proc-macro2", "quote", @@ -1802,9 +1822,9 @@ dependencies = [ [[package]] name = "holaplex-hub-core-schemas" version = "0.3.1" -source = "git+https://github.com/holaplex/hub-core?branch=stable#711b8a0c9a1056490dff05acadf5a2b354612f01" +source = "git+https://github.com/holaplex/hub-core?branch=master#f436cb38795adec5963f8e6b2eb3b5b1ebbca2cd" dependencies = [ - "holaplex-hub-core-build", + "holaplex-hub-core-build 0.2.1 (git+https://github.com/holaplex/hub-core?branch=master)", "prost", ] @@ -1816,7 +1836,7 @@ dependencies = [ "async-graphql-poem", "async-trait", "holaplex-hub-core", - "holaplex-hub-core-build", + "holaplex-hub-core-build 0.2.1 (git+https://github.com/holaplex/hub-core?branch=stable)", "poem", "prost", "prost-types", diff --git a/api/Cargo.toml b/api/Cargo.toml index a2ca25b..38fcaac 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -42,10 +42,10 @@ strum = { version = "0.24.1", features = ["derive"] } [dependencies.hub-core] package = "holaplex-hub-core" -version = "0.5.0" +version = "0.5.1" git = "https://github.com/holaplex/hub-core" -branch = "stable" -features = ["kafka", "credits", "asset_proxy"] +branch = "master" +features = ["kafka", "credits", "asset_proxy", "sea-orm"] [build-dependencies.hub-core-build] package = "holaplex-hub-core-build" diff --git a/api/src/entities/collection_mints.rs b/api/src/entities/collection_mints.rs index 112ce5c..f10d6e8 100644 --- a/api/src/entities/collection_mints.rs +++ b/api/src/entities/collection_mints.rs @@ -227,7 +227,7 @@ impl Related for Entity { } impl ActiveModelBehavior for ActiveModel { - hub_core::before_save_evm_addrs!(owner, address?); + hub_core::before_save_evm_addrs!(owner, address); } impl Entity { diff --git a/api/src/entities/collections.rs b/api/src/entities/collections.rs index e00687c..a414d18 100644 --- a/api/src/entities/collections.rs +++ b/api/src/entities/collections.rs @@ -26,7 +26,7 @@ pub struct Model { } impl ActiveModelBehavior for ActiveModel { - hub_core::before_save_evm_addrs!(address?); + hub_core::before_save_evm_addrs!(address); } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] From f8a0ed8d36d04af8c666ec17ed882e591f7ebdb2 Mon Sep 17 00:00:00 2001 From: Kyle Espinola Date: Thu, 17 Aug 2023 14:03:45 +0200 Subject: [PATCH 24/28] fix: validate that mint is not an edition for updating --- api/src/mutations/mint.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/api/src/mutations/mint.rs b/api/src/mutations/mint.rs index 6c7c3e5..ef07878 100644 --- a/api/src/mutations/mint.rs +++ b/api/src/mutations/mint.rs @@ -538,6 +538,10 @@ impl Mutation { return Err(Error::new("Mint not created")); } + if mint.edition > 0 { + return Err(Error::new("Mint is an edition and cannot be updated")); + } + let collection = collection.ok_or(Error::new("Collection not found"))?; let blockchain = collection.blockchain; From f688eecdaa98c9b7f569cdc71059dd1c72329076 Mon Sep 17 00:00:00 2001 From: Abdul Basit Date: Fri, 18 Aug 2023 18:16:57 +0500 Subject: [PATCH 25/28] Migration to downcase polygon addresses --- migration/src/lib.rs | 2 + ...30818_163948_downcase_polygon_addresses.rs | 100 ++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 migration/src/m20230818_163948_downcase_polygon_addresses.rs diff --git a/migration/src/lib.rs b/migration/src/lib.rs index f065357..8d41c10 100644 --- a/migration/src/lib.rs +++ b/migration/src/lib.rs @@ -51,6 +51,7 @@ mod m20230718_111347_add_created_at_and_created_by_columns_to_collections; mod m20230725_135946_rename_purchases_to_mint_histories; mod m20230725_144506_drop_solana_collections_table; mod m20230807_090847_create_histories_table; +mod m20230818_163948_downcase_polygon_addresses; pub struct Migrator; @@ -109,6 +110,7 @@ impl MigratorTrait for Migrator { Box::new(m20230725_135946_rename_purchases_to_mint_histories::Migration), Box::new(m20230725_144506_drop_solana_collections_table::Migration), Box::new(m20230807_090847_create_histories_table::Migration), + Box::new(m20230818_163948_downcase_polygon_addresses::Migration), ] } } diff --git a/migration/src/m20230818_163948_downcase_polygon_addresses.rs b/migration/src/m20230818_163948_downcase_polygon_addresses.rs new file mode 100644 index 0000000..e74e0b7 --- /dev/null +++ b/migration/src/m20230818_163948_downcase_polygon_addresses.rs @@ -0,0 +1,100 @@ +use sea_orm_migration::{ + prelude::*, + sea_orm::{ConnectionTrait, Statement}, +}; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + let db = manager.get_connection(); + + let stmt = Statement::from_string( + manager.get_database_backend(), + r#"UPDATE collection_creators + SET address = LOWER(address) + WHERE SUBSTRING(address, 1, 2) = '0x';"# + .to_string(), + ); + + db.execute(stmt).await?; + + let stmt = Statement::from_string( + manager.get_database_backend(), + r#"UPDATE collection_mints + SET address = LOWER(address), owner=LOWER(owner) + WHERE SUBSTRING(owner, 1, 2) = '0x';"# + .to_string(), + ); + + db.execute(stmt).await?; + + let stmt = Statement::from_string( + manager.get_database_backend(), + r#"UPDATE collections + SET address = LOWER(address) + WHERE SUBSTRING(address, 1, 2) = '0x';"# + .to_string(), + ); + + db.execute(stmt).await?; + + let stmt = Statement::from_string( + manager.get_database_backend(), + r#"UPDATE customer_wallets + SET address = LOWER(address) + WHERE SUBSTRING(address, 1, 2) = '0x';"# + .to_string(), + ); + + db.execute(stmt).await?; + + let stmt = Statement::from_string( + manager.get_database_backend(), + r#"UPDATE mint_creators + SET address = LOWER(address) + WHERE SUBSTRING(address, 1, 2) = '0x';"# + .to_string(), + ); + + db.execute(stmt).await?; + + let stmt = Statement::from_string( + manager.get_database_backend(), + r#"UPDATE mint_histories + SET wallet = LOWER(wallet) + WHERE SUBSTRING(wallet, 1, 2) = '0x';"# + .to_string(), + ); + + db.execute(stmt).await?; + + let stmt = Statement::from_string( + manager.get_database_backend(), + r#"UPDATE nft_transfers + SET sender = LOWER(sender), recipient = LOWER(recipient) + WHERE SUBSTRING(sender, 1, 2) = '0x';"# + .to_string(), + ); + + db.execute(stmt).await?; + + let stmt = Statement::from_string( + manager.get_database_backend(), + r#"UPDATE project_wallets + SET wallet_address = LOWER(wallet_address) + WHERE SUBSTRING(wallet_address, 1, 2) = '0x';"# + .to_string(), + ); + + db.execute(stmt).await?; + + Ok(()) + } + + async fn down(&self, _manager: &SchemaManager) -> Result<(), DbErr> { + Ok(()) + } +} From ebbaa32cdd3d81e3e46c98150085c209070a3e08 Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Fri, 18 Aug 2023 20:40:19 +0500 Subject: [PATCH 26/28] return err if compressed mint is updated --- api/src/mutations/mint.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/api/src/mutations/mint.rs b/api/src/mutations/mint.rs index ef07878..53dd07b 100644 --- a/api/src/mutations/mint.rs +++ b/api/src/mutations/mint.rs @@ -542,6 +542,10 @@ impl Mutation { return Err(Error::new("Mint is an edition and cannot be updated")); } + if mint.compressed { + return Err(Error::new("Mint is compressed and cannot be updated")); + } + let collection = collection.ok_or(Error::new("Collection not found"))?; let blockchain = collection.blockchain; From 5f65ea5082d6da5b408f1e261528ecdb6f04be9e Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Mon, 21 Aug 2023 17:53:25 +0500 Subject: [PATCH 27/28] Update seller fee basis points for update mint --- api/src/mutations/mint.rs | 50 +++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/api/src/mutations/mint.rs b/api/src/mutations/mint.rs index 53dd07b..77f6b4a 100644 --- a/api/src/mutations/mint.rs +++ b/api/src/mutations/mint.rs @@ -552,8 +552,6 @@ impl Mutation { validate_creators(blockchain, &creators)?; validate_json(blockchain, &input.metadata_json)?; - let seller_fee_basis_points = input.seller_fee_basis_points.unwrap_or_default(); - let owner_address = fetch_owner(conn, collection.project_id, collection.blockchain).await?; if collection.blockchain == BlockchainEnum::Solana { @@ -583,6 +581,25 @@ impl Mutation { ) .await?; + let mut mint_am: collection_mints::ActiveModel = mint.clone().into(); + + let metadata_json = MetadataJson::new(input.metadata_json) + .upload(nft_storage) + .await? + .save(mint.id, db) + .await?; + + let update_history_am = update_histories::ActiveModel { + mint_id: Set(mint.id), + txn_signature: Set(None), + credit_deduction_id: Set(deduction_id.0), + created_by: Set(user_id), + status: Set(CreationStatus::Pending), + ..Default::default() + }; + + let update_history = update_history_am.insert(db.get()).await?; + let sfbp = mint.seller_fee_basis_points.try_into()?; conn.transaction::<_, (), DbErr>(|txn| { Box::pin(async move { mint_creators::Entity::delete_many() @@ -602,28 +619,16 @@ impl Mutation { metadata_json_model.delete(txn).await?; + if let Some(sfbp) = input.seller_fee_basis_points { + mint_am.seller_fee_basis_points = Set(sfbp.try_into().unwrap_or_default()); + mint_am.update(txn).await?; + } + Ok(()) }) }) .await?; - let metadata_json = MetadataJson::new(input.metadata_json) - .upload(nft_storage) - .await? - .save(mint.id, db) - .await?; - - let update_history_am = update_histories::ActiveModel { - mint_id: Set(mint.id), - txn_signature: Set(None), - credit_deduction_id: Set(deduction_id.0), - created_by: Set(user_id), - status: Set(CreationStatus::Pending), - ..Default::default() - }; - - let update_history = update_history_am.insert(db.get()).await?; - match collection.blockchain { BlockchainEnum::Solana => { solana @@ -640,14 +645,17 @@ impl Mutation { name: metadata_json.name, symbol: metadata_json.symbol, metadata_uri: metadata_json.uri, - seller_fee_basis_points: seller_fee_basis_points.into(), + seller_fee_basis_points: input + .seller_fee_basis_points + .unwrap_or(sfbp) + .try_into()?, creators: creators .into_iter() .map(TryFrom::try_from) .collect::>()?, }), collection_id: collection.id.to_string(), - mint_id: mint.id.to_string(), + mint_id: update_history.mint_id.to_string(), }, ) .await?; From f0165dee3fbe57d55c307dff63c6d943cf4e73d4 Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Wed, 23 Aug 2023 18:01:59 +0500 Subject: [PATCH 28/28] Fix: remove metadata_json delete from transaction --- api/src/mutations/mint.rs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/api/src/mutations/mint.rs b/api/src/mutations/mint.rs index 77f6b4a..9e53643 100644 --- a/api/src/mutations/mint.rs +++ b/api/src/mutations/mint.rs @@ -583,12 +583,6 @@ impl Mutation { let mut mint_am: collection_mints::ActiveModel = mint.clone().into(); - let metadata_json = MetadataJson::new(input.metadata_json) - .upload(nft_storage) - .await? - .save(mint.id, db) - .await?; - let update_history_am = update_histories::ActiveModel { mint_id: Set(mint.id), txn_signature: Set(None), @@ -611,14 +605,6 @@ impl Mutation { .exec(txn) .await?; - let metadata_json_model = metadata_jsons::Entity::find() - .filter(metadata_jsons::Column::Id.eq(mint.id)) - .one(txn) - .await? - .ok_or(DbErr::RecordNotFound("Metadata Json not found".to_string()))?; - - metadata_json_model.delete(txn).await?; - if let Some(sfbp) = input.seller_fee_basis_points { mint_am.seller_fee_basis_points = Set(sfbp.try_into().unwrap_or_default()); mint_am.update(txn).await?; @@ -629,6 +615,12 @@ impl Mutation { }) .await?; + let metadata_json = MetadataJson::new(input.metadata_json) + .upload(nft_storage) + .await? + .save(mint.id, db) + .await?; + match collection.blockchain { BlockchainEnum::Solana => { solana