> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/solana-foundation/anchor/llms.txt
> Use this file to discover all available pages before exploring further.

# declare_program! Macro

> Use the declare_program! macro to interact with external Anchor programs without additional dependencies through IDL-based code generation.

The `declare_program!()` macro enables dependency-free interaction with Anchor programs by generating Rust modules from a program's IDL file. This eliminates the need to add the external program as a crate dependency.

## Overview

Traditionally, to interact with an external program, you would add it as a dependency in `Cargo.toml`. The `declare_program!()` macro provides an alternative approach:

**Traditional Approach:**

```toml theme={null}
[dependencies]
external_program = { version = "0.1.0", features = ["cpi"] }
```

**With declare\_program!:**

```rust theme={null}
declare_program!(external_program);
```

The macro generates all necessary modules for both on-chain (CPI) and off-chain (client) interactions.

## Generated Modules

The `declare_program!()` macro generates the following modules:

| Module      | Description                      | Use Case                                     |
| ----------- | -------------------------------- | -------------------------------------------- |
| `cpi`       | Cross-program invocation helpers | Making CPIs from on-chain programs           |
| `client`    | Client instruction builders      | Building transactions from off-chain clients |
| `accounts`  | Account data types               | Accessing program state                      |
| `program`   | Program ID constant              | Identifying the program                      |
| `constants` | Program constants                | Using program-defined constants              |
| `events`    | Program events                   | Listening to program events                  |
| `types`     | Custom types                     | Using program-defined structs/enums          |
| `errors`    | Program errors                   | Handling program-specific errors             |

## Setup

### 1. Obtain the IDL File

You need the target program's IDL file (JSON format). Place it in an `/idls` directory anywhere in your project structure:

```
project/
├── idls/
│   └── external_program.json
├── programs/
│   └── your_program/
│       └── src/
│           └── lib.rs
└── Cargo.toml
```

The `/idls` directory can be at any level in your project.

### 2. Invoke the Macro

In your program, invoke the macro with the IDL filename (without extension):

```rust theme={null}
use anchor_lang::prelude::*;

declare_program!(external_program);  // Looks for idls/external_program.json
```

## On-Chain Usage (CPI)

Use the generated `cpi` module to make cross-program invocations.

### Complete Example

Let's say you want to call an external counter program:

**Target Program (external\_program):**

```rust theme={null}
use anchor_lang::prelude::*;

declare_id!("ExternalProgram11111111111111111111111111111");

#[program]
pub mod external_program {
    use super::*;

    pub fn increment(ctx: Context<Increment>) -> Result<()> {
        let counter = &mut ctx.accounts.counter;
        counter.count += 1;
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Increment<'info> {
    #[account(mut)]
    pub counter: Account<'info, Counter>,
}

#[account]
pub struct Counter {
    pub count: u64,
}
```

**Your Program (caller):**

```rust theme={null}
use anchor_lang::prelude::*;

declare_id!("YourProgram111111111111111111111111111111111");

// Generate modules from IDL
declare_program!(external_program);

// Import generated types
use external_program::{
    accounts::Counter,
    cpi::{self, accounts::Increment},
    program::ExternalProgram,
};

#[program]
pub mod your_program {
    use super::*;

    pub fn call_external_increment(ctx: Context<CallExternal>) -> Result<()> {
        // Create CPI context
        let cpi_ctx = CpiContext::new(
            ctx.accounts.external_program.to_account_info(),
            Increment {
                counter: ctx.accounts.counter.to_account_info(),
            },
        );

        // Make CPI call
        cpi::increment(cpi_ctx)?;
        Ok(())
    }
}

#[derive(Accounts)]
pub struct CallExternal<'info> {
    #[account(mut)]
    pub counter: Account<'info, Counter>,
    pub external_program: Program<'info, ExternalProgram>,
}
```

### CPI with Seeds (PDA Signing)

When your program needs to sign the CPI as a PDA:

