Import Statement
Leo programs can import other programs to reuse functionality. Imports are declared before the program scope:
import credits.aleo;
import token.aleo;
program my_app.aleo {
// Use imported programs
}
Import Syntax
The basic import syntax is:
import program_name.aleo;
Multiple programs can be imported:
import credits.aleo;
import token.aleo;
import nft.aleo;
import marketplace.aleo;
program my_app.aleo {
// Program body
}
Using Imported Programs
Once imported, you can reference types and call functions from imported programs:
import credits.aleo;
import token.aleo;
program swap.aleo {
// Use imported record types
fn swap_for_credits(
token_record: token.token,
amount: u64
) -> (credits.credits, token.token) {
// Implementation
}
}
Accessing Imported Types
Access types from imported programs using dot notation:
import token.aleo;
program marketplace.aleo {
// Reference imported record type
fn list_token(item: token.token, price: u64) {
// Use token.token record type
}
// Use in return types
fn buy_token(listing_id: u64) -> token.token {
// Return token from imported program
}
}
Calling Imported Functions
While Leo supports imports for type definitions, calling external program functions typically happens through the Aleo VM’s program composition at runtime.
Built-in Programs
Credits Program
The credits.aleo program is available by default:
import credits.aleo;
program my_app.aleo {
fn use_credits(credit_record: credits.credits) {
// Work with Aleo credits
}
}
Import Resolution
Leo resolves imports in the following order:
Local programs : Programs in your project
Dependencies : Programs specified in program.json
Published programs : Programs deployed on the Aleo network
Project Structure
my-project/
├── src/
│ └── main.leo # Main program
├── imports/
│ ├── helper.aleo # Local imports
│ └── utils.aleo
├── program.json # Dependencies configuration
└── build/
Dependencies Configuration
Specify external dependencies in program.json:
{
"program" : "my_app.aleo" ,
"version" : "0.0.0" ,
"description" : "My Leo application" ,
"dependencies" : {
"token.aleo" : {
"version" : "1.0.0" ,
"network" : "testnet3"
},
"nft.aleo" : {
"version" : "2.1.0" ,
"network" : "testnet3"
}
}
}
Import Patterns
Wrapper Pattern
Wrap imported functionality with your own interface:
import token.aleo;
program wrapper.aleo {
// Wrap token operations
fn safe_transfer(
sender: token.token,
receiver: address,
amount: u64
) -> (token.token, token.token) {
// Add validation
assert(amount > 0u64);
assert(amount <= MAX_TRANSFER);
// Use imported type
// (actual transfer logic would go here)
return create_records(sender, receiver, amount);
}
}
Adapter Pattern
Adapt imported types to your program’s needs:
import external_token.aleo;
program adapter.aleo {
record InternalToken {
owner: address,
amount: u64,
metadata: u32,
}
// Convert between types
fn convert_token(
external: external_token.token
) -> InternalToken {
return InternalToken {
owner: external.owner,
amount: external.amount,
metadata: 0u32,
};
}
}
Composition Pattern
Combine multiple imported programs:
import token.aleo;
import nft.aleo;
import marketplace.aleo;
program bundle.aleo {
// Combine functionality from multiple imports
fn create_bundle(
token_record: token.token,
nft_record: nft.NFT,
price: u64
) {
// Create a bundled listing
// Combines tokens and NFTs
}
}
Import Limitations
No Wildcard Imports
Leo does not support wildcard imports:
// Not supported
import token.aleo::*;
// Correct: Import the full program
import token.aleo;
No Selective Imports
You must import the entire program, not individual items:
// Not supported
import token.aleo::{token, mint};
// Correct: Import the full program
import token.aleo;
No Aliasing
Leo does not support import aliases:
// Not supported
import token.aleo as tok;
// Correct: Use full program name
import token.aleo;
Best Practices
1. Explicit Imports
Import only what you need:
// Good: Only import programs you use
import token.aleo;
import marketplace.aleo;
program my_app.aleo {
fn use_token(t: token.token) { }
fn use_marketplace(id: u64) { }
}
// Avoid: Unused imports
import nft.aleo; // Not used anywhere
2. Document Dependencies
Comment on why imports are needed:
// Import token for fungible asset transfers
import token.aleo;
// Import marketplace for price discovery
import marketplace.aleo;
program swap.aleo {
// Implementation
}
3. Version Dependencies
Specify exact versions in program.json:
{
"dependencies" : {
"token.aleo" : {
"version" : "1.0.0" , // Exact version
"network" : "testnet3"
}
}
}
4. Validate Imported Data
Always validate data from imported programs:
import token.aleo;
program validator.aleo {
fn validate_and_use(t: token.token, min_amount: u64) {
// Validate imported record
assert(t.amount >= min_amount);
assert(t.owner == self.caller);
// Use validated record
process(t);
}
}
Circular Dependencies
Leo does not allow circular dependencies:
// program_a.aleo
import program_b.aleo; // program_a imports program_b
// program_b.aleo
import program_a.aleo; // ERROR: Circular dependency
Circular imports will cause a compilation error. Refactor shared functionality into a separate program.
Resolving Circular Dependencies
Create a common base program:
// common.aleo - Shared types
program common.aleo {
record SharedData {
owner: address,
value: u64,
}
}
// program_a.aleo
import common.aleo;
program program_a.aleo {
fn use_shared(data: common.SharedData) { }
}
// program_b.aleo
import common.aleo;
program program_b.aleo {
fn use_shared(data: common.SharedData) { }
}
Standard Library Patterns
Common patterns for importing standard functionality:
Token Standard
import token.aleo;
program my_defi.aleo {
fn deposit(token_record: token.token) {
// DeFi operations
}
fn withdraw(amount: u64) -> token.token {
// Return tokens
}
}
NFT Standard
import nft.aleo;
program gallery.aleo {
fn display(nft_record: nft.NFT) {
// Gallery operations
}
fn mint_art() -> nft.NFT {
// Create NFT
}
}
Local Development
When developing locally, ensure imported programs are available:
# Build imported programs first
cd ../token
leo build
# Then build your program
cd ../my_app
leo build
Deployment Considerations
When deploying programs with imports:
Deploy dependencies first : Imported programs must be deployed before programs that import them
Verify program IDs : Ensure imported program IDs match deployed versions
Network consistency : All programs must be on the same network (mainnet, testnet, etc.)
Example: Multi-Program Application
Complete example using multiple imports:
import token.aleo;
import credits.aleo;
program exchange.aleo {
// Exchange rate: 1 credit = 100 tokens
const EXCHANGE_RATE: u64 = 100u64;
// Swap credits for tokens
fn swap_credits_for_tokens(
credit_record: credits.credits,
amount: u64
) -> (credits.credits, token.token) {
// Calculate token amount
let token_amount: u64 = amount * EXCHANGE_RATE;
// Create token record
let tokens: token.token = token.token {
owner: credit_record.owner,
amount: token_amount,
};
// Return change and tokens
let remaining: credits.credits = credits.credits {
owner: credit_record.owner,
microcredits: credit_record.microcredits - amount,
};
return (remaining, tokens);
}
// Swap tokens for credits
fn swap_tokens_for_credits(
token_record: token.token,
amount: u64
) -> (token.token, credits.credits) {
// Calculate credit amount
let credit_amount: u64 = amount / EXCHANGE_RATE;
// Create credit record
let credits_out: credits.credits = credits.credits {
owner: token_record.owner,
microcredits: credit_amount,
};
// Return change and credits
let remaining: token.token = token.token {
owner: token_record.owner,
amount: token_record.amount - amount,
};
return (remaining, credits_out);
}
}
Next Steps
Programs Learn about program structure
Records Work with imported records
Data Types Understand type compatibility
Functions Use imported types in functions