> ## Documentation Index
> Fetch the complete documentation index at: https://docs.magicblock.gg/llms.txt
> Use this file to discover all available pages before exploring further.

# 프로그램 구현

> Magic Actions를 구축하기 위한 프로그램 측 가이드

***

### 빠른 접근

<CardGroup cols={2}>
  <Card title="Magic Actions Example" icon="code" href="https://github.com/magicblock-labs/magicblock-engine-examples/tree/main/magic-actions" iconType="duotone">
    GitHub에서 참조 구현 살펴보기
  </Card>
</CardGroup>

***

### 1) 액션 명령 생성

`update_leaderboard` 명령은 커밋이 완료된 직후 베이스 레이어에서 실행됩니다. 계정 컨텍스트에 부여된 `#[action]` 어트리뷰트는 이 명령이 커밋 후 액션에서 호출 가능함을 나타냅니다.

```rust theme={null}
// 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에서 실행됩니다. `MagicIntentBundleBuilder`를 사용해 커밋과 커밋 후 액션을 모두 `magic_context`에 예약하며 — ER 트랜잭션이 베이스 레이어로 확정될 때 두 작업이 함께 적용됩니다.

```rust theme={null}
// commit action instruction on ER
pub fn commit_and_update_leaderboard(ctx: Context<CommitAndUpdateLeaderboard>) -> Result<()> {
    // Build the post-commit action that updates the leaderboard on base layer
    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,
        // Signer that pays transaction fees for the action from its escrow PDA
        escrow_authority: ctx.accounts.payer.to_account_info(),
        compute_units: 200_000,
    };

    // Schedule commit + post-commit action on magic_context
    MagicIntentBundleBuilder::new(
        ctx.accounts.payer.to_account_info(),
        ctx.accounts.magic_context.to_account_info(),
        ctx.accounts.magic_program.to_account_info(),
    )
    .commit(&[ctx.accounts.counter.to_account_info()])
    .add_post_commit_actions([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 = [COUNTER_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>,
}
```

### 여러 액션 실행

여러 계정을 커밋하고 한 번의 호출로 여러 액션을 연결할 수 있습니다. 액션은 `add_post_commit_actions`에 전달된 순서대로 순차 실행됩니다.

```rust theme={null}
// Chain several actions — they execute sequentially on base layer after the commit lands.
MagicIntentBundleBuilder::new(
    ctx.accounts.payer.to_account_info(),
    ctx.accounts.magic_context.to_account_info(),
    ctx.accounts.magic_program.to_account_info(),
)
.commit(&[
    ctx.accounts.counter.to_account_info(),
    // ... additional committed accounts
])
.add_post_commit_actions([action_1, action_2, action_3])
.build_and_invoke()?;
```

### 위임 해제와 함께 액션 실행

액션은 위임 해제에도 연결할 수 있습니다 — counter 커밋, 위임 해제, 액션 실행이 모두 동일한 ER 트랜잭션 안에서 원자적으로 처리됩니다.

```rust theme={null}
// Commit, undelegate, AND execute actions — all atomically on base layer after the ER transaction seals.
MagicIntentBundleBuilder::new(
    ctx.accounts.payer.to_account_info(),
    ctx.accounts.magic_context.to_account_info(),
    ctx.accounts.magic_program.to_account_info(),
)
.commit_and_undelegate(&[ctx.accounts.counter.to_account_info()])
.add_post_commit_actions([action])
.build_and_invoke()?;
```

***
