use anchor_lang::prelude::*;
use crate::{Metadata, DelegatePermissions, PermissionType, UpdateMetadataInput, Group};
use crate::{errors::ErrorCode};
#[event]
pub struct EditMetadataEvent {
pub id: Pubkey,
pub name: String,
}
#[derive(Accounts)]
#[instruction(metadata_input: UpdateMetadataInput)]
pub struct UpdateMetadata<'info> {
#[account(mut)]
pub editor: Signer<'info>,
pub metadata: Box<Account<'info, Metadata>>,
#[account(seeds = ["permissions".as_ref(),
editor.key().as_ref(),
metadata.update_authority.as_ref(),
metadata.key().as_ref()],
bump)]
pub delegated_metadata_specific_permissions: Option<Box<Account<'info, DelegatePermissions>>>,
#[account(seeds = ["permissions".as_ref(), editor.key().as_ref(),
group.as_ref().expect("Group must be provided with group wide permissions").key().as_ref()], bump)]
pub delegated_group_wide_permissions: Option<Box<Account<'info, DelegatePermissions>>>,
#[account(constraint = metadata.group.expect("Metadata must have a group if you provided a group.") == group.key())]
pub group: Option<Box<Account<'info, Group>>>,
pub system_program: Program<'info, System>,
}
pub fn handler(ctx: Context<UpdateMetadata>,
update_metadata_input: UpdateMetadataInput,
) -> Result<()> {
let editor = &ctx.accounts.editor;
let UpdateMetadataInput {name,
symbol,
asset,
} = update_metadata_input;
let metadata = &mut ctx.accounts.metadata;
let mut can_edit = editor.key == &metadata.update_authority;
if let Some(group) = ctx.accounts.group.as_ref() {
can_edit = can_edit || &group.update_authority == editor.key;
if let Some(delegated_group_wide_permissions_account)
= ctx.accounts.delegated_group_wide_permissions.as_ref() {
let delegated_group_wide_permissions = &delegated_group_wide_permissions_account.permissions;
can_edit = can_edit || delegated_group_wide_permissions.contains(&PermissionType::Update);
}
}
if let Some(delegated_metadata_specific_permissions_account) = ctx.accounts.delegated_metadata_specific_permissions.as_ref() {
let delegated_metadata_specific_permissions = &delegated_metadata_specific_permissions_account.permissions;
can_edit = can_edit || delegated_metadata_specific_permissions.contains(&PermissionType::Update);
}
if !can_edit {
return Err(ErrorCode::InvalidPermissions.into())
}
metadata.name = name.clone();
metadata.asset = asset.clone();
metadata.symbol= symbol;
emit!(EditMetadataEvent{
id: metadata.key(),
name
});
Ok(())
}