Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch mint's collection #200

Merged
merged 4 commits into from
Aug 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/cargo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
- name: Install latest nightly
uses: actions-rs/toolchain@v1
with:
toolchain: 1.71.0
toolchain: nightly-2022-12-11
override: true
components: rustfmt, clippy

Expand Down
12 changes: 6 additions & 6 deletions api/proto.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ sha512 = "d75800df0d4744c6b0f4d9a9952d3bfd0bb6b24a8babd19104cc11b54a525f85551b3c

[[schemas]]
subject = "nfts"
version = 26
sha512 = "8191626dbd6e222f24914589a77855e5f0f5122b7adc655ef7e84af0d9ef104715408db97cdf7843882aaa65cfcacc436a01e01b336f6758b0863ec5e007b709"
version = 27
sha512 = "ec52dffa482eb3beb72b1ae1745f3b8cb1b6d321d20fdc30078f4362c924b0f75ebe3dc53c54e5de92ea55163b64f09fe4e2b749c1bc5bc64d92f8356835eb90"

[[schemas]]
subject = "organization"
Expand All @@ -20,8 +20,8 @@ sha512 = "c5ddf43d2958ec690ee2261d0ff9808b67ce810d2fc4b6077f96f561929a920f03509f

[[schemas]]
subject = "solana_nfts"
version = 9
sha512 = "312a84e8ae8b9222c7ec2b307d036dae0bd8dac4363e813c2fcffd5d7fba8741bd802953b1ec0a96baf57a7ce852debb724fcccf3b0bd8a27a9e4cc60344a56f"
version = 10
sha512 = "1bcb166ab5dfdf4841d60caa07a4098dcec03d7e3b0e63adb090ed2f5fe990c1e13826867e8df7521ec631027d5a931a08865fd2cf2daa905807c4b7dca40213"

[[schemas]]
subject = "timestamp"
Expand All @@ -30,5 +30,5 @@ sha512 = "d167e0a143c813073eef8597f0b237e5a8eaf32abbf709724e8071b2dd73ce0438b82f

[[schemas]]
subject = "treasury"
version = 21
sha512 = "734cff313b8b4854b9a4c03cfd6f95f07b1fd86f8678393ab466443d9da4d6e7c9fc400bdbcc718d83e6c7711857941d4b6dc0ea5d1d926f05a7859a65a15509"
version = 22
sha512 = "bde788b07f818aa52e684dcbd91e1f1e3db82f242f616ec2a42ab6d412df33a1461677c229f2f9bae345938c2f325e6332a95caef2c7e01a47531af53e39bf03"
6 changes: 3 additions & 3 deletions api/proto.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ endpoint = "https://schemas.holaplex.tools"

[schemas]
organization = 5
nfts = 26
nfts = 27
customer = 2
treasury = 21
solana_nfts = 9
treasury = 22
solana_nfts = 10
polygon_nfts = 6
timestamp = 1
9 changes: 8 additions & 1 deletion api/src/blockchains/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ pub mod solana;

use hub_core::anyhow::Result;

use crate::proto::{NftEventKey, RetryUpdateSolanaMintPayload, UpdateSolanaMintPayload};
use crate::proto::{
NftEventKey, RetryUpdateSolanaMintPayload, SwitchCollectionPayload, UpdateSolanaMintPayload,
};

/// Represents a response from a transaction on the blockchain. This struct
/// provides the serialized message and the signatures of the signed message.
Expand Down Expand Up @@ -41,6 +43,11 @@ pub trait CollectionEvent<A, B, C> {
key: NftEventKey,
payload: RetryUpdateSolanaMintPayload,
) -> Result<()>;
async fn switch_collection(
&self,
key: NftEventKey,
payload: SwitchCollectionPayload,
) -> Result<()>;
}

#[async_trait::async_trait]
Expand Down
20 changes: 17 additions & 3 deletions api/src/blockchains/solana.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ use crate::proto::{
nft_events::Event::{
SolanaCreateCollection, SolanaCreateDrop, SolanaMintDrop, SolanaMintToCollection,
SolanaRetryCreateCollection, SolanaRetryDrop, SolanaRetryMintDrop,
SolanaRetryMintToCollection, SolanaRetryUpdatedCollectionMint, SolanaTransferAsset,
SolanaUpdateCollection, SolanaUpdateDrop, SolanaUpdatedCollectionMint,
SolanaRetryMintToCollection, SolanaRetryUpdatedCollectionMint,
SolanaSwitchMintCollectionRequested, SolanaTransferAsset, SolanaUpdateCollection,
SolanaUpdateDrop, SolanaUpdatedCollectionMint,
},
MetaplexMasterEditionTransaction, MintMetaplexEditionTransaction,
MintMetaplexMetadataTransaction, NftEventKey, NftEvents, RetryUpdateSolanaMintPayload,
TransferMetaplexAssetTransaction, UpdateSolanaMintPayload,
SwitchCollectionPayload, TransferMetaplexAssetTransaction, UpdateSolanaMintPayload,
};
#[derive(Clone)]
pub struct Solana {
Expand Down Expand Up @@ -240,4 +241,17 @@ impl
self.producer.send(Some(&event), Some(&key)).await?;
Ok(())
}

