Skip to content

Commit

Permalink
Merge pull request #139 from holaplex/espi/1-of-1-mints
Browse files Browse the repository at this point in the history
Standalone Collections & 1:1 Mints
  • Loading branch information
kespinola authored Jul 18, 2023
2 parents 5241076 + fe25471 commit 7d18042
Show file tree
Hide file tree
Showing 31 changed files with 1,701 additions and 240 deletions.
4 changes: 2 additions & 2 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 = 19
sha512 = "94be29cc87e02f9622ba880302349b275262bc30546e6a6daacea541a6c1c740df9a185d0e18de782eda77ebf9c51c0e46c295d89abb9f7fb725b0ce9cfaf6f1"
version = 20
sha512 = "e1e47f595a3709db361e38d5995116a6fc03960a7e5f3c64e293454b062e72a95aa279d36161e7579209710d3f2e382efa559f8f380cc5a173ddc1b6ac44c259"

[[schemas]]
subject = "organization"
Expand Down
2 changes: 1 addition & 1 deletion api/proto.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ endpoint = "https://schemas.holaplex.tools"

[schemas]
organization = 5
nfts = 19
nfts = 20
customer = 2
treasury = 17
solana_nfts = 4
Expand Down
51 changes: 17 additions & 34 deletions api/src/blockchains/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pub mod polygon;
pub mod solana;

use hub_core::{anyhow::Result, uuid::Uuid};
use hub_core::anyhow::Result;

use crate::proto::NftEventKey;

Expand All @@ -15,42 +15,25 @@ pub struct TransactionResponse {
pub signed_message_signatures: Vec<String>,
}

/// A trait that defines the fundamental operations that can be performed
/// on a given blockchain for a specific edition of an NFT.
#[async_trait::async_trait]
pub trait Edition<A, B, C, D, E, M> {
/// Creates a new NFT on the blockchain. The specifics of the creation
/// process, such as the parameters it takes and the values it returns,
/// are dependent on the implementation of this method for the specific blockchain.
async fn create(&self, payload: A) -> Result<(M, TransactionResponse)>;

/// Mints a new instance of the NFT on the blockchain. The specifics of the minting
/// process, such as the parameters it takes and the values it returns,
/// are dependent on the implementation of this method for the specific blockchain.
async fn mint(&self, payload: B) -> Result<(M, TransactionResponse)>;

/// Updates an existing collection on the blockchain. The specifics of the update
/// process, such as the parameters it takes and the values it returns,
/// are dependent on the implementation of this method for the specific blockchain.
async fn update(&self, payload: C) -> Result<(M, TransactionResponse)>;

/// Transfers an NFT from one account to another on the blockchain. The specifics of the transfer
/// process, such as the parameters it takes and the values it returns,
/// are dependent on the implementation of this method for the specific blockchain.
async fn transfer(&self, payload: D) -> Result<(Uuid, TransactionResponse)>;

/// Retries a failed drop of an NFT on the blockchain. The specifics of the retry drop
/// process, such as the parameters it takes and the values it returns,
/// are dependent on the implementation of this method for the specific blockchain.
async fn retry_drop(&self, payload: E) -> Result<(M, TransactionResponse)>;
}