```rust theme={null}
pub fn call_with_seeds(ctx: Context<CallWithSeeds>) -> Result<()> {
    let seeds = &[
        b"authority",
        &[ctx.bumps.authority],
    ];
    let signer_seeds = &[&seeds[..]];

    let cpi_ctx = CpiContext::new_with_signer(
        ctx.accounts.external_program.to_account_info(),
        Increment {
            counter: ctx.accounts.counter.to_account_info(),
        },
        signer_seeds,
    );

    cpi::increment(cpi_ctx)?;
    Ok(())
}

#[derive(Accounts)]
pub struct CallWithSeeds<'info> {
    #[account(
        mut,
        seeds = [b"authority"],
        bump,
    )]
    pub authority: SystemAccount<'info>,
    #[account(mut)]
    pub counter: Account<'info, Counter>,
    pub external_program: Program<'info, ExternalProgram>,
}
```

## Off-Chain Usage (Client)

Use the generated `client` module to build instructions from your off-chain client.

### Rust Client Example

```rust theme={null}
use anchor_client::{
    solana_client::rpc_client::RpcClient,
    solana_sdk::{
        commitment_config::CommitmentConfig,
        signature::Keypair,
        signer::Signer,
    },
    Client, Cluster,
};
use anchor_lang::prelude::*;
use std::rc::Rc;

// Generate modules from IDL
declare_program!(external_program);

use external_program::{
    accounts::Counter,
    client::{accounts, args},
};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let payer = Keypair::new();
    let counter = Keypair::new();

    // Create client
    let client = Client::new_with_options(
        Cluster::Localnet,
        Rc::new(payer),
        CommitmentConfig::confirmed(),
    );
    let program = client.program(external_program::ID)?;

    // Build increment instruction
    let increment_ix = program
        .request()
        .accounts(accounts::Increment {
            counter: counter.pubkey(),
        })
        .args(args::Increment)
        .instructions()?
        .remove(0);

    // Send transaction
    let signature = program
        .request()
        .instruction(increment_ix)
        .send()
        .await?;

    println!("Transaction signature: {}", signature);

    // Fetch account data
    let counter_account: Counter = program
        .account::<Counter>(counter.pubkey())
        .await?;
    println!("Counter: {}", counter_account.count);

    Ok(())
}
```

### TypeScript Client

For TypeScript clients, use the generated IDL types:

```typescript theme={null}
import * as anchor from "@anchor-lang/core";
import { Program } from "@anchor-lang/core";
import { ExternalProgram } from "./target/types/external_program";

const program = anchor.workspace.ExternalProgram as Program<ExternalProgram>;

const counterKeypair = anchor.web3.Keypair.generate();

// Call increment instruction
const tx = await program.methods
  .increment()
  .accounts({
    counter: counterKeypair.publicKey,
  })
  .rpc();

console.log("Transaction signature:", tx);

// Fetch account
const counter = await program.account.counter.fetch(
  counterKeypair.publicKey
);
console.log("Count:", counter.count.toString());
```

## Working with Events

If the external program emits events, use the generated `events` module:

```rust theme={null}
use external_program::events::CounterUpdated;

pub fn handle_event(ctx: Context<HandleEvent>) -> Result<()> {
    // Events are typically read by off-chain listeners
    // but you can access event types for type safety
    Ok(())
}
```

**Off-chain event listening (Rust):**

```rust theme={null}
let mut event_subscriber = program.events()?;

loop {
    let event = event_subscriber.next().await?;
    match event {
        external_program::events::CounterUpdated { old_count, new_count } => {
            println!("Counter updated: {} -> {}", old_count, new_count);
        }
        _ => {}
    }
}
```

## Handling Errors

Access program-specific errors through the generated `errors` module:

```rust theme={null}
use external_program::errors::ErrorCode;

pub fn handle_error(ctx: Context<HandleError>) -> Result<()> {
    // Check for specific error conditions
    if some_condition {
        return Err(ErrorCode::CustomError.into());
    }
    Ok(())
}
```

## Working with Custom Types

Use the generated `types` module to access program-defined structs and enums:

```rust theme={null}
use external_program::types::{CustomStruct, CustomEnum};

pub fn use_custom_types(
    ctx: Context<UseCustom>,
    data: CustomStruct,
    variant: CustomEnum,
) -> Result<()> {
    // Use the custom types
    msg!("Received custom data");
    Ok(())
}
```

