Skip to main content

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 example demonstrates how to create and execute a private token transfer transaction on the Aleo network using SnarkVM.

Complete example

use snarkvm::{
    prelude::*,
    ledger::store::ConsensusStore,
};
use rand::thread_rng;

fn main() -> Result<()> {
    // Setup: Create sender and receiver accounts
    let sender_key = PrivateKey::<Testnet3>::new(&mut thread_rng())?;
    let receiver = Address::try_from(
        PrivateKey::<Testnet3>::new(&mut thread_rng())?  
    )?;
    
    println!("Sender:   {}", Address::try_from(&sender_key)?);
    println!("Receiver: {}", receiver);
    
    // Initialize the VM
    let store = ConsensusStore::<Testnet3, ConsensusMemory<Testnet3>>::open(
        Some(aleo_std::StorageMode::Development(0))
    )?;
    let vm = VM::from(store)?;
    
    // Create transfer inputs
    let inputs = [
        // Note: In a real application, you would use an actual record
        // from the ledger as the first input
        Value::from_str(&format!("{}u64", 1000000))?, // Amount: 1 million microcredits
        Value::from_str(&format!("{}", receiver))?,  // Recipient address
        Value::from_str("100000u64")?,                // Amount to transfer
    ];
    
    println!("\nCreating transfer transaction...");
    
    // Execute the transfer_private function
    let transaction = vm.execute(
        &sender_key,
        ("credits.aleo", "transfer_private"),
        inputs.iter(),
        None,           // No additional fee record
        0,              // Zero priority fee
        None,           // No query (using VM directly)
        &mut thread_rng()
    )?;
    
    println!("Transaction ID: {}", transaction.id());
    println!("Transaction created successfully!");
    
    Ok(())
}

Step by step

1

Create accounts

let sender_key = PrivateKey::<Testnet3>::new(&mut thread_rng())?;
let receiver = Address::try_from(
    PrivateKey::<Testnet3>::new(&mut thread_rng())?  
)?;
Generate a private key for the sender and an address for the receiver.
2

Initialize the VM

let store = ConsensusStore::<Testnet3, ConsensusMemory<Testnet3>>::open(
    Some(aleo_std::StorageMode::Development(0))
)?;
let vm = VM::from(store)?;
Create a VM instance with in-memory storage for testing. In production, you would use StorageMode::Production.
3

Prepare transfer inputs

let inputs = [
    Value::from_str(&format!("{}u64", 1000000))?, // Source amount
    Value::from_str(&format!("{}", receiver))?,   // Recipient
    Value::from_str("100000u64")?,                 // Transfer amount
];
The transfer_private function takes three inputs:
  1. The input record (or amount for this example)
  2. The recipient address
  3. The amount to transfer (in microcredits)
4

Execute the transaction

let transaction = vm.execute(
    &sender_key,
    ("credits.aleo", "transfer_private"),
    inputs.iter(),
    None,
    0,
    None,
    &mut thread_rng()
)?;
Execute the transfer_private function from the credits.aleo program. This generates a zero-knowledge proof and creates the transaction.

Real-world usage

In a production application, you would:
  1. Find an unspent record to use as input:
use snarkvm::ledger::Ledger;

let ledger = Ledger::load(genesis_block, storage_mode)?;
let view_key = ViewKey::try_from(&private_key)?;
let records = ledger.find_unspent_credits_records(&view_key)?;
  1. Use the record as the first input:
let record = records.values().next().unwrap();
let inputs = [
    Value::Record(record.clone()),
    Value::from_str(&format!("{}", recipient))?,
    Value::from_str(&format!("{}u64", amount))?,
];
  1. Include a fee for miners:
let fee_record = records.values().nth(1).unwrap();
let transaction = vm.execute(
    &private_key,
    ("credits.aleo", "transfer_private"),
    inputs.iter(),
    Some(fee_record.clone()),
    1000, // Priority fee in microcredits
    None,
    &mut thread_rng()
)?;

Transfer types

The credits.aleo program supports multiple transfer functions:
FunctionDescriptionInputs
transfer_privatePrivate to privateRecord, address, amount
transfer_private_to_publicPrivate to publicRecord, address, amount
transfer_publicPublic to publicAddress, amount
transfer_public_to_privatePublic to privateAddress, amount
Private transfers hide amounts and recipients using zero-knowledge proofs. Public transfers are visible on the blockchain.

Error handling

Common errors and solutions:
Make sure the input record has enough credits to cover both the transfer amount and the fee.
if record.microcredits()? < amount + fee {
    return Err(anyhow!("Insufficient balance"));
}
Verify the recipient address is valid for your network:
let address = Address::<Testnet3>::from_str(recipient_str)?;

Next steps

Custom program

Create your own Aleo program

Managing records

Learn how to work with records

Build docs developers (and LLMs) love