use {
crate::state::{
enums::{ProposalState, TransactionExecutionStatus},
governance::get_governance_data,
native_treasury::get_native_treasury_address_seeds,
proposal::{get_proposal_data_for_governance, OptionVoteResult},
proposal_transaction::get_proposal_transaction_data_for_proposal,
},
solana_program::{
account_info::{next_account_info, AccountInfo},
clock::Clock,
entrypoint::ProgramResult,
instruction::Instruction,
program::invoke_signed,
pubkey::Pubkey,
sysvar::Sysvar,
},
};
pub fn process_execute_transaction(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
let account_info_iter = &mut accounts.iter();
let governance_info = next_account_info(account_info_iter)?; let proposal_info = next_account_info(account_info_iter)?; let proposal_transaction_info = next_account_info(account_info_iter)?;
let clock = Clock::get()?;
let governance_data = get_governance_data(program_id, governance_info)?;
let mut proposal_data =
get_proposal_data_for_governance(program_id, proposal_info, governance_info.key)?;
let mut proposal_transaction_data = get_proposal_transaction_data_for_proposal(
program_id,
proposal_transaction_info,
proposal_info.key,
)?;
proposal_data
.assert_can_execute_transaction(&proposal_transaction_data, clock.unix_timestamp)?;
let instructions = proposal_transaction_data
.instructions
.iter()
.map(Instruction::from);
let instruction_account_infos = account_info_iter.as_slice();
let mut signers_seeds: Vec<&[&[u8]]> = vec![];
let mut governance_seeds = governance_data.get_governance_address_seeds()?.to_vec();
let (_, bump_seed) = Pubkey::find_program_address(&governance_seeds, program_id);
let bump = &[bump_seed];
governance_seeds.push(bump);
signers_seeds.push(&governance_seeds[..]);
let mut treasury_seeds = get_native_treasury_address_seeds(governance_info.key).to_vec();
let (treasury_address, treasury_bump_seed) =
Pubkey::find_program_address(&treasury_seeds, program_id);
let treasury_bump = &[treasury_bump_seed];
if instruction_account_infos
.iter()
.any(|a| a.key == &treasury_address)
{
treasury_seeds.push(treasury_bump);
signers_seeds.push(&treasury_seeds[..]);
}
for instruction in instructions {
invoke_signed(&instruction, instruction_account_infos, &signers_seeds[..])?;
}
if proposal_data.state == ProposalState::Succeeded {
proposal_data.executing_at = Some(clock.unix_timestamp);
proposal_data.state = ProposalState::Executing;
}
let option = &mut proposal_data.options[proposal_transaction_data.option_index as usize];
option.transactions_executed_count = option.transactions_executed_count.checked_add(1).unwrap();
if (proposal_data.state == ProposalState::Executing
|| proposal_data.state == ProposalState::ExecutingWithErrors)
&& proposal_data
.options
.iter()
.filter(|o| o.vote_result == OptionVoteResult::Succeeded)
.all(|o| o.transactions_executed_count == o.transactions_count)
{
proposal_data.closed_at = Some(clock.unix_timestamp);
proposal_data.state = ProposalState::Completed;
}
proposal_data.serialize(&mut proposal_info.data.borrow_mut()[..])?;
proposal_transaction_data.executed_at = Some(clock.unix_timestamp);
proposal_transaction_data.execution_status = TransactionExecutionStatus::Success;
proposal_transaction_data.serialize(&mut proposal_transaction_info.data.borrow_mut()[..])?;
Ok(())
}