use {
crate::{errors::ErrorCode, state::*},
anchor_lang::prelude::*,
hpl_utils::{reallocate, Default},
};
#[derive(Accounts)]
pub struct CreateProject<'info> {
pub key: AccountInfo<'info>,
#[account(
init, payer = payer,
space = Project::LEN,
seeds = [b"project".as_ref(), key.key().as_ref()],
bump
)]
pub project: Account<'info, Project>,
pub authority: AccountInfo<'info>,
#[account(mut)]
pub payer: Signer<'info>,
pub system_program: Program<'info, System>,
pub rent_sysvar: Sysvar<'info, Rent>,
#[account(mut)]
pub vault: AccountInfo<'info>,
}
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct CreateProjectArgs {
pub name: String,
pub expected_mint_addresses: u64,
pub driver: Option<Pubkey>,
pub allowed_programs: Option<Vec<Pubkey>>,
pub collections: Option<Vec<Pubkey>>,
pub creators: Option<Vec<Pubkey>>,
}
pub fn create_project(ctx: Context<CreateProject>, args: CreateProjectArgs) -> Result<()> {
let project = &mut ctx.accounts.project;
project.set_defaults();
project.bump = ctx.bumps["project"];
project.key = ctx.accounts.key.key();
project.driver = args.driver.unwrap_or(Pubkey::default());
project.authority = ctx.accounts.authority.key();
project.name = args.name;
project.mint_indexing = Indexing {
expected: args.expected_mint_addresses,
..Indexing::default()
};
if args.allowed_programs.is_some() {
let allowed_programs = args.allowed_programs.unwrap();
reallocate(
allowed_programs.len() as isize * 32,
project.to_account_info(),
ctx.accounts.payer.to_account_info(),
&ctx.accounts.rent_sysvar,
&ctx.accounts.system_program,
)?;
project.allowed_programs = allowed_programs;
}
if args.collections.is_some() {
let collections = args.collections.unwrap();
reallocate(
collections.len() as isize * 32,
project.to_account_info(),
ctx.accounts.payer.to_account_info(),
&ctx.accounts.rent_sysvar,
&ctx.accounts.system_program,
)?;
project.collections = collections;
}
if args.creators.is_some() {
let creators = args.creators.unwrap();
reallocate(
creators.len() as isize * 32,
project.to_account_info(),
ctx.accounts.payer.to_account_info(),
&ctx.accounts.rent_sysvar,
&ctx.accounts.system_program,
)?;
project.creators = creators;
}
Ok(())
}
#[derive(Accounts)]
pub struct ChangeDriver<'info> {
#[account(mut)]
pub project: Account<'info, Project>,
pub driver: AccountInfo<'info>,
#[account()]
pub delegate_authority: Option<Account<'info, DelegateAuthority>>,
pub authority: Signer<'info>,
#[account(mut)]
pub payer: Signer<'info>,
pub rent_sysvar: Sysvar<'info, Rent>,
pub system_program: Program<'info, System>,
#[account(mut)]
pub vault: AccountInfo<'info>,
}
pub fn change_driver(ctx: Context<ChangeDriver>) -> Result<()> {
let project = &mut ctx.accounts.project;
project.driver = ctx.accounts.driver.key();
Ok(())
}
#[derive(Accounts)]
pub struct AddRemoveCriteria<'info> {
#[account(mut)]
pub project: Account<'info, Project>,
#[account()]
pub delegate_authority: Option<Account<'info, DelegateAuthority>>,
pub authority: Signer<'info>,
#[account(mut)]
pub payer: Signer<'info>,
#[account(mut)]
pub vault: AccountInfo<'info>,
pub system_program: Program<'info, System>,
pub rent_sysvar: Sysvar<'info, Rent>,
}
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct AddRemoveCriteriaArgs {
pub allowed_program: Option<Pubkey>,
pub collection: Option<Pubkey>,
pub creator: Option<Pubkey>,
pub remove: Option<bool>,
}
pub fn add_remove_criteria(
ctx: Context<AddRemoveCriteria>,
args: AddRemoveCriteriaArgs,
) -> Result<()> {
let project = &mut ctx.accounts.project;
if let Some(allowed_program) = args.allowed_program {
if args.remove.unwrap_or(false) {
project
.allowed_programs
.retain(|key| !(*key).eq(&allowed_program.key()));
reallocate(
-32isize,
project.to_account_info(),
ctx.accounts.payer.to_account_info(),
&ctx.accounts.rent_sysvar,
&ctx.accounts.system_program,
)?;
} else {
reallocate(
32isize,
project.to_account_info(),
ctx.accounts.payer.to_account_info(),
&ctx.accounts.rent_sysvar,
&ctx.accounts.system_program,
)?;
project.allowed_programs.push(allowed_program.key());
}
}
if let Some(collection) = args.collection {
if args.remove.unwrap_or(false) {
project.collections.retain(|key| !(*key).eq(&collection));
reallocate(
-32isize,
project.to_account_info(),
ctx.accounts.payer.to_account_info(),
&ctx.accounts.rent_sysvar,
&ctx.accounts.system_program,
)?;
} else {
reallocate(
32isize,
project.to_account_info(),
ctx.accounts.payer.to_account_info(),
&ctx.accounts.rent_sysvar,
&ctx.accounts.system_program,
)?;
project.collections.push(collection);
}
}
if let Some(creator) = args.creator {
if args.remove.unwrap_or(false) {
project.creators.retain(|key| !(*key).eq(&creator));
reallocate(
-32isize,
project.to_account_info(),
ctx.accounts.payer.to_account_info(),
&ctx.accounts.rent_sysvar,
&ctx.accounts.system_program,
)?;
} else {
reallocate(
32isize,
project.to_account_info(),
ctx.accounts.payer.to_account_info(),
&ctx.accounts.rent_sysvar,
&ctx.accounts.system_program,
)?;
project.creators.push(creator);
}
}
Ok(())
}
#[derive(Accounts)]
pub struct AddRemoveService<'info> {
#[account(mut)]
pub project: Account<'info, Project>,
#[account()]
pub delegate_authority: Option<Account<'info, DelegateAuthority>>,
pub authority: Signer<'info>,
#[account(mut)]
pub payer: Signer<'info>,
pub rent_sysvar: Sysvar<'info, Rent>,
pub system_program: Program<'info, System>,
#[account(mut)]
pub vault: AccountInfo<'info>,
}
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct AddRemoveServiceArgs {
pub service: Service,
pub remove: Option<bool>,
}
pub fn add_remove_service(
ctx: Context<AddRemoveService>,
args: AddRemoveServiceArgs,
) -> Result<()> {
let project = &mut ctx.accounts.project;
if args.remove.unwrap_or(false) {
project.services.retain(|service| service != &args.service);
reallocate(
-33isize,
project.to_account_info(),
ctx.accounts.payer.to_account_info(),
&ctx.accounts.rent_sysvar,
&ctx.accounts.system_program,
)?;
} else {
reallocate(
33isize,
project.to_account_info(),
ctx.accounts.payer.to_account_info(),
&ctx.accounts.rent_sysvar,
&ctx.accounts.system_program,
)?;
project.services.push(args.service);
}
Ok(())
}
#[derive(Accounts)]
#[instruction(args: AddAddressContainerToProjectArgs)]
pub struct AddAddressContainerToProject<'info> {
#[account(mut)]
pub project: Account<'info, Project>,
#[account(
init, payer = payer,
space = AddressContainer::LEN,
seeds = [b"address_container", format!("{:?}", args.role).as_bytes(), project.key().as_ref(), &[project.mint_indexing.containers]],
bump
)]
pub address_container: Account<'info, AddressContainer>,
#[account()]
pub delegate_authority: Option<Account<'info, DelegateAuthority>>,
pub authority: Signer<'info>,
#[account(mut)]
pub payer: Signer<'info>,
pub system_program: Program<'info, System>,
#[account(mut)]
pub vault: AccountInfo<'info>,
}
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct AddAddressContainerToProjectArgs {
role: AddressContainerRole,
}
pub fn add_address_container_to_project(
ctx: Context<AddAddressContainerToProject>,
args: AddAddressContainerToProjectArgs,
) -> Result<()> {
let project = &mut ctx.accounts.project;
let address_container = &mut ctx.accounts.address_container;
address_container.set_defaults();
address_container.bump = ctx.bumps["address_container"];
address_container.associated_with = project.key();
address_container.role = args.role;
project.mint_indexing.containers += 1;
Ok(())
}
#[derive(Accounts)]
#[instruction(args: AddMintAddressesToAddressContainerArgs)]
pub struct AddMintAddressesToAddressContainer<'info> {
#[account(mut)]
pub project: Account<'info, Project>,
#[account(
mut,
seeds = [b"address_container", format!("{:?}", address_container.role).as_bytes(), project.key().as_ref(), &[args.index]],
bump
)]
pub address_container: Account<'info, AddressContainer>,
#[account()]
pub delegate_authority: Option<Account<'info, DelegateAuthority>>,
pub authority: Signer<'info>,
#[account(mut)]
pub payer: Signer<'info>,
pub rent_sysvar: Sysvar<'info, Rent>,
pub system_program: Program<'info, System>,
}
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct AddMintAddressesToAddressContainerArgs {
pub index: u8,
pub addresses: Vec<Pubkey>,
}
pub fn add_mint_addresses_to_address_container(
ctx: Context<AddMintAddressesToAddressContainer>,
args: AddMintAddressesToAddressContainerArgs,
) -> Result<()> {
let project = &mut ctx.accounts.project;
let address_container = &mut ctx.accounts.address_container;
if address_container.role != AddressContainerRole::ProjectMints {
return Err(ErrorCode::WrongAddressContainerRole.into());
}
if project.mint_indexing.indexed + args.addresses.len() as u64 > project.mint_indexing.expected
{
return Err(ErrorCode::TooManyAddresses.into());
}
if address_container.addresses.len() + args.addresses.len() > 317 {
return Err(ErrorCode::TooManyAddresses.into());
}
reallocate(
(args.addresses.len() * 32) as isize,
address_container.to_account_info(),
ctx.accounts.payer.to_account_info(),
&ctx.accounts.rent_sysvar,
&ctx.accounts.system_program,
)?;
address_container.addresses.extend(args.addresses.iter());
project.mint_indexing.indexed += args.addresses.len() as u64;
Ok(())
}
#[derive(Accounts)]
pub struct AddRemoveProfileDataConfig<'info> {
#[account(mut)]
pub project: Account<'info, Project>,
#[account()]
pub delegate_authority: Option<Account<'info, DelegateAuthority>>,
pub authority: Signer<'info>,
#[account(mut)]
pub payer: Signer<'info>,
pub rent_sysvar: Sysvar<'info, Rent>,
pub system_program: Program<'info, System>,
#[account(mut)]
pub vault: AccountInfo<'info>,
}
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct AddRemoveProfileDataConfigArgs {
pub label: String,
pub data_type: Option<ProfileDataType>,
}
pub fn add_remove_profile_data_config(
ctx: Context<AddRemoveProfileDataConfig>,
args: AddRemoveProfileDataConfigArgs,
) -> Result<()> {
let project = &mut ctx.accounts.project;
msg!("{}", project.to_account_info().data_len());
if let Some(data_type) = args.data_type {
reallocate(
args.label.as_bytes().len() as isize + ProfileDataType::LEN as isize,
project.to_account_info(),
ctx.accounts.payer.to_account_info(),
&ctx.accounts.rent_sysvar,
&ctx.accounts.system_program,
)?;
project.profile_data_config.insert(args.label, data_type);
} else {
project.profile_data_config.remove(&args.label);
reallocate(
(args.label.as_bytes().len() as isize + ProfileDataType::LEN as isize) * -1,
project.to_account_info(),
ctx.accounts.payer.to_account_info(),
&ctx.accounts.rent_sysvar,
&ctx.accounts.system_program,
)?;
}
Ok(())
}