I am trying to build a kind of a complex instruction in which there are lots of accounts and variables. I guess, I can't handle memory well that why there are some errors like "Access violation in unknown section error"
I am also using Box<> wrapper for smart pointers to reduce stack usage.
How can I solve that issue? I am not sure if I use zero_copy
account constraint
#[derive(Accounts)]
#[instruction(data: FractionSplitData)]
pub struct FractionSplit<'info> {
#[account(
mut @ Error::AccountNotMutable,
signer @ Error::AccountNotSigner
)]
pub payer: Signer<'info>,
#[account(
seeds = [ADMINISTRATOR_SEED],
seeds::program = administrator::id(),
bump = administrator.bump
)]
pub administrator: Box<Account<'info, Administrator>>,
// TODO: fraction_split_authority is required or not! Be sure that. If the pda that has fraction_create_authority also can split fractions, no problem
#[account(
signer @ Error::AccountNotSigner,
)]
pub user: Signer<'info>,
/// CHECK: checked in MPL Core
pub owner: AccountInfo<'info>,
#[account(
address = base_fraction.application
)]
pub application: Box<Account<'info, Application>>,
/// CHECK: Checked in fraction_create
#[account(
seeds = [
IDENTITY_SEED,
application.key().as_ref(),
identity.id.as_ref()
],
seeds::program = guardian::id(),
bump = identity.bump,
)]
pub identity: Box<Account<'info, Identity>>,
#[account(
address = base_fraction.asset
)]
pub asset: Box<Account<'info, Asset>>,
/// CHECK: Checked in mpl-core.
#[account(
mut @ Error::AccountNotMutable,
seeds = [
ASSET_MPL_CORE_COLLECTION_SEED,
application.key().as_ref(),
asset.key().as_ref()
],
bump = Asset::asset_mpl_core_collection(application.key(), asset.key()).1,
constraint = asset_mpl_core_collection.key() == asset.asset_mpl_core_collection.unwrap().clone().key()
@ Error::AccountAssetMplCoreCollectionInvalid
)]
pub asset_mpl_core_collection: AccountInfo<'info>,
#[account(
mut,
seeds = [
FRACTION_SEED,
application.key().as_ref(),
asset.key().as_ref(),
data.base_fraction_id.as_ref()
],
bump = base_fraction.bump
)]
pub base_fraction: Box<Account<'info, Fraction>>,
/// CHECK: Checked in mpl-core.
#[account(
mut @ Error::AccountNotMutable,
seeds = [
FRACTION_MPL_CORE_ASSET_SEED,
application.key().as_ref(),
asset.key().as_ref(),
base_fraction.key().as_ref()
],
bump = Fraction::fraction_mpl_core_asset(application.key(), asset.key(), base_fraction.key()).1
)]
pub base_fraction_mpl_core_asset: AccountInfo<'info>,
#[account(
init,
payer = payer,
space = 8 + Fraction::INIT_SPACE,
seeds = [
FRACTION_SEED,
application.key().as_ref(),
asset.key().as_ref(),
data.new_first_fraction_id.as_ref()
],
bump
)]
pub new_first_fraction: Box<Account<'info, Fraction>>,
#[account(
init,
payer = payer,
space = 8 + Fraction::INIT_SPACE,
seeds = [
FRACTION_SEED,
application.key().as_ref(),
asset.key().as_ref(),
data.new_second_fraction_id.as_ref()
],
bump
)]
pub new_second_fraction: Box<Account<'info, Fraction>>,
/// CHECK: Checked in mpl-core.
#[account(
mut @ Error::AccountNotMutable,
seeds = [
FRACTION_MPL_CORE_ASSET_SEED,
application.key().as_ref(),
asset.key().as_ref(),
new_first_fraction.key().as_ref()
],
bump = Fraction::fraction_mpl_core_asset(application.key(), asset.key(), new_first_fraction.key()).1
)]
pub new_first_fraction_mpl_core_asset: AccountInfo<'info>,
/// CHECK: Checked in mpl-core.
#[account(
mut @ Error::AccountNotMutable,
seeds = [
FRACTION_MPL_CORE_ASSET_SEED,
application.key().as_ref(),
asset.key().as_ref(),
new_second_fraction.key().as_ref()
],
bump = Fraction::fraction_mpl_core_asset(application.key(), asset.key(), new_second_fraction.key()).1
)]
pub new_second_fraction_mpl_core_asset: AccountInfo<'info>,
pub system_program: Program<'info, System>,
/// CHECK: The MPL Core program
#[account(address = mpl_core::ID)]
pub mpl_core_program: AccountInfo<'info>,
}
#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct FractionSplitData {
pub base_fraction_id: Pubkey,
pub new_first_fraction_id: Pubkey,
pub new_first_fraction_name: String,
pub new_first_fraction_uri: String,
pub new_second_fraction_id: Pubkey,
pub new_second_fraction_name: String,
pub new_second_fraction_uri: String,
pub split_ratios: Vec<u64>,
}
//impl method
// TODO: add validations and handling errors
impl<'info> FractionSplit<'info> {
pub fn process(&mut self, data: FractionSplitData) -> Result<()> {
let base_fraction_key = self.base_fraction.key();
let first_fraction_key = self.new_first_fraction.key();
let first_fraction_bump = self.new_first_fraction.bump;
let second_fraction_key = self.new_second_fraction.key();
let second_fraction_bump = self.new_second_fraction.bump;
//determine the split ratios. Think the originial token amount is 10, and user wants to split it 2:3
// Validate split ratios first to fail early
let first_ratio = data.split_ratios.get(0).ok_or(Error::InvalidSplitRatio)?;
let second_ratio = data.split_ratios.get(1).ok_or(Error::InvalidSplitRatio)?;
let total_ratio = first_ratio
.checked_add(*second_ratio)
.ok_or(Error::FractionSplitRatioOverflow)?;
require!(total_ratio > 0, Error::InvalidSplitRatio);
// Calculate new amounts once
let base_amount = self.base_fraction.tokens_amount;
let first_amount = base_amount
.checked_mul(*first_ratio)
.and_then(|v| v.checked_div(total_ratio))
.ok_or(Error::FractionSplitRatioOverflow)?;
let second_amount = base_amount
.checked_mul(*second_ratio)
.and_then(|v| v.checked_div(total_ratio))
.ok_or(Error::FractionSplitRatioOverflow)?;
msg!("new_fraction_amounts are calculated");
// --------- MARK: create the new fractions ---------
self.new_first_fraction.create(
FractionCreateData {
fraction_id: data.new_first_fraction_id,
fraction_name: data.new_first_fraction_name,
fraction_uri: data.new_first_fraction_uri,
tokens_amount: first_amount,
},
&self.identity,
&self.new_first_fraction_mpl_core_asset,
&self.payer,
&self.owner,
&self.system_program,
&self.mpl_core_program,
&self.application,
&self.asset,
&self.asset_mpl_core_collection,
first_fraction_key,
first_fraction_bump,
)?;
msg!("new_first_fraction created");
self.new_second_fraction.create(
FractionCreateData {
fraction_id: data.new_second_fraction_id,
fraction_name: data.new_second_fraction_name,
fraction_uri: data.new_second_fraction_uri,
tokens_amount: second_amount,
},
&self.identity,
&self.new_second_fraction_mpl_core_asset,
&self.payer,
&self.owner,
&self.system_program,
&self.mpl_core_program,
&self.application,
&self.asset,
&self.asset_mpl_core_collection,
second_fraction_key,
second_fraction_bump,
)?;
msg!("new_second_fraction created");
// burn the original fraction
self.base_fraction.burn(
&self.identity,
&self.base_fraction_mpl_core_asset,
&self.payer,
&self.mpl_core_program,
&self.application,
&self.asset,
&self.asset_mpl_core_collection,
base_fraction_key,
)?;
// close base_fraction account
self.base_fraction.close(self.payer.to_account_info())?;
Ok(())
}
}