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 inCargo.toml. The declare_program!() macro provides an alternative approach:
Traditional Approach:
Generated Modules
Thedeclare_program!() macro generates the following modules:
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:
/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):On-Chain Usage (CPI)
Use the generatedcpi module to make cross-program invocations.
Complete Example
Let’s say you want to call an external counter program: Target Program (external_program):CPI with Seeds (PDA Signing)
When your program needs to sign the CPI as a PDA:Off-Chain Usage (Client)
Use the generatedclient module to build instructions from your off-chain client.
Rust Client Example
TypeScript Client
For TypeScript clients, use the generated IDL types:Working with Events
If the external program emits events, use the generatedevents module:
Handling Errors
Access program-specific errors through the generatederrors module:
Working with Custom Types
Use the generatedtypes module to access program-defined structs and enums:
Multiple Programs
Declare multiple external programs in the same file:Advantages
Zero Dependencies
No need to add external programs as crate dependencies, reducing compilation time and dependency conflicts.
Version Flexibility
Work with different versions of external programs by simply swapping IDL files.
Unified Interface
Single macro generates both on-chain (CPI) and off-chain (client) code.
Type Safety
Fully typed interfaces generated from IDL ensure compile-time safety.
Limitations
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.IDL Availability: Requires the external program to publish its IDL. Programs without IDLs cannot be used with this macro.
Custom Types: Complex types that don’t derive
AnchorSerialize/AnchorDeserialize may require manual handling.Best Practices
Version IDL Files
Version IDL Files
Commit IDL files to version control to ensure reproducible builds:
Validate Program IDs
Validate Program IDs
Always verify the program ID matches the expected address:
Document IDL Sources
Document IDL Sources
Document where IDL files come from:
Test CPI Interactions
Test CPI Interactions
Thoroughly test all CPI interactions:
Troubleshooting
IDL Not Found
Error:/idls directory:
Module Not Found
Error:declare_program!() invocation: