Skip to content

Commit

Permalink
Merge pull request #12 from holaplex/ryans/compression
Browse files Browse the repository at this point in the history
Compressed NFTs
  • Loading branch information
kespinola authored Jul 24, 2023
2 parents 6d3f5ff + a2c2215 commit d8f51c0
Show file tree
Hide file tree
Showing 18 changed files with 1,981 additions and 1,027 deletions.
709 changes: 519 additions & 190 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 0 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
[workspace]
members = ["consumer", "core", "entity", "migration", "indexer"]
resolver = "2"

[workspace.dependencies]
holaplex-hub-nfts-solana-core = { path = "core" }
holaplex-hub-nfts-solana-entity = { path = "entity" }
8 changes: 7 additions & 1 deletion consumer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,28 @@ categories = ["cryptography::cryptocurrencies", "web-programming"]
[lib]

[dependencies]
anchor-lang = "0.26.0"
bincode = "1.3.3"

serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.93"
solana-program = "1.14.8"
solana-client = "1.14.8"
spl-account-compression = "0.1.10"
spl-noop = "0.1.3"
spl-token = "3.5.0"
solana-sdk = "1.14.8"
spl-associated-token-account = "1.1.2"
mpl-bubblegum = "0.8.0"
mpl-token-metadata = "1.8.3"
holaplex-hub-nfts-solana-core = { path = "../core" }
holaplex-hub-nfts-solana-entity = { path = "../entity" }
jsonrpsee = { version = "0.18.2", features = ["macros", "http-client"] }
bs58 = "0.5.0"

[dependencies.hub-core]
package = "holaplex-hub-core"
version = "0.2.0"
git = "https://github.com/holaplex/hub-core"
branch = "stable"
features = ["kafka"]
features = ["kafka"]
141 changes: 141 additions & 0 deletions consumer/src/asset_api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
mod b58 {
use serde::{de::Visitor, Deserializer, Serializer};

pub fn serialize<S: Serializer>(bytes: &[u8], ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_str(&bs58::encode(bytes).into_string())
}

pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result<Vec<u8>, D::Error> {
struct Vis;

impl<'a> Visitor<'a> for Vis {
type Value = Vec<u8>;

fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str("a base58-encoded string")
}

fn visit_str<E: serde::de::Error>(self, s: &str) -> Result<Self::Value, E> {
bs58::decode(s).into_vec().map_err(E::custom)
}
}

de.deserialize_str(Vis)
}
}

