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

add support to index token extensions (mint + token account with extensions data) #175

Closed
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
1,362 changes: 714 additions & 648 deletions Cargo.lock

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions blockbuster/src/programs/token_extensions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,42 @@ pub struct MintAccountExtensions {
pub token_group_member: Option<ShadowTokenGroupMember>,
}

impl MintAccountExtensions {
pub fn is_some(&self) -> bool {
self.default_account_state.is_some()
|| self.confidential_transfer_mint.is_some()
|| self.confidential_transfer_account.is_some()
|| self.confidential_transfer_fee_config.is_some()
|| self.interest_bearing_config.is_some()
|| self.transfer_fee_config.is_some()
|| self.mint_close_authority.is_some()
|| self.permanent_delegate.is_some()
|| self.metadata_pointer.is_some()
|| self.metadata.is_some()
|| self.transfer_hook.is_some()
|| self.group_pointer.is_some()
|| self.token_group.is_some()
|| self.group_member_pointer.is_some()
|| self.token_group_member.is_some()
}
}

#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct TokenAccountExtensions {
pub confidential_transfer: Option<ShadowConfidentialTransferAccount>,
pub cpi_guard: Option<ShadowCpiGuard>,
pub memo_transfer: Option<ShadowMemoTransfer>,
pub transfer_fee_amount: Option<ShadowTransferFeeAmount>,
}

