# Custom Instruction

## Create a Custom Instruction

SPL Governance proposals can execute arbitrary on-chain instructions once a vote succeeds. This is the core mechanism that makes DAOs powerful: any instruction that can be called by a Solana program can be governed by a vote.

### How Proposal Transactions Work

A Proposal can contain multiple **ProposalTransactions**, each with multiple instructions. After a successful vote, anyone can trigger execution once the `hold_up_time` has elapsed. The instructions are signed by the Governance PDA (specifically the DAO Wallet), giving them authority over any assets the DAO controls.

#### Two Transaction Types

SPL Governance v3.1.2 supports two types of proposal transactions:

1. **Legacy Transactions** (`InsertTransaction`) - The original format using `InstructionData`
2. **Versioned Transactions** (`InsertVersionedTransaction`) - New in v3.1.2, supports Address Lookup Tables and larger transactions

### Creating a Legacy Proposal Transaction

#### InstructionData Format

Each instruction in a proposal transaction is encoded as:

```rust
pub struct InstructionData {
    /// Target program ID
    pub program_id: Pubkey,
    /// Account metadata for the instruction
    pub accounts: Vec<AccountMetaData>,
    /// Instruction data bytes
    pub data: Vec<u8>,
}

pub struct AccountMetaData {
    pub pubkey: Pubkey,
    pub is_signer: bool,
    pub is_writable: bool,
}
```

#### Step-by-Step: Adding an Instruction to a Proposal

**1. Create the proposal:**

```rust
let proposal_seed = Pubkey::new_unique();

let create_proposal_ix = create_proposal(
    &governance_program_id,
    &governance,
    &proposal_owner_record,
    &governance_authority,
    &payer,
    None, // voter_weight_record
    &realm,
    "Transfer 100 SOL to Developer".to_string(),
    "https://forum.example.com/proposal-42".to_string(),
    &governing_token_mint,
    VoteType::SingleChoice,
    vec!["Approve".to_string()],
    true, // use_deny_option
    &proposal_seed,
);
```

**2. Insert a transaction with your custom instruction:**

```rust
// Example: Transfer SOL from the DAO treasury
let transfer_ix = system_instruction::transfer(
    &dao_wallet,      // source: the DAO's native treasury
    &recipient,       // destination
    100_000_000_000,  // 100 SOL in lamports
);

let instruction_data = vec![InstructionData {
    program_id: system_program::id(),
    accounts: transfer_ix.accounts.iter().map(|a| AccountMetaData {
        pubkey: a.pubkey,
        is_signer: a.is_signer,
        is_writable: a.is_writable,
    }).collect(),
    data: transfer_ix.data,
}];

let insert_tx_ix = insert_transaction(
    &governance_program_id,
    &governance,
    &proposal,
    &token_owner_record,
    &governance_authority,
    &payer,
    0,              // option_index (first option)
    0,              // transaction_index
    0,              // hold_up_time in seconds (0 = execute immediately after vote)
    instruction_data,
);
```

**3. Sign off the proposal to begin voting:**

```rust
let sign_off_ix = sign_off_proposal(
    &governance_program_id,
    &realm,
    &governance,
    &proposal,
    &governance_authority,
    Some(&proposal_owner_record),
);
```

### Creating Versioned Transactions (v3.1.2)

For larger instructions or when you need Address Lookup Tables, use versioned transactions:

#### Direct Insert (Small Transactions)

```rust
let insert_vtx_ix = insert_versioned_transaction(
    &governance_program_id,
    &governance,
    &proposal,
    &token_owner_record,
    &governance_authority,
    &payer,
    0,  // option_index
    0,  // ephemeral_signers count
    0,  // transaction_index
    transaction_message_bytes, // serialized VersionedMessage
);
```

#### Buffered Insert (Large Transactions)

For transactions that exceed the Solana transaction size limit, use the buffer mechanism:

```rust
// 1. Create a buffer
let create_buffer_ix = create_transaction_buffer(
    &governance_program_id,
    &governance,
    &proposal,
    &token_owner_record,
    &governance_authority,
    &payer,
    0, // buffer_index
    final_buffer_hash, // SHA-256 of the complete message
    final_buffer_size,
    initial_chunk, // first chunk of bytes
);

// 2. Extend the buffer with remaining chunks
let extend_buffer_ix = extend_transaction_buffer(
    &governance_program_id,
    &governance,
    &proposal,
    &payer,
    0, // buffer_index
    next_chunk, // next chunk of bytes
);

// 3. Insert the versioned transaction from the completed buffer
let insert_from_buffer_ix = insert_versioned_transaction_from_buffer(
    &governance_program_id,
    &governance,
    &proposal,
    &token_owner_record,
    &governance_authority,
    &payer,
    0, // option_index
    0, // ephemeral_signers
    0, // transaction_index
    0, // buffer_index
);
```

### Common Custom Instruction Patterns

#### Program Upgrade

The most common governance action - upgrading a program:

```rust
let upgrade_ix = bpf_loader_upgradeable::upgrade(
    &program_id_to_upgrade,
    &buffer_address,
    &dao_wallet,  // upgrade authority = DAO wallet
    &payer,
);
```

#### Token Transfer from Treasury

```rust
let transfer_ix = spl_token::instruction::transfer(
    &spl_token::id(),
    &dao_token_account,
    &recipient_token_account,
    &dao_wallet,  // authority = DAO wallet
    &[],
    amount,
)?;
```

#### Mint Tokens

```rust
let mint_ix = spl_token::instruction::mint_to(
    &spl_token::id(),
    &governed_mint,
    &destination_account,
    &dao_wallet,  // mint authority = DAO wallet
    &[],
    amount,
)?;
```

#### Call Any Program

You can create instructions for any program. The key insight is that the Governance PDA (DAO Wallet) acts as a signer, so it can authorize any action where it holds authority:

```rust
// Generic pattern for calling any program
let custom_ix = Instruction {
    program_id: target_program_id,
    accounts: vec![
        AccountMeta::new(dao_wallet, true),  // DAO wallet as signer
        // ... other accounts as needed
    ],
    data: your_instruction_data,
};
```

### Important Notes

* **DAO Wallet vs Governance PDA**: Always use the DAO Wallet (native treasury) as the authority over assets. It is a PDA with no data, derived from the Governance account, and owned by the System program. It behaves like a regular wallet.
* **hold\_up\_time**: Set this to add a delay between vote completion and execution. This gives the community time to react to controversial proposals.
* **Multiple transactions per option**: A proposal option can have multiple transactions that execute independently.
* **Execution is permissionless**: Once the vote passes and hold-up time elapses, anyone can trigger execution.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.realms.today/developer-resources/custom-instruction.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