async fn switch_collection(
&self,
key: NftEventKey,
payload: SwitchCollectionPayload,
) -> Result<()> {
let event = NftEvents {
event: Some(SolanaSwitchMintCollectionRequested(payload)),
};

self.producer.send(Some(&event), Some(&key)).await?;
Ok(())
}
}
8 changes: 4 additions & 4 deletions api/src/dataloaders/collection_mints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use async_graphql::{dataloader::Loader as DataLoader, FieldError, Result};
use poem::async_trait;
use sea_orm::prelude::*;

use crate::{db::Connection, entities::collection_mints};
use crate::{db::Connection, entities::collection_mints, objects::CollectionMint};

#[derive(Debug, Clone)]
pub struct Loader {
Expand All @@ -21,7 +21,7 @@ impl Loader {
#[async_trait]
impl DataLoader<Uuid> for Loader {
type Error = FieldError;
type Value = Vec<collection_mints::CollectionMint>;
type Value = Vec<CollectionMint>;

async fn load(&self, keys: &[Uuid]) -> Result<HashMap<Uuid, Self::Value>, Self::Error> {
let collection_mints = collection_mints::Entity::find()
Expand Down Expand Up @@ -60,7 +60,7 @@ impl OwnerLoader {
#[async_trait]
impl DataLoader<String> for OwnerLoader {
type Error = FieldError;
type Value = Vec<collection_mints::CollectionMint>;
type Value = Vec<CollectionMint>;

async fn load(&self, keys: &[String]) -> Result<HashMap<String, Self::Value>, Self::Error> {
let collection_mints = collection_mints::Entity::find()
Expand Down Expand Up @@ -100,7 +100,7 @@ impl CollectionMintLoader {
#[async_trait]
impl DataLoader<Uuid> for CollectionMintLoader {
type Error = FieldError;
type Value = collection_mints::CollectionMint;
type Value = CollectionMint;

async fn load(&self, keys: &[Uuid]) -> Result<HashMap<Uuid, Self::Value>, Self::Error> {
let collection_mints = collection_mints::Entity::find()
Expand Down
2 changes: 2 additions & 0 deletions api/src/dataloaders/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ mod mint_histories;
mod nft_transfers;
mod project_collection;
mod project_collections;
mod switch_collection_histories;
mod update_histories;

pub use collection::Loader as CollectionLoader;
Expand All @@ -34,4 +35,5 @@ pub use mint_histories::{
pub use nft_transfers::CollectionMintTransfersLoader;
pub use project_collection::ProjectCollectionLoader;
pub use project_collections::ProjectCollectionsLoader;
pub use switch_collection_histories::SwitchCollectionHistoryLoader;
pub use update_histories::UpdateMintHistoryLoader;
50 changes: 50 additions & 0 deletions api/src/dataloaders/switch_collection_histories.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
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::switch_collection_histories};

#[derive(Debug, Clone)]
pub struct SwitchCollectionHistoryLoader {
pub db: Connection,
}

impl SwitchCollectionHistoryLoader {
#[must_use]
pub fn new(db: Connection) -> Self {
Self { db }
}
}

#[async_trait]
impl DataLoader<Uuid> for SwitchCollectionHistoryLoader {
type Error = FieldError;
type Value = Vec<switch_collection_histories::Model>;

async fn load(&self, keys: &[Uuid]) -> Result<HashMap<Uuid, Self::Value>, Self::Error> {
let conn = self.db.get();
let switch_histories = switch_collection_histories::Entity::find()
.filter(
switch_collection_histories::Column::CollectionMintId
.is_in(keys.iter().map(ToOwned::to_owned)),
)
.order_by(switch_collection_histories::Column::CreatedAt, Order::Desc)
.all(conn)
.await?;

Ok(switch_histories.into_iter().fold(
HashMap::new(),
|mut acc: HashMap<Uuid, Vec<switch_collection_histories::Model>>, switch_history| {
acc.entry(switch_history.collection_mint_id.clone())

Check warning on line 40 in api/src/dataloaders/switch_collection_histories.rs

View workflow job for this annotation

GitHub Actions / clippy/check/doc

using `clone` on type `holaplex_hub_core::uuid::Uuid` which implements the `Copy` trait
.or_insert_with(Vec::new);

acc.entry(switch_history.collection_mint_id.clone())

Check warning on line 43 in api/src/dataloaders/switch_collection_histories.rs

View workflow job for this annotation

GitHub Actions / clippy/check/doc

using `clone` on type `holaplex_hub_core::uuid::Uuid` which implements the `Copy` trait
.and_modify(|switch_histories| switch_histories.push(switch_history.into()));

Check warning on line 44 in api/src/dataloaders/switch_collection_histories.rs

View workflow job for this annotation

GitHub Actions / clippy/check/doc

useless conversion to the same type: `entities::switch_collection_histories::Model`

acc
},
))
}
}
154 changes: 2 additions & 152 deletions api/src/entities/collection_mints.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.0

use async_graphql::{ComplexObject, Context, Error, Result, SimpleObject};
use async_graphql::Result;
use sea_orm::{entity::prelude::*, JoinType, QuerySelect, SelectTwo};

use super::{
collections, mint_creators, mint_histories, nft_transfers,
sea_orm_active_enums::{Blockchain, CreationStatus},
update_histories,
};
use crate::{
objects::{Collection, MetadataJson},
AppContext,
};
use super::{collections, sea_orm_active_enums::CreationStatus};

#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "collection_mints")]
Expand All @@ -34,148 +26,6 @@ pub struct Model {
pub compressed: bool,
}

/// Represents a single NFT minted from a collection.
#[derive(Clone, Debug, PartialEq, Eq, SimpleObject)]
#[graphql(complex)]
pub struct CollectionMint {
/// The unique ID of the minted NFT.
pub id: Uuid,
/// The ID of the collection the NFT was minted from.
pub collection_id: Uuid,
/// The address of the NFT
/// On Solana this is the mint address.
/// On EVM chains it is the concatenation of the contract address and the token id `{contractAddress}:{tokenId}`.
pub address: Option<String>,
/// The wallet address of the owner of the NFT.
pub owner: String,
/// The status of the NFT creation.
pub creation_status: CreationStatus,
/// The unique ID of the creator of the NFT.
pub created_by: Uuid,
/// The date and time when the NFT was created.
pub created_at: DateTimeWithTimeZone,
/// The transaction signature associated with the NFT.
pub signature: Option<String>,
/// The unique edition number of the NFT.
pub edition: i64,
/// The seller fee basis points (ie royalties) for the NFT.
pub seller_fee_basis_points: i16,
/// credits deduction id
pub credits_deduction_id: Option<Uuid>,
/// Indicates if the NFT is compressed. Compression is only supported on Solana.
pub compressed: bool,
}

#[ComplexObject]
impl CollectionMint {
/// The collection the NFT was minted from.
async fn collection(&self, ctx: &Context<'_>) -> Result<Option<Collection>> {
let AppContext {
collection_loader, ..
} = ctx.data::<AppContext>()?;

collection_loader.load_one(self.collection_id).await
}

/// The metadata json associated to the collection.
/// [Metaplex v1.1.0 Standard](https://docs.metaplex.com/programs/token-metadata/token-standard)
async fn metadata_json(&self, ctx: &Context<'_>) -> Result<Option<MetadataJson>> {
let AppContext {
metadata_json_loader,
..
} = ctx.data::<AppContext>()?;
let collection = self.collection(ctx).await?.ok_or(Error::new(format!(
"Collection not found for collection mint {:?}",
&self.id
)))?;

match collection.blockchain {
Blockchain::Solana => metadata_json_loader.load_one(self.id).await,
Blockchain::Polygon => metadata_json_loader.load_one(self.collection_id).await,
Blockchain::Ethereum => Err(Error::new("Ethereum not supported")),
}
}

/// The update history of the mint.
async fn update_histories(
&self,
ctx: &Context<'_>,
) -> Result<Option<Vec<update_histories::Model>>> {
let AppContext {
update_mint_history_loader,
..
} = ctx.data::<AppContext>()?;

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<Option<Vec<mint_creators::Model>>> {
let AppContext {
mint_creators_loader,
..
} = ctx.data::<AppContext>()?;

mint_creators_loader.load_one(self.id).await
}

/// The record of the original mint.
async fn mint_history(&self, ctx: &Context<'_>) -> Result<Option<mint_histories::Model>> {
let AppContext {
collection_mint_mint_history_loader,
..
} = ctx.data::<AppContext>()?;

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<Option<Vec<nft_transfers::Model>>> {
let AppContext {
collection_mint_transfers_loader,
..
} = ctx.data::<AppContext>()?;

collection_mint_transfers_loader.load_one(self.id).await
}
}

impl From<Model> for CollectionMint {
fn from(
Model {
id,
collection_id,
address,
owner,
creation_status,
created_by,
created_at,
signature,
edition,
seller_fee_basis_points,
credits_deduction_id,
compressed,
}: Model,
) -> Self {
Self {
id,
collection_id,
address,
owner,
creation_status,
created_by,
created_at,
signature,
edition,
seller_fee_basis_points,
credits_deduction_id,
compressed,
}
}
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
Expand Down
4 changes: 2 additions & 2 deletions api/src/entities/mint_histories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
use async_graphql::{ComplexObject, Context, Result, SimpleObject};
use sea_orm::entity::prelude::*;

use super::{collection_mints::CollectionMint, sea_orm_active_enums::CreationStatus};
use crate::AppContext;
use super::sea_orm_active_enums::CreationStatus;
use crate::{objects::CollectionMint, AppContext};

/// A record of a minted NFT.
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, SimpleObject)]
Expand Down
1 change: 1 addition & 0 deletions api/src/entities/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ pub mod mint_histories;
pub mod nft_transfers;
pub mod project_wallets;
pub mod sea_orm_active_enums;
pub mod switch_collection_histories;
pub mod transfer_charges;
pub mod update_histories;
Loading
Loading