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

Update Collection Mint and support retry #36

Merged
merged 4 commits into from
Aug 10, 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
22 changes: 21 additions & 1 deletion consumer/src/backend.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use holaplex_hub_nfts_solana_core::proto::{
MetaplexMasterEditionTransaction, SolanaPendingTransaction, TransferMetaplexAssetTransaction,
UpdateSolanaMintPayload,
};
use holaplex_hub_nfts_solana_entity::collections;
use holaplex_hub_nfts_solana_entity::{collection_mints, collections, update_revisions};
use hub_core::prelude::*;
use solana_program::pubkey::Pubkey;

Expand Down Expand Up @@ -54,6 +55,13 @@ pub struct UpdateMasterEditionAddresses {
pub update_authority: Pubkey,
}

#[derive(Clone)]
pub struct UpdateCollectionMintAddresses {
pub payer: Pubkey,
pub metadata: Pubkey,
pub update_authority: Pubkey,
}

#[derive(Clone)]
pub struct TransferAssetAddresses {
pub owner: Pubkey,
Expand Down Expand Up @@ -101,6 +109,18 @@ pub trait CollectionBackend {
collection: &collections::Model,
txn: MetaplexMasterEditionTransaction,
) -> Result<TransactionResponse<UpdateMasterEditionAddresses>>;

fn update_mint(
&self,
collection: &collections::Model,
mint: &collection_mints::Model,
txn: UpdateSolanaMintPayload,
) -> Result<TransactionResponse<UpdateCollectionMintAddresses>>;

fn retry_update_mint(
&self,
revision: &update_revisions::Model,
) -> Result<TransactionResponse<UpdateCollectionMintAddresses>>;
}

pub trait MintBackend<T, R> {
Expand Down
119 changes: 115 additions & 4 deletions consumer/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ use holaplex_hub_nfts_solana_core::{
MintMetaplexMetadataTransaction, SolanaCompletedMintTransaction,
SolanaCompletedTransferTransaction, SolanaCompletedUpdateTransaction,
SolanaFailedTransaction, SolanaNftEventKey, SolanaNftEvents, SolanaPendingTransaction,
SolanaTransactionFailureReason, TransferMetaplexAssetTransaction,
SolanaTransactionFailureReason, TransferMetaplexAssetTransaction, UpdateSolanaMintPayload,
},
sea_orm::{DatabaseConnection, DbErr, Set},
sea_orm::{ActiveModelTrait, DatabaseConnection, DbErr, EntityTrait, Set},
Collection, CollectionMint, CompressionLeaf, Services,
};
use holaplex_hub_nfts_solana_entity::{collection_mints, collections, compression_leafs};
use holaplex_hub_nfts_solana_entity::{
collection_mints, collections, compression_leafs, update_revisions,
};
use hub_core::{
chrono::Utc,
prelude::*,
Expand All @@ -29,7 +31,7 @@ use solana_sdk::signature::Signature;
use crate::{
backend::{
CollectionBackend, MasterEditionAddresses, MintBackend, MintEditionAddresses,
MintMetaplexAddresses, TransferBackend,
MintMetaplexAddresses, TransferBackend, UpdateCollectionMintAddresses,
},
solana::{CompressedRef, EditionRef, Solana, SolanaAssetIdError, UncompressedRef},
};
Expand Down Expand Up @@ -109,6 +111,8 @@ pub enum EventKind {
UpdateCollection,
MintToCollection,
RetryMintToCollection,
UpdateCollectionMint,
RetryUpdateCollectionMint,
}

impl EventKind {
Expand All @@ -125,6 +129,8 @@ impl EventKind {
Self::UpdateCollection => "collection update",
Self::MintToCollection => "mint to collection",
Self::RetryMintToCollection => "mint to collection retry",
Self::UpdateCollectionMint => "collection mint update",
Self::RetryUpdateCollectionMint => "collection mint update retry",
}
}

Expand All @@ -145,6 +151,12 @@ impl EventKind {
EventKind::RetryMintToCollection => {
SolanaNftEvent::RetryMintToCollectionSigningRequested(tx)
},
EventKind::UpdateCollectionMint => {
SolanaNftEvent::UpdateCollectionMintSigningRequested(tx)
},
EventKind::RetryUpdateCollectionMint => {
SolanaNftEvent::RetryUpdateMintSigningRequested(tx)
},
}
}

Expand Down Expand Up @@ -286,6 +298,16 @@ impl EventKind {
address: collection_mint.mint,
})
},
Self::UpdateCollectionMint => {
SolanaNftEvent::UpdateCollectionMintSubmitted(SolanaCompletedUpdateTransaction {
signature,
})
},
Self::RetryUpdateCollectionMint => {
SolanaNftEvent::RetryUpdateMintSubmitted(SolanaCompletedUpdateTransaction {
signature,
})
},
})
}

