use std::mem::size_of;
use spl_account_compression::{error::AccountCompressionError, ConcurrentMerkleTree};
use crate::state::{AddressContainer, IndexedReference, Info, PublicInfo, User};
use {
crate::{
errors::ErrorCode,
state::{Action, ActionType, DelegateAuthority, ServiceDelegation},
},
anchor_lang::prelude::*,
};
pub fn assert_authority<'info>(
action: Action,
index: Option<u8>,
signer_key: Pubkey,
authority: Option<Pubkey>,
delegate_authority: &Option<Account<'info, DelegateAuthority>>,
) -> Result<()> {
match action.action_type {
ActionType::Public => Ok(()),
ActionType::Restricted {
delegations: action_delegations,
} => {
if let Some(authority) = authority {
if authority == signer_key {
return Ok(());
}
Err(ErrorCode::Unauthorized.into())
} else if let Some(delegate_authority) = delegate_authority {
for action_delegation in action_delegations {
for authority_delegation in &delegate_authority.delegations {
match action_delegation {
ServiceDelegation::HiveControl {
permission: action_permission,
} => {
if let ServiceDelegation::HiveControl {
permission: authority_permission,
} = authority_delegation
{
if action_permission == authority_permission {
return Ok(());
}
}
continue;
}
ServiceDelegation::AssetAssembler {
index: _,
permission: action_permission,
} => {
if let ServiceDelegation::AssetAssembler {
index: authority_index,
permission: authority_permission,
} = authority_delegation
{
if index.is_some()
&& index.unwrap() == *authority_index
&& action_permission == authority_permission
{
return Ok(());
}
}
continue;
}
ServiceDelegation::AssetManager {
index: _,
permission: action_permission,
} => {
if let ServiceDelegation::AssetManager {
index: authority_index,
permission: authority_permission,
} = authority_delegation
{
if index.is_some()
&& index.unwrap() == *authority_index
&& action_permission == authority_permission
{
return Ok(());
}
}
continue;
}
ServiceDelegation::CurrencyManager {
permission: action_permission,
} => {
if let ServiceDelegation::CurrencyManager {
permission: authority_permission,
} = authority_delegation
{
if action_permission == authority_permission {
return Ok(());
}
}
continue;
}
ServiceDelegation::NectarStaking {
index: action_index,
permission: action_permission,
} => {
if let ServiceDelegation::NectarStaking {
index: authority_index,
permission: authority_permission,
} = authority_delegation
{
if action_index == authority_index
&& action_permission == authority_permission
{
return Ok(());
}
}
continue;
}
ServiceDelegation::NectarMissions {
index: action_index,
permission: action_permission,
} => {
if let ServiceDelegation::NectarMissions {
index: authority_index,
permission: authority_permission,
} = authority_delegation
{
if action_index == authority_index
&& action_permission == authority_permission
{
return Ok(());
}
}
continue;
}
ServiceDelegation::BuzzGuild {
index: action_index,
permission: action_permission,
} => {
if let ServiceDelegation::BuzzGuild {
index: authority_index,
permission: authority_permission,
} = authority_delegation
{
if action_index == authority_index
&& action_permission == authority_permission
{
return Ok(());
}
}
continue;
}
}
}
}
Err(ErrorCode::Unauthorized.into())
} else {
Err(ErrorCode::Unauthorized.into())
}
}
}
}
pub fn assert_indexed_reference<'info>(
indexed_reference: &IndexedReference,
address_container: &Account<'info, AddressContainer>,
address: Pubkey,
) -> Result<bool> {
let account_info = &address_container.to_account_info();
let mint_at_ref = address_container.addresses[indexed_reference.index_in_container as usize];
let address_key = Pubkey::create_program_address(
&[
b"address_container",
format!("{:?}", address_container.role).as_bytes(),
address_container.associated_with.as_ref(),
&[indexed_reference.address_container_index],
&[address_container.bump],
],
&crate::ID,
)
.unwrap();
Ok(mint_at_ref == address && address_key == account_info.key())
}
pub fn assert_user<'info>(user: &Account<'info, User>, signer: Pubkey) -> Result<()> {
msg!("Checking User");
if user.primary_wallet == signer {
return Ok(());
}
if user
.secondary_wallets
.iter()
.find(|secondary_wallet| **secondary_wallet == signer)
.is_some()
{
return Ok(());
}
Err(ErrorCode::Unauthorized.into())
}
pub fn merkle_tree_get_size(max_depth: u32, max_buffer_size: u32) -> Result<usize> {
let data = match (max_depth, max_buffer_size) {
(3, 8) => Ok(size_of::<ConcurrentMerkleTree<3, 8>>()),
(5, 8) => Ok(size_of::<ConcurrentMerkleTree<5, 8>>()),
(14, 64) => Ok(size_of::<ConcurrentMerkleTree<14, 64>>()),
(14, 256) => Ok(size_of::<ConcurrentMerkleTree<14, 256>>()),
(14, 1024) => Ok(size_of::<ConcurrentMerkleTree<14, 1024>>()),
(14, 2048) => Ok(size_of::<ConcurrentMerkleTree<14, 2048>>()),
(15, 64) => Ok(size_of::<ConcurrentMerkleTree<15, 64>>()),
(16, 64) => Ok(size_of::<ConcurrentMerkleTree<16, 64>>()),
(17, 64) => Ok(size_of::<ConcurrentMerkleTree<17, 64>>()),
(18, 64) => Ok(size_of::<ConcurrentMerkleTree<18, 64>>()),
(19, 64) => Ok(size_of::<ConcurrentMerkleTree<19, 64>>()),
(20, 64) => Ok(size_of::<ConcurrentMerkleTree<20, 64>>()),
(20, 256) => Ok(size_of::<ConcurrentMerkleTree<20, 256>>()),
(20, 1024) => Ok(size_of::<ConcurrentMerkleTree<20, 1024>>()),
(20, 2048) => Ok(size_of::<ConcurrentMerkleTree<20, 2048>>()),
(24, 64) => Ok(size_of::<ConcurrentMerkleTree<24, 64>>()),
(24, 256) => Ok(size_of::<ConcurrentMerkleTree<24, 256>>()),
(24, 512) => Ok(size_of::<ConcurrentMerkleTree<24, 512>>()),
(24, 1024) => Ok(size_of::<ConcurrentMerkleTree<24, 1024>>()),
(24, 2048) => Ok(size_of::<ConcurrentMerkleTree<24, 2048>>()),
(26, 512) => Ok(size_of::<ConcurrentMerkleTree<26, 512>>()),
(26, 1024) => Ok(size_of::<ConcurrentMerkleTree<26, 1024>>()),
(26, 2048) => Ok(size_of::<ConcurrentMerkleTree<26, 2048>>()),
(30, 512) => Ok(size_of::<ConcurrentMerkleTree<30, 512>>()),
(30, 1024) => Ok(size_of::<ConcurrentMerkleTree<30, 1024>>()),
(30, 2048) => Ok(size_of::<ConcurrentMerkleTree<30, 2048>>()),
_ => {
msg!(
"Failed to get size of max depth {} and max buffer size {}",
max_depth,
max_buffer_size
);
err!(AccountCompressionError::ConcurrentMerkleTreeConstantsError)
}
};
msg!(
"Got size {} of max depth {} and max buffer size {}",
data.as_ref().unwrap_or(&0),
max_depth,
max_buffer_size
);
data
}
pub fn assert_program_authority(
program: AccountInfo,
program_data: AccountInfo,
signer_address: &Pubkey,
) -> Result<()> {
let program = UpgradeableLoaderState::try_deserialize(&mut program.data.borrow().as_ref())?;
match program {
UpgradeableLoaderState::Program {
programdata_address,
} => {
if programdata_address.eq(program_data.key) {
let programdata = UpgradeableLoaderState::try_deserialize(
&mut program_data.data.borrow().as_ref(),
)?;
match programdata {
UpgradeableLoaderState::ProgramData {
slot: _,
upgrade_authority_address,
} => {
if upgrade_authority_address.is_none()
|| upgrade_authority_address.unwrap().ne(signer_address)
{
return Err(ErrorCode::Unauthorized.into());
}
}
_ => return Err(ErrorCode::InvalidProgram.into()),
}
} else {
return Err(ErrorCode::InvalidProgram.into());
}
}
_ => return Err(ErrorCode::InvalidProgram.into()),
}
return Ok(());
}
pub fn assert_auth_driver<'info>(
public_info: &Account<'info, PublicInfo>,
authority: &Signer<'info>,
) -> Result<()> {
let auth_driver_key = public_info.info.get("auth_driver_key").unwrap();
let Info::SingleValue {
value: auth_driver_key_str,
} = auth_driver_key;
if authority.key.to_string().ne(auth_driver_key_str) {
return Err(ErrorCode::Unauthorized.into());
}
Ok(())
}