#[async_trait::async_trait]
pub trait Event<A, B, C, D> {
pub trait DropEvent<A, B, C> {
async fn create_drop(&self, key: NftEventKey, payload: A) -> Result<()>;
async fn retry_create_drop(&self, key: NftEventKey, payload: A) -> Result<()>;
async fn update_drop(&self, key: NftEventKey, payload: D) -> Result<()>;
async fn update_drop(&self, key: NftEventKey, payload: C) -> Result<()>;
async fn mint_drop(&self, key: NftEventKey, payload: B) -> Result<()>;
async fn retry_mint_drop(&self, key: NftEventKey, payload: B) -> Result<()>;
async fn transfer_asset(&self, key: NftEventKey, payload: C) -> Result<()>;
}

#[async_trait::async_trait]
pub trait CollectionEvent<A, B, C> {
async fn create_collection(&self, key: NftEventKey, payload: A) -> Result<()>;
async fn retry_create_collection(&self, key: NftEventKey, payload: A) -> Result<()>;
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_trait::async_trait]
pub trait TransferEvent<A> {
async fn transfer_asset(&self, key: NftEventKey, payload: A) -> Result<()>;
}
23 changes: 9 additions & 14 deletions api/src/blockchains/polygon.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use hub_core::{anyhow::Result, producer::Producer};

use super::Event;
use super::{DropEvent, TransferEvent};
use crate::proto::{
nft_events::Event::{
PolygonCreateDrop, PolygonMintDrop, PolygonRetryDrop, PolygonRetryMintDrop,
Expand All @@ -24,24 +24,15 @@ impl Polygon {
#[must_use]
pub fn event(
&self,
) -> impl Event<
CreateEditionTransaction,
MintEditionTransaction,
TransferPolygonAsset,
UpdateEdtionTransaction,
> {
) -> impl DropEvent<CreateEditionTransaction, MintEditionTransaction, UpdateEdtionTransaction>
+ TransferEvent<TransferPolygonAsset> {
self.clone()
}
}

#[async_trait::async_trait]
impl
Event<
CreateEditionTransaction,
MintEditionTransaction,
TransferPolygonAsset,
UpdateEdtionTransaction,
> for Polygon
impl DropEvent<CreateEditionTransaction, MintEditionTransaction, UpdateEdtionTransaction>
for Polygon
{
async fn create_drop(&self, key: NftEventKey, payload: CreateEditionTransaction) -> Result<()> {
let event = NftEvents {
Expand Down Expand Up @@ -100,13 +91,17 @@ impl

Ok(())
}
}

#[async_trait::async_trait]
impl TransferEvent<TransferPolygonAsset> for Polygon {
async fn transfer_asset(&self, key: NftEventKey, payload: TransferPolygonAsset) -> Result<()> {
let event = NftEvents {
event: Some(PolygonTransferAsset(payload)),
};

self.producer.send(Some(&event), Some(&key)).await?;

Ok(())
}
}
105 changes: 96 additions & 9 deletions api/src/blockchains/solana.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use hub_core::{anyhow::Result, producer::Producer};

use super::Event;
use super::{CollectionEvent, DropEvent, TransferEvent};
use crate::proto::{
nft_events::Event::{
SolanaCreateDrop, SolanaMintDrop, SolanaRetryDrop, SolanaRetryMintDrop,
SolanaTransferAsset, SolanaUpdateDrop,
SolanaCreateCollection, SolanaCreateDrop, SolanaMintDrop, SolanaMintToCollection,
SolanaRetryCreateCollection, SolanaRetryDrop, SolanaRetryMintDrop,
SolanaRetryMintToCollection, SolanaTransferAsset, SolanaUpdateCollection, SolanaUpdateDrop,
},
MetaplexMasterEditionTransaction, MintMetaplexEditionTransaction, NftEventKey, NftEvents,
MetaplexCertifiedCollectionTransaction, MetaplexMasterEditionTransaction,
MintMetaplexEditionTransaction, MintMetaplexMetadataTransaction, NftEventKey, NftEvents,
TransferMetaplexAssetTransaction,
};

Expand All @@ -24,22 +26,25 @@ impl Solana {
#[must_use]
pub fn event(
&self,
) -> impl Event<
) -> impl DropEvent<
MetaplexMasterEditionTransaction,
MintMetaplexEditionTransaction,
TransferMetaplexAssetTransaction,
MetaplexMasterEditionTransaction,
> + TransferEvent<TransferMetaplexAssetTransaction>
+ CollectionEvent<
MetaplexCertifiedCollectionTransaction,
MetaplexCertifiedCollectionTransaction,
MintMetaplexMetadataTransaction,
> {
self.clone()
}
}

#[async_trait::async_trait]
impl
Event<
DropEvent<
MetaplexMasterEditionTransaction,
MintMetaplexEditionTransaction,
TransferMetaplexAssetTransaction,
MetaplexMasterEditionTransaction,
> for Solana
{
Expand Down Expand Up @@ -112,13 +117,16 @@ impl

Ok(())
}
}

#[async_trait::async_trait]
impl TransferEvent<TransferMetaplexAssetTransaction> for Solana {
async fn transfer_asset(
&self,
key: NftEventKey,
payload: TransferMetaplexAssetTransaction,
) -> Result<()> {
let event: NftEvents = NftEvents {
let event = NftEvents {
event: Some(SolanaTransferAsset(payload)),
};

Expand All @@ -127,3 +135,82 @@ impl
Ok(())
}
}

#[async_trait::async_trait]
impl
CollectionEvent<
MetaplexCertifiedCollectionTransaction,
MetaplexCertifiedCollectionTransaction,
MintMetaplexMetadataTransaction,
> for Solana
{
async fn create_collection(
&self,
key: NftEventKey,
payload: MetaplexCertifiedCollectionTransaction,
) -> Result<()> {
let event = NftEvents {
event: Some(SolanaCreateCollection(payload)),
};

self.producer.send(Some(&event), Some(&key)).await?;

Ok(())
}

async fn retry_create_collection(
&self,
key: NftEventKey,
payload: MetaplexCertifiedCollectionTransaction,
) -> Result<()> {
let event = NftEvents {
event: Some(SolanaRetryCreateCollection(payload)),
};

self.producer.send(Some(&event), Some(&key)).await?;

Ok(())
}

async fn update_collection(
&self,
key: NftEventKey,
payload: MetaplexCertifiedCollectionTransaction,
) -> Result<()> {
let event = NftEvents {
event: Some(SolanaUpdateCollection(payload)),
};

self.producer.send(Some(&event), Some(&key)).await?;

Ok(())
}

async fn mint_to_collection(
&self,
key: NftEventKey,
payload: MintMetaplexMetadataTransaction,
) -> Result<()> {
let event = NftEvents {
event: Some(SolanaMintToCollection(payload)),
};

self.producer.send(Some(&event), Some(&key)).await?;

Ok(())
}

async fn retry_mint_to_collection(
&self,
key: NftEventKey,
payload: MintMetaplexMetadataTransaction,
) -> Result<()> {
let event = NftEvents {
event: Some(SolanaRetryMintToCollection(payload)),
};

self.producer.send(Some(&event), Some(&key)).await?;

Ok(())
}
}
6 changes: 3 additions & 3 deletions api/src/collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ use crate::{
collection_creators::ActiveModel as CollectionCreatorActiveModel,
collections::{ActiveModel, Model},
},
objects::CollectionCreator,
objects::Creator,
};

#[derive(Debug, Clone)]
pub struct Collection {
collection: ActiveModel,
creators: Option<Vec<CollectionCreator>>,
creators: Option<Vec<Creator>>,
}

impl Collection {
Expand All @@ -25,7 +25,7 @@ impl Collection {
}
}

pub fn creators(&mut self, creators: Vec<CollectionCreator>) -> &Collection {
pub fn creators(&mut self, creators: Vec<Creator>) -> &Collection {
self.creators = Some(creators);

self
Expand Down
54 changes: 54 additions & 0 deletions api/src/dataloaders/collection_drop.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use std::collections::HashMap;

use async_graphql::{dataloader::Loader as DataLoader, FieldError, Result};
use poem::async_trait;
use sea_orm::{prelude::*, JoinType, QuerySelect};

use crate::{
db::Connection,
entities::{collections, drops},
objects::Drop,
};

#[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<Uuid> for Loader {
type Error = FieldError;
type Value = Drop;

async fn load(&self, keys: &[Uuid]) -> Result<HashMap<Uuid, Self::Value>, Self::Error> {
let drops = drops::Entity::find()
.join(JoinType::InnerJoin, drops::Relation::Collections.def())
.select_also(collections::Entity)
.filter(drops::Column::CollectionId.is_in(keys.iter().map(ToOwned::to_owned)))
.all(self.db.get())
.await?;

drops
.into_iter()
.map(|(drop, collection)| {
Ok((
drop.collection_id,
Drop::new(
drop.clone(),
collection.ok_or(FieldError::new(format!(
"no collection for the drop {}",
drop.id
)))?,
),
))
})
.collect::<Result<HashMap<Uuid, Self::Value>>>()
}
}
6 changes: 6 additions & 0 deletions api/src/dataloaders/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
mod collection;
mod collection_drop;
mod collection_mints;
mod creators;
mod drop;
mod drops;
mod holders;
mod metadata_json;
mod project_collection;
mod project_collections;
mod purchases;

pub use collection::Loader as CollectionLoader;
pub use collection_drop::Loader as CollectionDropLoader;
pub use collection_mints::{
Loader as CollectionMintsLoader, OwnerLoader as CollectionMintsOwnerLoader,
};
Expand All @@ -18,6 +22,8 @@ pub use holders::Loader as HoldersLoader;
pub use metadata_json::{
AttributesLoader as MetadataJsonAttributesLoader, Loader as MetadataJsonLoader,
};
pub use project_collection::ProjectCollectionLoader;
pub use project_collections::ProjectCollectionsLoader;
pub use purchases::{
CollectionLoader as CollectionPurchasesLoader, DropLoader as DropPurchasesLoader,
};
Loading

0 comments on commit 7d18042

Please sign in to comment.