diff --git a/Cargo.lock b/Cargo.lock index c5663bf4..f77ed9eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,9 +65,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ "getrandom 0.2.12", "once_cell", @@ -76,9 +76,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.6" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +checksum = "8b79b82693f705137f8fb9b37871d99e4f9a7df12b917eed79c3d3954830a60b" dependencies = [ "cfg-if", "getrandom 0.2.12", @@ -1527,7 +1527,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" dependencies = [ - "ahash 0.7.7", + "ahash 0.7.8", ] [[package]] @@ -1536,7 +1536,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.7", + "ahash 0.7.8", ] [[package]] @@ -1545,7 +1545,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.10", ] [[package]] @@ -3649,7 +3649,7 @@ version = "1.16.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7077f6495ccc313dff49c3e3f3ed03e49058258bae7fee77ac29ba0a474ba82" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.10", "blake3", "block-buffer 0.10.4", "bs58", @@ -3765,7 +3765,7 @@ version = "1.16.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5859de708bd12fb189f3c161cda03fdd341ffcf6be4fe787c7d730a30d589ac6" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.10", "bincode", "bv", "caps", diff --git a/programs/mpl-core/src/processor/burn.rs b/programs/mpl-core/src/processor/burn.rs index 9a840c4b..c1fdf206 100644 --- a/programs/mpl-core/src/processor/burn.rs +++ b/programs/mpl-core/src/processor/burn.rs @@ -5,8 +5,8 @@ use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult}; use crate::{ error::MplCoreError, instruction::accounts::BurnAccounts, - plugins::{CheckResult, Plugin, ValidationResult}, - state::{Asset, Compressible, CompressionProof, Key}, + plugins::{CheckResult, Plugin, PluginType, ValidationResult}, + state::{Asset, Authority, Compressible, CompressionProof, Key}, utils::{close_program_account, fetch_core_data, load_key, verify_proof}, }; @@ -25,62 +25,81 @@ pub(crate) fn burn<'a>(accounts: &'a [AccountInfo<'a>], args: BurnArgs) -> Progr assert_signer(payer)?; } - match load_key(ctx.accounts.asset_address, 0)? { - Key::HashedAsset => { - let compression_proof = args - .compression_proof - .ok_or(MplCoreError::MissingCompressionProof)?; - let (asset, _) = verify_proof(ctx.accounts.asset_address, &compression_proof)?; + let mut approved = false; - if ctx.accounts.authority.key != &asset.owner { - return Err(MplCoreError::InvalidAuthority.into()); - } - - // TODO: Check delegates in compressed case. + let plugins: Option)>> = + match load_key(ctx.accounts.asset_address, 0)? { + Key::HashedAsset => { + let compression_proof = args + .compression_proof + .as_ref() + .ok_or(MplCoreError::MissingCompressionProof)?; + let (asset, plugin_schemes) = + verify_proof(ctx.accounts.asset_address, compression_proof)?; - asset.wrap()?; - } - Key::Asset => { - let (asset, _, plugin_registry) = fetch_core_data::(ctx.accounts.asset_address)?; + if ctx.accounts.authority.key != &asset.owner { + return Err(MplCoreError::InvalidAuthority.into()); + } + asset.wrap()?; - let mut approved = false; - match Asset::check_transfer() { - CheckResult::CanApprove | CheckResult::CanReject => { - match asset.validate_burn(&ctx.accounts)? { - ValidationResult::Approved => { - approved = true; - } - ValidationResult::Rejected => { - return Err(MplCoreError::InvalidAuthority.into()) - } - ValidationResult::Pass => (), + Some( + plugin_schemes + .into_iter() + .map(|plugin_schema| { + ( + plugin_schema.plugin.clone(), + PluginType::from(&plugin_schema.plugin), + plugin_schema.authorities, + ) + }) + .collect(), + ) + } + Key::Asset => { + let (asset, _, plugin_registry) = + fetch_core_data::(ctx.accounts.asset_address)?; + match asset.validate_burn(&ctx.accounts)? { + ValidationResult::Approved => { + approved = true; } + ValidationResult::Rejected => return Err(MplCoreError::InvalidAuthority.into()), + ValidationResult::Pass => (), } - CheckResult::None => (), - }; - if let Some(plugin_registry) = plugin_registry { - for record in plugin_registry.registry { - if matches!( - record.plugin_type.check_transfer(), - CheckResult::CanApprove | CheckResult::CanReject - ) { - let result = Plugin::load(ctx.accounts.asset_address, record.offset)? - .validate_burn(&ctx.accounts, &args, &record.authorities)?; - if result == ValidationResult::Rejected { - return Err(MplCoreError::InvalidAuthority.into()); - } else if result == ValidationResult::Approved { - approved = true; - } + if let Some(plugin_registry) = plugin_registry { + let mut plugins = vec![]; + + for record in plugin_registry.registry { + let plugin = Plugin::load(ctx.accounts.asset_address, record.offset)?; + plugins.push((plugin, record.plugin_type, record.authorities)) } + Some(plugins) + } else { + None } - }; + } + _ => return Err(MplCoreError::IncorrectAccount.into()), + }; + + if plugins.is_some() { + for (plugin, plugin_type, authorities) in plugins.unwrap() { + if matches!( + plugin_type.check_burn(), + CheckResult::CanApprove | CheckResult::CanReject + ) { + let result = plugin.validate_burn(&ctx.accounts, &args, &authorities)?; - if !approved { - return Err(MplCoreError::InvalidAuthority.into()); + match result { + ValidationResult::Approved => approved = true, + ValidationResult::Pass => (), + ValidationResult::Rejected => return Err(MplCoreError::InvalidAuthority.into()), + } } } - _ => return Err(MplCoreError::IncorrectAccount.into()), + } + + if !approved { + return Err(MplCoreError::InvalidAuthority.into()); } close_program_account(ctx.accounts.asset_address, ctx.accounts.authority) diff --git a/programs/mpl-core/src/processor/transfer.rs b/programs/mpl-core/src/processor/transfer.rs index 8623b96d..ba8a7988 100644 --- a/programs/mpl-core/src/processor/transfer.rs +++ b/programs/mpl-core/src/processor/transfer.rs @@ -5,8 +5,8 @@ use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult}; use crate::{ error::MplCoreError, instruction::accounts::TransferAccounts, - plugins::{CheckResult, Plugin, ValidationResult}, - state::{Asset, Compressible, CompressionProof, HashedAsset, Key, SolanaAccount}, + plugins::{CheckResult, Plugin, PluginType, ValidationResult}, + state::{Asset, Authority, Compressible, CompressionProof, HashedAsset, Key, SolanaAccount}, utils::{fetch_core_data, load_key, verify_proof}, }; @@ -26,100 +26,89 @@ pub(crate) fn transfer<'a>(accounts: &'a [AccountInfo<'a>], args: TransferArgs) assert_signer(payer)?; } - match load_key(ctx.accounts.asset_address, 0)? { - Key::HashedAsset => { - let compression_proof = args - .compression_proof - .ok_or(MplCoreError::MissingCompressionProof)?; - let (mut asset, _) = verify_proof(ctx.accounts.asset_address, &compression_proof)?; - - if ctx.accounts.authority.key != &asset.owner { - return Err(MplCoreError::InvalidAuthority.into()); + let mut approved = false; + let (mut asset_outer, mut key_type) = (None, Key::HashedAsset); + let plugins: Option)>> = + match load_key(ctx.accounts.asset_address, 0)? { + Key::HashedAsset => { + let compression_proof = args + .compression_proof + .as_ref() + .ok_or(MplCoreError::MissingCompressionProof)?; + let (asset, plugin_schemes) = + verify_proof(ctx.accounts.asset_address, compression_proof)?; + if ctx.accounts.authority.key != &asset.owner { + return Err(MplCoreError::InvalidAuthority.into()); + } + asset_outer = Some(asset); + + Some( + plugin_schemes + .into_iter() + .map(|plugin_schema| { + ( + plugin_schema.plugin.clone(), + PluginType::from(&plugin_schema.plugin), + plugin_schema.authorities, + ) + }) + .collect(), + ) } - - // TODO: Check delegates in compressed case. - - asset.owner = *ctx.accounts.new_owner.key; - - asset.wrap()?; - - // Make a new hashed asset with updated owner and save to account. - HashedAsset::new(asset.hash()?).save(ctx.accounts.asset_address, 0) - } - Key::Asset => { - // let mut asset = Asset::load(ctx.accounts.asset_address, 0)?; - - // let mut authority_check: Result<(), ProgramError> = - // Err(MplCoreError::InvalidAuthority.into()); - // if asset.get_size() != ctx.accounts.asset_address.data_len() { - // solana_program::msg!("Fetch Plugin"); - // let (authorities, plugin, _) = - // fetch_plugin(ctx.accounts.asset_address, PluginType::Delegate)?; - - // solana_program::msg!("Assert authority"); - // authority_check = assert_authority(&asset, ctx.accounts.authority, &authorities); - - // if let Plugin::Delegate(delegate) = plugin { - // if delegate.frozen { - // return Err(MplCoreError::AssetIsFrozen.into()); - // } - // } - // } - - // match authority_check { - // Ok(_) => Ok::<(), ProgramError>(()), - // Err(_) => { - // if ctx.accounts.authority.key != &asset.owner { - // Err(MplCoreError::InvalidAuthority.into()) - // } else { - // Ok(()) - // } - // } - // }?; - - let (mut asset, _, plugin_registry) = - fetch_core_data::(ctx.accounts.asset_address)?; - - let mut approved = false; - match Asset::check_transfer() { - CheckResult::CanApprove | CheckResult::CanReject => { - match asset.validate_transfer(&ctx.accounts)? { - ValidationResult::Approved => { - approved = true; - } - ValidationResult::Rejected => { - return Err(MplCoreError::InvalidAuthority.into()) - } - ValidationResult::Pass => (), + Key::Asset => { + let (asset, _, plugin_registry) = + fetch_core_data::(ctx.accounts.asset_address)?; + match asset.validate_transfer(&ctx.accounts)? { + ValidationResult::Approved => { + approved = true; } + ValidationResult::Rejected => return Err(MplCoreError::InvalidAuthority.into()), + ValidationResult::Pass => (), } - CheckResult::None => (), - }; + (asset_outer, key_type) = (Some(asset), Key::Asset); + + if let Some(plugin_registry) = plugin_registry { + let mut plugins = vec![]; - if let Some(plugin_registry) = plugin_registry { - for record in plugin_registry.registry { - if matches!( - record.plugin_type.check_transfer(), - CheckResult::CanApprove | CheckResult::CanReject - ) { - let result = Plugin::load(ctx.accounts.asset_address, record.offset)? - .validate_transfer(&ctx.accounts, &args, &record.authorities)?; - if result == ValidationResult::Rejected { - return Err(MplCoreError::InvalidAuthority.into()); - } else if result == ValidationResult::Approved { - approved = true; - } + for record in plugin_registry.registry { + let plugin = Plugin::load(ctx.accounts.asset_address, record.offset)?; + plugins.push((plugin, record.plugin_type, record.authorities)) } + Some(plugins) + } else { + None + } + } + _ => return Err(MplCoreError::IncorrectAccount.into()), + }; + + if plugins.is_some() { + for (plugin, plugin_type, authorities) in plugins.unwrap() { + if matches!( + plugin_type.check_transfer(), + CheckResult::CanApprove | CheckResult::CanReject + ) { + let result = plugin.validate_transfer(&ctx.accounts, &args, &authorities)?; + + match result { + ValidationResult::Approved => approved = true, + ValidationResult::Pass => (), + ValidationResult::Rejected => return Err(MplCoreError::InvalidAuthority.into()), } - }; - - if !approved { - return Err(MplCoreError::InvalidAuthority.into()); } - - asset.owner = *ctx.accounts.new_owner.key; - asset.save(ctx.accounts.asset_address, 0) } - _ => Err(MplCoreError::IncorrectAccount.into()), + } + + if !approved { + return Err(MplCoreError::InvalidAuthority.into()); + } + + // cannot be None + let mut asset = asset_outer.unwrap(); + asset.owner = *ctx.accounts.new_owner.key; + match key_type { + Key::Asset => asset.save(ctx.accounts.asset_address, 0), + Key::HashedAsset => HashedAsset::new(asset.hash()?).save(ctx.accounts.asset_address, 0), + _ => unreachable!() } }