Expand All @@ -302,6 +324,8 @@ impl EventKind {
Self::UpdateCollection => SolanaNftEvent::UpdateCollectionFailed(tx),
Self::MintToCollection => SolanaNftEvent::MintToCollectionFailed(tx),
Self::RetryMintToCollection => SolanaNftEvent::RetryMintToCollectionFailed(tx),
Self::UpdateCollectionMint => SolanaNftEvent::UpdateCollectionMintFailed(tx),
Self::RetryUpdateCollectionMint => SolanaNftEvent::RetryUpdateMintFailed(tx),
}
}
}
Expand Down Expand Up @@ -435,6 +459,29 @@ impl Processor {
)
.await
},
Some(NftEvent::SolanaUpdatedCollectionMint(payload)) => {
self.process_nft(
EventKind::UpdateCollectionMint,
&key,
self.update_collection_mint(
&UncompressedRef(self.solana()),
&key,
payload,
),
)
.await
},
Some(NftEvent::SolanaRetryUpdatedCollectionMint(_)) => {
self.process_nft(
EventKind::RetryUpdateCollectionMint,
&key,
self.retry_update_collection_mint(
&UncompressedRef(self.solana()),
&key,
),
)
.await
},
_ => Ok(()),
}
},
Expand Down Expand Up @@ -483,6 +530,14 @@ impl Processor {
self.process_treasury(EventKind::RetryCreateCollection, key, res)
.await
},
Some(TreasuryEvent::SolanaUpdateCollectionMintSigned(res)) => {
self.process_treasury(EventKind::UpdateCollectionMint, key, res)
.await
},
Some(TreasuryEvent::SolanaRetryUpdateCollectionMintSigned(res)) => {
self.process_treasury(EventKind::RetryUpdateCollectionMint, key, res)
.await
},
_ => Ok(()),
}
},
Expand Down Expand Up @@ -735,6 +790,62 @@ impl Processor {
Ok(tx.into())
}

async fn update_collection_mint<B: CollectionBackend>(
&self,
backend: &B,
key: &SolanaNftEventKey,
payload: UpdateSolanaMintPayload,
) -> ProcessResult<SolanaPendingTransaction> {
let collection_id = Uuid::parse_str(&payload.collection_id)?;
let collection = Collection::find_by_id(self.db.get(), collection_id)
.await?
.ok_or(ProcessorErrorKind::RecordNotFound)?;
let mint = CollectionMint::find_by_id(self.db.get(), key.id.parse()?)
.await?
.ok_or(ProcessorErrorKind::RecordNotFound)?;

let tx = backend
.update_mint(&collection, &mint, payload)
.map_err(ProcessorErrorKind::Solana)?;

let UpdateCollectionMintAddresses {
payer,
metadata,
update_authority,
} = tx.addresses.clone();
let msg_bytes = tx.serialized_message.clone();

let revision = update_revisions::ActiveModel {
id: Set(key.id.parse()?),
mint_id: Set(mint.id),
serialized_message: Set(msg_bytes),
payer: Set(payer.to_string()),
metadata: Set(metadata.to_string()),
update_authority: Set(update_authority.to_string()),
};

revision.insert(self.db.get()).await?;

Ok(tx.into())
}

async fn retry_update_collection_mint<B: CollectionBackend>(
&self,
backend: &B,
key: &SolanaNftEventKey,
) -> ProcessResult<SolanaPendingTransaction> {
let revision = update_revisions::Entity::find_by_id(Uuid::from_str(&key.id)?)
.one(self.db.get())
.await?
.ok_or(ProcessorErrorKind::RecordNotFound)?;

let tx = backend
.retry_update_mint(&revision)
.map_err(ProcessorErrorKind::Solana)?;

Ok(tx.into())
}

async fn transfer_asset(
&self,
_key: &SolanaNftEventKey,
Expand Down
121 changes: 118 additions & 3 deletions consumer/src/solana.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ use anchor_lang::{prelude::AccountMeta, AnchorDeserialize, InstructionData};
use holaplex_hub_nfts_solana_core::proto::{
treasury_events::SolanaTransactionResult, MasterEdition, MetaplexMasterEditionTransaction,
MetaplexMetadata, MintMetaplexEditionTransaction, MintMetaplexMetadataTransaction,
TransferMetaplexAssetTransaction,
TransferMetaplexAssetTransaction, UpdateSolanaMintPayload,
};
use holaplex_hub_nfts_solana_entity::{
collection_mints, collections, compression_leafs, update_revisions,
};
use holaplex_hub_nfts_solana_entity::{collection_mints, collections, compression_leafs};
use hub_core::{anyhow::Result, clap, prelude::*, thiserror, uuid::Uuid};
use mpl_bubblegum::state::metaplex_adapter::{
Collection, Creator as BubblegumCreator, TokenProgramVersion,
Expand Down Expand Up @@ -41,7 +43,8 @@ use crate::{
backend::{
CollectionBackend, MasterEditionAddresses, MintBackend, MintCompressedMintV1Addresses,
MintEditionAddresses, MintMetaplexAddresses, TransactionResponse, TransferAssetAddresses,
TransferBackend, TransferCompressedMintV1Addresses, UpdateMasterEditionAddresses,
TransferBackend, TransferCompressedMintV1Addresses, UpdateCollectionMintAddresses,
UpdateMasterEditionAddresses,
},
};

Expand Down Expand Up @@ -468,6 +471,118 @@ impl<'a> CollectionBackend for UncompressedRef<'a> {
},
})
}