## Multiple Programs

Declare multiple external programs in the same file:

```rust theme={null}
use anchor_lang::prelude::*;

// Declare multiple programs
declare_program!(program_a);
declare_program!(program_b);
declare_program!(program_c);

use program_a::cpi as program_a_cpi;
use program_b::cpi as program_b_cpi;
use program_c::cpi as program_c_cpi;

#[program]
pub mod your_program {
    use super::*;

    pub fn call_multiple(ctx: Context<CallMultiple>) -> Result<()> {
        // Call program A
        program_a_cpi::instruction_a(
            CpiContext::new(/* ... */),
        )?;

        // Call program B
        program_b_cpi::instruction_b(
            CpiContext::new(/* ... */),
        )?;

        Ok(())
    }
}
```

## Advantages

<CardGroup cols={2}>
  <Card title="Zero Dependencies" icon="ban">
    No need to add external programs as crate dependencies, reducing compilation time and dependency conflicts.
  </Card>

  <Card title="Version Flexibility" icon="code-branch">
    Work with different versions of external programs by simply swapping IDL files.
  </Card>

  <Card title="Unified Interface" icon="layer-group">
    Single macro generates both on-chain (CPI) and off-chain (client) code.
  </Card>

  <Card title="Type Safety" icon="shield">
    Fully typed interfaces generated from IDL ensure compile-time safety.
  </Card>
</CardGroup>

## Limitations

<Callout type="warning">
  **Account Validation**: The `declare_program!()` macro generates type definitions but doesn't include the constraint validation logic from the original program. Always validate account relationships in your program.
</Callout>

<Callout type="warning">
  **IDL Availability**: Requires the external program to publish its IDL. Programs without IDLs cannot be used with this macro.
</Callout>

<Callout type="info">
  **Custom Types**: Complex types that don't derive `AnchorSerialize`/`AnchorDeserialize` may require manual handling.
</Callout>

## Best Practices

<AccordionGroup>
  <Accordion title="Version IDL Files">
    Commit IDL files to version control to ensure reproducible builds:

    ```gitignore theme={null}
    # .gitignore
    # Don't ignore IDL files
    !idls/*.json
    ```
  </Accordion>

  <Accordion title="Validate Program IDs">
    Always verify the program ID matches the expected address:

    ```rust theme={null}
    require_keys_eq!(
        ctx.accounts.external_program.key(),
        external_program::ID,
        ErrorCode::InvalidProgram
    );
    ```
  </Accordion>

  <Accordion title="Document IDL Sources">
    Document where IDL files come from:

    ```rust theme={null}
    // IDL from: https://github.com/project/external-program/releases/tag/v1.0.0
    declare_program!(external_program);
    ```
  </Accordion>

  <Accordion title="Test CPI Interactions">
    Thoroughly test all CPI interactions:

    ```rust theme={null}
    #[cfg(test)]
    mod tests {
        use super::*;

        #[test]
        fn test_external_cpi() {
            // Test CPI calls
        }
    }
    ```
  </Accordion>
</AccordionGroup>

## Troubleshooting

### IDL Not Found

**Error:**

```
error: could not find IDL file for program 'external_program'
```

**Solution:**
Ensure the IDL file exists in an `/idls` directory:

```
project/
└── idls/
    └── external_program.json
```

### Module Not Found

**Error:**

```
error[E0433]: failed to resolve: use of undeclared crate or module `external_program`
```

**Solution:**
Add the `declare_program!()` invocation:

```rust theme={null}
declare_program!(external_program);
```

### Type Mismatch

**Error:**

```
expected struct `Account<'_, Counter>`, found `InterfaceAccount<'_, ...>`
```

**Solution:**
Use the generated account types:

```rust theme={null}
use external_program::accounts::Counter;

pub counter: Account<'info, Counter>,
```

## Resources

* [declare\_program! Source](https://github.com/coral-xyz/anchor/tree/master/lang/attribute/program/src/declare_program)
* [Example Program](https://github.com/coral-xyz/anchor/tree/master/tests/declare-program)
* [Cross Program Invocations](/concepts/cpi)
* [Anchor Client Documentation](/clients/rust)