impl TokenAccountExtensions {
pub fn is_some(&self) -> bool {
self.confidential_transfer.is_some()
|| self.cpi_guard.is_some()
|| self.memo_transfer.is_some()
|| self.transfer_fee_amount.is_some()
}
}
#[derive(Debug, PartialEq)]
pub struct TokenAccount {
pub account: Account,
Expand Down
1 change: 1 addition & 0 deletions digital_asset_types/src/dao/extensions/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ impl Default for asset::Model {
mpl_core_plugins_json_version: None,
mpl_core_external_plugins: None,
mpl_core_unknown_external_plugins: None,
mint_extensions: None,
}
}
}
3 changes: 3 additions & 0 deletions digital_asset_types/src/dao/generated/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ pub struct Model {
pub mpl_core_plugins_json_version: Option<i32>,
pub mpl_core_external_plugins: Option<Json>,
pub mpl_core_unknown_external_plugins: Option<Json>,
pub mint_extensions: Option<Json>,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
Expand Down Expand Up @@ -100,6 +101,7 @@ pub enum Column {
MplCorePluginsJsonVersion,
MplCoreExternalPlugins,
MplCoreUnknownExternalPlugins,
MintExtensions,
}

#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
Expand Down Expand Up @@ -160,6 +162,7 @@ impl ColumnTrait for Column {
Self::MplCorePluginsJsonVersion => ColumnType::Integer.def().null(),
Self::MplCoreExternalPlugins => ColumnType::JsonBinary.def().null(),
Self::MplCoreUnknownExternalPlugins => ColumnType::JsonBinary.def().null(),
Self::MintExtensions => ColumnType::JsonBinary.def().null(),
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions digital_asset_types/src/dao/generated/token_accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub struct Model {
pub delegated_amount: i64,
pub slot_updated: i64,
pub token_program: Vec<u8>,
pub extensions: Option<Json>,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
Expand All @@ -38,6 +39,7 @@ pub enum Column {
DelegatedAmount,
SlotUpdated,
TokenProgram,
Extensions,
}

#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
Expand Down Expand Up @@ -69,6 +71,7 @@ impl ColumnTrait for Column {
Self::DelegatedAmount => ColumnType::BigInteger.def(),
Self::SlotUpdated => ColumnType::BigInteger.def(),
Self::TokenProgram => ColumnType::Binary.def(),
Self::Extensions => ColumnType::Json.def().null(),
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions digital_asset_types/src/dao/generated/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub struct Model {
pub close_authority: Option<Vec<u8>>,
pub extension_data: Option<Vec<u8>>,
pub slot_updated: i64,
pub extensions: Option<Json>,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
Expand All @@ -36,6 +37,7 @@ pub enum Column {
CloseAuthority,
ExtensionData,
SlotUpdated,
Extensions,
}

#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
Expand Down Expand Up @@ -66,6 +68,7 @@ impl ColumnTrait for Column {
Self::CloseAuthority => ColumnType::Binary.def().null(),
Self::ExtensionData => ColumnType::Binary.def().null(),
Self::SlotUpdated => ColumnType::BigInteger.def(),
Self::Extensions => ColumnType::JsonBinary.def().null(),
}
}
}
Expand Down
27 changes: 27 additions & 0 deletions digital_asset_types/src/dapi/common/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use log::warn;
use mime_guess::Mime;

use sea_orm::DbErr;
use serde_json::Map;
use serde_json::Value;
use std::cmp::Ordering;
use std::collections::HashMap;
Expand Down Expand Up @@ -47,6 +48,30 @@ pub fn file_from_str(str: String) -> File {
}
}

fn filter_non_null_fields(value: Option<&Value>) -> Option<Value> {
match value {
Some(Value::Null) => None,
Some(Value::Object(map)) => {
if map.values().all(|v| matches!(v, Value::Null)) {
None
} else {
let filtered_map: Map<String, Value> = map
.into_iter()
.filter(|(_k, v)| !matches!(v, Value::Null))
.map(|(k, v)| (k.clone(), v.clone()))
.collect();

if filtered_map.is_empty() {
None
} else {
Some(Value::Object(filtered_map))
}
}
}
_ => value.cloned(),
}
}

pub fn build_asset_response(
assets: Vec<FullAsset>,
limit: u64,
Expand Down Expand Up @@ -377,6 +402,7 @@ pub fn asset_to_rpc(asset: FullAsset, options: &Options) -> Result<RpcAsset, DbE
_ => None,
};

let mint_ext = filter_non_null_fields(asset.mint_extensions.as_ref());
Ok(RpcAsset {
interface: interface.clone(),
id: bs58::encode(asset.id).into_string(),
Expand Down Expand Up @@ -449,6 +475,7 @@ pub fn asset_to_rpc(asset: FullAsset, options: &Options) -> Result<RpcAsset, DbE
mpl_core_info,
external_plugins: asset.mpl_core_external_plugins,
unknown_external_plugins: asset.mpl_core_unknown_external_plugins,
mint_extensions: mint_ext,
})
}

Expand Down
2 changes: 2 additions & 0 deletions digital_asset_types/src/rpc/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,4 +398,6 @@ pub struct Asset {
pub external_plugins: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub unknown_external_plugins: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mint_extensions: Option<Value>,
}
1 change: 1 addition & 0 deletions digital_asset_types/tests/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ pub fn create_asset(
mpl_core_plugins_json_version: None,
mpl_core_external_plugins: None,
mpl_core_unknown_external_plugins: None,
mint_extensions: None,
},
)
}
Expand Down
Binary file not shown.
Binary file not shown.
1 change: 1 addition & 0 deletions integration_tests/tests/integration_tests/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ mod common;
mod general_scenario_tests;
mod mpl_core_tests;
mod regular_nft_tests;
mod token_extensions_tests;
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
source: integration_tests/tests/integration_tests/token_extensions_tests.rs
expression: response
---
{
"interface": "V1_NFT",
"id": "BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y",
"content": {
"$schema": "https://schema.metaplex.com/nft1.0.json",
"json_uri": "https://acme.com/demo.json",
"files": [],
"metadata": {
"name": "DAS Dev",
"symbol": "DAS"
},
"links": {}
},
"authorities": [
{
"address": "Em34oqDQYQZ9b6ycPHD28K47mttrRsdNu1S1pgK6NtPL",
"scopes": [
"full"
]
}
],
"compression": {
"eligible": false,
"compressed": false,
"data_hash": "",
"creator_hash": "",
"asset_hash": "",
"tree": "",
"seq": 0,
"leaf_id": 0
},
"grouping": [],
"royalty": {
"royalty_model": "creators",
"target": null,
"percent": 0.0,
"basis_points": 0,
"primary_sale_happened": false,
"locked": false
},
"creators": [],
"ownership": {
"frozen": false,
"delegated": false,
"delegate": null,
"ownership_model": "single",
"owner": "Em34oqDQYQZ9b6ycPHD28K47mttrRsdNu1S1pgK6NtPL"
},
"supply": {
"print_max_supply": 0,
"print_current_supply": 0,
"edition_nonce": null
},
"mutable": true,
"burnt": false,
"mint_extensions": {
"metadata": {
"uri": "https://acme.com/demo.json",
"mint": "BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y",
"name": "DAS Dev",
"symbol": "DAS",
"update_authority": "Em34oqDQYQZ9b6ycPHD28K47mttrRsdNu1S1pgK6NtPL",
"additional_metadata": []
},
"metadata_pointer": {
"authority": "Em34oqDQYQZ9b6ycPHD28K47mttrRsdNu1S1pgK6NtPL",
"metadata_address": "BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use function_name::named;

use das_api::api::{self, ApiContract};

use itertools::Itertools;

use serial_test::serial;

use super::common::*;

#[tokio::test]
#[serial]
#[named]
async fn test_token_extensions_get_asset() {
let name = trim_test_name(function_name!());
let setup = TestSetup::new_with_options(
name.clone(),
TestSetupOptions {
network: Some(Network::Devnet),
},
)
.await;

let seeds: Vec<SeedEvent> = seed_accounts([
"BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y",
"AXKwjfsx6qpiw3RkwUbQZgjm9t6cpf6gnvGmNJPunerx",
]);

apply_migrations_and_delete_data(setup.db.clone()).await;
index_seed_events(&setup, seeds.iter().collect_vec()).await;

let request = r#"
{
"id": "BPU5vrAHafRuVeK33CgfdwTKSsmC4p6t3aqyav3cFF7Y"
}
"#;

let request: api::GetAsset = serde_json::from_str(request).unwrap();
let response = setup.das_api.get_asset(request).await.unwrap();

insta::assert_json_snapshot!(name, response);
}
2 changes: 2 additions & 0 deletions migration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ mod m20240116_130744_add_update_metadata_ix;
mod m20240117_120101_alter_creator_indices;
mod m20240124_173104_add_tree_seq_index_to_cl_audits_v2;
mod m20240124_181900_add_slot_updated_column_per_update_type;
mod m20240219_115532_add_extensions_column;
mod m20240313_120101_add_mpl_core_plugins_columns;
mod m20240319_120101_add_mpl_core_enum_vals;
mod m20240320_120101_add_mpl_core_info_items;
Expand Down Expand Up @@ -90,6 +91,7 @@ impl MigratorTrait for Migrator {
Box::new(m20240117_120101_alter_creator_indices::Migration),
Box::new(m20240124_173104_add_tree_seq_index_to_cl_audits_v2::Migration),
Box::new(m20240124_181900_add_slot_updated_column_per_update_type::Migration),
Box::new(m20240219_115532_add_extensions_column::Migration),
Box::new(m20240313_120101_add_mpl_core_plugins_columns::Migration),
Box::new(m20240319_120101_add_mpl_core_enum_vals::Migration),
Box::new(m20240320_120101_add_mpl_core_info_items::Migration),
Expand Down
59 changes: 59 additions & 0 deletions migration/src/m20240219_115532_add_extensions_column.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use sea_orm_migration::{
prelude::*,
sea_orm::{ConnectionTrait, DatabaseBackend, Statement},
};

#[derive(DeriveMigrationName)]
pub struct Migration;

#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
let connection = manager.get_connection();

connection
.execute(Statement::from_string(
DatabaseBackend::Postgres,
"ALTER TABLE asset ADD COLUMN mint_extensions jsonb;".to_string(),
))
.await?;
connection
.execute(Statement::from_string(
DatabaseBackend::Postgres,
"ALTER TABLE tokens ADD COLUMN extensions jsonb;".to_string(),
))
.await?;
connection
.execute(Statement::from_string(
DatabaseBackend::Postgres,
"ALTER TABLE token_accounts ADD COLUMN extensions jsonb;".to_string(),
))
.await?;
Ok(())
}

async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
let connection = manager.get_connection();

connection
.execute(Statement::from_string(
DatabaseBackend::Postgres,
"ALTER TABLE asset DROP COLUMN mint_extensions;".to_string(),
))
.await?;
connection
.execute(Statement::from_string(
DatabaseBackend::Postgres,
"ALTER TABLE tokens DROP COLUMN extensions;".to_string(),
))
.await?;
connection
.execute(Statement::from_string(
DatabaseBackend::Postgres,
"ALTER TABLE token_accounts DROP COLUMN extensions;".to_string(),
))
.await?;

Ok(())
}
}
2 changes: 1 addition & 1 deletion program_transformers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ sqlx = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["time"] }
tracing = { workspace = true }

spl-token-2022 = { workspace = true }
[lints]
workspace = true
Loading
Loading