빠른 접근
Magic Actions Example
GitHub에서 참조 구현 살펴보기
1) 액션 명령 생성
update_leaderboard 명령은 커밋 직후 베이스 레이어에서 실행됩니다.
// program instruction
pub fn update_leaderboard(ctx: Context<UpdateLeaderboard>) -> Result<()> {
let leaderboard = &mut ctx.accounts.leaderboard;
let counter_info = &mut ctx.accounts.counter.to_account_info();
let mut data: &[u8] = &counter_info.try_borrow_data()?;
let counter = Counter::try_deserialize(&mut data)?;
if counter.count > leaderboard.high_score {
leaderboard.high_score = counter.count;
}
msg!(
"Leaderboard updated! High score: {}",
leaderboard.high_score
);
Ok(())
}
// instruction context
#[action]
#[derive(Accounts)]
pub struct UpdateLeaderboard<'info> {
#[account(mut, seeds = [LEADERBOARD_SEED], bump)]
pub leaderboard: Account<'info, Leaderboard>,
/// CHECK: PDA owner depends on: 1) Delegated: Delegation Program; 2) Undelegated: Your program ID
pub counter: UncheckedAccount<'info>,
}
2) 액션이 포함된 커밋 명령 구성
commit_and_update_leaderboard 커밋 명령은 ER에서 실행되며 액션이 포함된 커밋을 예약합니다.
// commit action instruction on ER
pub fn commit_and_update_leaderboard(ctx: Context<CommitAndUpdateLeaderboard>) -> Result<()> {
// Create action instruction
let instruction_data =
anchor_lang::InstructionData::data(&crate::instruction::UpdateLeaderboard {});
let action_args = ActionArgs::new(instruction_data);
let action_accounts = vec![
ShortAccountMeta {
pubkey: ctx.accounts.leaderboard.key(),
is_writable: true,
},
ShortAccountMeta {
pubkey: ctx.accounts.counter.key(),
is_writable: false,
},
];
let action = CallHandler {
destination_program: crate::ID,
accounts: action_accounts,
args: action_args,
escrow_authority: ctx.accounts.payer.to_account_info(), // Signer authorized to pay transaction fees for action from escrow PDA
compute_units: 200_000,
};
// Build commit and action instruction
let magic_action = MagicInstructionBuilder {
payer: ctx.accounts.payer.to_account_info(),
magic_context: ctx.accounts.magic_context.to_account_info(),
magic_program: ctx.accounts.magic_program.to_account_info(),
magic_action: MagicAction::Commit(CommitType::WithHandler {
commited_accounts: vec![ctx.accounts.counter.to_account_info()],
call_handlers: vec![action],
}),
};
// Invoke
magic_action.build_and_invoke()?;
Ok(())
}
// commit action context on ER
#[commit]
#[derive(Accounts)]
pub struct CommitAndUpdateLeaderboard<'info> {
#[account(mut)]
pub payer: Signer<'info>,
#[account(mut, seeds = [TEST_PDA_SEED], bump)]
pub counter: Account<'info, Counter>,
/// CHECK: Leaderboard PDA - not mut here, writable set in handler
#[account(seeds = [LEADERBOARD_SEED], bump)]
pub leaderboard: UncheckedAccount<'info>,
/// CHECK: Your program ID
pub program_id: AccountInfo<'info>,
}
여러 액션 실행
여러 계정을 커밋하고 여러 액션을 연결할 수 있습니다. 액션은 순차적으로 실행됩니다.let magic_builder = MagicInstructionBuilder {
payer: ctx.accounts.payer.to_account_info(),
magic_context: ctx.accounts.magic_context.to_account_info(),
magic_program: ctx.accounts.magic_program.to_account_info(),
magic_action: MagicAction::Commit(CommitType::WithHandler {
commited_accounts: vec![ctx.accounts.counter.to_account_info(), ...],
call_handlers: vec![call_handler, ...],
}),
};
다른 액션
액션은 위임 해제와 함께 실행할 수도 있고, 별도 커밋 없이 실행할 수도 있습니다.// Undelegate + Action
let magic_action = MagicInstructionBuilder {
payer: ctx.accounts.payer.to_account_info(),
magic_context: ctx.accounts.magic_context.to_account_info(),
magic_program: ctx.accounts.magic_program.to_account_info(),
magic_action: MagicAction::CommitAndUndelegate(CommitType::WithHandler {
commited_accounts: vec![ctx.accounts.counter.to_account_info()],
call_handlers: vec![action],
}),
};
// Action only
let magic_action = MagicInstructionBuilder {
payer: ctx.accounts.payer.to_account_info(),
magic_context: ctx.accounts.magic_context.to_account_info(),
magic_program: ctx.accounts.magic_program.to_account_info(),
magic_action: MagicAction::BaseActions(vec![action]),
};

