Documentation Index
Fetch the complete documentation index at: https://mintlify.com/provablehq/snarkvm/llms.txt
Use this file to discover all available pages before exploring further.
This guide covers deploying programs to the Aleo network, including deployment preparation, fee calculation, and transaction creation.
Prerequisites
Before deploying a program, ensure you:
- Have a compiled program (see Creating Programs)
- Have sufficient credits for deployment fees
- Have access to unspent records or public balance
Basic Deployment
Deploy a program using the VM:
use snarkvm_synthesizer::{VM, Program};
use snarkvm_console::account::PrivateKey;
use snarkvm_console::network::MainnetV0;
use snarkvm_ledger_store::ConsensusStore;
use aleo_std::StorageMode;
use rand::thread_rng;
type CurrentNetwork = MainnetV0;
let rng = &mut thread_rng();
// Initialize VM
let store = ConsensusStore::open(StorageMode::Production)?;
let vm = VM::from(store)?;
// Parse the program
let program_source = r"
program hello.aleo;
function main:
input r0 as u32.public;
add r0 1u32 into r1;
output r1 as u32.public;
";
let program = Program::<CurrentNetwork>::from_str(program_source)?;
// Deploy the program
let private_key = PrivateKey::<CurrentNetwork>::new(rng)?;
let transaction = vm.deploy(
&private_key,
&program,
None, // No fee record (uses public fee)
0, // No priority fee
None, // Use default query
rng,
)?;
println!("Deployment transaction: {}", transaction.id());
Deployment with Private Fee
Use a credits record to pay the deployment fee:
Find Unspent Credits Records
use snarkvm_console::account::ViewKey;
use snarkvm_ledger::Ledger;
// Derive view key
let view_key = ViewKey::try_from(&private_key)?;
// Find unspent records
let records = ledger.find_unspent_credits_records(&view_key)?;
if records.len() == 0 {
return Err(anyhow!("No unspent records available for deployment fee"));
}
Create Deployment Transaction
// Select a record for the fee
let fee_record = records.values().next().cloned();
// Deploy with private fee
let transaction = vm.deploy(
&private_key,
&program,
fee_record,
10_000, // Priority fee in microcredits
None,
rng,
)?;
Deployment Cost Calculation
Calculate deployment costs before deploying:
use snarkvm_synthesizer_process::{deployment_cost, deploy_compute_cost_in_microcredits};
use snarkvm_ledger_query::Query;
// Get the current block height and consensus version
let query = Query::VM(vm.block_store().clone());
let current_height = query.current_block_height()?;
let consensus_version = CurrentNetwork::CONSENSUS_VERSION(current_height)?;
// Generate deployment
let deployment = vm.deploy_raw(&program, rng)?;
// Calculate cost
let (minimum_cost, (storage_cost, namespace_cost)) = deployment_cost(
&vm.process().read(),
&deployment,
consensus_version,
)?;
println!("Minimum deployment cost: {} microcredits", minimum_cost);
println!(" Storage cost: {} microcredits", storage_cost);
println!(" Namespace cost: {} microcredits", namespace_cost);
Deployment costs vary based on program complexity. Larger programs with more functions and verifying keys cost more to deploy.
Using the Ledger Helper
The Ledger provides a convenient method for creating deployments:
use snarkvm_ledger::Ledger;
// Create deployment using ledger
let transaction = ledger.create_deploy(
&private_key,
&program,
10_000, // Priority fee (on top of base deployment fee)
None, // Query (optional)
rng,
)?;
println!("Created deployment: {}", transaction.id());
Deployment Verification
Verify the deployment before broadcasting:
// Verify the transaction
vm.check_transaction(&transaction, None, rng)?;
println!("Deployment transaction is valid");
// Extract deployment details
if let Some(deployment) = transaction.deployment() {
println!("Program ID: {}", deployment.program_id());
println!("Edition: {}", deployment.edition());
// Verify program owner (available in V9+)
if let Some(owner) = deployment.program_owner() {
let address = Address::try_from(&private_key)?;
println!("Program owner: {}", owner.address());
assert_eq!(owner.address(), &address);
}
}
Program Ownership
Starting with consensus version V9, programs have owners:
use snarkvm_console::program::ProgramOwner;
// After deployment, the program has an owner
if let Some(deployment) = transaction.deployment() {
if let Some(owner) = deployment.program_owner() {
println!("Program owner address: {}", owner.address());
println!("Program owner signature verified");
} else {
println!("Program deployed before V9 (no owner)");
}
}
Program Ownership Rules
- Programs deployed after V9 activation have owners
- Only the owner can upgrade programs (future functionality)
- Owner is set to the deployment transaction signer
- Programs deployed before V9 have no owner
Program Editions
Deploy program updates using editions:
program hello.aleo;
constructor:
assert.eq edition 1u16;
function main:
input r0 as u32.public;
add r0 2u32 into r1; // Updated logic
output r1 as u32.public;
Deploy the updated version:
// Parse the updated program
let updated_program = Program::<CurrentNetwork>::from_str(program_source_v2)?;
// Deploy new edition
let transaction = vm.deploy(
&private_key,
&updated_program,
fee_record,
0,
None,
rng,
)?;
// Check the edition
if let Some(deployment) = transaction.deployment() {
println!("Deployed edition: {}", deployment.edition());
}
Handling Deployment Failures
match vm.deploy(&private_key, &program, fee_record, 0, None, rng) {
Ok(transaction) => {
println!("Deployment successful: {}", transaction.id());
}
Err(e) => {
eprintln!("Deployment failed: {}", e);
// Common errors:
// - Program already exists
// - Insufficient balance for fees
// - Invalid program syntax
// - Dependency not found (imports)
// - Invalid edition number
}
}
Advanced: Multi-Step Deployment
For more control, separate key generation from transaction creation:
// Generate the deployment (keys and verification)
let deployment = vm.deploy_raw(&program, rng)?;
println!("Generated deployment:");
println!(" Program: {}", deployment.program_id());
println!(" Functions: {}", deployment.program().functions().len());
println!(" Verifying keys: {}", deployment.verifying_keys().len());
Configure checksum and owner (for V9+):
use snarkvm_ledger_block::Deployment;
let mut deployment = vm.deploy_raw(&program, rng)?;
// Set checksum (V9+)
let checksum = deployment.program().to_checksum();
deployment.set_program_checksum_raw(Some(checksum));
// Set owner (V9+)
let owner_address = Address::try_from(&private_key)?;
deployment.set_program_owner_raw(Some(owner_address));
Create Transaction with Fee
use snarkvm_console::types::Field;
// Get deployment ID for fee authorization
let deployment_id = deployment.to_deployment_id()?;
// Authorize fee
let fee_authorization = vm.authorize_fee_public(
&private_key,
minimum_cost,
priority_fee,
deployment_id,
rng,
)?;
// Execute fee
let fee = vm.execute_fee_authorization(fee_authorization, None, rng)?;
// Create owner signature
use snarkvm_console::program::ProgramOwner;
let owner = ProgramOwner::new(&private_key, deployment_id, rng)?;
// Construct final transaction
let transaction = Transaction::from_deployment(owner, deployment, fee)?;
Deploying with Imports
Ensure imported programs are deployed first:
// Deploy dependency first
let dependency = Program::<CurrentNetwork>::from_str(r"
program math.aleo;
function add:
input r0 as u32.public;
input r1 as u32.public;
add r0 r1 into r2;
output r2 as u32.public;
")?;
let dep_tx = vm.deploy(&private_key, &dependency, fee_record_1, 0, None, rng)?;
// Deploy main program with import
let main_program = Program::<CurrentNetwork>::from_str(r"
import math.aleo;
program calculator.aleo;
function compute:
input r0 as u32.public;
input r1 as u32.public;
call math.aleo/add r0 r1 into r2;
output r2 as u32.public;
")?;
let main_tx = vm.deploy(&private_key, &main_program, fee_record_2, 0, None, rng)?;
Checking Deployment Status
Check if a program is already deployed:
use snarkvm_console::program::ProgramID;
let program_id = ProgramID::<CurrentNetwork>::from_str("hello.aleo")?;
if vm.contains_program(&program_id) {
println!("Program {} is already deployed", program_id);
} else {
println!("Program {} is not deployed", program_id);
}
Deployment Best Practices
Test Locally First
Test your program thoroughly before deploying:
// Execute functions locally
let inputs = [Value::from_str("42u32")?];
let transaction = vm.execute(
&private_key,
(program.id(), "main"),
inputs.iter(),
None,
0,
None,
rng,
)?;
println!("Function executed successfully");
Optimize Program Size
Minimize deployment costs by:
- Removing unnecessary functions
- Simplifying complex logic
- Using efficient data structures
- Avoiding redundant computations
Version Control
Maintain program versions:
// Document program versions
let versions = vec![
("hello.aleo", 0, "Initial release"),
("hello.aleo", 1, "Added validation"),
("hello.aleo", 2, "Performance improvements"),
];
for (program_id, edition, description) in versions {
println!("{}@{}: {}", program_id, edition, description);
}
Monitor Deployment Costs
Track costs over time:
use std::collections::HashMap;
struct DeploymentTracker {
costs: HashMap<String, u64>,
}
impl DeploymentTracker {
fn record_deployment(&mut self, program_id: String, cost: u64) {
self.costs.insert(program_id, cost);
}
fn total_spent(&self) -> u64 {
self.costs.values().sum()
}
}
Error Recovery
Handle deployment transaction failures:
fn deploy_with_retry(
vm: &VM<CurrentNetwork, impl ConsensusStorage<CurrentNetwork>>,
private_key: &PrivateKey<CurrentNetwork>,
program: &Program<CurrentNetwork>,
max_retries: usize,
) -> Result<Transaction<CurrentNetwork>> {
let mut attempts = 0;
loop {
attempts += 1;
match vm.deploy(private_key, program, None, 0, None, &mut thread_rng()) {
Ok(tx) => return Ok(tx),
Err(e) if attempts < max_retries => {
eprintln!("Deployment attempt {} failed: {}", attempts, e);
std::thread::sleep(std::time::Duration::from_secs(1));
continue;
}
Err(e) => return Err(e),
}
}
}
Next Steps