fn update_mint(
&self,
collection: &collections::Model,
collection_mint: &collection_mints::Model,
payload: UpdateSolanaMintPayload,
) -> Result<TransactionResponse<UpdateCollectionMintAddresses>> {
let metadata = payload
.metadata
.ok_or(SolanaErrorNotFoundMessage::Metadata)?;
let payer: Pubkey = self.0.treasury_wallet_address;
let rpc = &self.0.rpc_client;

let MetaplexMetadata {
name,
symbol,
seller_fee_basis_points,
metadata_uri,
creators,
owner_address,
} = metadata;
let update_authority: Pubkey = owner_address.parse()?;
let mint_pubkey: Pubkey = collection_mint.mint.parse()?;

let (metadata, _) = Pubkey::find_program_address(
&[
b"metadata",
mpl_token_metadata::ID.as_ref(),
mint_pubkey.as_ref(),
],
&mpl_token_metadata::ID,
);

let blockhash = rpc.get_latest_blockhash()?;

let update_ins: Instruction = mpl_token_metadata::instruction::update_metadata_accounts_v2(
mpl_token_metadata::ID,
metadata,
update_authority,
None,
Some(DataV2 {
name,
symbol,
uri: metadata_uri,
seller_fee_basis_points: seller_fee_basis_points.try_into()?,
creators: Some(
creators
.into_iter()
.map(TryInto::try_into)
.collect::<Result<Vec<Creator>, _>>()?,
),
collection: Some(mpl_token_metadata::state::Collection {
verified: true,
key: collection.mint.parse()?,
}),
uses: None,
}),
None,
Some(true),
);

let message = solana_program::message::Message::new_with_blockhash(
&[update_ins],
Some(&payer),
&blockhash,
);

let serialized_message = message.serialize();

Ok(TransactionResponse {
serialized_message,
signatures_or_signers_public_keys: vec![
payer.to_string(),
update_authority.to_string(),
],
addresses: UpdateCollectionMintAddresses {
payer,
metadata,
update_authority,
},
})
}

fn retry_update_mint(
&self,
revision: &update_revisions::Model,
) -> Result<TransactionResponse<UpdateCollectionMintAddresses>> {
let rpc = &self.0.rpc_client;

let update_authority: Pubkey = revision.update_authority.parse()?;
let metadata = revision.metadata.parse()?;
let payer = Pubkey::from_str(&revision.payer)?;

let mut message: solana_program::message::Message =
bincode::deserialize(&revision.serialized_message)?;

let blockhash = rpc.get_latest_blockhash()?;
message.recent_blockhash = blockhash;

Ok(TransactionResponse {
serialized_message: message.serialize(),
signatures_or_signers_public_keys: vec![
payer.to_string(),
update_authority.to_string(),
],
addresses: UpdateCollectionMintAddresses {
payer,
metadata,
update_authority,
},
})
}
}

impl<'a> MintBackend<MintMetaplexEditionTransaction, MintEditionAddresses> for EditionRef<'a> {
Expand Down
12 changes: 6 additions & 6 deletions core/proto.lock
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
[[schemas]]
subject = "nfts"
version = 22
sha512 = "c9920f6a5792b067396c88e40b9bd2adfcb55b582734aff924a67a9d5841a5e2839fc734c1bbff66f402f9a9d8852ca5fef1339aaaa3d5b05aa7868ddfa375c1"
version = 25
sha512 = "90dadff6bc75b59bb79d9ed2a65d582923f9ce66b5915c020306571bb446d68ff6648543386838510a60081d7cbb14f43fa2ae22c4c8ecd85874bee4323dd26a"

[[schemas]]
subject = "solana_nfts"
version = 7
sha512 = "73570b9e58f91a06901ba6455986ce1a0d3675e33860d2447160d711a8cebcfb78cfc714fb08644ad83495dc8612b0b123203561af6d93d29ffb0256725047ba"
version = 9
sha512 = "312a84e8ae8b9222c7ec2b307d036dae0bd8dac4363e813c2fcffd5d7fba8741bd802953b1ec0a96baf57a7ce852debb724fcccf3b0bd8a27a9e4cc60344a56f"

[[schemas]]
subject = "treasury"
version = 19
sha512 = "af9c5b6f8f6aef713a686b9253ef87a2332e8a69b4e0adbeab3a587ef2b74c09b510e3b017bf75bc2d1e083846073dcfd39cd104d95a4a76406a3a7fa0dbe2fb"
version = 21
sha512 = "734cff313b8b4854b9a4c03cfd6f95f07b1fd86f8678393ab466443d9da4d6e7c9fc400bdbcc718d83e6c7711857941d4b6dc0ea5d1d926f05a7859a65a15509"
Loading
Loading