#[derive(serde::Serialize, serde::Deserialize)]
pub struct Base58(#[serde(with = "b58")] pub Vec<u8>);

impl From<Vec<u8>> for Base58 {
fn from(v: Vec<u8>) -> Self {
Self(v)
}
}

impl From<Base58> for Vec<u8> {
fn from(Base58(v): Base58) -> Self {
v
}
}

#[derive(serde::Serialize, serde::Deserialize)]
pub struct Asset {
pub interface: String,
pub id: Base58,
pub content: serde_json::Value,
pub authorities: Vec<AssetAuthority>,
pub compression: AssetCompression,
pub grouping: Vec<AssetGrouping>,
pub royalty: AssetRoyalty,
pub creators: Vec<AssetCreator>,
pub ownership: AssetOwnership,
pub supply: Option<u32>,
pub mutable: bool,
}

#[derive(serde::Serialize, serde::Deserialize)]
pub struct AssetAuthority {
pub address: Base58,
pub scopes: Vec<String>,
}

#[derive(serde::Serialize, serde::Deserialize)]
pub struct AssetCompression {
pub eligible: bool,
pub compressed: bool,
pub data_hash: Base58,
pub creator_hash: Base58,
pub asset_hash: Base58,
pub tree: Base58,
pub seq: u32,
pub leaf_id: u32,
}

#[derive(serde::Serialize, serde::Deserialize)]
pub struct AssetGrouping {
pub group_key: String,
pub group_value: Base58,
}

#[derive(serde::Serialize, serde::Deserialize)]
pub struct AssetRoyalty {
pub royalty_model: String,
pub target: Option<serde_json::Number>, // TODO: what type is this
pub percent: serde_json::Number, // TODO: this is fractional, use BCD to avoid rounding error
pub basis_points: u32,
pub primary_sale_happened: bool,
pub locked: bool,
}

#[derive(serde::Serialize, serde::Deserialize)]
pub struct AssetCreator {
pub address: Base58,
pub share: u32,
pub verified: bool,
}

#[derive(serde::Serialize, serde::Deserialize)]
pub struct AssetOwnership {
pub frozen: bool,
pub delegated: bool,
pub delegate: Base58,
pub ownership_model: String,
pub owner: Base58,
}

#[derive(serde::Serialize, serde::Deserialize)]
pub struct AssetProof {
pub root: Base58,
pub proof: Vec<Base58>,
pub node_index: u32,
pub leaf: Base58,
pub tree_id: Base58,
}

#[jsonrpsee::proc_macros::rpc(client)]
pub trait Rpc {
#[method(name = "getAsset", param_kind = map)]
fn get_asset(&self, id: &str) -> Result<Asset, Error>;

#[method(name = "getAssetProof", param_kind = map)]
fn get_asset_proof(&self, id: &str) -> Result<AssetProof, Error>;

// Supposedly Triton offers these but their docs were crashing my browser
// so I don't know what the signatures are.

// #[method(name = "getAssetsByAuthority")]
// fn get_assets_by_authority(&self);

// #[method(name = "getAssetsByOwner")]
// fn get_assets_by_owner(&self);

// #[method(name = "getAssetsByGroup")]
// fn get_assets_by_group(&self);

// #[method(name = "getAssetsByCreator")]
// fn get_assets_by_creator(&self);

// #[method(name = "searchAssets")]
// fn search_assets(&self);
}
110 changes: 110 additions & 0 deletions consumer/src/backend.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
use holaplex_hub_nfts_solana_core::proto::{
MetaplexMasterEditionTransaction, SolanaPendingTransaction, TransferMetaplexAssetTransaction,
};
use holaplex_hub_nfts_solana_entity::{collection_mints, collections};
use hub_core::prelude::*;
use solana_program::pubkey::Pubkey;

#[derive(Clone)]
pub struct MasterEditionAddresses {
pub metadata: Pubkey,
pub associated_token_account: Pubkey,
pub owner: Pubkey,
pub master_edition: Pubkey,
pub mint: Pubkey,
pub update_authority: Pubkey,
}

#[derive(Clone)]
pub struct MintEditionAddresses {
pub edition: Pubkey,
pub mint: Pubkey,
pub metadata: Pubkey,
pub owner: Pubkey,
pub associated_token_account: Pubkey,
pub recipient: Pubkey,
}

#[derive(Clone)]
pub struct MintMetaplexAddresses {
pub mint: Pubkey,
pub metadata: Pubkey,
pub owner: Pubkey,
pub associated_token_account: Pubkey,
pub recipient: Pubkey,
pub update_authority: Pubkey,
}

#[derive(Clone)]
pub struct MintCompressedMintV1Addresses {
pub owner: Pubkey,
pub recipient: Pubkey,
}

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

#[derive(Clone)]
pub struct TransferAssetAddresses {
pub owner: Pubkey,
pub recipient: Pubkey,
pub recipient_associated_token_account: Pubkey,
pub owner_associated_token_account: Pubkey,
}

/// Represents a response from a transaction on the blockchain. This struct
/// provides the serialized message and the signatures of the signed message.
pub struct TransactionResponse<A> {
/// The serialized version of the message from the transaction.
pub serialized_message: Vec<u8>,

/// The signatures of the signed message or the public keys of wallets that should sign the transaction. Order matters.
pub signatures_or_signers_public_keys: Vec<String>,

/// Addresses that are related to the transaction.
pub addresses: A,
}

impl<A> From<TransactionResponse<A>> for SolanaPendingTransaction {
fn from(
TransactionResponse {
serialized_message,
signatures_or_signers_public_keys,
..
}: TransactionResponse<A>,
) -> Self {
Self {
serialized_message,
signatures_or_signers_public_keys,
}
}
}

pub trait CollectionBackend {
fn create(
&self,
txn: MetaplexMasterEditionTransaction,
) -> Result<TransactionResponse<MasterEditionAddresses>>;

fn update(
&self,
collection: &collections::Model,
txn: MetaplexMasterEditionTransaction,
) -> Result<TransactionResponse<UpdateMasterEditionAddresses>>;
}

pub trait MintBackend<T, R> {
fn mint(&self, collection: &collections::Model, txn: T) -> Result<TransactionResponse<R>>;
}

#[async_trait]
pub trait TransferBackend {
async fn transfer(
&self,
collection_mint: &collection_mints::Model,
txn: TransferMetaplexAssetTransaction,
) -> Result<TransactionResponse<TransferAssetAddresses>>;
}
Loading

0 comments on commit d8f51c0

Please sign in to comment.