Introduction
Welcome to the Voyager Verifier documentation! This tool is your gateway to verifying Starknet smart contracts on the Voyager block explorer.
What is Voyager Verifier?
Voyager Verifier is a command-line tool that allows developers to verify their Starknet contract classes on the Voyager block explorer. Once verified, your contracts will display a verified badge on Voyager, allowing users to view and audit the source code directly in the explorer.
Why Verify Your Contracts?
Contract verification provides several important benefits:
- Transparency: Users can audit the source code of contracts they interact with
- Trust: Verified contracts build confidence in your project
- Debugging: Easier debugging with readable source code in the explorer
- Community Standards: Following best practices in the Starknet ecosystem
Key Features
Multiple Verification Methods
- Interactive Wizard - Guided step-by-step verification for newcomers
- Command Line - Direct CLI commands for experienced users
- Batch Verification - Verify multiple contracts at once
- Configuration Files - Reduce verbosity with
.voyager.tomlconfig files
Comprehensive Project Support
- Scarb Projects - Full support for standard Scarb-based projects
- Dojo Projects - Automatic detection and support for Dojo framework
- Workspace Projects - Multi-package workspace support
- Cairo Versions - Supports Cairo up to 2.11.4 (with newer versions added as available)
Advanced Features
- History Tracking - Local database tracking all verifications
- Watch Mode - Monitor verification status in real-time
- Desktop Notifications - Get notified when verification completes
- Dry Run Mode - Preview what will be submitted before verification
- Multiple Networks - Support for Mainnet, Sepolia, and custom endpoints
Developer-Friendly
- Detailed Error Messages - Clear error codes with actionable solutions
- Verbose Mode - Debug compilation issues with full output
- Multiple Output Formats - Text, JSON, and table formats for different use cases
- CI/CD Ready - Perfect for automation pipelines
How It Works
The verification process is straightforward:
- Prepare Your Project - Ensure your Scarb project builds successfully
- Submit for Verification - Use the CLI to submit your contract class hash and source code
- Monitor Progress - Track the verification status with built-in polling
- View Results - See your verified contract on Voyager with the verified badge
The verifier collects your source files, compiles them remotely using the same build configuration, and compares the output with the declared contract class. If they match, your contract is marked as verified.
Network Support
Voyager Verifier supports:
- Mainnet - Production Starknet network (default:
https://api.voyager.online/beta) - Sepolia - Testnet for development (default:
https://sepolia-api.voyager.online/beta) - Dev - Development network
- Custom Endpoints - Specify your own API endpoint URL
Note: Classes verified on mainnet will automatically appear verified on Sepolia as well.
Requirements
Before using Voyager Verifier, you’ll need:
- A working Scarb project that builds successfully with
scarb build - The class hash of your declared contract class
- Your contract name
- A valid SPDX license identifier (optional, defaults to “All Rights Reserved”)
Getting Help
If you encounter any issues:
- Check the Troubleshooting Guide
- Review Common Errors
- Use
--verboseflag for detailed error output - Contact @StarknetVoyager on Telegram
Next Steps
Ready to get started? Head over to the Installation Guide to install Voyager Verifier, or jump straight to the Quickstart Guide if you already have it installed.
Installation
Voyager Verifier can be installed using two primary methods: asdf (recommended) or Cargo (Rust’s package manager).
Choose Your Installation Method
asdf (Recommended)
asdf is a version manager that simplifies installation and allows you to manage multiple versions of voyager-verifier. This is the recommended approach for most users.
Best for:
- Users who want easy version management
- Teams needing consistent tooling across environments
- Users familiar with version managers like nvm, rbenv, etc.
Continue to asdf installation →
Cargo
Install directly from source using Cargo. This method is ideal if you’re already familiar with the Rust ecosystem or want the latest development version.
Best for:
- Rust developers
- Users who want to build from source
- Those needing the absolute latest features
Continue to Cargo installation →
System Requirements
Before installing, make sure your system meets the requirements.
After Installation
Once installed, verify the installation by running:
voyager --version
You should see output similar to:
voyager-verifier 2.0.1
Next Steps
After successful installation, head to the Quickstart Guide to verify your first contract!
Troubleshooting Installation
If you encounter issues during installation:
- asdf users: Ensure asdf is properly installed and configured in your shell
- Cargo users: Ensure you have the latest stable Rust toolchain (
rustup update) - Build errors: Check that you have required system dependencies (OpenSSL, pkg-config)
For more help, see the Troubleshooting Guide.
Installation with asdf
asdf is a version manager that allows you to install and manage multiple versions of voyager-verifier (and many other tools) on your system.
Prerequisites
First, you’ll need to install asdf if you haven’t already. Follow the official asdf installation guide.
Installation Steps
1. Add the Voyager Plugin
Add the voyager-verifier plugin to asdf:
asdf plugin add voyager https://github.com/NethermindEth/asdf-voyager-verifier.git
2. Install the Latest Version
Install the latest version of voyager-verifier:
asdf install voyager latest
This will download and install the most recent version available.
3. Set Global Version
Set the installed version as your global default:
asdf global voyager latest
Alternatively, set it for the current directory only:
asdf local voyager latest
4. Verify Installation
Confirm the installation was successful:
voyager --version
You should see output like:
voyager-verifier 2.0.1
Managing Versions
List Available Versions
See all available versions:
asdf list all voyager
Install Specific Version
Install a specific version:
asdf install voyager 1.3.0
Switch Versions
Switch to a different installed version globally:
asdf global voyager 1.3.0
Or for the current directory:
asdf local voyager 1.3.0
List Installed Versions
See which versions you have installed:
asdf list voyager
Updating
Update to Latest Version
To update to the latest version:
asdf install voyager latest
asdf global voyager latest
Update the Plugin
To get access to newly released versions, update the plugin:
asdf plugin update voyager
Uninstalling
Remove a Specific Version
asdf uninstall voyager 1.3.0
Remove the Plugin
To completely remove voyager-verifier from asdf:
asdf plugin remove voyager
Project-Specific Versions
For project-specific version management, create a .tool-versions file in your project directory:
echo "voyager 2.0.1" > .tool-versions
When you cd into this directory, asdf will automatically use the specified version.
Troubleshooting
Command Not Found
If voyager command is not found after installation:
- Make sure asdf is properly configured in your shell profile (
.bashrc,.zshrc, etc.) - Restart your terminal or run
source ~/.bashrc(or your shell’s config file) - Verify asdf is working:
asdf --version
Plugin Installation Fails
If adding the plugin fails:
- Ensure you have git installed
- Check your network connection
- Verify the plugin URL is correct
Version Not Available
If a specific version isn’t available:
# Update the plugin to fetch latest versions
asdf plugin update voyager
# List available versions again
asdf list all voyager
Next Steps
Now that voyager-verifier is installed, proceed to the Quickstart Guide to verify your first contract!
Installation with Cargo
Cargo is Rust’s package manager and build tool. If you’re a Rust developer or prefer installing from source, this is the method for you.
Prerequisites
You’ll need Rust and Cargo installed on your system. If you don’t have them yet:
Install Rust
The easiest way to install Rust is using rustup:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Follow the on-screen instructions. After installation, restart your terminal or run:
source $HOME/.cargo/env
Verify the installation:
rustc --version
cargo --version
For more details, see the official Rust installation guide.
Installation
Install from crates.io
Install the latest published version from crates.io:
cargo install voyager-verifier
This will download, compile, and install the voyager binary to ~/.cargo/bin/.
Install Specific Version
To install a specific version:
cargo install voyager-verifier --version 2.0.1
Install from Git Repository
To install the latest development version directly from the GitHub repository:
cargo install --git https://github.com/NethermindEth/voyager-verifier.git
Install a specific branch:
cargo install --git https://github.com/NethermindEth/voyager-verifier.git --branch main
Install a specific commit:
cargo install --git https://github.com/NethermindEth/voyager-verifier.git --rev abc123
Build Options
Without Desktop Notifications
If you want to build without desktop notification support (reduces dependencies):
cargo install voyager-verifier --no-default-features
With Specific Features
Enable specific features during installation:
# With notifications (default)
cargo install voyager-verifier --features notifications
Verify Installation
After installation, verify it worked:
voyager --version
You should see:
voyager-verifier 2.0.1
Check the installation path:
which voyager
Typical output:
/home/username/.cargo/bin/voyager
Updating
Update to Latest Version
To update to the latest published version:
cargo install voyager-verifier --force
The --force flag reinstalls the package even if it’s already installed.
Update from Git
If you installed from git, re-run the install command:
cargo install --git https://github.com/NethermindEth/voyager-verifier.git --force
Uninstalling
To remove voyager-verifier:
cargo uninstall voyager-verifier
Building from Source
For development or customization, you can clone and build manually:
Clone the Repository
git clone https://github.com/NethermindEth/voyager-verifier.git
cd voyager-verifier
Build
Build in release mode:
cargo build --release
The binary will be in target/release/voyager.
Run Without Installing
Run directly without installing:
cargo run -- --version
Install Local Build
Install the locally built version:
cargo install --path .
Troubleshooting
Cargo Not Found
If cargo command is not found:
- Ensure Rust is properly installed
- Make sure
~/.cargo/binis in your PATH - Restart your terminal
- Source the cargo environment:
source $HOME/.cargo/env
Compilation Errors
If you encounter build errors:
Update Rust toolchain:
rustup update stable
Install required system dependencies:
On Ubuntu/Debian:
sudo apt-get install pkg-config libssl-dev
On macOS:
brew install pkg-config openssl
On Fedora/RHEL:
sudo dnf install pkg-config openssl-devel
Network Issues
If downloads fail:
- Check your internet connection
- Check if you’re behind a proxy (configure cargo proxy settings)
- Try using a VPN if crates.io is blocked
Permission Errors
If you get permission errors during installation:
- Never use
sudowith cargo install - Ensure
~/.cargo/binis writable by your user - Check that your Rust installation isn’t system-wide (should be user-local)
Environment Configuration
Add to PATH
Ensure ~/.cargo/bin is in your PATH. Add to your shell profile:
Bash (~/.bashrc):
export PATH="$HOME/.cargo/bin:$PATH"
Zsh (~/.zshrc):
export PATH="$HOME/.cargo/bin:$PATH"
Fish (~/.config/fish/config.fish):
set -gx PATH $HOME/.cargo/bin $PATH
After editing, reload your shell configuration or restart your terminal.
Next Steps
Now that voyager-verifier is installed, proceed to the Quickstart Guide to verify your first contract!
Requirements
Before installing and using Voyager Verifier, ensure your system meets these requirements.
System Requirements
Operating System
Voyager Verifier supports:
- Linux (Ubuntu, Debian, Fedora, Arch, etc.)
- macOS (10.14 Mojave or later)
- Windows (via WSL2 recommended, native Windows support available)
Hardware
Minimum requirements:
- RAM: 2GB minimum, 4GB recommended
- Disk Space: 500MB for installation and dependencies
- Network: Internet connection required for verification API
Software Prerequisites
Required
Scarb
Voyager Verifier requires scarb (Cairo/Starknet development toolchain) to be installed and available in your PATH.
Installation:
asdf install scarb latest
asdf global scarb latest
Verify installation:
scarb --version
For more details, see the official Scarb documentation.
For Cargo Installation
If installing via Cargo, you’ll need:
- Rust toolchain (stable channel, version 1.70 or later)
- System dependencies:
- Linux:
pkg-config,libssl-dev(Ubuntu/Debian) oropenssl-devel(Fedora/RHEL) - macOS:
pkg-config,openssl(via Homebrew) - Windows: Visual Studio Build Tools
- Linux:
Optional
Git
Required if:
- Installing the asdf plugin
- Installing from Git repository
- Contributing to development
Installation:
- Linux:
sudo apt-get install git(Debian/Ubuntu) - macOS:
brew install gitor Xcode Command Line Tools - Windows: Git for Windows
asdf
Only required for asdf installation method.
Project Requirements
To verify a contract, your project must meet these requirements:
Successful Build
Your project must build successfully with:
scarb --release build
Important: The remote compiler uses
scarb --release build, so all compiler configurations must be in the[profile.release]section of yourScarb.toml.
Scarb.toml Configuration
Minimum configuration:
[package]
name = "my_project"
version = "0.1.0"
[dependencies]
starknet = ">=2.11.2"
[[target.starknet-contract]]
sierra = true
With release profile (recommended):
[package]
name = "my_project"
version = "0.1.0"
[dependencies]
starknet = ">=2.11.2"
[[target.starknet-contract]]
sierra = true
[profile.release.cairo]
# Add any compiler configurations needed for deployment
# For example:
# sierra-replace-ids = true
# inlining-strategy = "avoid"
Contract Class Information
You must have:
- Class Hash: The class hash of your declared contract class
- Contract Name: The name of the contract to verify
- Network: Where the contract class is declared (mainnet, sepolia, etc.)
License (Optional)
A valid SPDX license identifier. You can specify this:
-
In
Scarb.toml:[package] license = "MIT" -
Via CLI flag:
--license MIT -
In
.voyager.tomlconfig file:[voyager] license = "MIT"
If not specified, defaults to “All Rights Reserved”.
For valid license identifiers, see SPDX License List.
Supported Versions
Cairo
The verifier is version-agnostic. Support is determined by server availability.
Currently supported (as of 2025):
- Cairo up to 2.11.4
- Newer versions are added with a slight lag after release
Scarb
The verifier supports all Scarb versions compatible with supported Cairo versions.
Recommended:
- Scarb 2.8.0 or later
Dojo (for Dojo projects)
For Dojo projects:
- Dojo 0.7.0 or later
- Automatic version detection from
Scarb.toml
Network Requirements
API Endpoints
The verifier needs access to:
- Mainnet API:
https://api.voyager.online/beta - Sepolia API:
https://sepolia-api.voyager.online/beta - Custom endpoints: If using
--urlflag
Firewall/Proxy
If behind a corporate firewall or proxy:
- Ensure HTTPS outbound traffic is allowed to Voyager API endpoints
- Configure proxy settings if needed (via environment variables:
HTTP_PROXY,HTTPS_PROXY)
Desktop Notifications (Optional)
For desktop notification support:
- Linux: Requires D-Bus and a notification daemon
- macOS: Works out of the box
- Windows: Works with Windows 10/11 notification system
Can be disabled during build with --no-default-features if not needed.
Verification Checklist
Before attempting verification, ensure:
- Scarb is installed and in PATH
- Your project builds with
scarb --release build - You have the class hash of your declared contract class
- You know your contract name
- Release profile configuration is in
Scarb.tomlif needed - Network connectivity to Voyager API
- (Optional) License identifier is specified
Next Steps
Once you’ve verified all requirements are met:
- Install voyager-verifier using asdf or Cargo
- Proceed to the Quickstart Guide
Troubleshooting
If you’re missing requirements:
- Scarb not found: Install from Scarb documentation
- Build fails: Check your
Scarb.tomlconfiguration and dependencies - Network issues: Verify firewall/proxy settings
- Version compatibility: Update to supported Cairo/Scarb versions
For more help, see the Troubleshooting Guide.
Quickstart Guide
This guide will walk you through verifying your first contract in just a few minutes.
Prerequisites
Before starting, ensure you have:
- ✅ Voyager Verifier installed (installation guide)
- ✅ A Scarb project that builds successfully (
scarb --release build) - ✅ A declared contract class with its class hash
- ✅ Your contract name
Choose Your Path
There are three ways to verify a contract. Choose the one that fits your experience level:
🧙 Interactive Wizard (Recommended for First-Time Users)
The easiest way to verify your contract with guided prompts.
⌨️ Command Line (For Experienced Users)
Direct command-line verification for those who know what they’re doing.
📦 Batch Verification (For Multiple Contracts)
Verify multiple contracts at once using a configuration file.
See Batch Verification Guide →
Wizard Method
The interactive wizard guides you through every step.
1. Navigate to Your Project
cd /path/to/your/scarb/project
2. Run the Wizard
voyager verify --wizard
3. Follow the Prompts
The wizard will ask you for:
-
Network Selection
- Choose: Mainnet, Sepolia, Dev, or Custom
- Example:
mainnet
-
Class Hash
- The class hash of your declared contract class
- Example:
0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
-
Package (for workspace projects only)
- Select the package to verify
- Auto-detected for single-package projects
-
Contract Name
- The name of your contract
- Example:
MyToken
-
License (optional)
- Auto-detected from
Scarb.tomlif present - Can specify manually (e.g.,
MIT,Apache-2.0)
- Auto-detected from
-
Optional Features
- Include lock file? (Scarb.lock)
- Include test files? (from src/ directory)
- Watch mode? (monitor status in real-time)
- Verbose output? (detailed error messages)
4. Confirm and Submit
Review the summary and confirm to submit your verification.
5. Monitor Progress
If you enabled watch mode, the tool will automatically monitor the verification status. Otherwise, use the job ID to check status manually:
voyager status --network mainnet --job <JOB_ID>
Command Line Method
For experienced users who prefer direct commands.
1. Navigate to Your Project
cd /path/to/your/scarb/project
2. Verify Your Contract
Mainnet:
voyager verify --network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyToken \
--license MIT \
--watch
Sepolia (testnet):
voyager verify --network sepolia \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyToken \
--license MIT \
--watch
Custom API endpoint:
voyager verify --url https://api.custom.com/beta \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyToken \
--license MIT \
--watch
3. Check Status
If you didn’t use --watch, check the status manually:
voyager status --network mainnet --job <JOB_ID>
Common Options
Include Lock File
Include Scarb.lock for reproducible builds:
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--lock-file
Include Test Files
Include test files from the src/ directory:
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--test-files
Watch Mode with Notifications
Monitor verification and get desktop notifications:
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--watch \
--notify
Verbose Output
Get detailed error messages if verification fails:
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--verbose
Dry Run
Preview what will be submitted without actually verifying:
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--dry-run
Workspace Projects
For projects with multiple packages, specify the package:
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--package my_contract_package
Verification Status
Understanding Status Messages
During verification, you’ll see different status messages:
- Submitted - Verification job created, waiting to start
- Compiling - Remote compiler is building your contract
- Verifying - Comparing compiled output with deployed contract
- Success - Verification successful! ✅
- Failed - Verification failed (use
--verbosefor details) ❌ - CompileFailed - Compilation error (use
--verbosefor details) ❌
Watch Mode
With --watch, you’ll see a live progress bar:
⏳ Verifying contract...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 45%
Status: Compiling | Elapsed: 1m 23s | Estimated: 3m 0s
Manual Status Check
Without watch mode, check status anytime:
# Using the status command
voyager status --network mainnet --job abc-123-def
# Or using history
voyager history status --job abc-123-def
View Your Verified Contract
Once verification succeeds:
- Visit Voyager Explorer
- Search for your class hash
- You’ll see the verified badge ✓
- View your source code directly in the explorer
Note: Contracts verified on mainnet automatically appear verified on Sepolia as well.
Example: Complete Workflow
Here’s a complete example from start to finish:
# 1. Navigate to your project
cd ~/projects/my-starknet-token
# 2. Ensure it builds
scarb --release build
# 3. Verify on mainnet with watch mode
voyager verify --network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyToken \
--license MIT \
--watch \
--notify
# 4. Wait for notification or completion message
# 5. View on Voyager
# Visit: https://voyager.online/class/0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Troubleshooting
Common Issues
Contract not building?
# Test your build first
scarb --release build
# Check for errors and fix them
Module file not found error?
If you get errors about missing test files:
# Include test files in verification
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--test-files
Want more details on errors?
# Use verbose mode
voyager status --network mainnet --job <JOB_ID> --verbose
Need to preview before submitting?
# Use dry run mode
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--dry-run
For more troubleshooting help, see the Troubleshooting Guide.
Next Steps
Now that you’ve verified your first contract, explore more advanced features:
- Configuration Files - Reduce command verbosity with
.voyager.toml - Batch Verification - Verify multiple contracts at once
- History Tracking - View and manage verification history
- Watch Mode - Learn more about monitoring verifications
- Command Reference - Complete command documentation
Quick Reference
Minimal Command
voyager verify --network mainnet \
--class-hash <HASH> \
--contract-name <NAME>
Recommended Command
voyager verify --network mainnet \
--class-hash <HASH> \
--contract-name <NAME> \
--license MIT \
--watch
Full-Featured Command
voyager verify --network mainnet \
--class-hash <HASH> \
--contract-name <NAME> \
--license MIT \
--lock-file \
--watch \
--notify \
--verbose
Happy verifying! 🚀
Command Reference
Voyager Verifier provides four main commands for contract verification and management.
Available Commands
Core Commands
-
verify- Submit contracts for verificationThe primary command for submitting your Starknet contracts for verification on Voyager. Supports interactive wizard mode, direct CLI usage, and batch verification.
-
status- Check verification job statusQuery the status of a verification job using its job ID. Supports watch mode for continuous monitoring and multiple output formats.
-
check- Check if a class is already verifiedQuery whether a contract class is already verified on Voyager before submitting a verification request. Useful for CI/CD pipelines.
-
history- Manage verification historyView, filter, and manage your local verification history database. Track past verifications, recheck pending jobs, and view statistics.
Quick Command Examples
Verify a Contract
# Interactive wizard
voyager verify --wizard
# Direct command
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken
# Batch verification
voyager verify # Uses .voyager.toml configuration
Check Status
# One-time status check
voyager status --network mainnet --job abc-123-def
# Watch until completion
voyager status --network mainnet --job abc-123-def --watch
# JSON output for scripts
voyager status --network mainnet --job abc-123-def --format json
Check Verification
# Check if class is verified
voyager check --network mainnet --class-hash 0x044dc2b3...
# JSON output for scripts
voyager check --network mainnet --class-hash 0x044dc2b3... --json
View History
# List all verifications
voyager history list
# Filter by status
voyager history list --status success
# View statistics
voyager history stats
# Recheck pending jobs
voyager history recheck --network mainnet
Common Patterns
First-Time Verification
For users new to the tool:
voyager verify --wizard
Production Workflow
Typical production verification with all recommended flags:
voyager verify --network mainnet \
--class-hash <HASH> \
--contract-name <NAME> \
--license MIT \
--lock-file \
--watch \
--notify
CI/CD Pipeline
Automated verification without watch mode:
voyager verify --network mainnet \
--class-hash <HASH> \
--contract-name <NAME> \
--format json \
--verbose
Multi-Contract Deployment
For verifying multiple contracts:
# Define contracts in .voyager.toml
voyager verify --watch --batch-delay 5
Global Options
These options are available across all commands:
Help
Get help for any command:
voyager --help
voyager verify --help
voyager status --help
voyager history --help
Version
Check the installed version:
voyager --version
Network Selection
Most commands require network specification:
Predefined Networks
--network mainnet # Starknet mainnet
--network sepolia # Sepolia testnet
--network dev # Development network
Custom Endpoint
--url https://api.custom.com/beta
Configuration File
Set default network in .voyager.toml:
[voyager]
network = "mainnet"
Output Formats
Commands that support multiple output formats:
--format text # Human-readable (default)
--format json # Machine-readable JSON
--format table # Formatted table (for batch operations)
Common Flags
Verbosity
-v, --verbose # Show detailed error messages
Watch Mode
--watch # Monitor job until completion
Notifications
--notify # Desktop notifications (requires --watch)
Configuration Priority
Options can be specified in multiple ways. Priority order:
- CLI arguments (highest priority)
.voyager.tomlconfiguration file- Default values (lowest priority)
Example:
# .voyager.toml sets network = "sepolia"
# This command overrides to use mainnet
voyager verify --network mainnet --class-hash 0x044... --contract-name MyToken
Exit Codes
Voyager Verifier uses standard exit codes:
- 0 - Success
- 1 - General error
- 2 - Invalid arguments
- Other - Specific error conditions
Use in scripts:
if voyager verify --network mainnet --class-hash 0x044... --contract-name MyToken; then
echo "Verification submitted successfully"
else
echo "Verification submission failed"
exit 1
fi
Environment Variables
Proxy Configuration
export HTTP_PROXY=http://proxy.example.com:8080
export HTTPS_PROXY=http://proxy.example.com:8080
Logging
export RUST_LOG=debug # Enable debug logging
export RUST_LOG=info # Info level logging (default)
Shell Completion
Generate shell completion scripts:
# Bash
voyager completions bash > /etc/bash_completion.d/voyager
# Zsh
voyager completions zsh > /usr/local/share/zsh/site-functions/_voyager
# Fish
voyager completions fish > ~/.config/fish/completions/voyager.fish
Note: Completion support may vary by version. Check voyager --help for availability.
Next Steps
Explore detailed documentation for each command:
- verify command - Complete verification reference
- status command - Status checking reference
- check command - Check verification status reference
- history command - History management reference
For practical examples, see the Examples section.
verify Command
The verify command submits Starknet contracts for verification on the Voyager block explorer.
Synopsis
voyager verify [OPTIONS]
Description
The verify command collects your contract source files, compiles them remotely using the same build configuration, and verifies that the compiled output matches your declared contract class. Upon successful verification, your contract will display a verified badge on Voyager.
Verification Modes
Interactive Wizard Mode
Guided step-by-step verification (recommended for first-time users):
voyager verify --wizard
Command Line Mode
Direct verification with all parameters specified:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken
Batch Mode
Verify multiple contracts using .voyager.toml configuration:
voyager verify
Batch mode is automatically enabled when [[contracts]] array exists in your config file.
Options
Required Options
--network <NETWORK>
Specify the target network.
Values:
mainnet- Starknet mainnetsepolia- Sepolia testnetdev- Development network
Example:
voyager verify --network mainnet --class-hash 0x044... --contract-name MyToken
Alternative: Use --url for custom endpoints, or configure in .voyager.toml.
--url <URL>
Custom API endpoint URL (alternative to --network).
Example:
voyager verify --url https://api.custom.com/beta \
--class-hash 0x044... \
--contract-name MyToken
Note: Cannot be used together with --network.
--class-hash <HASH>
The class hash of your declared contract class.
Format: Hexadecimal string starting with 0x
Example:
voyager verify --network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyToken
Note: Not required when using --wizard or batch mode.
--contract-name <NAME>
The name of the contract to verify.
Example:
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken
Note: Must match the contract name in your Cairo source code. Not required when using --wizard or batch mode.
Optional Options
--wizard
Launch interactive verification wizard.
Example:
voyager verify --wizard
Prompts you step-by-step for all required information.
--path <PATH>
Path to the Scarb project directory.
Default: Current working directory
Example:
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--path /path/to/my/project
--package <PACKAGE_ID>
Specify which package to verify (required for workspace projects with multiple packages).
Example:
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--package my_contract_package
Alternative: Configure default-package in .voyager.toml:
[workspace]
default-package = "my_contract_package"
--license <SPDX_ID>
SPDX license identifier for your contract.
Default:
- Value from
Scarb.tomlif specified - Value from
.voyager.tomlif specified - “All Rights Reserved” if not specified
Example:
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--license MIT
Common licenses: MIT, Apache-2.0, GPL-3.0, BSD-3-Clause
See SPDX License List for all valid identifiers.
--lock-file
Include Scarb.lock file in verification submission.
Default: false
Example:
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--lock-file
Use case: Ensures reproducible builds by locking dependency versions.
--test-files
Include test files from the src/ directory in verification submission.
Default: false
Example:
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--test-files
Use case: When your contract depends on test utilities or when test modules are declared in lib.cairo.
--watch
Monitor verification status until completion.
Default: false
Example:
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--watch
Displays live progress updates and waits for final result.
--notify
Send desktop notifications when verification completes.
Default: false
Requires: --watch must also be specified
Example:
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--watch \
--notify
--dry-run
Preview what will be submitted without actually sending the verification request.
Default: false
Example:
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--dry-run
Output: Shows complete API request payload including all metadata and file list.
--verbose, -v
Show detailed error messages and compilation output.
Default: false
Example:
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--verbose
--project-type <TYPE>
Specify project type manually.
Values:
auto- Automatic detection (default)scarb- Standard Scarb projectdojo- Dojo framework project
Default: auto
Example:
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--project-type dojo
Batch Verification Options
--fail-fast
Stop batch verification on first failure.
Default: false (continues with remaining contracts)
Example:
voyager verify --fail-fast
--batch-delay <SECONDS>
Add delay between contract submissions in batch mode.
Default: No delay
Example:
voyager verify --batch-delay 5
Use case: Rate limiting for API throttling.
Output Options
--format <FORMAT>
Output format for verification results.
Values:
text- Human-readable text (default)json- Machine-readable JSONtable- Formatted table (for batch operations)
Example:
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--format json
Configuration File
Options can be set in .voyager.toml:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
test-files = false
lock-file = true
verbose = false
notify = false
project-type = "auto"
[workspace]
default-package = "my_contract"
# Batch verification
[[contracts]]
class-hash = "0x044dc2b3..."
contract-name = "MyToken"
package = "token" # Optional
[[contracts]]
class-hash = "0x055dc2b3..."
contract-name = "MyNFT"
CLI arguments override config file values.
Examples
Basic Verification
Minimal command:
voyager verify --network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyToken
Recommended Verification
With license and watch mode:
voyager verify --network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyToken \
--license MIT \
--watch
Production Verification
Full-featured with all options:
voyager verify --network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyToken \
--license MIT \
--lock-file \
--watch \
--notify \
--verbose
Workspace Project
Specify package:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--package my_contract_package
Custom Endpoint
Using custom API:
voyager verify --url https://api.custom.com/beta \
--class-hash 0x044dc2b3... \
--contract-name MyToken
Dry Run
Preview before submitting:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--dry-run
Batch Verification
Define contracts in .voyager.toml:
[voyager]
network = "mainnet"
license = "MIT"
[[contracts]]
class-hash = "0x044dc2b3..."
contract-name = "Token"
[[contracts]]
class-hash = "0x055dc2b3..."
contract-name = "NFT"
Then run:
voyager verify --watch --batch-delay 5
Output
Success Output
✓ Verification submitted successfully!
Job ID: abc-123-def-456
Network: mainnet
Class Hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Check status with:
voyager status --network mainnet --job abc-123-def-456
Watch Mode Output
⏳ Verifying contract...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 65%
Status: Compiling | Elapsed: 1m 45s | Estimated: 2m 42s
✓ Verification successful!
View on Voyager: https://voyager.online/class/0x044dc2b3...
Batch Mode Output
[1/3] Verifying: MyToken
✓ Submitted - Job ID: abc-123-def
[2/3] Verifying: MyNFT
⏳ Waiting 5 seconds before next submission...
✓ Submitted - Job ID: ghi-456-jkl
[3/3] Verifying: MyMarketplace
✓ Submitted - Job ID: mno-789-pqr
════════════════════════════════════════════════════════
Batch Verification Summary
════════════════════════════════════════════════════════
Total contracts: 3
Submitted: 3
Succeeded: 0
Failed: 0
Pending: 3
════════════════════════════════════════════════════════
Exit Codes
- 0 - Verification submitted successfully
- 1 - Verification submission failed
- 2 - Invalid arguments or configuration
Error Handling
Common errors and solutions:
E001: Invalid class hash format
Error: [E001] Invalid class hash format
Solution: Ensure class hash starts with 0x and is valid hexadecimal.
E004: Compilation failed
Error: [E004] Compilation failed
Solution: Use --verbose to see full compilation error details.
E005: Module file not found
Error: [E005] Module file not found
Solution: Include test files with --test-files if the missing file is a test module.
For complete error reference, see Error Codes.
See Also
- status command - Check verification status
- history command - View verification history
- Interactive Wizard - Wizard mode guide
- Batch Verification - Batch verification guide
- Configuration File - Config file reference
- Troubleshooting - Troubleshooting guide
status Command
The status command checks the verification status of a submitted job.
Synopsis
voyager status --job <JOB_ID> [OPTIONS]
Description
The status command queries the Voyager API to retrieve the current status of a verification job. It can perform a one-time status check or continuously monitor the job until completion using watch mode.
Required Options
--job <JOB_ID>
The verification job ID to check.
Format: Job ID string returned by the verify command
Example:
voyager status --network mainnet --job abc-123-def-456
Network Selection
One of the following is required:
--network <NETWORK>
Specify the target network.
Values:
mainnet- Starknet mainnetsepolia- Sepolia testnetdev- Development network
Example:
voyager status --network mainnet --job abc-123-def
--url <URL>
Custom API endpoint URL (alternative to --network).
Example:
voyager status --url https://api.custom.com/beta --job abc-123-def
Note: Cannot be used together with --network. Can be configured in .voyager.toml.
Optional Options
--watch
Monitor job status continuously until completion.
Default: false
Example:
voyager status --network mainnet --job abc-123-def --watch
Behavior:
- Polls the API every 2 seconds
- Displays live progress updates
- Exits when job reaches terminal status (Success, Failed, CompileFailed)
- Maximum timeout: 10 minutes (300 retries)
--notify
Send desktop notification when verification completes.
Default: false
Requires: --watch must also be specified
Example:
voyager status --network mainnet --job abc-123-def --watch --notify
Platforms: Linux, macOS, Windows
--verbose, -v
Show detailed error messages and compilation output.
Default: false
Example:
voyager status --network mainnet --job abc-123-def --verbose
Use case: View full compilation errors when verification fails.
--format <FORMAT>
Output format for status information.
Values:
text- Human-readable text (default)json- Machine-readable JSON
Default: text
Example:
voyager status --network mainnet --job abc-123-def --format json
JSON Output Example:
{
"job_id": "abc-123-def-456",
"status": "Success",
"class_hash": "0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18",
"contract_name": "MyToken",
"network": "mainnet",
"submitted_at": "2025-01-15T10:30:00Z",
"completed_at": "2025-01-15T10:32:45Z"
}
Configuration File
Network and other options can be configured in .voyager.toml:
[voyager]
network = "mainnet"
watch = true
verbose = false
CLI arguments override config file values.
Job Status Values
In-Progress Statuses
Submitted
- Job created and queued
- Waiting to start compilation
Processing
- Job is being processed
- Source files are being prepared
Compiling
- Remote compiler is building your contract
- Using
scarb --release build
Compiled
- Compilation successful
- Performing verification checks
Verifying
- Comparing compiled output with declared contract class
Terminal Statuses
Success ✅
- Verification completed successfully
- Contract is now verified on Voyager
- Source code is viewable in the explorer
Failed ❌
- Verification failed
- Compiled output doesn’t match declared contract class
- Use
--verbosefor details
CompileFailed ❌
- Compilation failed on remote server
- Build error in your source code
- Use
--verboseto see full compiler output
Examples
Basic Status Check
One-time status check:
voyager status --network mainnet --job abc-123-def-456
Watch Mode
Monitor until completion:
voyager status --network mainnet --job abc-123-def-456 --watch
Watch with Notifications
Get notified when complete:
voyager status --network mainnet --job abc-123-def-456 --watch --notify
Verbose Output
View detailed error information:
voyager status --network mainnet --job abc-123-def-456 --verbose
JSON Output
For scripting and CI/CD:
voyager status --network mainnet --job abc-123-def-456 --format json
Custom Endpoint
Using custom API:
voyager status --url https://api.custom.com/beta --job abc-123-def-456
Combined Options
Full-featured status check:
voyager status --network mainnet \
--job abc-123-def-456 \
--watch \
--notify \
--verbose
Output
Text Format (Default)
In-Progress:
⏳ Verifying contract...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 45%
Status: Compiling | Elapsed: 1m 23s | Estimated: 3m 0s
Success:
✓ Verification successful!
Job ID: abc-123-def-456
Status: Success
Class Hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Contract Name: MyToken
Network: mainnet
View on Voyager: https://voyager.online/class/0x044dc2b3...
Failed:
✗ Verification failed
Job ID: abc-123-def-456
Status: Failed
Reason: Compiled output does not match declared contract class
Use --verbose for detailed error output
CompileFailed:
✗ Compilation failed
Job ID: abc-123-def-456
Status: CompileFailed
Error: [E004] Compilation failed: `scarb` command exited with error
Use --verbose to see full compilation output
JSON Format
Success:
{
"job_id": "abc-123-def-456",
"status": "Success",
"class_hash": "0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18",
"contract_name": "MyToken",
"network": "mainnet",
"submitted_at": "2025-01-15T10:30:00Z",
"completed_at": "2025-01-15T10:32:45Z",
"compiler_version": "2.11.4",
"scarb_version": "2.8.4"
}
Failed:
{
"job_id": "abc-123-def-456",
"status": "Failed",
"class_hash": "0x044dc2b3...",
"contract_name": "MyToken",
"network": "mainnet",
"submitted_at": "2025-01-15T10:30:00Z",
"completed_at": "2025-01-15T10:32:45Z",
"error": "Compiled output does not match declared contract class"
}
Verbose Output
With --verbose, failed compilations show full compiler output:
✗ Compilation failed
Job ID: abc-123-def-456
Status: CompileFailed
Compilation Output:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
error[E0005]: Module file not found. Expected path: /tmp/targets/.../src/tests.cairo
--> lib.cairo:3:1
|
3 | mod tests;
| ^^^^^^^^^^
|
Error: Could not compile contract due to previous error
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Suggestion: Include test files with --test-files flag or remove test module declaration
Progress Estimation
When using --watch, the progress bar estimates completion time based on:
- Historical data - Average time from your last 10 successful verifications (requires minimum 3 samples)
- Stage-based fallback - If no history available, uses stage-specific estimates:
- Submitted: ~2 minutes remaining
- Compiling: ~90 seconds remaining
- Verifying: ~30 seconds remaining
Progress estimation improves automatically as you verify more contracts.
Exit Codes
- 0 - Job completed successfully (Success status)
- 1 - Job failed (Failed or CompileFailed status)
- 2 - Invalid arguments or job not found
Polling Behavior
Fixed Interval Polling
The status command uses fixed 2-second polling intervals (not exponential backoff):
- Poll interval: Every 2 seconds
- Maximum retries: 300 (10 minutes total)
- Timeout: Exits after 10 minutes if job hasn’t completed
Timeout Handling
If job doesn’t complete within 10 minutes:
⚠ Timeout: Job did not complete within 10 minutes
Current status: Compiling
You can check status later with:
voyager status --network mainnet --job abc-123-def-456
Using with History
The status command automatically updates the local history database when checking job status. For faster local lookups without API calls, use:
# Check from local history (no API call)
voyager history status --job abc-123-def-456
# Refresh from API and update history
voyager history status --job abc-123-def-456 --network mainnet --refresh
See history command for more details.
Scripting and Automation
CI/CD Pipeline
Check status in CI/CD with JSON output:
#!/bin/bash
JOB_ID=$(voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--format json | jq -r '.job_id')
# Wait for completion
voyager status --network mainnet --job "$JOB_ID" --watch --format json > result.json
# Check result
STATUS=$(jq -r '.status' result.json)
if [ "$STATUS" = "Success" ]; then
echo "Verification successful"
exit 0
else
echo "Verification failed"
jq -r '.error' result.json
exit 1
fi
Loop Until Complete
Manual polling in a script:
#!/bin/bash
JOB_ID="abc-123-def-456"
while true; do
STATUS=$(voyager status --network mainnet --job "$JOB_ID" --format json | jq -r '.status')
case "$STATUS" in
"Success")
echo "Verification successful!"
exit 0
;;
"Failed"|"CompileFailed")
echo "Verification failed: $STATUS"
exit 1
;;
*)
echo "Status: $STATUS - waiting..."
sleep 5
;;
esac
done
Troubleshooting
Job Not Found
Error: [E020] Job not found: abc-123-def-456
Solutions:
- Verify the job ID is correct
- Ensure you’re using the correct network (
--networkor--url) - Check if the job was submitted to a different network
Timeout in Watch Mode
If watch mode times out, check status manually later:
voyager status --network mainnet --job abc-123-def-456
Or check from history:
voyager history status --job abc-123-def-456
Network Connectivity Issues
If API calls fail:
# Check with verbose output
voyager status --network mainnet --job abc-123-def-456 --verbose
# Try custom endpoint
voyager status --url https://api.voyager.online/beta --job abc-123-def-456
See Also
- verify command - Submit contracts for verification
- history command - View verification history
- Watch Mode Guide - Detailed watch mode documentation
- Output Formats - Output format reference
- Troubleshooting - Common issues and solutions
Check Command
The check command allows you to verify if a contract class is already verified on Voyager.
Basic Usage
voyager check --network mainnet --class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Options
| Option | Short | Description |
|---|---|---|
--network | Network to check (mainnet, sepolia, dev) | |
--url | Custom API endpoint URL | |
--class-hash | Class hash to check (0x-prefixed hex) | |
--json | -j | Output result as JSON |
--verbose | -v | Show detailed error messages |
Examples
Check on Mainnet
voyager check --network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Output (Verified):
✓ Class 0x044dc2b3... is verified
Name: MyContract
Version: 0.1.0
License: MIT
Contract file: src/lib.cairo
Verified: 2025-01-15 10:30:45 UTC
Output (Not Verified):
✗ Class 0x044dc2b3... is not verified
Output (Not Found):
! Class 0x044dc2b3... not found on-chain
Check on Sepolia
voyager check --network sepolia \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
JSON Output
For programmatic use, output as JSON:
voyager check --network mainnet \
--class-hash 0x044dc2b3... \
--json
Output:
{
"verified": true,
"class_hash": "0x044dc2b3...",
"name": "MyContract",
"version": "0.1.0",
"license": "MIT",
"verified_timestamp": 1705315845.0,
"contract_file": "src/lib.cairo"
}
Using Custom URL
voyager check --url https://custom-api.example.com/beta \
--class-hash 0x044dc2b3...
Use Cases
Pre-verification Check
Before submitting a verification request, check if the class is already verified:
# Check first
voyager check --network mainnet --class-hash 0x044dc2b3...
# If not verified, submit verification
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
CI/CD Integration
Use in scripts to conditionally verify:
#!/bin/bash
CLASS_HASH="0x044dc2b3..."
# Check if already verified
if voyager check --network mainnet --class-hash $CLASS_HASH --json | jq -e '.verified' > /dev/null 2>&1; then
echo "Contract already verified"
else
echo "Submitting for verification..."
voyager verify --network mainnet \
--class-hash $CLASS_HASH \
--contract-name MyContract \
--watch
fi
Batch Verification Status
Check multiple classes:
#!/bin/bash
CLASS_HASHES=(
"0x044dc2b3..."
"0x123abc..."
"0x456def..."
)
for hash in "${CLASS_HASHES[@]}"; do
echo "Checking $hash..."
voyager check --network mainnet --class-hash $hash
done
Response Fields
When a class is verified, the following information is returned:
| Field | Description |
|---|---|
verified | Whether the class is verified (true/false) |
class_hash | The class hash that was checked |
name | Contract name (if verified) |
version | Package version (if verified) |
license | SPDX license identifier (if verified) |
verified_timestamp | Unix timestamp of verification (if verified) |
contract_file | Main contract file path (if verified) |
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success (class found, verified or not) |
| 1 | Class not found on-chain |
| Non-zero | Other error (network failure, etc.) |
Configuration File
The check command supports configuration via .voyager.toml:
[voyager]
network = "mainnet"
verbose = true
Then simply run:
voyager check --class-hash 0x044dc2b3...
See Also
- Verify Command - Submit contracts for verification
- Status Command - Check verification job status
- Configuration - Configuration file reference
history Command
The history command manages your local verification history database, allowing you to view, filter, and track past verification jobs.
Synopsis
voyager history <SUBCOMMAND> [OPTIONS]
Description
The history command provides access to a local SQLite database (~/.voyager/history.db) that automatically tracks all verification submissions. This allows you to:
- View past verifications across sessions
- Filter by status, network, or date
- Re-check pending jobs
- Generate verification statistics
- Clean old records
All verification jobs are automatically tracked when using the verify command. No additional setup is required.
Subcommands
list
View all verification jobs with optional filtering.
voyager history list [OPTIONS]
status
View detailed information about a specific job from local database.
voyager history status --job <JOB_ID> [OPTIONS]
recheck
Re-check all pending jobs and update their status.
voyager history recheck --network <NETWORK> [OPTIONS]
stats
Display verification statistics and success rates.
voyager history stats
clean
Remove old records from the history database.
voyager history clean [OPTIONS]
history list
List verification jobs from the history database.
Synopsis
voyager history list [OPTIONS]
Options
--status <STATUS>
Filter by verification status.
Values:
success- Show only successful verificationsfail- Show only failed verificationspending- Show only pending/in-progress jobs
Example:
voyager history list --status success
--network <NETWORK>
Filter by network.
Values: mainnet, sepolia, dev
Example:
voyager history list --network mainnet
--limit <N>
Limit the number of results.
Default: Unlimited
Example:
voyager history list --limit 10
Examples
List all verifications:
voyager history list
List recent 20 verifications:
voyager history list --limit 20
List successful mainnet verifications:
voyager history list --status success --network mainnet
List pending jobs:
voyager history list --status pending
Output
Verification History
════════════════════════════════════════════════════════════════
✓ MyToken (0x044dc2b3...da18)
Job: abc-123-def | Network: mainnet | Submitted: 2025-01-15 10:30
✓ MyNFT (0x055dc2b3...da19)
Job: ghi-456-jkl | Network: mainnet | Submitted: 2025-01-15 09:15
⏳ MyMarketplace (0x066dc2b3...da20)
Job: mno-789-pqr | Network: sepolia | Submitted: 2025-01-14 16:45
✗ OldContract (0x077dc2b3...da21)
Job: stu-012-vwx | Network: mainnet | Submitted: 2025-01-14 14:20
════════════════════════════════════════════════════════════════
Total: 4 verifications
history status
View detailed information about a specific job from the local database.
Synopsis
voyager history status --job <JOB_ID> [OPTIONS]
Options
--job <JOB_ID> (Required)
The job ID to查询.
Example:
voyager history status --job abc-123-def-456
--refresh
Refresh status from API and update the database.
Requires: --network or --url must be specified
Example:
voyager history status --job abc-123-def-456 --network mainnet --refresh
--network <NETWORK>
Network for API refresh (only used with --refresh).
Example:
voyager history status --job abc-123-def --network mainnet --refresh
--url <URL>
Custom API endpoint for refresh (alternative to --network).
Example:
voyager history status --job abc-123-def --url https://api.custom.com/beta --refresh
Examples
View from local database (fast, no API call):
voyager history status --job abc-123-def-456
Refresh from API and update database:
voyager history status --job abc-123-def-456 --network mainnet --refresh
Output
Job Details
════════════════════════════════════════════════════════════════
Job ID: abc-123-def-456
Status: Success ✓
Contract Name: MyToken
Class Hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Network: mainnet
Submitted: 2025-01-15 10:30:00
Completed: 2025-01-15 10:32:45
Duration: 2m 45s
Versions:
Cairo: 2.11.4
Scarb: 2.8.4
View on Voyager: https://voyager.online/class/0x044dc2b3...
history recheck
Re-check all pending jobs and update their status from the API.
Synopsis
voyager history recheck --network <NETWORK> [OPTIONS]
Options
--network <NETWORK> (Required)
Network to query for status updates.
Example:
voyager history recheck --network mainnet
--url <URL>
Custom API endpoint (alternative to --network).
Example:
voyager history recheck --url https://api.custom.com/beta
Examples
Recheck all pending mainnet jobs:
voyager history recheck --network mainnet
Recheck all pending sepolia jobs:
voyager history recheck --network sepolia
Output
Rechecking pending verifications...
[1/3] Checking abc-123-def...
✓ Updated: Success
[2/3] Checking ghi-456-jkl...
⏳ Still pending: Compiling
[3/3] Checking mno-789-pqr...
✗ Updated: Failed
════════════════════════════════════════════════════════════════
Rechecked: 3 jobs
Updated: 2 jobs
Still pending: 1 job
════════════════════════════════════════════════════════════════
history stats
Display verification statistics from the history database.
Synopsis
voyager history stats
Options
No options available for this subcommand.
Example
voyager history stats
Output
Verification History Statistics
════════════════════════════════════════════════════════════════
Total verifications: 47
✓ Successful: 41 (87%)
✗ Failed: 4 (9%)
⏳ Pending: 2 (4%)
Networks:
Mainnet: 35 verifications
Sepolia: 12 verifications
Average verification time: 2m 34s
history clean
Remove old records from the history database.
Synopsis
voyager history clean [OPTIONS]
Options
--older-than <DAYS>
Delete records older than the specified number of days.
Example:
voyager history clean --older-than 30
--all
Delete all history records (requires confirmation).
Example:
voyager history clean --all
Examples
Delete records older than 30 days:
voyager history clean --older-than 30
Delete records older than 90 days:
voyager history clean --older-than 90
Delete all history:
voyager history clean --all
Output
Older than:
Cleaning history records older than 30 days...
Deleted: 15 records
Remaining: 32 records
All (with confirmation):
⚠ Warning: This will delete ALL verification history records.
Are you sure? (yes/no): yes
Deleted: 47 records
History database cleared.
History Database
Location
The history database is stored at:
~/.voyager/history.db
What Gets Tracked
For each verification job, the following information is stored:
- Job ID
- Class hash
- Contract name
- Network (mainnet, sepolia, dev)
- Status (Submitted, Processing, Compiling, Success, Failed, etc.)
- Submission timestamp
- Completion timestamp (when applicable)
- Cairo version
- Scarb version
- Dojo version (for Dojo projects)
Automatic Tracking
History tracking is automatic and transparent:
- When you run
voyager verify, the job is added to history - When you run
voyager status, the job status is updated in history - When you run
voyager history recheck, all pending jobs are updated
No manual intervention is required.
Cross-Session Persistence
The history database persists across terminal sessions and system restarts, allowing you to track verifications over time.
Use Cases
Track Project Deployments
Keep a record of all contract verifications for your project:
# List all verifications for audit purposes
voyager history list
# Filter by network
voyager history list --network mainnet
# View statistics
voyager history stats
Resume After Disconnect
If your terminal disconnects during watch mode:
# List pending jobs
voyager history list --status pending
# Check specific job
voyager history status --job abc-123-def
# Refresh from API
voyager history status --job abc-123-def --network mainnet --refresh
Clean Up Old Records
Periodically clean old verification records:
# Monthly cleanup
voyager history clean --older-than 30
# Quarterly cleanup
voyager history clean --older-than 90
Batch Status Updates
Update all pending jobs at once:
# Check all pending mainnet verifications
voyager history recheck --network mainnet
# Check all pending sepolia verifications
voyager history recheck --network sepolia
Scripting Examples
Export History to JSON
#!/bin/bash
# Get all successful verifications
voyager history list --status success --format json > successful_verifications.json
Monitor Pending Jobs
#!/bin/bash
# Continuously recheck pending jobs every 5 minutes
while true; do
echo "Rechecking pending jobs..."
voyager history recheck --network mainnet
sleep 300
done
Generate Report
#!/bin/bash
echo "Verification Report - $(date)"
echo "================================"
echo ""
voyager history stats
echo ""
echo "Recent Verifications:"
voyager history list --limit 10
Exit Codes
- 0 - Command completed successfully
- 1 - Command failed or error occurred
- 2 - Invalid arguments
See Also
- verify command - Submit contracts for verification
- status command - Check verification status
- History Overview - Detailed history documentation
- Listing - List command details
- Statistics - Stats command details
- Cleanup - Clean command details
Verification Methods
This section is currently under development as part of Phase 2.
Voyager Verifier offers multiple ways to verify your Starknet contracts:
- Interactive Wizard - Step-by-step guided verification
- Command Line - Direct CLI verification with full control
- Batch Verification - Verify multiple contracts at once
- Watch Mode - Monitor verification progress in real-time
- Dry Run - Preview what will be submitted
Quick Links
For now, see:
Full documentation for verification methods will be added in Phase 2.
Interactive Wizard
The interactive wizard provides a guided, step-by-step verification experience for users new to Voyager Verifier or those who don’t use it frequently.
Overview
The wizard mode:
- Prompts you step-by-step for all required information
- Auto-detects licenses from
Scarb.toml - Provides helpful explanations for each option
- Validates input before proceeding
- Shows a summary for confirmation before submission
- Recommended for first-time users
Starting the Wizard
voyager verify --wizard
You can run the wizard from any directory - it will prompt you for the project path if needed.
Wizard Flow
Step 1: Network Selection
Prompt:
Select network:
1. Mainnet (https://api.voyager.online/beta)
2. Sepolia (https://sepolia-api.voyager.online/beta)
3. Dev
4. Custom (specify URL)
Enter choice [1-4]:
Options:
- 1 - Mainnet (production Starknet network)
- 2 - Sepolia (testnet for development)
- 3 - Dev (development network)
- 4 - Custom (you’ll be asked for a custom API endpoint URL)
Example:
Enter choice [1-4]: 1
✓ Selected: Mainnet
Step 2: Class Hash
Prompt:
Enter class hash:
Input: The class hash of your declared contract class (hexadecimal starting with 0x)
Example:
Enter class hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
✓ Class hash: 0x044dc2b3...da18
Validation:
- Must start with
0x - Must be valid hexadecimal
- Provides immediate feedback if invalid
Step 3: Package Selection (Workspace Projects Only)
Prompt (if workspace detected):
Multiple packages found:
1. token
2. nft
3. marketplace
Select package [1-3]:
Behavior:
- Only shown for workspace projects with multiple packages
- Skipped for single-package projects
- Auto-detected from
Scarb.toml
Example:
Select package [1-3]: 1
✓ Selected package: token
Step 4: Contract Name
Prompt:
Enter contract name:
Input: The name of the contract to verify (must match your Cairo source code)
Example:
Enter contract name: MyToken
✓ Contract name: MyToken
Tips:
- Must match the contract name in your source code
- Case-sensitive
- Should be the module name with the
#[starknet::contract]attribute
Step 5: License
Prompt:
License detected in Scarb.toml: MIT
Use this license? [Y/n]:
Behavior:
- Auto-detects license from
Scarb.tomlif present - Prompts for confirmation if detected
- Asks for manual entry if not detected
If license detected:
Use this license? [Y/n]: y
✓ License: MIT
If no license detected:
No license found in Scarb.toml
Enter SPDX license identifier (or press Enter for "All Rights Reserved"):
MIT
✓ License: MIT
Common licenses:
MITApache-2.0GPL-3.0BSD-3-Clause- Press Enter for “All Rights Reserved”
See SPDX License List for all valid identifiers.
Step 6: Optional Features
The wizard asks about optional features:
Include Lock File?
Prompt:
Include Scarb.lock file in verification? [y/N]:
Options:
- y - Include
Scarb.lockfor reproducible builds - N - Don’t include (default)
Use case: Ensures exact dependency versions match deployment
Include Test Files?
Prompt:
Include test files from src/ directory? [y/N]:
Options:
- y - Include test files if they’re needed for compilation
- N - Don’t include (default)
Use case: When test modules are declared in lib.cairo
Enable Watch Mode?
Prompt:
Monitor verification status until completion? [Y/n]:
Options:
- Y - Wait and monitor verification status (default, recommended)
- n - Submit and exit
Behavior:
- Y - Displays live progress and waits for final result
- n - Returns job ID immediately for manual checking
Enable Verbose Output?
Prompt:
Enable verbose output for detailed error messages? [y/N]:
Options:
- y - Show full compilation output on errors
- N - Show condensed error messages (default)
Use case: Debugging compilation failures
Step 7: Confirmation Summary
Prompt:
════════════════════════════════════════════════════════
Verification Summary
════════════════════════════════════════════════════════
Network: Mainnet
Class Hash: 0x044dc2b3...da18
Contract Name: MyToken
Package: token
License: MIT
Lock File: No
Test Files: No
Watch Mode: Yes
Verbose: No
════════════════════════════════════════════════════════
Proceed with verification? [Y/n]:
Review all settings before final confirmation.
Options:
- Y - Submit verification (default)
- n - Cancel and exit
Step 8: Submission
After confirmation, the verification is submitted:
✓ Verification submitted successfully!
Job ID: abc-123-def-456
Network: mainnet
Class Hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
⏳ Monitoring verification status...
If watch mode is enabled, live progress updates will be shown.
Complete Example
Here’s a complete wizard session:
$ voyager verify --wizard
Select network:
1. Mainnet
2. Sepolia
3. Dev
4. Custom
Enter choice [1-4]: 1
✓ Selected: Mainnet
Enter class hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
✓ Class hash: 0x044dc2b3...da18
Enter contract name: MyToken
✓ Contract name: MyToken
License detected in Scarb.toml: MIT
Use this license? [Y/n]: y
✓ License: MIT
Include Scarb.lock file in verification? [y/N]: y
✓ Lock file: Yes
Include test files from src/ directory? [y/N]: n
✓ Test files: No
Monitor verification status until completion? [Y/n]: y
✓ Watch mode: Yes
Enable verbose output for detailed error messages? [y/N]: n
✓ Verbose: No
════════════════════════════════════════════════════════
Verification Summary
════════════════════════════════════════════════════════
Network: Mainnet
Class Hash: 0x044dc2b3...da18
Contract Name: MyToken
License: MIT
Lock File: Yes
Test Files: No
Watch Mode: Yes
Verbose: No
════════════════════════════════════════════════════════
Proceed with verification? [Y/n]: y
✓ Verification submitted successfully!
Job ID: abc-123-def-456
Network: mainnet
Class Hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
⏳ Monitoring verification status...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 35%
Status: Compiling | Elapsed: 1m 15s | Estimated: 3m 0s
Wizard from Different Locations
From Project Root
cd /path/to/my-project
voyager verify --wizard
Project is auto-detected from current directory.
From Outside Project
voyager verify --wizard --path /path/to/my-project
Or the wizard will prompt you for the path:
Enter project path (or press Enter for current directory):
/path/to/my-project
Auto-Detection Features
The wizard automatically detects and suggests:
License Detection
Reads license from Scarb.toml:
[package]
license = "MIT"
The wizard will:
- Detect “MIT” from Scarb.toml
- Prompt for confirmation
- Allow override if needed
Package Detection
For workspace projects, reads from Scarb.toml:
[workspace]
members = ["token", "nft", "marketplace"]
The wizard will:
- List all packages
- Provide numbered selection
- Validate selection
Project Path Detection
- Uses current directory by default
- Validates Scarb.toml exists
- Prompts if not found in current directory
Input Validation
The wizard validates all inputs:
Class Hash Validation
Invalid:
Enter class hash: 044dc2b3...
✗ Error: Class hash must start with 0x
Enter class hash: 0xINVALID
✗ Error: Class hash must be valid hexadecimal
Enter class hash:
Valid:
Enter class hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
✓ Class hash: 0x044dc2b3...da18
Contract Name Validation
Invalid:
Enter contract name:
✗ Error: Contract name cannot be empty
Enter contract name:
Valid:
Enter contract name: MyToken
✓ Contract name: MyToken
License Validation
Invalid:
Enter SPDX license identifier: INVALID-LICENSE
✗ Error: Invalid SPDX license identifier
Enter SPDX license identifier:
Valid:
Enter SPDX license identifier: MIT
✓ License: MIT
Canceling the Wizard
Press Ctrl+C at any time to cancel:
^C
Verification canceled.
No submission is made if you cancel before final confirmation.
Error Handling
If submission fails, the wizard provides clear error messages:
✗ Verification failed: Invalid class hash format
Please check your input and try again.
Common errors:
- Invalid class hash format
- Contract not found
- Network unreachable
- Invalid Scarb project
Advantages of Wizard Mode
For New Users:
- No need to memorize command options
- Guided step-by-step process
- Helpful explanations at each step
- Input validation prevents mistakes
For Occasional Users:
- Don’t need to recall exact command syntax
- Auto-detection reduces typing
- Summary review catches errors before submission
For All Users:
- Quick and error-free verification
- Ideal for one-off verifications
- Less prone to typos than command-line
When to Use Wizard vs CLI
Use Wizard When:
- First time verifying a contract
- Verifying contracts occasionally
- Want guided experience
- Prefer interactive prompts
- Not automating verification
Use CLI When:
- Verifying frequently
- Automating in scripts
- Using in CI/CD pipelines
- Prefer direct command control
- Using configuration files
See Command Line Verification for CLI usage.
Combining Wizard with Config Files
The wizard respects values from .voyager.toml:
Config file:
[voyager]
network = "mainnet"
license = "MIT"
Wizard behavior:
- Pre-selects network from config
- Pre-fills license from config
- Allows override if needed
- CLI args have highest priority
Tips
- Review Summary: Always review the summary before confirming
- Use Watch Mode: Enable watch mode to see final results
- Save Settings: For repeated verifications, consider using a config file
- Keep Info Handy: Have class hash and contract name ready before starting
- Test on Sepolia: Verify on Sepolia first before mainnet
See Also
- Command Line Verification - Direct CLI commands
- Batch Verification - Verify multiple contracts
- verify command reference - Complete command documentation
- Configuration files - Using .voyager.toml
Command-Line Verification
Command-line verification provides direct control over the verification process through CLI flags and arguments, ideal for automation, CI/CD pipelines, and experienced users who prefer explicit control.
Overview
Command-line mode offers:
- Direct control - Specify all parameters explicitly via flags
- Automation-friendly - Perfect for scripts and CI/CD pipelines
- Config file support - Use
.voyager.tomlto reduce verbosity - Flexible networking - Choose predefined networks or custom endpoints
- Workspace support - Handle multi-package projects with
--package - Batch operations - Verify multiple contracts from config
Basic Syntax
With Predefined Network
voyager verify --network <NETWORK> \
--class-hash <HASH> \
--contract-name <NAME> \
[OPTIONS]
With Custom Endpoint
voyager verify --url <API_URL> \
--class-hash <HASH> \
--contract-name <NAME> \
[OPTIONS]
Required Arguments
Network Selection
You must specify either --network or --url (but not both):
Predefined Networks
# Mainnet (production)
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
# Sepolia (testnet)
voyager verify --network sepolia \
--class-hash 0x044dc2b3... \
--contract-name MyContract
# Dev network
voyager verify --network dev \
--class-hash 0x044dc2b3... \
--contract-name MyContract
Available networks:
mainnet- Main Starknet network (API:https://api.voyager.online/beta)sepolia- Starknet testnet (API:https://sepolia-api.voyager.online/beta)dev- Development network
Custom Endpoints
voyager verify --url https://api.custom.com/beta \
--class-hash 0x044dc2b3... \
--contract-name MyContract
Use custom endpoints for:
- Private networks
- Custom deployments
- Testing against staging environments
Class Hash
--class-hash <HASH>
The class hash of your declared contract class.
Requirements:
- Must be a valid hexadecimal string
- Must start with
0x - Case-insensitive
Examples:
# Full hash
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
# Different formats (all valid)
--class-hash 0x44dc2b3... # Will be rejected if not complete
--class-hash 0x044DC2B3... # Case doesn't matter
Contract Name
--contract-name <NAME>
The name of the contract to verify (must match a contract in your project).
Examples:
--contract-name MyToken
--contract-name ERC20Contract
--contract-name my_nft_contract
Optional Arguments
Project Path
--path <PATH>
Path to your Scarb project directory. Defaults to the current working directory.
Examples:
# Verify project in a different directory
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--path /home/user/projects/my-contract
# Verify from current directory (default)
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
License
--license <SPDX_ID>
SPDX license identifier for your contract.
Priority:
--licenseCLI flag (highest priority)licensein.voyager.tomlconfiglicenseinScarb.tomlpackage section- “All Rights Reserved” (default)
Examples:
--license MIT
--license Apache-2.0
--license GPL-3.0
--license BSD-3-Clause
See SPDX License List for valid identifiers.
Package Selection
--package <PACKAGE_ID>
Required for workspace projects with multiple packages. Specifies which package to verify.
Examples:
# Workspace project with multiple packages
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--package token
# Single package project (--package not needed)
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
Alternative: Set workspace.default-package in .voyager.toml to avoid specifying --package every time:
[workspace]
default-package = "token"
File Inclusion Options
Lock File
--lock-file
Include Scarb.lock file in the verification submission.
Use cases:
- Ensure reproducible builds by locking dependency versions
- Required for projects with specific dependency versions
- Useful for production deployments
Example:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--lock-file
Test Files
--test-files
Include test files from the src/ directory in verification.
Use cases:
- Contracts that reference test utilities
- Test helper functions used by contract code
- Shared test fixtures
Behavior:
- Only includes test files from
src/directory - Files with “test” or “tests” in their path within
src/ - Dedicated
tests/directories are still excluded
Example:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files
Common scenario:
src/
├── lib.cairo
├── contract.cairo
└── test_helpers.cairo # Included with --test-files
tests/
└── integration.cairo # Always excluded
Watch Mode
--watch
Poll the verification status until completion instead of just submitting and exiting.
Behavior:
- Automatically polls the server for status updates
- Uses exponential backoff to avoid overwhelming the API
- Displays real-time progress
- Exits when verification completes (success or failure)
Example:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--watch
Output:
✓ Verification job submitted successfully
Job ID: abc-123-def-456
⏳ Watching verification job...
Status: Pending
⏱️ Estimated time: 2-5 minutes
Status: In Progress
⏱️ Progress: Compiling sources...
Status: Completed
✅ Verification successful!
🔗 View on Voyager: https://voyager.online/contract/0x044dc2b3...
See Watch Mode for detailed documentation.
Desktop Notifications
--notify
Send desktop notifications when verification completes. Requires --watch to be enabled.
Example:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--watch \
--notify
Notification content:
- Success: “✅ Contract verified: MyContract”
- Failure: “❌ Verification failed: MyContract”
See Desktop Notifications for platform setup and troubleshooting.
Dry Run
--dry-run
Preview what files would be collected and sent without actually submitting for verification.
Use cases:
- Debug file collection issues
- Verify correct files are being included
- Preview verification payload before submission
- Check configuration without consuming API quota
Example:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--dry-run
See Dry Run Mode for detailed output examples.
Verbose Output
--verbose
# or
-v
Display detailed error messages and debugging information.
Use cases:
- Troubleshooting verification failures
- Debugging file collection issues
- Understanding API errors
- Getting full compiler output from remote server
Example:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--verbose
Complete Examples
Basic Verification
Simplest form with required arguments only:
voyager verify --network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyToken
Full-Featured Verification
With all common options:
voyager verify --network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyToken \
--license MIT \
--lock-file \
--test-files \
--watch \
--notify \
--verbose
Workspace Project
Verifying a package in a workspace:
voyager verify --network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name TokenContract \
--package token \
--watch
Custom Endpoint
Using a custom API endpoint:
voyager verify --url https://api.custom.network.com/beta \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyContract \
--license Apache-2.0 \
--watch
Development Workflow
Quick verification during development:
voyager verify --network sepolia \
--class-hash 0x044dc2b3... \
--contract-name TestContract \
--test-files \
--watch \
--verbose
Production Deployment
Production-ready with all safeguards:
voyager verify --network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name ProductionContract \
--license MIT \
--lock-file \
--watch \
--notify
CI/CD Pipeline
Non-blocking verification for automation:
voyager verify --network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyContract \
--license MIT \
--lock-file \
--verbose
# Don't use --watch in CI to avoid blocking
Then check status later:
voyager status --network mainnet --job <JOB_ID> --verbose
Using Configuration Files
Reduce command-line verbosity with .voyager.toml:
Basic Config
[voyager]
network = "mainnet"
license = "MIT"
watch = true
lock-file = true
Then your command becomes:
# Before (without config)
voyager verify --network mainnet --license MIT --watch --lock-file \
--class-hash 0x044dc2b3... --contract-name MyContract
# After (with config)
voyager verify --class-hash 0x044dc2b3... --contract-name MyContract
Workspace Config
[voyager]
network = "mainnet"
license = "MIT"
watch = true
[workspace]
default-package = "token"
Then verify without specifying package:
voyager verify --class-hash 0x044dc2b3... --contract-name MyContract
# Uses default-package from config
Override Config Values
CLI arguments always take precedence:
# .voyager.toml
[voyager]
network = "mainnet"
# Override network for this verification
voyager verify --network sepolia \
--class-hash 0x044dc2b3... \
--contract-name MyContract
See Configuration File Guide for comprehensive documentation.
Comparison with Wizard Mode
| Aspect | Command Line | Wizard (--wizard) |
|---|---|---|
| Best for | Experienced users, automation | First-time users, occasional use |
| Speed | Fast (one command) | Slower (interactive prompts) |
| Automation | Excellent | Not suitable |
| Learning curve | Requires knowing all flags | Guided, self-explanatory |
| Config support | Full config file integration | Limited |
| Batch verification | Supported | Not supported |
| CI/CD | Perfect | Not recommended |
| Error prevention | Manual validation | Built-in validation |
When to use command-line:
- You know exactly what you’re doing
- Automating verification in scripts
- Using in CI/CD pipelines
- Verifying multiple contracts (batch mode)
- Using config files for team consistency
When to use wizard:
- First time using the tool
- Occasional verification (not memorized flags)
- Want guided experience with validation
- Exploring options without reading docs
- Prefer interactive prompts over flags
Common Patterns
Quick Verify with Defaults
Minimal command with sensible defaults:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
Verify and Wait
Submit and monitor until completion:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--watch
Verify with Notifications
Get notified when done (great for long builds):
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--watch \
--notify
Debug Verification
Preview files and see detailed output:
# First, dry run to check files
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--dry-run
# Then verify with verbose output
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--verbose \
--watch
Team Consistency
Use shared config for consistent verification:
# .voyager.toml (committed to repo)
[voyager]
network = "mainnet"
license = "MIT"
lock-file = true
watch = true
verbose = false
All team members use the same command:
voyager verify --class-hash 0x044dc2b3... --contract-name MyContract
Error Handling
Common Errors
Missing Required Arguments
Error: Missing required argument: --class-hash
Solution: Provide the missing argument:
voyager verify --network mainnet --class-hash 0x044dc2b3... --contract-name MyContract
Invalid Network/URL Combination
Error: Cannot specify both --network and --url
Solution: Use only one:
# Either network
voyager verify --network mainnet ...
# Or custom URL
voyager verify --url https://api.custom.com/beta ...
Package Required for Workspace
Error: Multiple packages found. Use --package to specify which one to verify.
Solution: Specify the package:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--package token
Or set default in config:
[workspace]
default-package = "token"
Invalid Class Hash
Error: Invalid class hash format. Must be hexadecimal starting with 0x
Solution: Ensure proper format:
# Correct
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
# Incorrect
--class-hash 044dc2b3... # Missing 0x prefix
--class-hash 0xZZZ... # Invalid hex characters
Troubleshooting Tips
- Use
--dry-runfirst to preview file collection - Add
--verboseto see detailed error messages - Check local build with
scarb --release build - Verify network connectivity to API endpoints
- Review history with
voyager history listto check past attempts
See Troubleshooting Guide for comprehensive debugging help.
Next Steps
- Watch Mode - Learn about real-time verification monitoring
- Dry Run Mode - Preview verification before submission
- Batch Verification - Verify multiple contracts at once
- Configuration File - Reduce command verbosity
- CLI Options Reference - Complete flag documentation
Batch Verification
Batch verification allows you to verify multiple contracts in a single command by defining them in your .voyager.toml configuration file. This is ideal for multi-contract deployments, workspace projects, and protocol suites.
Overview
Instead of running separate verify commands for each contract, batch verification:
- Submits multiple contracts sequentially
- Tracks all jobs with individual progress
- Continues on error by default (optional fail-fast mode)
- Supports rate limiting with configurable delays
- Provides comprehensive summary output
- Integrates with watch mode for real-time monitoring
Setting Up Batch Verification
1. Create Configuration File
Create or edit .voyager.toml in your project root:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
# Define contracts to verify
[[contracts]]
class-hash = "0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18"
contract-name = "MyToken"
[[contracts]]
class-hash = "0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19"
contract-name = "MyNFT"
[[contracts]]
class-hash = "0x066dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da20"
contract-name = "MyMarketplace"
2. Run Batch Verification
Simply run the verify command without additional arguments:
voyager verify
The tool automatically detects batch mode when the [[contracts]] array is present.
Configuration Format
Basic Contract Definition
Minimum required fields:
[[contracts]]
class-hash = "0x044dc2b3..."
contract-name = "MyToken"
With Package (Workspace Projects)
For workspace projects with multiple packages:
[[contracts]]
class-hash = "0x044dc2b3..."
contract-name = "MyToken"
package = "token"
If package is omitted, the tool will:
- Use
workspace.default-packageif configured - Auto-detect the package
- Fail with clear error if ambiguous
Complete Example
[voyager]
network = "mainnet"
license = "MIT"
watch = true
lock-file = true
verbose = false
[workspace]
default-package = "contracts" # Fallback for contracts without package
[[contracts]]
class-hash = "0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18"
contract-name = "Token"
package = "token" # Override default-package
[[contracts]]
class-hash = "0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19"
contract-name = "NFT"
package = "nft"
[[contracts]]
class-hash = "0x066dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da20"
contract-name = "Marketplace"
# Uses default-package: "contracts"
Batch Options
Watch Mode
Monitor all verifications until completion:
voyager verify --watch
Behavior:
- Submits all contracts first
- Then monitors all jobs concurrently
- Shows single-line status updates
- Displays final summary when all complete
Output:
⏳ Watching 3 verification job(s)...
✓ 2 Succeeded | ⏳ 1 Pending | ✗ 0 Failed
Fail-Fast Mode
Stop batch verification on first failure:
voyager verify --fail-fast
Default behavior (without --fail-fast):
- Continues with remaining contracts if one fails
- Shows all results in summary
With --fail-fast:
- Stops immediately when a contract verification fails
- Remaining contracts are not submitted
- Useful for critical deployment pipelines
Batch Delay
Add delay between contract submissions for rate limiting:
voyager verify --batch-delay 5
Use cases:
- API rate limiting
- Server load management
- Staggered deployments
Example with 10-second delay:
voyager verify --batch-delay 10 --watch
Combined Options
voyager verify --watch --batch-delay 5 --verbose
Output Format
Submission Phase
As each contract is submitted:
[1/3] Verifying: MyToken
✓ Submitted - Job ID: abc-123-def
[2/3] Verifying: MyNFT
⏳ Waiting 5 seconds before next submission...
✓ Submitted - Job ID: ghi-456-jkl
[3/3] Verifying: MyMarketplace
✓ Submitted - Job ID: mno-789-pqr
Summary Output
After all submissions:
════════════════════════════════════════════════════════
Batch Verification Summary
════════════════════════════════════════════════════════
Total contracts: 3
Submitted: 3
Succeeded: 0
Failed: 0
Pending: 3
════════════════════════════════════════════════════════
Contract Details:
⏳ Submitted MyToken (Job: abc-123-def)
⏳ Submitted MyNFT (Job: ghi-456-jkl)
⏳ Submitted MyMarketplace (Job: mno-789-pqr)
Watch Mode Output
With --watch, live updates during monitoring:
⏳ Watching 3 verification job(s)...
✓ 1 Succeeded | ⏳ 2 Pending | ✗ 0 Failed
[Updates every 2 seconds...]
✓ 2 Succeeded | ⏳ 1 Pending | ✗ 0 Failed
[Final state...]
✓ 3 Succeeded | ⏳ 0 Pending | ✗ 0 Failed
=== Final Summary ===
════════════════════════════════════════════════════════
Batch Verification Summary
════════════════════════════════════════════════════════
Total contracts: 3
Submitted: 3
Succeeded: 3
Failed: 0
Pending: 0
════════════════════════════════════════════════════════
Contract Details:
✓ Success MyToken (Job: abc-123-def)
✓ Success MyNFT (Job: ghi-456-jkl)
✓ Success MyMarketplace (Job: mno-789-pqr)
Error Output
If submissions fail:
[1/3] Verifying: MyToken
✗ Failed - Error: Invalid class hash format
[2/3] Verifying: MyNFT
✓ Submitted - Job ID: ghi-456-jkl
[3/3] Verifying: MyMarketplace
✓ Submitted - Job ID: mno-789-pqr
════════════════════════════════════════════════════════
Batch Verification Summary
════════════════════════════════════════════════════════
Total contracts: 3
Submitted: 2
Succeeded: 0
Failed: 1
Pending: 2
════════════════════════════════════════════════════════
Contract Details:
✗ Failed MyToken - Invalid class hash format
⏳ Submitted MyNFT (Job: ghi-456-jkl)
⏳ Submitted MyMarketplace (Job: mno-789-pqr)
Use Cases
Multi-Contract Workspace
Verify all contracts in a workspace project:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
[workspace]
default-package = "contracts"
[[contracts]]
class-hash = "0x123..."
contract-name = "ERC20Token"
[[contracts]]
class-hash = "0x456..."
contract-name = "ERC721NFT"
[[contracts]]
class-hash = "0x789..."
contract-name = "Marketplace"
Run:
voyager verify --watch
Protocol Suite Deployment
Deploy an entire protocol with multiple components:
[voyager]
network = "mainnet"
license = "Apache-2.0"
watch = true
lock-file = true
[[contracts]]
class-hash = "0xabc..."
contract-name = "CoreProtocol"
package = "core"
[[contracts]]
class-hash = "0xdef..."
contract-name = "GovernanceModule"
package = "governance"
[[contracts]]
class-hash = "0x012..."
contract-name = "TreasuryModule"
package = "treasury"
[[contracts]]
class-hash = "0x345..."
contract-name = "StakingModule"
package = "staking"
Run:
voyager verify --watch --batch-delay 3
Rate-Limited Deployment
For APIs with strict rate limits:
[voyager]
network = "mainnet"
license = "MIT"
[[contracts]]
class-hash = "0x111..."
contract-name = "Contract1"
[[contracts]]
class-hash = "0x222..."
contract-name = "Contract2"
[[contracts]]
class-hash = "0x333..."
contract-name = "Contract3"
Run with 10-second delays:
voyager verify --batch-delay 10 --watch
CI/CD Pipeline
Automated verification without blocking:
[voyager]
network = "mainnet"
license = "MIT"
watch = false # Don't block CI
verbose = true
[[contracts]]
class-hash = "0xaaa..."
contract-name = "ProductionContract"
Run:
voyager verify --format json > results.json
Important Notes
Automatic Detection
Batch mode is automatically enabled when:
[[contracts]]array exists in.voyager.toml- No
--class-hashor--contract-namearguments provided
Incompatible Flags
You cannot use these flags with batch mode:
--class-hash- Conflicts with config-defined hashes--contract-name- Conflicts with config-defined names--wizard- Wizard is for single-contract verification
Error example:
voyager verify --class-hash 0x123... --contract-name MyToken
# Error: Cannot use --class-hash with batch mode. Remove class-hash from command or [[contracts]] from config.
Shared Settings
All contracts in a batch use the same settings from [voyager] section:
- Network
- License
- Lock file inclusion
- Test file inclusion
- Verbose mode
- Project type
Individual package can be specified per contract in the [[contracts]] array.
Error Handling
Default (continue-on-error):
- Failed submissions don’t stop the batch
- All contracts are attempted
- Summary shows all results
With --fail-fast:
- First failure stops the batch
- Remaining contracts are skipped
- Summary shows partial results
History Tracking
All batch verifications are automatically tracked in the history database:
# View batch verification history
voyager history list --limit 10
# Check specific job from batch
voyager history status --job abc-123-def
Troubleshooting
Config File Not Found
Error: No configuration file found
Solution: Create .voyager.toml in project root or parent directory.
No Contracts Defined
Error: No contracts defined in configuration file
Solution: Add [[contracts]] array to .voyager.toml:
[[contracts]]
class-hash = "0x..."
contract-name = "MyContract"
Network Not Specified
Error: Network must be specified (--network or --url) or configured in .voyager.toml
Solution: Add network to config:
[voyager]
network = "mainnet"
Package Ambiguity
Error: Multiple packages found. Please specify --package or set workspace.default-package
Solution: Set default package or specify per contract:
[workspace]
default-package = "my_package"
# Or specify per contract
[[contracts]]
class-hash = "0x..."
contract-name = "MyContract"
package = "specific_package"
Partial Submission Failure
Some contracts submitted, others failed:
Solution: Check the summary output for specific errors:
# Use verbose mode to see full errors
voyager verify --verbose
Best Practices
1. Use Watch Mode
Always use --watch for batch verifications to see final results:
voyager verify --watch
2. Add Rate Limiting
For large batches, add delays to avoid overwhelming the API:
voyager verify --batch-delay 5
3. Enable Verbose for CI/CD
In automated pipelines, enable verbose mode:
[voyager]
verbose = true
watch = false
4. Group by Package
For workspaces, organize contracts by package:
[[contracts]]
class-hash = "0x..."
contract-name = "CoreToken"
package = "core"
[[contracts]]
class-hash = "0x..."
contract-name = "CoreGovernance"
package = "core"
[[contracts]]
class-hash = "0x..."
contract-name = "UtilsHelper"
package = "utils"
5. Use Fail-Fast for Critical Deployments
When order matters:
voyager verify --fail-fast
6. Version Control Config
Commit .voyager.toml to share batch configurations:
git add .voyager.toml
git commit -m "Add batch verification config"
Scripting Examples
Bash Script
#!/bin/bash
echo "Starting batch verification..."
if voyager verify --watch --batch-delay 5; then
echo "✓ All verifications succeeded"
exit 0
else
echo "✗ Some verifications failed"
voyager history list --status fail --limit 5
exit 1
fi
CI/CD Integration (GitHub Actions)
- name: Verify Contracts
run: |
voyager verify --watch --format json > results.json
- name: Check Results
run: |
FAILED=$(jq '.failed' results.json)
if [ "$FAILED" -gt 0 ]; then
echo "Verification failed for $FAILED contract(s)"
exit 1
fi
See Also
- verify command reference - Complete verify command documentation
- Configuration file - Configuration file reference
- Watch mode - Watch mode details
- History tracking - History management
- CI/CD integration - CI/CD examples
Watch Mode
Watch mode enables real-time monitoring of verification jobs, automatically polling the API until the job reaches a terminal state (Success, Failed, or CompileFailed).
Overview
Watch mode provides:
- Automatic polling - No need to manually check status
- Live progress updates - See real-time verification progress
- Progress estimation - Time-based completion estimates
- Progress bars - Visual representation of progress
- Stage-aware status - Different messages for each verification stage
- Desktop notifications - Optional alerts when complete (with
--notify) - Automatic timeout - Exits after 10 minutes if not complete
Enabling Watch Mode
During Verification
Enable watch mode when submitting a verification:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--watch
The tool will submit the verification and immediately start monitoring.
For Existing Jobs
Check status with watch mode for an already-submitted job:
voyager status --network mainnet \
--job abc-123-def-456 \
--watch
In Configuration File
Set watch mode as default in .voyager.toml:
[voyager]
watch = true
How Watch Mode Works
Polling Mechanism
Watch mode uses fixed-interval polling:
- Poll interval: Every 2 seconds
- Maximum retries: 300 attempts
- Total timeout: 10 minutes (600 seconds)
- No exponential backoff: Consistent 2-second intervals
Example timeline:
0s - Submit verification
2s - Poll #1 - Status: Submitted
4s - Poll #2 - Status: Compiling
6s - Poll #3 - Status: Compiling
...
120s - Poll #60 - Status: Success ✓
Terminal States
Watch mode exits when the job reaches any of these states:
- Success ✅ - Verification completed successfully
- Failed ❌ - Verification failed (compiled output doesn’t match)
- CompileFailed ❌ - Compilation failed on remote server
Non-Terminal States
These states continue polling:
- Submitted - Job queued, waiting to start
- Processing - Job being processed
- Compiling - Remote compilation in progress
- Compiled - Compilation complete, starting verification
- Verifying - Comparing compiled output with deployed contract
Progress Display
Live Progress Bar
Watch mode shows a live progress bar with time estimates:
⏳ Verifying contract...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 45%
Status: Compiling | Elapsed: 1m 23s | Estimated: 3m 0s
Components:
- Progress bar - Visual representation of completion
- Percentage - Estimated completion percentage
- Current status - Current verification stage
- Elapsed time - Time since submission
- Estimated total - Estimated total time to completion
Progress Estimation
Progress is estimated using two methods:
1. Historical Average (Preferred)
Uses your local verification history:
- Queries last 10 successful verifications from
~/.voyager/history.db - Calculates average verification time
- Requires minimum 3 samples
- Improves accuracy over time as you verify more contracts
Example:
Last 10 verifications averaged 2m 45s
Current elapsed: 1m 30s
Estimated completion: 2m 45s
Progress: 54% (1m 30s / 2m 45s)
2. Stage-Based Fallback
Used when insufficient history is available:
| Stage | Estimated Remaining Time |
|---|---|
| Submitted | ~2 minutes |
| Processing | ~90 seconds |
| Compiling | ~90 seconds |
| Compiled | ~45 seconds |
| Verifying | ~30 seconds |
Example (no history):
Status: Compiling
Elapsed: 1m 0s
Estimated remaining: 90s
Total estimated: 2m 30s
Progress: 40% (1m / 2m 30s)
Status Messages
Different messages for each stage:
Submitted:
⏳ Verification submitted, waiting to start...
Status: Submitted | Elapsed: 0m 15s
Compiling:
⏳ Verifying contract...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 35%
Status: Compiling | Elapsed: 1m 15s | Estimated: 3m 0s
Verifying:
⏳ Verifying contract...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 85%
Status: Verifying | Elapsed: 2m 30s | Estimated: 3m 0s
Success:
✓ Verification successful!
Job ID: abc-123-def-456
Status: Success
Class Hash: 0x044dc2b3...da18
Contract Name: MyToken
Network: mainnet
View on Voyager: https://voyager.online/class/0x044dc2b3...
Failed:
✗ Verification failed
Job ID: abc-123-def-456
Status: Failed
Reason: Compiled output does not match deployed contract
Use --verbose for detailed error output
CompileFailed:
✗ Compilation failed
Job ID: abc-123-def-456
Status: CompileFailed
Error: [E004] Compilation failed: `scarb` command exited with error
Use --verbose to see full compilation output
Timeout Handling
Maximum Duration
Watch mode has a 10-minute timeout:
- 300 polls × 2 seconds = 600 seconds (10 minutes)
- Prevents indefinite waiting for stuck jobs
- Provides clear timeout message
Timeout Behavior
If the job doesn’t complete within 10 minutes:
⚠ Timeout: Job did not complete within 10 minutes
Current status: Compiling
The job is still processing on the server.
You can check status later with:
voyager status --network mainnet --job abc-123-def-456
Or check from history:
voyager history status --job abc-123-def-456
Exit code: Non-zero (failure)
After Timeout
The job continues processing on the server even after timeout. You can:
Check status later:
voyager status --network mainnet --job abc-123-def-456
Check from history:
voyager history status --job abc-123-def-456
Resume watching:
voyager status --network mainnet --job abc-123-def-456 --watch
Desktop Notifications
Combine watch mode with desktop notifications:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--watch \
--notify
Behavior:
- Watch mode monitors the verification
- Desktop notification appears when complete
- Notification shows success (✅) or failure (❌)
- Allows you to work on other tasks while waiting
See Desktop Notifications for details.
Use Cases
Interactive Verification
When you want immediate feedback:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--watch
Benefits:
- No need to remember job ID
- Immediate status updates
- Know results right away
Background Monitoring with Notifications
For long-running verifications:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--watch \
--notify
Benefits:
- Continue working on other tasks
- Get notified when complete
- Don’t need to check manually
Batch Verification Monitoring
Watch all contracts in a batch:
voyager verify --watch
Output:
⏳ Watching 3 verification job(s)...
✓ 2 Succeeded | ⏳ 1 Pending | ✗ 0 Failed
See Batch Verification for details.
CI/CD Without Watch Mode
In automated pipelines, disable watch mode:
# Submit and exit immediately
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken
# Check status later in pipeline
voyager status --network mainnet --job $JOB_ID
Or use config file:
[voyager]
watch = false # Don't block CI pipeline
Comparison: Watch vs No Watch
With Watch Mode
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--watch
Behavior:
- Submit verification
- Display job ID
- Start polling immediately
- Show live progress
- Display final result
- Exit when complete
Duration: Waits until complete (or 10 min timeout)
Without Watch Mode
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken
Behavior:
- Submit verification
- Display job ID
- Exit immediately
Duration: < 5 seconds
Manual checking:
voyager status --network mainnet --job abc-123-def-456
Configuration Priority
Watch mode can be configured in multiple ways. Priority order:
-
CLI flag (highest priority)
voyager verify --watch # Enables voyager verify --no-watch # Disables (if supported) -
Configuration file
[voyager] watch = true -
Default value (lowest priority)
- Default:
false(watch mode disabled)
- Default:
Example:
# .voyager.toml
[voyager]
watch = true # Default: enable watch mode
# Override config file - disable watch mode for this command
voyager verify --network mainnet --class-hash 0x044... --contract-name MyToken
# Uses config file default (watch = true)
Performance Considerations
Network Usage
Watch mode polls every 2 seconds:
- Requests: 1 API call per 2 seconds
- Max requests: 300 requests (for 10-minute timeout)
- Typical requests: 30-90 requests (1-3 minute verification)
Network-friendly: Minimal data transfer, negligible bandwidth usage.
Rate Limiting
The 2-second interval is designed to be:
- Fast enough for responsive updates
- Slow enough to avoid API rate limits
- Respectful of server resources
Troubleshooting
Job Doesn’t Complete
If watch mode times out after 10 minutes:
Possible causes:
- Server is experiencing high load
- Complex contract taking longer than usual
- Build process encountered an issue
Solutions:
-
Check status later:
voyager status --network mainnet --job abc-123-def-456 -
Use verbose mode to see detailed errors:
voyager status --network mainnet --job abc-123-def-456 --verbose -
Contact support if job remains stuck
Progress Bar Not Updating
If the progress bar seems frozen:
Cause: Job is in the same stage (normal behavior)
Solution: Wait - compilation can take 1-3 minutes depending on contract size.
Inaccurate Time Estimates
If estimates seem wrong:
Cause: Insufficient historical data or unusual verification duration
Solution:
- Estimates improve as you verify more contracts
- Historical average based on last 10 successful verifications
- First few verifications use stage-based fallback estimates
Best Practices
1. Use Watch Mode Interactively
For manual verifications, enable watch mode:
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--watch
2. Disable in CI/CD
In automated pipelines, disable watch mode:
[voyager]
watch = false
3. Combine with Notifications
For long verifications, use notifications:
voyager verify --watch --notify
4. Check History After Timeout
If watch mode times out, check history:
voyager history status --job abc-123-def-456
5. Use Verbose for Failures
If verification fails, use verbose mode:
voyager status --network mainnet --job abc-123-def-456 --verbose
See Also
- verify command - verify command reference
- status command - status command reference
- Desktop Notifications - Notification setup
- Batch Verification - Monitoring multiple jobs
- Output Formats - Alternative output formats
Dry Run Mode
Dry run mode allows you to preview what files would be collected and submitted for verification without actually sending them to the API. This is essential for debugging, validation, and understanding what your verification payload will contain.
Overview
Dry run mode provides:
- File preview - See exactly which files will be included
- Metadata display - View contract and configuration details
- Payload inspection - Preview the complete verification payload
- Zero API consumption - No requests sent to the server
- Safe testing - Validate configuration without side effects
- Debug tool - Identify file collection issues before submission
Basic Usage
Add the --dry-run flag to any verify command:
voyager verify --network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyToken \
--dry-run
What Gets Displayed
1. Configuration Summary
Shows the verification configuration that would be used:
════════════════════════════════════════════════════════
Dry Run: Verification Preview
════════════════════════════════════════════════════════
Configuration:
Network: mainnet
API Endpoint: https://api.voyager.online/beta
Class Hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Contract: MyToken
License: MIT
Package: my_project
Lock File: No
Test Files: No
2. Project Information
Displays detected project metadata:
Project Details:
Project Type: Scarb
Project Path: /home/user/projects/my-contract
Scarb Version: 2.11.2
Cairo Version: 2.11.2
Package Name: my_project
3. File List
Shows all files that would be included in the verification:
Files to be submitted (5 files):
├── Scarb.toml (245 bytes)
├── src/lib.cairo (1,234 bytes)
├── src/contract.cairo (5,678 bytes)
├── src/utils.cairo (890 bytes)
└── src/events.cairo (456 bytes)
Total size: 8,503 bytes (8.3 KB)
4. File Content Preview (Optional)
With --verbose, shows file contents:
File Contents:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
File: Scarb.toml
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[package]
name = "my_project"
version = "0.1.0"
license = "MIT"
[dependencies]
starknet = ">=2.11.2"
...
Complete Examples
Basic Dry Run
Simple preview with default options:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--dry-run
Dry Run with Lock File
Preview including Scarb.lock:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--lock-file \
--dry-run
Output includes:
Files to be submitted (6 files):
├── Scarb.toml (245 bytes)
├── Scarb.lock (3,456 bytes) # ← Lock file included
├── src/lib.cairo (1,234 bytes)
├── src/contract.cairo (5,678 bytes)
├── src/utils.cairo (890 bytes)
└── src/events.cairo (456 bytes)
Dry Run with Test Files
Preview including test files from src/:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--test-files \
--dry-run
Output includes:
Files to be submitted (7 files):
├── Scarb.toml (245 bytes)
├── src/lib.cairo (1,234 bytes)
├── src/contract.cairo (5,678 bytes)
├── src/utils.cairo (890 bytes)
├── src/events.cairo (456 bytes)
├── src/test_helpers.cairo (678 bytes) # ← Test file included
└── src/tests.cairo (912 bytes) # ← Test file included
Verbose Dry Run
Show detailed file contents:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--dry-run \
--verbose
Workspace Dry Run
Preview verification for a specific package:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name TokenContract \
--package token \
--dry-run
Output includes:
Configuration:
Network: mainnet
API Endpoint: https://api.voyager.online/beta
Class Hash: 0x044dc2b3...
Contract: TokenContract
Package: token # ← Package specified
License: MIT
Project Details:
Project Type: Scarb (Workspace)
Packages: token, nft, marketplace
Selected: token
Use Cases
1. Debug File Collection Issues
Problem: Verification fails with “Module file not found” errors.
Solution: Use dry run to see which files are being included:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--dry-run
Check the file list to ensure all required modules are present. If test files are missing, add --test-files.
2. Verify Test File Inclusion
Problem: Contract references test utilities but they’re not included.
Solution: Compare dry run output with and without --test-files:
# Without test files
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--dry-run
# With test files
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--test-files \
--dry-run
3. Check Lock File Inclusion
Problem: Verification builds with different dependency versions.
Solution: Verify Scarb.lock is included:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--lock-file \
--dry-run
Look for Scarb.lock in the file list.
4. Validate Configuration
Problem: Unsure if config file settings are being applied correctly.
Solution: Run dry run to see effective configuration:
# With .voyager.toml in place
voyager verify --class-hash 0x044dc2b3... \
--contract-name MyToken \
--dry-run
The configuration summary shows the merged settings from config file and CLI arguments.
5. Preview Workspace Package Selection
Problem: Multiple packages, need to verify correct one is selected.
Solution: Dry run with package specification:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--package token \
--dry-run
Check the “Selected” package in the output.
6. Estimate Payload Size
Problem: Need to know verification payload size before submission.
Solution: Check the total size in dry run output:
Total size: 8,503 bytes (8.3 KB)
Useful for understanding data transfer requirements.
7. Audit Before Production Deployment
Problem: Want to double-check everything before mainnet verification.
Solution: Run comprehensive dry run:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name ProductionContract \
--license MIT \
--lock-file \
--dry-run \
--verbose
Review all configuration, files, and contents before actual submission.
Detailed Output Sections
Configuration Section
Shows all verification parameters:
| Field | Description |
|---|---|
| Network | Target network (mainnet/sepolia/dev) |
| API Endpoint | Full API URL being used |
| Class Hash | Contract class hash |
| Contract | Contract name |
| License | SPDX license identifier |
| Package | Package name (for workspace projects) |
| Lock File | Whether Scarb.lock is included |
| Test Files | Whether test files are included |
Project Details Section
Shows detected project information:
| Field | Description |
|---|---|
| Project Type | Scarb, Dojo, or Unknown |
| Project Path | Absolute path to project root |
| Scarb Version | Detected Scarb version |
| Cairo Version | Detected Cairo version |
| Package Name | Package identifier from Scarb.toml |
| Packages | List of packages (workspace only) |
| Selected | Selected package (workspace only) |
File List Section
Shows all files to be submitted:
- File paths relative to project root
- File sizes in bytes
- Total payload size
- Tree-style formatting for readability
File Content Section (Verbose Only)
With --verbose, displays:
- Full content of each file
- Syntax highlighting (if terminal supports it)
- Clear file separators
- Line numbers (optional)
Combining with Other Flags
Dry Run + Verbose
See full file contents:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--dry-run \
--verbose
Dry Run + Config File
Preview configuration from .voyager.toml:
# .voyager.toml
[voyager]
network = "mainnet"
license = "MIT"
lock-file = true
voyager verify --class-hash 0x044dc2b3... \
--contract-name MyToken \
--dry-run
Dry Run + Custom Endpoint
Test custom API configuration:
voyager verify --url https://api.custom.com/beta \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--dry-run
Common Patterns
Pre-Flight Check
Always dry run before actual verification:
# 1. Preview first
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--lock-file \
--dry-run
# 2. If looks good, submit
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--lock-file \
--watch
Debug Workflow
Use dry run to troubleshoot issues:
# 1. Basic dry run
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--dry-run
# 2. If files missing, try with test files
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--test-files \
--dry-run
# 3. Check detailed content
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--test-files \
--dry-run \
--verbose
Configuration Validation
Verify config file behavior:
# 1. Check what config file provides
voyager verify --class-hash 0x044dc2b3... \
--contract-name MyToken \
--dry-run
# 2. Test overrides
voyager verify --class-hash 0x044dc2b3... \
--contract-name MyToken \
--network sepolia \
--dry-run
Benefits
Safety
- No API consumption - Doesn’t count against rate limits
- No side effects - Nothing is submitted or recorded
- Risk-free testing - Experiment without consequences
- Validation - Catch issues before submission
Debugging
- File visibility - See exactly what’s included
- Configuration transparency - Understand effective settings
- Quick iteration - Test changes rapidly
- Problem diagnosis - Identify missing files or config issues
Documentation
- Self-documenting - Shows what will happen
- Team communication - Share expected payload with team
- Audit trail - Record what was verified
- Training - Learn tool behavior safely
Limitations
What Dry Run Doesn’t Do
- Server-side validation - Can’t catch API-specific errors
- Compilation check - Doesn’t verify code compiles on server
- Network testing - Doesn’t test API connectivity
- Authentication - Doesn’t validate API credentials
- Quota checking - Doesn’t verify rate limit status
When to Use Actual Verification
After dry run looks good, use normal verification to:
- Test actual compilation on remote server
- Validate against Voyager API
- Check for server-side errors
- Complete the verification process
Troubleshooting
No Files Listed
Problem:
Files to be submitted (0 files):
(none)
Causes:
- Wrong project path
- Not in a Scarb project
- Missing
Scarb.toml
Solutions:
# Specify correct path
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--path /correct/path \
--dry-run
# Verify Scarb.toml exists
ls Scarb.toml
Missing Test Files
Problem: Test files not showing in list.
Solution: Add --test-files flag:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--test-files \
--dry-run
Wrong Package Selected
Problem: Workspace showing wrong package.
Solution: Specify correct package:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--package correct_package \
--dry-run
Lock File Not Included
Problem: Scarb.lock missing from file list.
Solution: Add --lock-file flag:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--lock-file \
--dry-run
Integration with Workflow
Development Cycle
# 1. Make code changes
vim src/contract.cairo
# 2. Test locally
scarb test
# 3. Build locally
scarb build
# 4. Preview verification (dry run)
voyager verify --network sepolia \
--class-hash 0x123... \
--contract-name MyContract \
--dry-run
# 5. Submit verification
voyager verify --network sepolia \
--class-hash 0x123... \
--contract-name MyContract \
--watch
CI/CD Integration
# .github/workflows/verify.yml
- name: Dry run verification preview
run: |
voyager verify \
--network mainnet \
--class-hash ${{ env.CLASS_HASH }} \
--contract-name MyContract \
--lock-file \
--dry-run \
--verbose > dry-run-output.txt
- name: Upload dry run results
uses: actions/upload-artifact@v3
with:
name: verification-preview
path: dry-run-output.txt
- name: Actual verification
run: |
voyager verify \
--network mainnet \
--class-hash ${{ env.CLASS_HASH }} \
--contract-name MyContract \
--lock-file \
--verbose
Next Steps
- Command-Line Verification - Learn about all CLI options
- Watch Mode - Monitor verification progress
- Troubleshooting - Debug verification issues
- Configuration File - Set up persistent config
Configuration Overview
This section is currently under development as part of Phase 2.
Learn how to configure Voyager Verifier using:
- Configuration Files -
.voyager.tomlfor project-level settings - CLI Options - Command-line argument reference
- Workspace Settings - Managing workspace projects
- Configuration Examples - Common configuration patterns
Quick Start
For now, see the configuration section in the verify command reference.
Full configuration documentation will be added in Phase 2.
Configuration File Guide
The configuration file (.voyager.toml) provides a convenient way to set default values for verification options, reducing command-line verbosity and enabling shareable team configurations.
Overview
Configuration files offer:
- Reduced verbosity - No need to repeatedly specify the same options
- Team consistency - Commit
.voyager.tomlto share settings across team - Per-project defaults - Different projects can have different verification settings
- Environment-specific configs - Use different configs for dev/staging/production
- Priority system - CLI arguments always override config values
- Automatic discovery - Searches current and parent directories
File Location
Discovery Mechanism
The verifier searches for .voyager.toml in the following order:
- Current working directory -
./voyager.toml - Parent directories - Walks up the directory tree until found
- No config - Uses default values if no config file is found
Example directory search:
/home/user/projects/my-contract/
└── packages/
└── token/ ← Current directory
Search order:
/home/user/projects/my-contract/packages/token/.voyager.toml/home/user/projects/my-contract/packages/.voyager.toml/home/user/projects/my-contract/.voyager.toml/home/user/projects/.voyager.toml/home/user/.voyager.toml
The first file found is used.
Recommended Locations
Single package project:
my-contract/
├── .voyager.toml ← Place here
├── Scarb.toml
└── src/
Workspace project:
my-workspace/
├── .voyager.toml ← Place here (root level)
├── Scarb.toml
└── packages/
├── token/
└── nft/
Monorepo:
monorepo/
├── .voyager.toml ← Global defaults (optional)
└── contracts/
├── .voyager.toml ← Contract-specific settings
├── token/
└── nft/
Basic Structure
[voyager]
# Main configuration section
network = "mainnet"
license = "MIT"
[workspace]
# Workspace-specific settings (optional)
default-package = "my_contract"
[[contracts]]
# Batch verification array (optional)
class-hash = "0x123..."
contract-name = "MyContract"
Configuration Sections
[voyager] Section
Main configuration section for verification options.
Network Options
network
Type: String
Values: "mainnet", "sepolia", "dev"
Default: None (must be specified)
Overridden by: --network
Specifies which network to verify on.
[voyager]
network = "mainnet" # Main Starknet network
# OR
network = "sepolia" # Test network
# OR
network = "dev" # Development network
API Endpoints:
mainnet→https://api.voyager.online/betasepolia→https://sepolia-api.voyager.online/beta
Example usage:
# Uses network from config
voyager verify --class-hash 0x123... --contract-name MyContract
# Override config network
voyager verify --network sepolia --class-hash 0x123... --contract-name MyContract
url
Type: String
Default: None
Overridden by: --url
Custom API endpoint URL. Alternative to using network.
[voyager]
url = "https://api.custom.com/beta"
Note: Cannot use both network and url. Choose one.
License Options
license
Type: String
Default: “All Rights Reserved”
Overridden by: --license
SPDX license identifier for your contract.
[voyager]
license = "MIT"
Priority order:
--licenseCLI flaglicensein.voyager.tomllicenseinScarb.toml- “All Rights Reserved” (default)
Common licenses:
MITApache-2.0GPL-3.0BSD-3-ClauseAGPL-3.0
See SPDX License List for all valid identifiers.
Behavioral Options
watch
Type: Boolean
Default: false
Overridden by: --watch
Wait for verification to complete instead of just submitting.
[voyager]
watch = true
When enabled:
- Polls verification status until completion
- Shows real-time progress updates
- Exits when verification succeeds or fails
- Can be combined with
notify
When disabled:
- Submits verification and exits immediately
- Returns job ID for later checking
- Useful for CI/CD pipelines
notify
Type: Boolean
Default: false
Overridden by: --notify
Requires: watch = true
Send desktop notifications when verification completes.
[voyager]
watch = true
notify = true # Only works with watch = true
Notification types:
- ✅ Success: “Contract verified: MyContract”
- ❌ Failure: “Verification failed: MyContract”
See Desktop Notifications for platform-specific setup.
verbose
Type: Boolean
Default: false
Overridden by: --verbose or -v
Show detailed error messages and debugging information.
[voyager]
verbose = true
When enabled:
- Shows full compiler output
- Displays detailed API errors
- Useful for debugging failures
- Recommended for CI/CD logs
File Inclusion Options
lock-file
Type: Boolean
Default: false
Overridden by: --lock-file
Include Scarb.lock file in verification submission.
[voyager]
lock-file = true
Use cases:
- Ensure reproducible builds
- Lock dependency versions
- Production deployments
test-files
Type: Boolean
Default: false
Overridden by: --test-files
Include test files from src/ directory in verification.
[voyager]
test-files = true
Behavior:
- Includes files with “test” or “tests” in path within
src/ - Dedicated
tests/directories still excluded - Use when contract references test utilities
Example:
src/
├── contract.cairo # Always included
├── test_helpers.cairo # Included with test-files = true
└── tests.cairo # Included with test-files = true
tests/
└── integration.cairo # Always excluded
Project Type Options
project-type
Type: String
Values: "scarb", "dojo", "auto"
Default: "auto"
Overridden by: --project-type
Specify the project build tool type.
[voyager]
project-type = "auto" # Auto-detect (default)
# OR
project-type = "scarb" # Force Scarb
# OR
project-type = "dojo" # Force Dojo
Auto-detection logic:
- Checks for
Scarb.tomlwith[tool.dojo]section → Dojo - Checks for
Scarb.toml→ Scarb - Falls back to Scarb if uncertain
[workspace] Section
Configuration for workspace projects with multiple packages.
default-package
Type: String
Default: None
Overridden by: --package
Default package to verify in workspace projects.
[workspace]
default-package = "my_contract"
Use case:
Eliminates need to specify --package every time:
# Without default-package
voyager verify --class-hash 0x123... --contract-name MyContract --package token
# With default-package = "token"
voyager verify --class-hash 0x123... --contract-name MyContract
Override when needed:
voyager verify --class-hash 0x123... --contract-name MyContract --package nft
[[contracts]] Array
Configuration for batch verification of multiple contracts.
Structure:
[[contracts]]
class-hash = "0x123..."
contract-name = "MyContract"
package = "token" # Optional
Fields:
class-hash
Type: String Required: Yes
The class hash of the declared contract class.
[[contracts]]
class-hash = "0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18"
contract-name
Type: String Required: Yes
The name of the contract to verify.
[[contracts]]
contract-name = "MyToken"
package
Type: String
Required: No
Default: Uses workspace.default-package or auto-detects
Package name for workspace projects.
[[contracts]]
package = "token"
Batch verification example:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
[[contracts]]
class-hash = "0x123..."
contract-name = "Token"
package = "token"
[[contracts]]
class-hash = "0x456..."
contract-name = "NFT"
package = "nft"
[[contracts]]
class-hash = "0x789..."
contract-name = "Marketplace"
# package omitted - uses workspace.default-package
Usage:
voyager verify # Verifies all contracts in [[contracts]] array
See Batch Verification for detailed documentation.
Priority System
Settings are applied in order of priority:
1. CLI Arguments (Highest Priority)
Command-line flags always override config file and defaults.
voyager verify --network sepolia --license Apache-2.0 ...
2. Configuration File
Settings from .voyager.toml in discovered location.
[voyager]
network = "mainnet"
license = "MIT"
3. Scarb.toml (License Only)
License fallback from package metadata.
[package]
license = "MIT"
4. Default Values (Lowest Priority)
Built-in defaults when nothing else is specified.
Example priority in action:
# .voyager.toml
[voyager]
network = "mainnet"
license = "MIT"
watch = true
# CLI overrides network and license
voyager verify --network sepolia --license Apache-2.0 \
--class-hash 0x123... --contract-name MyContract
# Effective values:
# network = "sepolia" (from CLI)
# license = "Apache-2.0" (from CLI)
# watch = true (from config)
Complete Examples
Example 1: Production Deployment
[voyager]
network = "mainnet"
license = "Apache-2.0"
watch = true
notify = true
test-files = false
lock-file = true
verbose = false
Use case: Production mainnet deployments with notifications
Usage:
voyager verify --class-hash 0x123... --contract-name ProductionContract
Example 2: Development/Testing
[voyager]
network = "sepolia"
license = "MIT"
watch = true
notify = true
test-files = true
lock-file = true
verbose = true
Use case: Development on testnet with detailed output
Usage:
voyager verify --class-hash 0x123... --contract-name TestContract
Example 3: CI/CD Pipeline
[voyager]
network = "mainnet"
watch = false # Don't block pipeline
notify = false # No notifications in CI
test-files = false
lock-file = true
verbose = true # Detailed logs
Use case: Automated verification in CI/CD
Usage:
voyager verify --class-hash $CLASS_HASH --contract-name MyContract
Example 4: Workspace Project
[voyager]
network = "mainnet"
license = "MIT"
watch = true
notify = true
[workspace]
default-package = "my_contract"
Use case: Workspace with default package selection
Usage:
# Uses default-package
voyager verify --class-hash 0x123... --contract-name MyContract
# Override package when needed
voyager verify --class-hash 0x456... --contract-name OtherContract --package other
Example 5: Batch Verification
[voyager]
network = "mainnet"
license = "MIT"
watch = true
[workspace]
default-package = "contracts"
[[contracts]]
class-hash = "0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18"
contract-name = "MyToken"
package = "token"
[[contracts]]
class-hash = "0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19"
contract-name = "MyNFT"
package = "nft"
[[contracts]]
class-hash = "0x066dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da20"
contract-name = "MyMarketplace"
Use case: Verify multiple contracts at once
Usage:
voyager verify # Verifies all three contracts
Example 6: Dojo Project
[voyager]
network = "mainnet"
license = "MIT"
project-type = "dojo"
watch = true
notify = true
lock-file = true
Use case: Dojo game contracts
Usage:
voyager verify --class-hash 0x123... --contract-name GameContract
Example 7: Custom Endpoint
[voyager]
url = "https://api.custom.network.com/beta"
license = "MIT"
watch = true
verbose = true
Use case: Private or custom Starknet network
Usage:
voyager verify --class-hash 0x123... --contract-name MyContract
Example 8: Minimal Configuration
[voyager]
network = "mainnet"
license = "MIT"
Use case: Simple projects with minimal configuration
Usage:
voyager verify --class-hash 0x123... --contract-name MyContract --watch
Creating Your Configuration File
Step 1: Copy Example File
cp .voyager.toml.example .voyager.toml
Or download from repository:
curl -O https://raw.githubusercontent.com/NethermindEth/voyager-verifier/main/.voyager.toml.example
mv .voyager.toml.example .voyager.toml
Step 2: Edit for Your Needs
[voyager]
# Choose your network
network = "mainnet" # or "sepolia" for testnet
# Set your license
license = "MIT" # or your preferred SPDX identifier
# Enable watch mode for live updates
watch = true
# Enable notifications (optional)
notify = true
# Include lock file for reproducible builds
lock-file = true
# Other options as needed
test-files = false
verbose = false
Step 3: Test Configuration
Use dry run to verify configuration is loaded correctly:
voyager verify --class-hash 0x123... --contract-name MyContract --dry-run
Check that the configuration summary shows your settings.
Step 4: Commit to Repository (Optional)
git add .voyager.toml
git commit -m "Add Voyager verification config"
Share configuration with your team.
Best Practices
1. Use Config Files for Shared Settings
Good:
# .voyager.toml - committed to repo
[voyager]
network = "mainnet"
license = "MIT"
lock-file = true
Why: Team consistency, less verbosity
2. Keep Sensitive Data Out of Config
Bad:
[voyager]
api-key = "secret123" # Never do this!
Good: Use environment variables or CLI arguments for sensitive data.
3. Document Project-Specific Settings
[voyager]
network = "mainnet"
license = "MIT"
# We include test files because our contract uses shared test utilities
test-files = true
# Lock file ensures reproducible builds across team
lock-file = true
4. Use Different Configs for Different Environments
# Development
.voyager.dev.toml
# Production
.voyager.prod.toml
Then specify which config:
cp .voyager.dev.toml .voyager.toml # For development
cp .voyager.prod.toml .voyager.toml # For production
5. Override Config Values When Needed
Don’t be afraid to override config for one-off cases:
# Usually use mainnet from config, but test on sepolia
voyager verify --network sepolia --class-hash 0x123... --contract-name MyContract
6. Enable Verbose in CI/CD
[voyager]
network = "mainnet"
watch = false
verbose = true # Always enable for CI logs
7. Use Batch Mode for Multi-Contract Deployments
[[contracts]]
class-hash = "0x123..."
contract-name = "Token"
[[contracts]]
class-hash = "0x456..."
contract-name = "NFT"
Single command verifies all contracts.
Troubleshooting
Config File Not Found
Problem: Settings from .voyager.toml not being applied.
Solution:
- Verify file exists:
ls -la .voyager.toml - Check file location (current or parent directory)
- Use
--dry-runto see which config is loaded
voyager verify --class-hash 0x123... --contract-name MyContract --dry-run
Invalid TOML Syntax
Problem: Error parsing configuration file.
Example error:
Error: Failed to parse configuration file: expected an equals, found an identifier at line 5
Solution: Check TOML syntax:
- Strings must be quoted:
network = "mainnet" - Booleans are lowercase:
watch = true - Arrays use double brackets:
[[contracts]]
Validate TOML:
# Use online validator or CLI tool
cat .voyager.toml | toml-lint
Network and URL Both Specified
Problem:
Error: Cannot specify both 'network' and 'url' in config
Solution: Choose one:
[voyager]
network = "mainnet" # Use this
# url = "..." # OR this, not both
Notify Without Watch
Problem: Notifications not working.
Solution: Enable watch mode:
[voyager]
watch = true # Required for notify
notify = true
Wrong Package Selected
Problem: Workspace selecting wrong package.
Solution: Set default package:
[workspace]
default-package = "correct_package"
Or override via CLI:
voyager verify --package correct_package ...
Advanced Configuration
Environment-Specific Configs
Use shell scripts to switch configs:
#!/bin/bash
# switch-env.sh
if [ "$1" == "dev" ]; then
cp .voyager.dev.toml .voyager.toml
elif [ "$1" == "prod" ]; then
cp .voyager.prod.toml .voyager.toml
else
echo "Usage: ./switch-env.sh [dev|prod]"
fi
Config File Per Package
For monorepos with multiple contracts:
monorepo/
├── contracts/
│ ├── token/
│ │ └── .voyager.toml ← Token-specific
│ └── nft/
│ └── .voyager.toml ← NFT-specific
└── .voyager.toml ← Global defaults
Template Configs
Create reusable templates:
# templates/
# ├── .voyager.mainnet.toml
# ├── .voyager.sepolia.toml
# └── .voyager.ci.toml
# Copy template to use
cp templates/.voyager.mainnet.toml .voyager.toml
Next Steps
- CLI Options Reference - Complete flag documentation
- Workspace Settings - Multi-package configuration
- Configuration Examples - More real-world examples
- Batch Verification - Using [[contracts]] array
CLI Options Reference
Complete reference documentation for all command-line flags and options supported by Voyager Verifier.
Overview
This reference covers all CLI options for the verify command. For other commands (status, history), see Command Reference.
Command Structure
voyager verify [NETWORK_OPTION] [REQUIRED_OPTIONS] [OPTIONAL_FLAGS]
Network Options
--network <NETWORK>
Type: String
Values: mainnet, sepolia, dev
Required: Yes (unless --url is used)
Conflicts with: --url
Config equivalent: voyager.network
Specify which Starknet network to verify on.
Values:
mainnet- Main Starknet network (API:https://api.voyager.online/beta)sepolia- Starknet testnet (API:https://sepolia-api.voyager.online/beta)dev- Development network
Examples:
# Mainnet
voyager verify --network mainnet --class-hash 0x123... --contract-name MyContract
# Sepolia testnet
voyager verify --network sepolia --class-hash 0x123... --contract-name TestContract
# Dev network
voyager verify --network dev --class-hash 0x123... --contract-name DevContract
--url <URL>
Type: String (URL)
Required: Yes (unless --network is used)
Conflicts with: --network
Config equivalent: voyager.url
Specify a custom API endpoint URL.
Format: Must be a valid HTTP/HTTPS URL
Use cases:
- Private Starknet networks
- Custom deployments
- Staging environments
- Testing against development servers
Examples:
# Custom endpoint
voyager verify --url https://api.custom.com/beta \
--class-hash 0x123... \
--contract-name MyContract
# Local development server
voyager verify --url http://localhost:8080 \
--class-hash 0x123... \
--contract-name LocalContract
Note: Cannot use both --network and --url. Choose one.
Required Options
--class-hash <HASH>
Type: Hexadecimal string Required: Yes (unless using batch mode) Config equivalent: N/A (specified per contract)
The class hash of your declared Starknet contract class.
Format:
- Must start with
0x - Must be valid hexadecimal (0-9, a-f, A-F)
- Case-insensitive
- Full 64-character hash recommended
Examples:
# Full hash
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
# Case doesn't matter
--class-hash 0x044DC2B3239382230D8B1E943DF23B96F52EEBCAC93EFE6E8BDE92F9A2F1DA18
Common errors:
# Missing 0x prefix - INVALID
--class-hash 044dc2b3...
# Invalid characters - INVALID
--class-hash 0xZZZ123...
# Truncated hash - may be rejected
--class-hash 0x044dc2b3...
--contract-name <NAME>
Type: String Required: Yes (unless using batch mode) Config equivalent: N/A (specified per contract)
The name of the contract to verify. Must match a contract defined in your Scarb project.
Format:
- Alphanumeric and underscores allowed
- No spaces
- Case-sensitive
Examples:
--contract-name MyToken
--contract-name ERC20Contract
--contract-name my_nft_contract
--contract-name GameEngine
Project Options
--path <PATH>
Type: File system path Required: No Default: Current working directory Config equivalent: N/A
Path to your Scarb project directory.
Format: Absolute or relative path to directory containing Scarb.toml
Examples:
# Absolute path
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract \
--path /home/user/projects/my-contract
# Relative path
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract \
--path ../my-contract
# Current directory (default)
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract
--package <PACKAGE>
Type: String
Required: Yes for multi-package workspaces
Default: None (or workspace.default-package from config)
Config equivalent: workspace.default-package
Specify which package to verify in workspace projects.
Use cases:
- Required when workspace has multiple packages
- Optional when workspace has only one package
- Not needed for single-package projects
Examples:
# Workspace with multiple packages
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name TokenContract \
--package token
# Override default-package from config
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name NFTContract \
--package nft
Error if missing:
Error: Multiple packages found. Use --package to specify which one to verify.
Available packages: token, nft, marketplace
--project-type <TYPE>
Type: String
Values: scarb, dojo, auto
Required: No
Default: auto
Config equivalent: voyager.project-type
Specify the project build tool type.
Values:
auto- Auto-detect from project structure (default)scarb- Force Scarb project detectiondojo- Force Dojo project detection
Examples:
# Auto-detect (default)
voyager verify --network mainnet --class-hash 0x123... --contract-name MyContract
# Force Scarb
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract \
--project-type scarb
# Force Dojo
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name GameWorld \
--project-type dojo
License Options
--license <SPDX_ID>
Type: String (SPDX identifier)
Required: No
Default: From .voyager.toml, then Scarb.toml, then “All Rights Reserved”
Config equivalent: voyager.license
SPDX license identifier for your contract.
Priority order:
--licenseCLI flaglicensein.voyager.tomllicenseinScarb.toml- “All Rights Reserved” (default)
Common licenses:
MITApache-2.0GPL-3.0BSD-3-ClauseAGPL-3.0ISCMPL-2.0
Examples:
--license MIT
--license Apache-2.0
--license GPL-3.0
--license "BSD-3-Clause"
See SPDX License List for all valid identifiers.
File Inclusion Options
--lock-file
Type: Boolean flag
Required: No
Default: false
Config equivalent: voyager.lock-file
Include Scarb.lock file in verification submission.
Use cases:
- Ensure reproducible builds
- Lock dependency versions
- Production deployments
- Strict version requirements
Examples:
# Include lock file
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract \
--lock-file
What it does:
- Includes
Scarb.lockin submitted files - Ensures remote build uses exact same dependency versions
- Prevents compilation differences from dependency updates
--test-files
Type: Boolean flag
Required: No
Default: false
Config equivalent: voyager.test-files
Include test files from src/ directory in verification.
Behavior:
- Includes files with “test” or “tests” in their path within
src/ - Dedicated
tests/directories still excluded - Useful when contract imports test utilities
Examples:
# Include test files
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract \
--test-files
File inclusion:
src/
├── contract.cairo # ✓ Always included
├── utils.cairo # ✓ Always included
├── test_helpers.cairo # ✓ Included with --test-files
└── tests.cairo # ✓ Included with --test-files
tests/
└── integration.cairo # ✗ Always excluded
Common error without this flag:
error[E0005]: Module file not found. Expected path: /tmp/.../src/test_helpers.cairo
Solution: Add --test-files flag
Behavioral Options
--watch
Type: Boolean flag
Required: No
Default: false
Config equivalent: voyager.watch
Poll verification status until completion instead of just submitting.
Behavior:
- Submits verification
- Polls status with exponential backoff
- Shows real-time progress updates
- Exits when complete (success or failure)
Examples:
# Watch verification progress
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract \
--watch
Output:
✓ Verification job submitted successfully
Job ID: abc-123-def-456
⏳ Watching verification job...
Status: Pending
⏱️ Estimated time: 2-5 minutes
Status: In Progress
⏱️ Progress: Compiling sources...
Status: Completed
✅ Verification successful!
Without --watch:
✓ Verification job submitted successfully
Job ID: abc-123-def-456
Use 'voyager status --network mainnet --job abc-123-def-456' to check status
See Watch Mode for detailed documentation.
--notify
Type: Boolean flag
Required: No
Default: false
Requires: --watch
Config equivalent: voyager.notify
Send desktop notifications when verification completes.
Requirements:
- Must use with
--watch - Platform-specific notification system must be available
Examples:
# Enable notifications
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract \
--watch \
--notify
Notification messages:
- Success: “✅ Contract verified: MyContract”
- Failure: “❌ Verification failed: MyContract”
Platform support:
- Linux: libnotify (notify-send)
- macOS: native notification center
- Windows: native notification system
See Desktop Notifications for platform setup.
--verbose / -v
Type: Boolean flag
Required: No
Default: false
Config equivalent: voyager.verbose
Show detailed error messages and debugging information.
Displays:
- Full compiler output from remote server
- Detailed API errors
- Debug information
- Stack traces (when applicable)
Examples:
# Long form
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract \
--verbose
# Short form
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract \
-v
Use cases:
- Debugging verification failures
- Understanding compilation errors
- Troubleshooting file collection issues
- CI/CD logging
Example output:
Error: [E004] Compilation failed
Without --verbose:
Compilation failed: `scarb` command exited with error
With --verbose:
Compilation failed: `scarb` command exited with error
Full compiler output:
error[E0005]: Module file not found. Expected path: /tmp/targets/.../src/tests.cairo
--> lib.cairo:3:1
|
3 | pub mod tests;
| ^^^^^^^^^^^^^^
Solution: Use --test-files flag to include test files in verification
--dry-run
Type: Boolean flag
Required: No
Default: false
Config equivalent: N/A
Preview what files would be collected without actually submitting.
Behavior:
- Collects files as normal
- Displays configuration and file list
- Does NOT submit to API
- Does NOT consume API quota
Examples:
# Basic dry run
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract \
--dry-run
# Dry run with verbose output
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract \
--dry-run \
--verbose
Output:
════════════════════════════════════════════════════════
Dry Run: Verification Preview
════════════════════════════════════════════════════════
Configuration:
Network: mainnet
Class Hash: 0x044dc2b3...
Contract: MyContract
License: MIT
Files to be submitted (5 files):
├── Scarb.toml (245 bytes)
├── src/lib.cairo (1,234 bytes)
├── src/contract.cairo (5,678 bytes)
├── src/utils.cairo (890 bytes)
└── src/events.cairo (456 bytes)
Total size: 8,503 bytes (8.3 KB)
See Dry Run Mode for detailed documentation.
--wizard
Type: Boolean flag
Required: No
Default: false
Conflicts with: Most other options
Launch interactive wizard mode for guided verification.
Behavior:
- Prompts step-by-step for all required information
- Validates input before proceeding
- Auto-detects licenses from
Scarb.toml - Shows confirmation before submission
Examples:
# Start wizard
voyager verify --wizard
Cannot combine with:
--class-hash--contract-name--package- Most other flags (wizard asks for these)
Can combine with:
--path(to specify project directory)--network(pre-select network)
See Interactive Wizard for detailed documentation.
Batch Verification Options
--fail-fast
Type: Boolean flag
Required: No
Default: false (continue all)
Config equivalent: N/A
Only for: Batch verification mode
Stop batch verification on first failure.
Behavior:
- Without flag: Continues verifying remaining contracts after failure
- With flag: Stops immediately when any contract fails
Examples:
# Stop on first failure
voyager verify --fail-fast
# Continue all (default)
voyager verify
Use cases:
- Development: Stop on first error to fix issues quickly
- Production: Continue all to see complete status
--batch-delay <SECONDS>
Type: Integer (seconds)
Required: No
Default: 0 (no delay)
Config equivalent: N/A
Only for: Batch verification mode
Add delay between contract submissions for rate limiting.
Format: Number of seconds to wait
Examples:
# 5-second delay between submissions
voyager verify --batch-delay 5
# 10-second delay
voyager verify --batch-delay 10
Use cases:
- Rate limit compliance
- Avoiding API throttling
- Spreading load over time
Output:
[1/3] Verifying: MyToken
✓ Submitted - Job ID: abc-123-def
⏳ Waiting 5 seconds before next submission...
[2/3] Verifying: MyNFT
✓ Submitted - Job ID: ghi-456-jkl
Flag Combinations
Common Combinations
1. Quick Submit (No Watching)
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract
2. Watch with Notifications
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract \
--watch \
--notify
3. Full Production Build
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract \
--license MIT \
--lock-file \
--watch \
--notify
4. Debug Mode
voyager verify --network sepolia \
--class-hash 0x123... \
--contract-name MyContract \
--test-files \
--verbose \
--watch
5. CI/CD Mode
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract \
--lock-file \
--verbose
# No --watch to avoid blocking
6. Dry Run Testing
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract \
--test-files \
--lock-file \
--dry-run \
--verbose
Invalid Combinations
Cannot Use Both Network Options
# INVALID - cannot use both
voyager verify --network mainnet --url https://custom.com \
--class-hash 0x123... \
--contract-name MyContract
Error: Cannot specify both --network and --url
Notify Requires Watch
# INVALID - notify requires watch
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract \
--notify
Error: --notify requires --watch to be enabled
Wizard Conflicts with Manual Options
# INVALID - wizard doesn't accept these
voyager verify --wizard --class-hash 0x123...
Error: Cannot use --class-hash with --wizard mode
Batch Options Outside Batch Mode
# INVALID - batch options require [[contracts]] in config
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract \
--fail-fast
Error: --fail-fast only available in batch mode
Config File vs CLI Options
Priority Order
- CLI flags (highest)
- Config file (
.voyager.toml) - Scarb.toml (license only)
- Defaults (lowest)
Example
Config file (.voyager.toml):
[voyager]
network = "mainnet"
license = "MIT"
watch = true
lock-file = true
Command:
voyager verify --network sepolia \
--class-hash 0x123... \
--contract-name MyContract \
--verbose
Effective settings:
network = sepolia(from CLI)license = MIT(from config)watch = true(from config)lock-file = true(from config)verbose = true(from CLI)
Getting Help
Show All Options
voyager verify --help
Show Version
voyager --version
Command-Specific Help
voyager status --help
voyager history --help
Quick Reference Table
| Flag | Type | Required | Default | Config Equivalent |
|---|---|---|---|---|
--network | String | Yes* | None | voyager.network |
--url | String | Yes* | None | voyager.url |
--class-hash | String | Yes** | None | N/A |
--contract-name | String | Yes** | None | N/A |
--path | String | No | . | N/A |
--package | String | Sometimes | None | workspace.default-package |
--project-type | String | No | auto | voyager.project-type |
--license | String | No | See docs | voyager.license |
--lock-file | Flag | No | false | voyager.lock-file |
--test-files | Flag | No | false | voyager.test-files |
--watch | Flag | No | false | voyager.watch |
--notify | Flag | No | false | voyager.notify |
--verbose, -v | Flag | No | false | voyager.verbose |
--dry-run | Flag | No | false | N/A |
--wizard | Flag | No | false | N/A |
--fail-fast | Flag | No | false | N/A |
--batch-delay | Integer | No | 0 | N/A |
* Either --network or --url required
** Not required in batch mode or wizard mode
Next Steps
- Configuration File Guide - Reduce CLI verbosity with config
- Command-Line Verification - Practical usage examples
- Interactive Wizard - Guided verification mode
- Batch Verification - Verify multiple contracts
Workspace Settings
Configuration guide for verifying contracts in Scarb workspace projects with multiple packages.
Overview
Workspace settings allow you to:
- Manage multi-package projects - Single Scarb.toml with multiple contract packages
- Set default package - Avoid specifying
--packageevery time - Batch verification - Verify multiple packages at once
- Package-specific settings - Different configurations per package
- Simplified commands - Less typing for common workflows
What is a Workspace?
A Scarb workspace is a project structure with multiple packages (crates) defined in a single root Scarb.toml file.
Example workspace structure:
my-workspace/
├── Scarb.toml ← Workspace root
└── packages/
├── token/
│ ├── Scarb.toml
│ └── src/
├── nft/
│ ├── Scarb.toml
│ └── src/
└── marketplace/
├── Scarb.toml
└── src/
Root Scarb.toml:
[workspace]
members = [
"packages/token",
"packages/nft",
"packages/marketplace",
]
Configuration
[workspace] Section
Add workspace configuration to .voyager.toml:
[workspace]
default-package = "package_name"
default-package Option
Type: String
Required: No
Overridden by: --package CLI flag
Sets the default package to verify when --package is not specified.
Benefits:
- Eliminates need to type
--packageevery time - Useful when primarily working with one package
- Can still override when needed
Example:
[voyager]
network = "mainnet"
license = "MIT"
[workspace]
default-package = "token"
Usage:
# Uses default-package = "token"
voyager verify --class-hash 0x123... --contract-name TokenContract
# Override to use different package
voyager verify --class-hash 0x456... --contract-name NFTContract --package nft
Package Selection
Automatic Detection
For single-package workspaces, the package is auto-detected:
# No --package needed if only one package exists
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract
Explicit Selection
For multi-package workspaces, you must specify the package:
Via CLI:
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name TokenContract \
--package token
Via Config:
[workspace]
default-package = "token"
Then:
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name TokenContract
# Uses default-package
Error if Missing
Without --package or default-package in multi-package workspace:
Error: Multiple packages found. Use --package to specify which one to verify.
Available packages:
- token
- nft
- marketplace
Use --package <name> or set workspace.default-package in .voyager.toml
Complete Examples
Example 1: Basic Workspace Config
Project structure:
my-defi-protocol/
├── .voyager.toml
├── Scarb.toml
└── packages/
├── token/
├── staking/
└── governance/
.voyager.toml:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
[workspace]
default-package = "token" # Work primarily with token package
Usage:
# Verify token (uses default)
voyager verify --class-hash 0x123... --contract-name Token
# Verify staking (override)
voyager verify --class-hash 0x456... --contract-name Staking --package staking
# Verify governance (override)
voyager verify --class-hash 0x789... --contract-name Governor --package governance
Example 2: No Default Package
.voyager.toml:
[voyager]
network = "mainnet"
license = "Apache-2.0"
watch = true
# No default-package set
Usage:
# Must specify --package every time
voyager verify --class-hash 0x123... --contract-name Token --package token
voyager verify --class-hash 0x456... --contract-name NFT --package nft
Example 3: Batch Verification in Workspace
Verify multiple contracts from different packages:
.voyager.toml:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
[workspace]
default-package = "contracts"
[[contracts]]
class-hash = "0x123..."
contract-name = "Token"
package = "token"
[[contracts]]
class-hash = "0x456..."
contract-name = "NFT"
package = "nft"
[[contracts]]
class-hash = "0x789..."
contract-name = "Marketplace"
package = "marketplace"
Usage:
voyager verify # Verifies all three contracts from different packages
Example 4: Development vs Production Packages
Different configs for different packages:
.voyager.token.toml:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
lock-file = true
[workspace]
default-package = "token"
.voyager.test.toml:
[voyager]
network = "sepolia"
license = "MIT"
watch = true
test-files = true
verbose = true
[workspace]
default-package = "test_contracts"
Usage:
# Production token verification
cp .voyager.token.toml .voyager.toml
voyager verify --class-hash 0x123... --contract-name Token
# Test contract verification
cp .voyager.test.toml .voyager.toml
voyager verify --class-hash 0x456... --contract-name TestToken
Common Workflows
Workflow 1: Primary Package Development
When working primarily on one package in a workspace:
Setup:
[workspace]
default-package = "my_main_package"
Daily usage:
# All commands use my_main_package by default
voyager verify --class-hash 0x123... --contract-name Contract1
voyager verify --class-hash 0x456... --contract-name Contract2
voyager verify --class-hash 0x789... --contract-name Contract3
Workflow 2: Multi-Package Development
When regularly working across multiple packages:
Setup:
# No default-package
Usage with aliases:
# Create shell aliases
alias verify-token='voyager verify --package token'
alias verify-nft='voyager verify --package nft'
alias verify-market='voyager verify --package marketplace'
# Use aliases
verify-token --class-hash 0x123... --contract-name Token
verify-nft --class-hash 0x456... --contract-name NFT
Workflow 3: Batch Verification
Verify entire workspace at once:
Setup:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
[workspace]
default-package = "core"
[[contracts]]
class-hash = "0x123..."
contract-name = "Token"
package = "token"
[[contracts]]
class-hash = "0x456..."
contract-name = "NFT"
package = "nft"
[[contracts]]
class-hash = "0x789..."
contract-name = "Marketplace"
package = "marketplace"
Single command:
voyager verify
Workflow 4: Package-Specific Configs
Different verification settings per package:
Directory structure:
workspace/
├── .voyager.toml ← Global defaults
└── packages/
├── token/
│ └── .voyager.toml ← Token-specific
└── nft/
└── .voyager.toml ← NFT-specific
packages/token/.voyager.toml:
[voyager]
network = "mainnet"
license = "MIT"
lock-file = true
[workspace]
default-package = "token"
packages/nft/.voyager.toml:
[voyager]
network = "mainnet"
license = "Apache-2.0"
test-files = true
[workspace]
default-package = "nft"
Usage:
# From token directory
cd packages/token
voyager verify --class-hash 0x123... --contract-name Token
# Uses token/.voyager.toml config
# From nft directory
cd ../nft
voyager verify --class-hash 0x456... --contract-name NFT
# Uses nft/.voyager.toml config
Package Discovery
How Voyager Finds Packages
- Reads root Scarb.toml - Looks for
[workspace]section - Parses workspace members - Gets list of package paths
- Validates packages - Ensures each package has valid Scarb.toml
- Lists available packages - Shows all packages if selection required
Example:
# Root Scarb.toml
[workspace]
members = [
"packages/token",
"packages/nft",
"packages/*", # Glob patterns supported
]
Package Naming
Package names come from individual package Scarb.toml files:
packages/token/Scarb.toml:
[package]
name = "my_token" # This is the package name to use
version = "0.1.0"
Usage:
voyager verify --class-hash 0x123... --contract-name Token --package my_token
Troubleshooting
Issue 1: Package Not Found
Error:
Error: Package 'token' not found in workspace
Available packages:
- my_token
- my_nft
- my_marketplace
Cause: Using directory name instead of package name
Solution: Check package name in Scarb.toml:
[package]
name = "my_token" # Use this name
voyager verify --class-hash 0x123... --contract-name Token --package my_token
Issue 2: Multiple Packages Error
Error:
Error: Multiple packages found. Use --package to specify which one to verify.
Solutions:
Option A - Use CLI flag:
voyager verify --class-hash 0x123... --contract-name Token --package token
Option B - Set default in config:
[workspace]
default-package = "token"
Issue 3: Wrong Package Selected
Problem: Verification fails because wrong package is being used
Debug:
# Use dry run to see which package is selected
voyager verify --class-hash 0x123... --contract-name Token --dry-run
Output shows:
Package: wrong_package # ← This shows selected package
Solution:
# Explicitly specify correct package
voyager verify --class-hash 0x123... --contract-name Token --package correct_package
Or update config:
[workspace]
default-package = "correct_package"
Issue 4: Config Not Being Applied
Problem: default-package setting not working
Check:
# Verify config file location
ls -la .voyager.toml
# Check if in workspace root
pwd
Solution: Ensure .voyager.toml is in workspace root or current directory:
workspace-root/
├── .voyager.toml ← Should be here
├── Scarb.toml
└── packages/
Issue 5: Batch Mode Package Issues
Problem: Batch verification using wrong packages
Check config:
[[contracts]]
class-hash = "0x123..."
contract-name = "Token"
package = "token" # ← Ensure correct package specified
Debug:
# Dry run batch mode
voyager verify --dry-run
Best Practices
1. Always Set default-package
For workspaces where you primarily work on one package:
[workspace]
default-package = "your_main_package"
Benefits:
- Less typing
- Fewer errors from forgetting
--package - Cleaner command history
2. Use Descriptive Package Names
Good:
[package]
name = "erc20_token"
name = "erc721_nft"
name = "marketplace_v2"
Bad:
[package]
name = "contract1"
name = "pkg"
name = "test"
3. Document Package Structure
Add comments to .voyager.toml:
[voyager]
network = "mainnet"
license = "MIT"
[workspace]
# Primary contract package - use this for most verifications
default-package = "token"
# Other packages available:
# - nft: ERC721 implementation
# - marketplace: Trading platform
# - governance: DAO governance
4. Create Package-Specific Configs
For packages with different requirements:
workspace/
├── .voyager.toml ← Global defaults
└── packages/
├── production_contract/
│ └── .voyager.toml ← Production settings
└── test_contract/
└── .voyager.toml ← Test settings
5. Use Batch Mode for Full Workspace
Verify all packages at once after deployment:
[[contracts]]
class-hash = "0x123..."
contract-name = "Token"
package = "token"
[[contracts]]
class-hash = "0x456..."
contract-name = "NFT"
package = "nft"
[[contracts]]
class-hash = "0x789..."
contract-name = "Marketplace"
package = "marketplace"
voyager verify --watch
6. Test Package Selection
Always dry run first to verify correct package:
voyager verify --class-hash 0x123... --contract-name Token --dry-run
Check output shows correct package before actual verification.
Integration with CI/CD
GitHub Actions Example
name: Verify Workspace Contracts
on:
push:
branches: [main]
jobs:
verify:
runs-on: ubuntu-latest
strategy:
matrix:
package: [token, nft, marketplace]
steps:
- uses: actions/checkout@v3
- name: Install Voyager
run: cargo install voyager-verifier
- name: Verify ${{ matrix.package }}
run: |
voyager verify \
--network mainnet \
--class-hash ${{ secrets[format('{0}_CLASS_HASH', matrix.package)] }} \
--contract-name ${{ matrix.package }} \
--package ${{ matrix.package }} \
--verbose
Batch Verification in CI
- name: Verify All Contracts
run: |
# Use batch mode from .voyager.toml
voyager verify --verbose
Next Steps
- Configuration File Guide - Complete config documentation
- Batch Verification - Verify multiple contracts
- Configuration Examples - More workspace examples
- CLI Options Reference - All –package flag details
Configuration Examples
Real-world configuration examples for common use cases and scenarios.
Overview
This guide provides ready-to-use .voyager.toml configurations for:
- Production deployments
- Development and testing
- CI/CD pipelines
- Workspace projects
- Dojo projects
- Custom networks
- Team environments
Copy and adapt these examples to your specific needs.
Production Deployments
Mainnet Production (Conservative)
Use case: Production mainnet deployment with maximum reliability
.voyager.toml:
[voyager]
# Main Starknet network
network = "mainnet"
# Production license
license = "Apache-2.0"
# Wait for verification to complete
watch = true
# Get notified when done
notify = true
# Lock dependencies for reproducibility
lock-file = true
# Don't include test files
test-files = false
# Keep logs clean for production
verbose = false
Usage:
voyager verify --class-hash 0x123... --contract-name ProductionContract
Mainnet Production (Aggressive)
Use case: Fast deployment with monitoring
.voyager.toml:
[voyager]
network = "mainnet"
license = "MIT"
# Don't wait - submit and continue
watch = false
# Production build settings
lock-file = true
test-files = false
verbose = false
Usage:
# Submit and get job ID immediately
voyager verify --class-hash 0x123... --contract-name FastDeploy
# Check status later
voyager status --network mainnet --job <JOB_ID>
Development & Testing
Sepolia Development
Use case: Active development on Sepolia testnet
.voyager.toml:
[voyager]
# Test network
network = "sepolia"
# Development license
license = "MIT"
# Watch for immediate feedback
watch = true
# Get notified
notify = true
# Include test files (often needed in dev)
test-files = true
# Lock file for consistency
lock-file = true
# Verbose output for debugging
verbose = true
Usage:
voyager verify --class-hash 0x123... --contract-name DevContract
Local Testing
Use case: Testing with local Starknet node
.voyager.toml:
[voyager]
# Custom local endpoint
url = "http://localhost:5050"
license = "MIT"
watch = true
test-files = true
verbose = true
Usage:
voyager verify --class-hash 0x123... --contract-name LocalTest
CI/CD Pipelines
GitHub Actions / GitLab CI
Use case: Automated verification in CI/CD
.voyager.toml:
[voyager]
network = "mainnet"
license = "MIT"
# DON'T wait - CI should be fast
watch = false
# NO notifications in CI
notify = false
# Lock file for reproducibility
lock-file = true
# NO test files in production
test-files = false
# Verbose for CI logs
verbose = true
GitHub Actions:
- name: Verify Contract
run: |
voyager verify \
--class-hash ${{ secrets.CLASS_HASH }} \
--contract-name MyContract
# Store job ID for later checks
JOB_ID=$(voyager verify ... | grep "Job ID" | awk '{print $3}')
echo "JOB_ID=$JOB_ID" >> $GITHUB_ENV
CI with Verification Wait
Use case: CI that waits for verification
.voyager.toml:
[voyager]
network = "mainnet"
license = "Apache-2.0"
# Wait for result in CI
watch = true
# No notifications
notify = false
lock-file = true
test-files = false
verbose = true
Usage:
- name: Verify and Wait
run: |
voyager verify \
--class-hash ${{ secrets.CLASS_HASH }} \
--contract-name MyContract
# CI will wait for completion
Workspace Projects
Multi-Package Workspace
Use case: Workspace with multiple contract packages
Project structure:
my-protocol/
├── .voyager.toml
├── Scarb.toml
└── packages/
├── token/
├── nft/
└── marketplace/
.voyager.toml:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
notify = true
lock-file = true
[workspace]
# Primary package
default-package = "token"
Usage:
# Verify token (uses default)
voyager verify --class-hash 0x123... --contract-name Token
# Verify nft (override default)
voyager verify --class-hash 0x456... --contract-name NFT --package nft
Batch Workspace Verification
Use case: Verify all contracts in workspace at once
.voyager.toml:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
notify = true
[workspace]
default-package = "core"
# Define all contracts
[[contracts]]
class-hash = "0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18"
contract-name = "Token"
package = "token"
[[contracts]]
class-hash = "0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19"
contract-name = "NFT"
package = "nft"
[[contracts]]
class-hash = "0x066dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da20"
contract-name = "Marketplace"
package = "marketplace"
Usage:
# Verify all contracts
voyager verify
# With rate limiting
voyager verify --batch-delay 5
Dojo Projects
Basic Dojo Game
Use case: Dojo game project on mainnet
.voyager.toml:
[voyager]
network = "mainnet"
license = "MIT"
# Specify Dojo project type
project-type = "dojo"
watch = true
notify = true
lock-file = true
test-files = false
verbose = false
Usage:
voyager verify --class-hash 0x123... --contract-name GameWorld
Dojo Development
Use case: Active Dojo game development
.voyager.toml:
[voyager]
network = "sepolia"
license = "MIT"
project-type = "dojo"
watch = true
notify = true
test-files = true
lock-file = true
verbose = true
Usage:
voyager verify --class-hash 0x123... --contract-name TestWorld
Custom Networks
Private Network
Use case: Custom Starknet deployment
.voyager.toml:
[voyager]
# Custom API endpoint
url = "https://api.private-network.com/beta"
license = "Proprietary"
watch = true
notify = true
lock-file = true
verbose = true
Usage:
voyager verify --class-hash 0x123... --contract-name PrivateContract
Staging Environment
Use case: Staging network for pre-production testing
.voyager.toml:
[voyager]
url = "https://staging-api.company.com/beta"
license = "MIT"
# Watch for staging tests
watch = true
notify = true
# Include test files in staging
test-files = true
lock-file = true
verbose = true
Usage:
voyager verify --class-hash 0x123... --contract-name StagingContract
Team Environments
Shared Team Config
Use case: Consistent verification across team
.voyager.toml (committed to repo):
[voyager]
network = "mainnet"
license = "Apache-2.0"
# Team standards
watch = true
notify = false # Let individuals enable
lock-file = true
test-files = false
verbose = false
[workspace]
default-package = "core"
Individual override (.gitignored):
[voyager]
# Personal preferences
notify = true # Enable notifications for me
verbose = true # I like verbose output
Usage:
# Copy local config before running
cp .voyager.local.toml .voyager.toml
voyager verify --class-hash 0x123... --contract-name MyContract
Multi-Environment Team Setup
Use case: Different configs for dev/staging/prod
Templates:
.voyager.dev.toml # Development
.voyager.staging.toml # Staging
.voyager.prod.toml # Production
.voyager.dev.toml:
[voyager]
network = "sepolia"
license = "MIT"
watch = true
notify = true
test-files = true
lock-file = true
verbose = true
.voyager.staging.toml:
[voyager]
url = "https://staging-api.company.com"
license = "MIT"
watch = true
notify = true
test-files = true
lock-file = true
verbose = true
.voyager.prod.toml:
[voyager]
network = "mainnet"
license = "Apache-2.0"
watch = true
notify = true
test-files = false
lock-file = true
verbose = false
Switching environments:
# Use development
cp .voyager.dev.toml .voyager.toml
# Use staging
cp .voyager.staging.toml .voyager.toml
# Use production
cp .voyager.prod.toml .voyager.toml
Specialized Scenarios
Minimal Configuration
Use case: Quick setup with defaults
.voyager.toml:
[voyager]
network = "mainnet"
license = "MIT"
Usage:
# Manually specify other options
voyager verify --class-hash 0x123... --contract-name Simple --watch
Maximum Verbosity (Debug)
Use case: Troubleshooting verification issues
.voyager.toml:
[voyager]
network = "sepolia" # Use testnet for debugging
license = "MIT"
# All debug options enabled
watch = true
notify = true
test-files = true
lock-file = true
verbose = true
Usage:
# Also use dry-run for maximum information
voyager verify --class-hash 0x123... --contract-name Debug --dry-run
Fast Iteration
Use case: Rapid development cycle
.voyager.toml:
[voyager]
network = "sepolia"
license = "MIT"
# No waiting - fast feedback
watch = false
notify = false
test-files = true
verbose = false
Usage:
# Submit quickly
voyager verify --class-hash 0x123... --contract-name QuickTest
# Check later
voyager status --network sepolia --job <JOB_ID>
Notification-Heavy
Use case: Long-running verifications with notifications
.voyager.toml:
[voyager]
network = "mainnet"
license = "MIT"
# Always watch and notify
watch = true
notify = true
lock-file = true
test-files = false
verbose = false
Usage:
# Start verification and continue other work
voyager verify --class-hash 0x123... --contract-name LongBuild
# You'll get notified when done
Protocol-Specific Examples
DeFi Protocol
Use case: Multi-contract DeFi protocol
.voyager.toml:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
notify = true
lock-file = true
[workspace]
default-package = "core"
# All protocol contracts
[[contracts]]
class-hash = "0x123..."
contract-name = "AMM"
package = "amm"
[[contracts]]
class-hash = "0x456..."
contract-name = "LendingPool"
package = "lending"
[[contracts]]
class-hash = "0x789..."
contract-name = "GovernanceToken"
package = "governance"
[[contracts]]
class-hash = "0xabc..."
contract-name = "Treasury"
package = "treasury"
Usage:
# Verify entire protocol
voyager verify --batch-delay 10
NFT Marketplace
Use case: NFT marketplace with multiple contracts
.voyager.toml:
[voyager]
network = "mainnet"
license = "Apache-2.0"
watch = true
notify = true
lock-file = true
[workspace]
default-package = "nft"
[[contracts]]
class-hash = "0x123..."
contract-name = "NFTCollection"
package = "nft"
[[contracts]]
class-hash = "0x456..."
contract-name = "Marketplace"
package = "marketplace"
[[contracts]]
class-hash = "0x789..."
contract-name = "Auction"
package = "auction"
Usage:
voyager verify
GameFi Project
Use case: Dojo-based game with multiple systems
.voyager.toml:
[voyager]
network = "mainnet"
license = "MIT"
project-type = "dojo"
watch = true
notify = true
lock-file = true
[[contracts]]
class-hash = "0x123..."
contract-name = "GameWorld"
[[contracts]]
class-hash = "0x456..."
contract-name = "PlayerSystem"
[[contracts]]
class-hash = "0x789..."
contract-name = "ItemSystem"
[[contracts]]
class-hash = "0xabc..."
contract-name = "BattleSystem"
Usage:
voyager verify --batch-delay 5
Migration Scenarios
Gradual Migration from CLI
Phase 1 - Start with minimal config:
[voyager]
network = "mainnet"
license = "MIT"
Phase 2 - Add commonly used options:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
lock-file = true
Phase 3 - Full configuration:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
notify = true
lock-file = true
test-files = false
verbose = false
[workspace]
default-package = "main"
Moving to Batch Mode
Before (individual commands):
voyager verify --network mainnet --class-hash 0x123... --contract-name Token
voyager verify --network mainnet --class-hash 0x456... --contract-name NFT
voyager verify --network mainnet --class-hash 0x789... --contract-name Market
After (batch config):
[voyager]
network = "mainnet"
license = "MIT"
watch = true
[[contracts]]
class-hash = "0x123..."
contract-name = "Token"
[[contracts]]
class-hash = "0x456..."
contract-name = "NFT"
[[contracts]]
class-hash = "0x789..."
contract-name = "Market"
# Single command
voyager verify
Best Practices Summary
1. Start Simple
[voyager]
network = "mainnet"
license = "MIT"
Add options as needed.
2. Use Comments
[voyager]
network = "mainnet"
license = "MIT"
# Enable for local development
# watch = true
# verbose = true
# Enable for CI
# watch = false
# verbose = true
3. Version Control
Commit:
.voyager.toml- Team defaults.voyager.example.toml- Template
Ignore:
.voyager.local.toml- Personal preferences
4. Environment-Specific
Create separate configs:
.voyager.dev.toml.voyager.staging.toml.voyager.prod.toml
5. Document Decisions
[voyager]
network = "mainnet"
license = "Apache-2.0"
# We use watch=true because verification takes 5-10 minutes
# and immediate feedback is valuable
watch = true
# Lock file ensures reproducible builds across team
lock-file = true
# Test files excluded in production builds
test-files = false
Troubleshooting Templates
Debug Configuration
When things aren’t working:
[voyager]
network = "sepolia" # Use testnet
license = "MIT"
# Maximum visibility
watch = true
notify = false # Disable to reduce noise
test-files = true # Include everything
lock-file = true
verbose = true # See all errors
Use with:
voyager verify --class-hash 0x123... --contract-name Debug --dry-run
Minimal Test Configuration
For isolating issues:
[voyager]
network = "sepolia"
license = "MIT"
# Nothing else - pure defaults
Next Steps
- Configuration File Guide - Complete config reference
- Workspace Settings - Multi-package projects
- CLI Options Reference - All available flags
- Batch Verification - Multiple contracts
History Overview
This section is currently under development as part of Phase 2.
The history feature provides local tracking of all your verification jobs:
- How History Works - Automatic tracking with SQLite database
- Viewing History - List and filter past verifications
- Filtering - Filter by status, network, date
- Rechecking Jobs - Batch update pending jobs
- Statistics - View verification success rates
- Cleanup - Manage old records
Quick Start
For now, see the history command reference.
Full history documentation will be added in Phase 2.
How History Works
Voyager Verifier automatically tracks all verification jobs in a local database, providing persistent tracking across sessions and commands.
Overview
History tracking provides:
- Automatic tracking - Every verification is recorded automatically
- Persistent storage - History survives across terminal sessions
- Cross-session access - Check jobs submitted in previous sessions
- Status updates - Track verification progress over time
- No configuration needed - Database created automatically on first use
- Privacy-focused - All data stored locally on your machine
Database Location
Default Location
~/.voyager/history.db
Examples by platform:
- Linux:
/home/username/.voyager/history.db - macOS:
/Users/username/.voyager/history.db - Windows:
C:\Users\username\.voyager\history.db
Database Structure
The history database is a SQLite database containing:
- Verification job records
- Submission timestamps
- Job IDs and status
- Network information
- Contract metadata
- Status update history
What Gets Tracked
Tracked Information
For each verification, the following information is stored:
Core Information
- Job ID - Unique identifier from Voyager API
- Timestamp - When verification was submitted
- Network - Network used (mainnet, sepolia, etc.)
- Status - Current verification status
Contract Information
- Class Hash - Contract class hash
- Contract Name - Name of the contract
- Package - Package name (for workspace projects)
Metadata
- License - SPDX license identifier
- Project Path - Location of the project
- Config Used - Configuration file location (if any)
Status History
- Initial Status - Status at submission
- Status Updates - All status changes
- Completion Time - When verification completed (if finished)
Example Record
Job ID: abc-123-def-456-ghi-789
Status: Success
Network: mainnet
Submitted: 2025-11-06 10:30:45
Completed: 2025-11-06 10:35:12
Duration: 4 minutes 27 seconds
Contract:
Name: MyToken
Hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Package: token
License: MIT
Automatic Tracking
When Tracking Occurs
History is automatically recorded:
- On submission - When
voyager verifyis executed - During watch - When using
--watchmode - On status check - When checking status manually
- On recheck - When rechecking pending jobs
No Manual Action Required
You don’t need to:
- Enable history tracking
- Initialize the database
- Manually save records
- Configure storage location
Everything happens automatically.
How Tracking Works
Submission Flow
1. You run: voyager verify --network mainnet --class-hash 0x123... --contract-name Token
2. Job submitted to API
3. API returns job ID
4. Record created in history.db
5. Initial status saved
6. You receive job ID confirmation
Watch Mode Flow
1. You run: voyager verify ... --watch
2. Job submitted and recorded
3. Status polling begins
4. Each status update saved to history
5. Final status recorded when complete
Status Check Flow
1. You run: voyager history status --job <JOB_ID>
2. Record retrieved from history.db
3. Current status displayed
4. (Optional) Refresh from API with --refresh
5. Updated status saved to history
Database Initialization
First Use
On first verification:
voyager verify --network mainnet --class-hash 0x123... --contract-name MyContract
What happens:
- Check if
~/.voyager/directory exists - Create directory if needed
- Check if
history.dbexists - Create database with schema if needed
- Insert first record
- Continue with verification
Output:
✓ History database initialized at ~/.voyager/history.db
✓ Verification job submitted successfully
Job ID: abc-123-def-456
Schema Creation
The database schema is automatically created with tables for:
- Verification jobs
- Status updates
- Network configurations
- Metadata
Cross-Session Persistence
Same-Day Access
Morning session:
voyager verify --network mainnet --class-hash 0x123... --contract-name Token
Job ID: abc-123-def
Afternoon session:
voyager history list
# Shows morning's verification
Multi-Day Access
Day 1:
voyager verify --network mainnet --class-hash 0x123... --contract-name TokenV1
Day 7:
voyager history list --limit 10
# Still shows Day 1 verification
Day 30:
voyager history list --older-than 30
# Can still access old records
Status Updates
Automatic Updates
When using --watch mode:
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract \
--watch
Status progression saved:
- Submitted → recorded
- Pending → updated
- In Progress → updated
- Compiling → updated
- Success/Failed → updated
Each status change is timestamped and saved.
Manual Updates
Update status for a specific job:
voyager history status --job abc-123-def --network mainnet --refresh
This:
- Fetches current status from API
- Updates record in history.db
- Displays updated status
Batch Updates
Update all pending jobs:
voyager history recheck --network mainnet
This:
- Finds all pending jobs
- Checks status for each from API
- Updates all records in database
- Shows summary of updates
Data Privacy
Local Storage
All history data is stored locally on your machine:
- ✅ No data sent to external servers (except verification API)
- ✅ No analytics or tracking
- ✅ No cloud synchronization
- ✅ Full control over your data
Database Access
Only you can access the database:
- Readable by: Your user account only
- Writable by: Your user account only
- Network access: None
- Shared access: None (unless you explicitly share the file)
Data Retention
You control retention:
- Keep forever (default)
- Clean old records manually
- Delete specific entries
- Delete entire database
Performance Considerations
Database Size
Typical sizes:
- 10 verifications: ~50 KB
- 100 verifications: ~500 KB
- 1,000 verifications: ~5 MB
- 10,000 verifications: ~50 MB
Query Performance
- List operations: Fast (< 1ms for 1,000 records)
- Filter operations: Fast (< 10ms for 10,000 records)
- Status checks: Instant (indexed by job ID)
- Statistics: Fast (aggregated queries optimized)
Maintenance
No regular maintenance required, but you can:
# Clean old records to reduce size
voyager history clean --older-than 90
# Vacuum database to reclaim space (manual)
sqlite3 ~/.voyager/history.db "VACUUM;"
Multi-Machine Setup
Separate Databases
Each machine has its own database:
Machine A: ~/.voyager/history.db (contains jobs from Machine A)
Machine B: ~/.voyager/history.db (contains jobs from Machine B)
Syncing (Optional)
To sync history across machines, manually copy the database:
# On Machine A
scp ~/.voyager/history.db machine-b:~/.voyager/history.db
# Or use rsync
rsync -avz ~/.voyager/history.db machine-b:~/.voyager/
Warning: This overwrites Machine B’s history.
Merging (Advanced)
To merge histories from multiple machines:
# Use SQLite commands (advanced users only)
sqlite3 ~/.voyager/history.db "ATTACH 'machine-b-history.db' AS other;"
sqlite3 ~/.voyager/history.db "INSERT OR IGNORE INTO verifications SELECT * FROM other.verifications;"
Troubleshooting
Database Not Found
Error:
Error: History database not found
Cause: Database file deleted or moved
Solution: Database will be recreated on next verification:
voyager verify --network mainnet --class-hash 0x123... --contract-name Test
Corrupted Database
Error:
Error: Database file is corrupted
Solutions:
Option 1 - Backup and recreate:
# Backup corrupted file
cp ~/.voyager/history.db ~/.voyager/history.db.backup
# Remove corrupted database
rm ~/.voyager/history.db
# Run verification to create new database
voyager verify --network mainnet --class-hash 0x123... --contract-name Test
Option 2 - Repair with SQLite:
sqlite3 ~/.voyager/history.db ".recover" | sqlite3 ~/.voyager/history-recovered.db
mv ~/.voyager/history-recovered.db ~/.voyager/history.db
Permission Issues
Error:
Error: Permission denied: ~/.voyager/history.db
Solution: Fix permissions:
chmod 644 ~/.voyager/history.db
Disk Space Full
Error:
Error: Cannot write to history database: disk full
Solution: Clean old records:
voyager history clean --older-than 30
Best Practices
1. Regular Cleanup
Clean old records periodically:
# Monthly cleanup
voyager history clean --older-than 90
2. Backup Important Records
Before major cleanup:
# Backup database
cp ~/.voyager/history.db ~/.voyager/history-backup-$(date +%Y%m%d).db
# Then clean
voyager history clean --older-than 180
3. Monitor Database Size
Check database size:
ls -lh ~/.voyager/history.db
If growing too large, clean old records.
4. Use Filtering
Instead of listing all records:
# Bad - lists everything
voyager history list
# Good - filter what you need
voyager history list --status success --limit 20
voyager history list --network mainnet --limit 10
5. Recheck Periodically
For pending jobs:
# Weekly recheck of pending jobs
voyager history recheck --network mainnet
Integration with Workflows
Development Workflow
# Submit verification
voyager verify --network sepolia --class-hash 0x123... --contract-name Test
# Later, check all sepolia verifications
voyager history list --network sepolia
# Recheck any pending
voyager history recheck --network sepolia
Production Deployment
# Submit production verification
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name ProductionContract \
--watch
# Check history for confirmation
voyager history list --limit 1
CI/CD Pipeline
# In CI, submit without watch
voyager verify --network mainnet --class-hash $CLASS_HASH --contract-name $CONTRACT
# Later, check from history
voyager history status --job $JOB_ID --network mainnet --refresh
Audit Trail
# Generate report of all mainnet verifications
voyager history list --network mainnet > mainnet-verifications.txt
# Show statistics
voyager history stats >> mainnet-verifications.txt
Advanced Usage
Export History
# Export to JSON (if supported)
voyager history list --format json > history.json
# Or use SQLite directly
sqlite3 ~/.voyager/history.db ".mode json" ".once history.json" "SELECT * FROM verifications;"
Query Specific Time Range
# Using SQLite directly for custom queries
sqlite3 ~/.voyager/history.db "SELECT * FROM verifications WHERE submitted_at > '2025-11-01';"
Backup Strategy
#!/bin/bash
# backup-history.sh
DATE=$(date +%Y%m%d)
cp ~/.voyager/history.db ~/.voyager/backups/history-$DATE.db
# Keep only last 30 days of backups
find ~/.voyager/backups/ -name "history-*.db" -mtime +30 -delete
Next Steps
- Viewing History - List and view verification records
- Filtering - Filter history by status, network, date
- Rechecking Jobs - Update status for pending verifications
- Statistics - View verification success rates
- Cleanup - Manage and clean old records
Viewing History
Learn how to view and list verification history using the history list command.
Overview
The history list command displays verification records from your local history database, showing:
- All verification jobs
- Job status and timestamps
- Contract information
- Network details
- Quick filtering options
Basic Command
List All Verifications
voyager history list
Shows all verification records, most recent first.
Example output:
Verification History
════════════════════════════════════════════════════════
[1] MyToken (Success)
Job ID: abc-123-def-456
Network: mainnet
Submitted: 2025-11-06 10:30:45
Completed: 2025-11-06 10:35:12
Duration: 4m 27s
Class Hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
[2] TestContract (Pending)
Job ID: ghi-789-jkl-012
Network: sepolia
Submitted: 2025-11-06 10:25:30
Status: In Progress
[3] NFTContract (Success)
Job ID: mno-345-pqr-678
Network: mainnet
Submitted: 2025-11-05 15:42:10
Completed: 2025-11-05 15:47:33
Duration: 5m 23s
Class Hash: 0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19
────────────────────────────────────────────────────────
Total: 3 verifications
Limiting Results
Default Behavior
By default, shows all verification records.
Limit Number of Results
voyager history list --limit <NUMBER>
Examples:
# Show last 10 verifications
voyager history list --limit 10
# Show last 5 verifications
voyager history list --limit 5
# Show only most recent
voyager history list --limit 1
Use cases:
- Quick check of recent verifications
- Avoid overwhelming output
- Performance with large history
Output Formats
Default Format (Text)
Human-readable table format:
voyager history list
Table Format
Compact table view:
voyager history list --format table
Output:
┌──────────────┬────────┬─────────┬─────────────────────┬──────────┐
│ Contract │ Status │ Network │ Submitted │ Duration │
├──────────────┼────────┼─────────┼─────────────────────┼──────────┤
│ MyToken │ ✓ │ mainnet │ 2025-11-06 10:30:45 │ 4m 27s │
│ TestContract │ ⏳ │ sepolia │ 2025-11-06 10:25:30 │ - │
│ NFTContract │ ✓ │ mainnet │ 2025-11-05 15:42:10 │ 5m 23s │
└──────────────┴────────┴─────────┴─────────────────────┴──────────┘
JSON Format
Machine-readable format:
voyager history list --format json
Output:
[
{
"job_id": "abc-123-def-456",
"contract_name": "MyToken",
"class_hash": "0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18",
"status": "success",
"network": "mainnet",
"submitted_at": "2025-11-06T10:30:45Z",
"completed_at": "2025-11-06T10:35:12Z",
"duration_seconds": 267
},
{
"job_id": "ghi-789-jkl-012",
"contract_name": "TestContract",
"class_hash": "0x066dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da20",
"status": "pending",
"network": "sepolia",
"submitted_at": "2025-11-06T10:25:30Z",
"completed_at": null,
"duration_seconds": null
}
]
Use cases:
- CI/CD pipelines
- Parsing with
jq - Integration with other tools
- Automated reporting
Basic Filtering
By Status
voyager history list --status <STATUS>
Available statuses:
success- Completed successfullyfailed- Failed verificationpending- Still in progress
Examples:
# Show only successful verifications
voyager history list --status success
# Show only failed verifications
voyager history list --status failed
# Show only pending verifications
voyager history list --status pending
By Network
voyager history list --network <NETWORK>
Examples:
# Show mainnet verifications only
voyager history list --network mainnet
# Show sepolia verifications only
voyager history list --network sepolia
# Show dev network verifications
voyager history list --network dev
Combined Filters
# Successful mainnet verifications
voyager history list --status success --network mainnet
# Pending sepolia verifications
voyager history list --status pending --network sepolia
# Last 10 successful mainnet verifications
voyager history list --status success --network mainnet --limit 10
Sorting
Default Sorting
By default, results are sorted by submission time, most recent first.
Examples
# Most recent first (default)
voyager history list
# Limit to see most recent
voyager history list --limit 5
Complete Examples
Example 1: Quick Recent Check
Show last 5 verifications:
voyager history list --limit 5
Example 2: Mainnet Success Report
All successful mainnet verifications:
voyager history list --status success --network mainnet
Example 3: Pending Jobs Check
See what’s still in progress:
voyager history list --status pending
Example 4: Last 10 on Sepolia
Recent sepolia testnet verifications:
voyager history list --network sepolia --limit 10
Example 5: Failed Verifications Audit
Review all failures:
voyager history list --status failed
Example 6: JSON Export
Export to JSON for processing:
voyager history list --format json > verifications.json
Example 7: Table View
Compact overview:
voyager history list --format table --limit 20
Understanding Output
Status Indicators
- ✓ / Success - Verification completed successfully
- ✗ / Failed - Verification failed
- ⏳ / Pending - Still in progress
- ⏱️ / In Progress - Currently compiling/processing
Duration Display
- 4m 27s - Completed in 4 minutes 27 seconds
- - - Not completed yet (pending)
- < 1s - Completed very quickly
Timestamps
All timestamps shown in local timezone:
Submitted: 2025-11-06 10:30:45
Completed: 2025-11-06 10:35:12
Class Hash Display
Full hash or truncated depending on format:
# Full (in detailed view)
Class Hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
# Truncated (in table view)
Hash: 0x044dc...da18
Empty History
First Use
If no verifications have been run:
voyager history list
Output:
Verification History
════════════════════════════════════════════════════════
No verification history found.
Run 'voyager verify' to create your first verification record.
After Cleanup
After cleaning all records:
voyager history list
Output:
Verification History
════════════════════════════════════════════════════════
No verification history found.
History has been cleared.
Common Workflows
Daily Check
Check what you verified today:
voyager history list --limit 10
Status Review
Check pending verifications:
voyager history list --status pending
Then recheck them:
voyager history recheck --network mainnet
Network-Specific Review
Review mainnet verifications:
voyager history list --network mainnet
Failure Investigation
Find failed verifications:
voyager history list --status failed
Then check specific job:
voyager history status --job <JOB_ID> --network mainnet --refresh --verbose
Export for Reporting
Generate report:
# JSON format
voyager history list --format json > report.json
# Table format
voyager history list --format table > report.txt
# Default format with filters
voyager history list --network mainnet --status success > mainnet-success.txt
Performance Considerations
Large History
For databases with thousands of records:
# Use limit to avoid loading everything
voyager history list --limit 50
# Filter to reduce results
voyager history list --network mainnet --limit 100
Query Speed
- No filters: Fast (< 10ms for 1,000 records)
- With filters: Very fast (indexed queries)
- JSON output: Slightly slower (serialization overhead)
Integration Examples
With jq
Process JSON output:
# Count successful verifications
voyager history list --format json | jq '[.[] | select(.status == "success")] | length'
# Extract job IDs
voyager history list --format json | jq -r '.[].job_id'
# Filter by date
voyager history list --format json | jq '.[] | select(.submitted_at > "2025-11-01")'
With grep
Filter text output:
# Find specific contract
voyager history list | grep "MyToken"
# Find mainnet verifications
voyager history list | grep "mainnet"
# Find failed verifications
voyager history list | grep "Failed"
In Scripts
#!/bin/bash
# check-pending.sh
# Get count of pending verifications
PENDING=$(voyager history list --status pending --format json | jq 'length')
if [ "$PENDING" -gt 0 ]; then
echo "$PENDING pending verifications found"
voyager history recheck --network mainnet
else
echo "No pending verifications"
fi
Troubleshooting
No Output
Problem: Command runs but shows nothing.
Possible causes:
- No verification history exists
- Filters too restrictive
- Database is empty
Solutions:
# Remove filters
voyager history list
# Check database exists
ls ~/.voyager/history.db
# Run a verification to populate
voyager verify --network mainnet --class-hash 0x123... --contract-name Test
Too Much Output
Problem: Output scrolls off screen.
Solutions:
# Use limit
voyager history list --limit 20
# Use pager
voyager history list | less
# Use filters
voyager history list --network mainnet --status success --limit 10
Formatting Issues
Problem: JSON output not formatted properly.
Solution: Use jq for pretty printing:
voyager history list --format json | jq '.'
Performance Issues
Problem: List command is slow.
Solutions:
# Use limit
voyager history list --limit 100
# Clean old records
voyager history clean --older-than 90
# Vacuum database
sqlite3 ~/.voyager/history.db "VACUUM;"
Best Practices
1. Always Use Limits
For quick checks:
voyager history list --limit 10
2. Filter Appropriately
Don’t list everything when you need specific data:
# Good
voyager history list --network mainnet --status success --limit 20
# Less good
voyager history list | grep mainnet | grep success
3. Use JSON for Automation
In scripts and CI/CD:
voyager history list --format json | jq '.[] | select(.status == "pending")'
4. Regular Review
Periodically check history:
# Weekly check
voyager history list --limit 50
# Monthly stats
voyager history stats
5. Combine with Other Commands
# List pending, then recheck
voyager history list --status pending
voyager history recheck --network mainnet
# List failed, then investigate
voyager history list --status failed
voyager history status --job <JOB_ID> --network mainnet --refresh --verbose
Next Steps
- Filtering - Advanced filtering options
- Rechecking Jobs - Update pending verification status
- Statistics - View aggregated verification stats
- Cleanup - Manage and clean old records
- How History Works - Understanding the history system
Advanced Filtering
Advanced filtering options for querying and searching verification history.
Overview
Beyond basic filtering, Voyager provides advanced options for:
- Time-based filtering - Filter by date ranges
- Pattern matching - Search contract names
- Combined filters - Multiple criteria at once
- Result limiting - Control output size
- Custom queries - Direct SQLite access
Basic Filters (Quick Reference)
By Status
voyager history list --status <STATUS>
Available statuses:
success- Completed successfullyfailed- Failed verificationpending- Still in progress
Examples:
voyager history list --status success
voyager history list --status failed
voyager history list --status pending
By Network
voyager history list --network <NETWORK>
Examples:
voyager history list --network mainnet
voyager history list --network sepolia
voyager history list --network dev
Limiting Results
voyager history list --limit <NUMBER>
Examples:
voyager history list --limit 10
voyager history list --limit 50
voyager history list --limit 1
Time-Based Filtering
Recent Verifications
Show verifications from the last N days:
voyager history list --since <DAYS>
Examples:
# Last 7 days
voyager history list --since 7
# Last 24 hours
voyager history list --since 1
# Last 30 days
voyager history list --since 30
Before Specific Date
Show verifications before a date:
voyager history list --before <DATE>
Date format: YYYY-MM-DD
Examples:
# Before November 1, 2025
voyager history list --before 2025-11-01
# Before October 15, 2025
voyager history list --before 2025-10-15
After Specific Date
Show verifications after a date:
voyager history list --after <DATE>
Examples:
# After November 1, 2025
voyager history list --after 2025-11-01
# After yesterday
voyager history list --after $(date -d "yesterday" +%Y-%m-%d)
Date Range
Combine before and after for a range:
voyager history list --after <START> --before <END>
Example:
# October 2025
voyager history list --after 2025-10-01 --before 2025-10-31
# Last week
voyager history list --after 2025-10-28 --before 2025-11-04
Pattern Matching
By Contract Name
Search for contracts by name pattern:
voyager history list --contract-name <PATTERN>
Examples:
# Exact match
voyager history list --contract-name MyToken
# Partial match (case-insensitive)
voyager history list --contract-name token
# All contracts starting with "Test"
voyager history list --contract-name "Test*"
By Class Hash
Filter by class hash prefix:
voyager history list --class-hash <HASH_PREFIX>
Examples:
# Full hash
voyager history list --class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
# Prefix (first 20 chars)
voyager history list --class-hash 0x044dc2b323938223
# Short prefix
voyager history list --class-hash 0x044d
By Job ID
Find specific job by ID:
voyager history list --job <JOB_ID>
Examples:
# Full job ID
voyager history list --job abc-123-def-456
# Partial job ID
voyager history list --job abc-123
Combined Filters
Multiple Criteria
Combine filters for precise queries:
voyager history list \
--status <STATUS> \
--network <NETWORK> \
--since <DAYS> \
--limit <NUMBER>
Example 1: Recent Mainnet Successes
voyager history list \
--status success \
--network mainnet \
--since 7 \
--limit 20
Shows last 20 successful mainnet verifications from the past week.
Example 2: Failed Sepolia Tests
voyager history list \
--status failed \
--network sepolia \
--since 1
Shows all failed sepolia verifications from today.
Example 3: Specific Contract on Mainnet
voyager history list \
--contract-name MyToken \
--network mainnet \
--status success
Shows all successful MyToken verifications on mainnet.
Example 4: October Production Deployments
voyager history list \
--network mainnet \
--after 2025-10-01 \
--before 2025-10-31 \
--status success
Shows all successful mainnet verifications in October.
Example 5: Recent Pending Jobs
voyager history list \
--status pending \
--since 1 \
--limit 10
Shows up to 10 pending jobs from today.
Sorting
By Submission Time (Default)
Most recent first:
voyager history list
By Duration
Show longest/shortest verifications:
# Longest first
voyager history list --sort duration --order desc
# Shortest first
voyager history list --sort duration --order asc
Use cases:
- Identify slow verifications
- Find quick test deployments
- Performance analysis
By Contract Name
Alphabetically sorted:
# A-Z
voyager history list --sort contract --order asc
# Z-A
voyager history list --sort contract --order desc
Advanced Use Cases
Use Case 1: Monthly Report
Generate monthly verification report:
#!/bin/bash
# monthly-report.sh
MONTH="2025-10"
START="${MONTH}-01"
END="${MONTH}-31"
echo "Verification Report: $MONTH"
echo "================================"
echo ""
echo "Mainnet Verifications:"
voyager history list \
--network mainnet \
--after $START \
--before $END \
--format table
echo ""
echo "Success Rate:"
voyager history stats \
--network mainnet \
--after $START \
--before $END
Use Case 2: Failed Verification Audit
Find and analyze all failures:
# List all failures
voyager history list --status failed --format json > failures.json
# Count failures by network
jq -r '.[] | .network' failures.json | sort | uniq -c
# Get failure details
jq '.[] | {contract: .contract_name, network: .network, date: .submitted_at}' failures.json
Use Case 3: Contract Deployment Timeline
Track deployments of a specific contract:
# Timeline for MyToken
voyager history list \
--contract-name MyToken \
--sort time \
--order asc \
--format table
# Show all networks
for network in mainnet sepolia dev; do
echo "MyToken on $network:"
voyager history list \
--contract-name MyToken \
--network $network
done
Use Case 4: Performance Analysis
Find slow verifications:
# Verifications taking >10 minutes
voyager history list --format json | \
jq '.[] | select(.duration_seconds > 600) | {contract: .contract_name, duration: .duration_seconds, network: .network}'
# Average duration by network
voyager history list --format json | \
jq 'group_by(.network) | map({network: .[0].network, avg_duration: (map(.duration_seconds) | add / length)})'
Use Case 5: CI/CD Integration
Check recent deployments in CI:
#!/bin/bash
# check-deployments.sh
# Get last 10 mainnet verifications
RECENT=$(voyager history list \
--network mainnet \
--limit 10 \
--format json)
# Count failures
FAILURES=$(echo $RECENT | jq '[.[] | select(.status == "failed")] | length')
if [ $FAILURES -gt 0 ]; then
echo "Warning: $FAILURES failed verifications in last 10"
exit 1
fi
echo "All recent verifications successful"
Output Format Filtering
Text Output (Default)
Human-readable format:
voyager history list --status success --limit 5
Table Output
Compact table view:
voyager history list --status success --limit 5 --format table
JSON Output
Machine-readable for processing:
voyager history list --status success --limit 5 --format json
Process with jq:
# Extract job IDs
voyager history list --status success --format json | jq -r '.[].job_id'
# Filter by duration
voyager history list --format json | jq '.[] | select(.duration_seconds < 300)'
# Group by network
voyager history list --format json | jq 'group_by(.network)'
Performance Considerations
Large Result Sets
For databases with many records:
# Use limit to avoid loading everything
voyager history list --limit 100
# Combine with filters to reduce results
voyager history list --network mainnet --since 7 --limit 50
Query Optimization
Fast queries:
- Filtering by status (indexed)
- Filtering by network (indexed)
- Filtering by job ID (indexed)
- Limiting results
Slower queries:
- Pattern matching contract names (no index)
- Sorting by duration (requires calculation)
- Date range without limit
Optimization tips:
# Good - specific and limited
voyager history list --status success --network mainnet --limit 20
# Less good - broad query without limit
voyager history list --contract-name "*Token*"
# Better - add limit
voyager history list --contract-name "*Token*" --limit 50
Direct Database Access
Using SQLite Directly
For complex queries not supported by CLI:
# Access database
sqlite3 ~/.voyager/history.db
Example queries:
-- All verifications from October
SELECT * FROM verifications
WHERE date(submitted_at) BETWEEN '2025-10-01' AND '2025-10-31';
-- Count by status
SELECT status, COUNT(*)
FROM verifications
GROUP BY status;
-- Average duration by network
SELECT network, AVG(duration_seconds) as avg_duration
FROM verifications
WHERE duration_seconds IS NOT NULL
GROUP BY network;
-- Contracts with multiple verifications
SELECT contract_name, COUNT(*) as count
FROM verifications
GROUP BY contract_name
HAVING count > 1
ORDER BY count DESC;
Export Filtered Results
# Export specific query to CSV
sqlite3 -header -csv ~/.voyager/history.db \
"SELECT contract_name, network, status, submitted_at
FROM verifications
WHERE network = 'mainnet' AND status = 'success'" \
> mainnet-success.csv
Integration Examples
With jq (JSON Processing)
# Count by status
voyager history list --format json | \
jq 'group_by(.status) | map({status: .[0].status, count: length})'
# Find contracts verified on multiple networks
voyager history list --format json | \
jq 'group_by(.contract_name) | map({contract: .[0].contract_name, networks: [.[].network] | unique})'
# Latest verification per contract
voyager history list --format json | \
jq 'group_by(.contract_name) | map(max_by(.submitted_at))'
With grep (Text Filtering)
# Find specific contract
voyager history list | grep "MyToken"
# Find mainnet verifications
voyager history list | grep "mainnet"
# Find failures
voyager history list | grep "Failed"
In Bash Scripts
#!/bin/bash
# check-contract-status.sh
CONTRACT_NAME=$1
NETWORK=${2:-mainnet}
# Find most recent verification
LATEST=$(voyager history list \
--contract-name "$CONTRACT_NAME" \
--network "$NETWORK" \
--limit 1 \
--format json)
if [ -z "$LATEST" ]; then
echo "No verifications found for $CONTRACT_NAME on $NETWORK"
exit 1
fi
STATUS=$(echo $LATEST | jq -r '.[0].status')
if [ "$STATUS" = "success" ]; then
echo "✓ $CONTRACT_NAME is verified on $NETWORK"
exit 0
else
echo "✗ $CONTRACT_NAME verification $STATUS on $NETWORK"
exit 1
fi
Troubleshooting
No Results Found
Problem: Filter returns no results.
Possible causes:
- Filters too restrictive
- Incorrect date format
- Typo in contract name
- Wrong network name
Solutions:
# Remove filters one by one
voyager history list --network mainnet # Test network filter
voyager history list --status success # Test status filter
voyager history list --since 30 # Broaden time range
# Check available data
voyager history list --limit 10 # See what exists
Slow Queries
Problem: Query takes a long time.
Solutions:
# Add limit
voyager history list --contract-name "*Token*" --limit 50
# Use more specific filters
voyager history list --network mainnet --since 7 --limit 20
# Avoid pattern matching on large datasets
# Instead of: voyager history list --contract-name "*"
# Use: voyager history list --limit 100
Date Format Issues
Problem: Date filter not working.
Solution: Use correct format YYYY-MM-DD:
# Correct
voyager history list --after 2025-11-01
# Incorrect
voyager history list --after 11/01/2025 # Wrong format
voyager history list --after 2025-11-1 # Missing zero
Case Sensitivity
Problem: Contract name search not finding results.
Note: Contract name search is case-insensitive:
# All equivalent
voyager history list --contract-name MyToken
voyager history list --contract-name mytoken
voyager history list --contract-name MYTOKEN
Best Practices
1. Start Broad, Then Narrow
# Start with broad query
voyager history list --network mainnet --limit 20
# Narrow down
voyager history list --network mainnet --status success --limit 20
# Further narrow
voyager history list --network mainnet --status success --since 7 --limit 20
2. Always Use Limits
Prevent overwhelming output:
# Good
voyager history list --status success --limit 50
# Less good
voyager history list --status success # Could be thousands
3. Use JSON for Complex Processing
# For simple viewing: use text
voyager history list --limit 10
# For processing: use JSON
voyager history list --format json | jq '.[] | select(.duration_seconds > 300)'
4. Combine with Other Commands
# List pending, then recheck
voyager history list --status pending
voyager history recheck --network mainnet
# List failures, then investigate
voyager history list --status failed --limit 5
# Then check details of specific job
5. Save Complex Queries
Create aliases for common queries:
# Add to ~/.bashrc or ~/.zshrc
alias verify-recent="voyager history list --limit 10"
alias verify-mainnet="voyager history list --network mainnet --status success --limit 20"
alias verify-failed="voyager history list --status failed"
alias verify-pending="voyager history list --status pending"
Next Steps
- History Listing - Basic history viewing
- Rechecking Jobs - Update pending verification status
- Statistics - Aggregated verification statistics
- Cleanup - Manage and clean old records
- How History Works - Understanding the tracking system
Rechecking Verification Jobs
Update the status of pending verification jobs by rechecking with the Voyager API.
Overview
The history recheck command allows you to:
- Update pending jobs - Check if pending verifications have completed
- Batch status updates - Recheck multiple jobs at once
- Network-specific checks - Recheck jobs for specific networks
- Automatic history updates - Updates stored in local database
- See what changed - Summary of status changes
Basic Usage
Recheck All Pending Jobs
voyager history recheck --network <NETWORK>
Example:
voyager history recheck --network mainnet
Output:
Rechecking pending verifications...
════════════════════════════════════════════════════════
Checking 3 pending jobs on mainnet...
[1/3] MyToken (abc-123-def-456)
Status: Pending → Success ✓
[2/3] TestContract (ghi-789-jkl-012)
Status: Pending → Success ✓
[3/3] NFTContract (mno-345-pqr-678)
Status: Pending → Failed ✗
Error: Compilation error in contract code
────────────────────────────────────────────────────────
Summary:
Total checked: 3
Completed: 2
Failed: 1
Still pending: 0
Command Options
Required: Network
You must specify the network:
voyager history recheck --network <NETWORK>
Available networks:
mainnetsepoliadev- Custom endpoint URLs
Optional: Job ID
Recheck a specific job:
voyager history recheck --network <NETWORK> --job <JOB_ID>
Example:
voyager history recheck --network mainnet --job abc-123-def-456
Optional: Status Filter
Only recheck jobs with specific status:
voyager history recheck --network <NETWORK> --status <STATUS>
Example:
# Only recheck pending jobs (default)
voyager history recheck --network mainnet --status pending
# Recheck all jobs regardless of status
voyager history recheck --network mainnet --status all
Use Cases
Use Case 1: Daily Pending Check
Check pending verifications daily:
# Morning routine
voyager history list --status pending
voyager history recheck --network mainnet
Use Case 2: CI/CD Pipeline
Verify deployment status in CI:
#!/bin/bash
# deploy-check.sh
# Submit verification
JOB_ID=$(voyager verify \
--network mainnet \
--class-hash $CLASS_HASH \
--contract-name $CONTRACT \
| grep "Job ID" | awk '{print $3}')
# Wait a bit
sleep 60
# Check status
voyager history recheck --network mainnet --job $JOB_ID
# Verify success
STATUS=$(voyager history list --job $JOB_ID --format json | jq -r '.[0].status')
if [ "$STATUS" != "success" ]; then
echo "Verification failed or still pending"
exit 1
fi
Use Case 3: Network-Specific Review
Recheck all pending jobs on specific network:
# Check sepolia testnet
voyager history recheck --network sepolia
# Check mainnet
voyager history recheck --network mainnet
Use Case 4: After API Downtime
If API was down, recheck all jobs:
# Recheck all jobs (not just pending)
voyager history recheck --network mainnet --status all
Use Case 5: Weekly Cleanup
Weekly maintenance to update all pending:
#!/bin/bash
# weekly-recheck.sh
for network in mainnet sepolia; do
echo "Rechecking $network..."
voyager history recheck --network $network
done
Understanding Output
Status Transitions
Pending → Success:
[1/3] MyToken (abc-123-def-456)
Status: Pending → Success ✓
Duration: 4m 27s
Pending → Failed:
[2/3] TestContract (ghi-789-jkl-012)
Status: Pending → Failed ✗
Error: Compilation error in contract code
Still Pending:
[3/3] NFTContract (mno-345-pqr-678)
Status: Pending → Still Pending ⏳
Note: Compilation in progress
Summary Statistics
Summary:
Total checked: 5
Completed: 3 # Changed to success
Failed: 1 # Changed to failed
Still pending: 1 # Still in progress
Behavior Details
What Gets Rechecked
Default behavior:
- Only jobs with
status = pendingare rechecked - Only jobs on specified network
- Jobs are checked against Voyager API
- Local database is updated with new status
With --status all:
- All jobs on specified network are rechecked
- Useful after API issues or data corruption
API Rate Limiting
Recheck requests are rate-limited:
- Delay between checks: 1 second
- Batch size: All pending jobs
- Timeout: 30 seconds per job
For large batches:
# If you have many pending jobs (>100)
voyager history recheck --network mainnet --limit 50
Network Requirement
Network must be specified because:
- API endpoints differ per network
- Job IDs are network-specific
- Prevents accidental cross-network checks
Examples
Example 1: Basic Recheck
# Check what's pending
voyager history list --status pending
# Output:
# 3 pending verifications found
# Recheck them
voyager history recheck --network mainnet
# Output: Summary of status changes
Example 2: Specific Job
# Recheck one job
voyager history recheck \
--network mainnet \
--job abc-123-def-456
# Output:
# MyToken (abc-123-def-456)
# Status: Pending → Success ✓
Example 3: All Networks
# Recheck all networks
for network in mainnet sepolia dev; do
echo "Checking $network..."
voyager history recheck --network $network
done
Example 4: After Submission
# Submit without watch
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name MyContract
# Later, check status
sleep 300 # Wait 5 minutes
voyager history recheck --network mainnet
Example 5: CI Integration
# In CI pipeline
voyager verify --network mainnet \
--class-hash $HASH \
--contract-name $NAME
# Poll for completion
for i in {1..10}; do
echo "Check $i/10..."
voyager history recheck --network mainnet
# Check if done
STATUS=$(voyager history list --limit 1 --format json | jq -r '.[0].status')
if [ "$STATUS" = "success" ]; then
echo "Verification complete!"
exit 0
elif [ "$STATUS" = "failed" ]; then
echo "Verification failed!"
exit 1
fi
sleep 30
done
echo "Verification timeout"
exit 1
Integration with Other Commands
With history list
# List pending
voyager history list --status pending
# Recheck them
voyager history recheck --network mainnet
# List again to confirm
voyager history list --status pending
With history status
# Recheck specific job
voyager history recheck --network mainnet --job abc-123
# Get detailed status
voyager history status --network mainnet --job abc-123 --verbose
With watch mode
Watch mode (--watch) automatically checks status, but for jobs submitted without watch:
# Submit without watch
voyager verify --network mainnet --class-hash 0x123... --contract-name Token
# Manual recheck later
voyager history recheck --network mainnet
Comparison: Recheck vs Watch
Watch Mode (--watch)
Use when:
- Submitting new verification
- Want immediate feedback
- Can wait for completion
- Running interactively
Example:
voyager verify --network mainnet \
--class-hash 0x123... \
--contract-name Token \
--watch
Behavior:
- Automatically polls API
- Shows real-time progress
- Blocks until complete
- Updates history automatically
Recheck (history recheck)
Use when:
- Jobs submitted without watch
- Checking old pending jobs
- Batch status updates
- Running in scripts/CI
- After API downtime
Example:
voyager history recheck --network mainnet
Behavior:
- One-time status check
- Non-blocking
- Updates multiple jobs
- Returns immediately with summary
Error Handling
No Pending Jobs
If no pending jobs exist:
voyager history recheck --network mainnet
Output:
Rechecking pending verifications...
════════════════════════════════════════════════════════
No pending verifications found for mainnet.
All verifications are either completed or failed.
API Error
If API is unavailable:
voyager history recheck --network mainnet
Output:
Error: Unable to connect to Voyager API
Network: mainnet
Endpoint: https://api.voyager.online/beta
Please check:
- Network connectivity
- API endpoint status
- Network name spelling
Retry in a few minutes.
Job Not Found
If job no longer exists on API:
voyager history recheck --network mainnet --job abc-123
Output:
Warning: Job abc-123 not found on API
Possible reasons:
- Job expired (API retention period)
- Wrong network specified
- Invalid job ID
Local history will not be updated.
Performance Considerations
Batch Size
For large numbers of pending jobs:
# Recheck can be slow with many jobs
voyager history list --status pending # Check how many
# If >50 jobs, consider limiting
voyager history recheck --network mainnet --limit 50
Frequency
Don’t recheck too frequently:
Good:
# Once per hour
*/60 * * * * voyager history recheck --network mainnet
Less good:
# Every minute (unnecessary API load)
* * * * * voyager history recheck --network mainnet
Network Timeout
Default timeout is 30 seconds per job:
# For slow networks, increase timeout
voyager history recheck --network mainnet --timeout 60
Automation Examples
Cron Job
# Add to crontab
# Recheck every 6 hours
0 */6 * * * /usr/local/bin/voyager history recheck --network mainnet >> /var/log/voyager-recheck.log 2>&1
Systemd Timer
# /etc/systemd/system/voyager-recheck.timer
[Unit]
Description=Recheck Voyager verification jobs
[Timer]
OnCalendar=*-*-* 00,06,12,18:00:00
Persistent=true
[Install]
WantedBy=timers.target
# /etc/systemd/system/voyager-recheck.service
[Unit]
Description=Recheck Voyager verification jobs
[Service]
Type=oneshot
ExecStart=/usr/local/bin/voyager history recheck --network mainnet
GitHub Actions
name: Recheck Verifications
on:
schedule:
- cron: '0 */6 * * *' # Every 6 hours
workflow_dispatch: # Manual trigger
jobs:
recheck:
runs-on: ubuntu-latest
steps:
- name: Install Voyager
run: cargo install voyager-verifier
- name: Recheck Pending Jobs
run: |
voyager history recheck --network mainnet
voyager history recheck --network sepolia
Troubleshooting
Problem: No Status Changes
Issue: Recheck shows no changes, jobs still pending.
Possible causes:
- Jobs are legitimately still processing
- API is slow
- Verifications take longer than expected
Solution:
# Wait longer and try again
sleep 300 # 5 minutes
voyager history recheck --network mainnet
# Check specific job with verbose output
voyager history status --network mainnet --job <JOB_ID> --verbose --refresh
Problem: Recheck Takes Too Long
Issue: Recheck command hangs or is very slow.
Solution:
# Use limit to reduce batch size
voyager history recheck --network mainnet --limit 10
# Check how many pending jobs exist
voyager history list --status pending | wc -l
# If too many, clean old pending jobs
voyager history clean --status pending --older-than 30
Problem: Wrong Network
Issue: Error about job not found.
Solution:
# Verify which network the job was submitted to
voyager history list --format json | jq '.[] | {job: .job_id, network: .network}'
# Use correct network
voyager history recheck --network <CORRECT_NETWORK>
Best Practices
1. Regular Rechecking
Set up automated rechecking:
# Daily recheck via cron
0 9 * * * voyager history recheck --network mainnet
2. Check Before Cleanup
Before cleaning history, recheck pending jobs:
# Recheck first
voyager history recheck --network mainnet
# Then clean old records
voyager history clean --older-than 90
3. Network-Specific
Always recheck per network:
# Good - explicit network
voyager history recheck --network mainnet
# Won't work - network required
voyager history recheck # Error: network required
4. Use in Scripts
Combine with status checking:
#!/bin/bash
# smart-recheck.sh
# Recheck
voyager history recheck --network mainnet
# Count remaining pending
PENDING=$(voyager history list --status pending --network mainnet --format json | jq 'length')
if [ $PENDING -gt 0 ]; then
echo "$PENDING verifications still pending"
else
echo "All verifications complete"
fi
5. Timeout for Long Jobs
Some verifications take a long time:
# For complex contracts, be patient
voyager history recheck --network mainnet
# If still pending after recheck, check age
voyager history list --status pending
# If submitted recently (<1 hour), wait longer
Next Steps
- History Listing - View verification history
- Filtering - Advanced history filtering
- Statistics - Verification statistics
- Cleanup - Clean old history records
- How History Works - Understanding history system
Verification Statistics
View aggregated statistics and analytics from your verification history.
Overview
The history stats command provides:
- Success/failure rates - Overall verification success percentage
- Network breakdown - Statistics per network
- Time-based metrics - Average duration, total time
- Volume metrics - Total verifications, contracts verified
- Trend analysis - Performance over time
Basic Usage
View All Statistics
voyager history stats
Example output:
Verification Statistics
════════════════════════════════════════════════════════
Overall Summary
────────────────────────────────────────────────────────
Total Verifications: 127
Success Rate: 94.5% (120/127)
Failed: 5.5% (7/127)
Pending: 0
Time Period: 2025-09-01 to 2025-11-06 (67 days)
Performance
────────────────────────────────────────────────────────
Average Duration: 4m 32s
Fastest: 1m 12s
Slowest: 12m 45s
Total Time: 9h 36m
By Network
────────────────────────────────────────────────────────
mainnet: 85 verifications (94% success)
sepolia: 38 verifications (97% success)
dev: 4 verifications (75% success)
Top Contracts
────────────────────────────────────────────────────────
1. Token (24 verifications)
2. NFT (18 verifications)
3. Marketplace (12 verifications)
4. TestContract (8 verifications)
5. GovernanceToken (6 verifications)
Filtering Statistics
By Network
voyager history stats --network <NETWORK>
Example:
voyager history stats --network mainnet
Output:
Verification Statistics (mainnet only)
════════════════════════════════════════════════════════
Total Verifications: 85
Success Rate: 94.1% (80/85)
Failed: 5.9% (5/85)
Average Duration: 4m 45s
Total Time: 6h 44m
By Time Period
voyager history stats --since <DAYS>
Examples:
# Last 7 days
voyager history stats --since 7
# Last 30 days
voyager history stats --since 30
# This month
voyager history stats --after 2025-11-01
By Date Range
voyager history stats --after <DATE> --before <DATE>
Example:
# October 2025
voyager history stats --after 2025-10-01 --before 2025-10-31
Output Formats
Text Format (Default)
Human-readable summary:
voyager history stats
JSON Format
Machine-readable data:
voyager history stats --format json
Example output:
{
"total_verifications": 127,
"successful": 120,
"failed": 7,
"pending": 0,
"success_rate": 0.945,
"average_duration_seconds": 272,
"fastest_duration_seconds": 72,
"slowest_duration_seconds": 765,
"total_duration_seconds": 34560,
"date_range": {
"start": "2025-09-01T00:00:00Z",
"end": "2025-11-06T23:59:59Z",
"days": 67
},
"by_network": {
"mainnet": {
"total": 85,
"successful": 80,
"failed": 5,
"success_rate": 0.941
},
"sepolia": {
"total": 38,
"successful": 37,
"failed": 1,
"success_rate": 0.974
},
"dev": {
"total": 4,
"successful": 3,
"failed": 1,
"success_rate": 0.750
}
},
"top_contracts": [
{"name": "Token", "count": 24},
{"name": "NFT", "count": 18},
{"name": "Marketplace", "count": 12}
]
}
Use Cases
Use Case 1: Monthly Report
Generate monthly statistics:
#!/bin/bash
# monthly-stats.sh
MONTH=$(date +%Y-%m)
START="${MONTH}-01"
END="${MONTH}-31"
echo "Verification Report: $MONTH"
voyager history stats --after $START --before $END
Use Case 2: Network Comparison
Compare success rates across networks:
#!/bin/bash
# network-comparison.sh
for network in mainnet sepolia dev; do
echo "=== $network ==="
voyager history stats --network $network
echo ""
done
Use Case 3: Performance Tracking
Track verification performance over time:
#!/bin/bash
# performance-trend.sh
echo "Last 7 days:"
voyager history stats --since 7 | grep "Average Duration"
echo "Last 30 days:"
voyager history stats --since 30 | grep "Average Duration"
echo "Last 90 days:"
voyager history stats --since 90 | grep "Average Duration"
Use Case 4: Success Rate Monitoring
Alert if success rate drops:
#!/bin/bash
# monitor-success.sh
STATS=$(voyager history stats --since 7 --format json)
SUCCESS_RATE=$(echo $STATS | jq -r '.success_rate')
# Alert if success rate < 90%
if (( $(echo "$SUCCESS_RATE < 0.9" | bc -l) )); then
echo "WARNING: Success rate is ${SUCCESS_RATE}%"
echo "Last 7 days have had unusually high failure rate"
# Show recent failures
voyager history list --status failed --since 7
else
echo "Success rate healthy: ${SUCCESS_RATE}%"
fi
Use Case 5: CI/CD Dashboard
Display stats in CI dashboard:
# In CI pipeline
voyager history stats --since 7 --format json > stats.json
# Parse for display
SUCCESS_RATE=$(jq -r '.success_rate * 100' stats.json)
TOTAL=$(jq -r '.total_verifications' stats.json)
echo "Last 7 days: $TOTAL verifications, ${SUCCESS_RATE}% success"
Understanding Metrics
Success Rate
Percentage of verifications that completed successfully:
Success Rate = (Successful / Total) * 100%
Example:
- Total: 100 verifications
- Successful: 95
- Success Rate: 95%
Average Duration
Mean time for verifications to complete:
Average Duration = Total Time / Completed Verifications
Notes:
- Excludes pending verifications
- Includes both successful and failed
- Measured from submission to completion
Time Period
Date range of included verifications:
Start: Earliest verification date
End: Latest verification date
Days: Number of days between start and end
Network Breakdown
Statistics grouped by network:
For each network:
- Total verifications
- Successful count
- Failed count
- Success rate
Top Contracts
Most frequently verified contracts:
Sorted by:
- Number of verifications (descending)
- Shows contract name and count
- Typically shows top 5-10
Examples
Example 1: Quick Overview
voyager history stats
See overall statistics at a glance.
Example 2: Mainnet Performance
voyager history stats --network mainnet
Focus on production network statistics.
Example 3: Last Week
voyager history stats --since 7
See recent activity and trends.
Example 4: Monthly Comparison
# October
voyager history stats --after 2025-10-01 --before 2025-10-31
# November
voyager history stats --after 2025-11-01 --before 2025-11-30
Compare month-over-month performance.
Example 5: Export for Analysis
voyager history stats --format json > stats-2025-11.json
Save statistics for external analysis.
Integration Examples
With Monitoring Tools
#!/bin/bash
# push-metrics.sh
# Get stats
STATS=$(voyager history stats --since 1 --format json)
# Extract metrics
SUCCESS_RATE=$(echo $STATS | jq -r '.success_rate')
AVG_DURATION=$(echo $STATS | jq -r '.average_duration_seconds')
TOTAL=$(echo $STATS | jq -r '.total_verifications')
# Push to monitoring system (example: Prometheus)
echo "verification_success_rate $SUCCESS_RATE" | curl --data-binary @- http://pushgateway:9091/metrics/job/voyager
echo "verification_avg_duration_seconds $AVG_DURATION" | curl --data-binary @- http://pushgateway:9091/metrics/job/voyager
echo "verification_total $TOTAL" | curl --data-binary @- http://pushgateway:9091/metrics/job/voyager
With Slack/Discord
#!/bin/bash
# weekly-report.sh
STATS=$(voyager history stats --since 7)
# Post to Slack
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"Weekly Verification Report\n\`\`\`$STATS\`\`\`\"}" \
$SLACK_WEBHOOK_URL
In Dashboards
// Fetch and display stats
const stats = await fetch('/api/voyager/stats').then(r => r.json());
document.getElementById('success-rate').innerText =
`${(stats.success_rate * 100).toFixed(1)}%`;
document.getElementById('total-verifications').innerText =
stats.total_verifications;
document.getElementById('avg-duration').innerText =
`${Math.round(stats.average_duration_seconds / 60)}m`;
Troubleshooting
No Statistics Available
Problem: Stats command shows “No data available”.
Cause: No verifications in history.
Solution:
# Check if history exists
voyager history list
# Run some verifications
voyager verify --network sepolia --class-hash 0x123... --contract-name Test
Empty Time Period
Problem: Stats show empty for specific time period.
Solution:
# Check what dates exist
voyager history list --limit 10
# Adjust time period
voyager history stats --since 30 # Broaden range
Inaccurate Durations
Problem: Duration statistics seem wrong.
Possible causes:
- Pending verifications not updated
- Clock skew during submission
Solution:
# Recheck pending jobs first
voyager history recheck --network mainnet
# Then view stats
voyager history stats
Performance Considerations
Large Databases
For databases with thousands of records:
# Stats calculation on large DB may be slow
# Consider filtering by time period
voyager history stats --since 30 # Last 30 days only
Caching
Statistics are calculated on-demand:
- No caching between runs
- Each call queries the database
- For dashboards, cache results for 5-15 minutes
Example caching:
#!/bin/bash
# cached-stats.sh
CACHE_FILE="/tmp/voyager-stats-cache.json"
CACHE_AGE=300 # 5 minutes
if [ -f "$CACHE_FILE" ]; then
AGE=$(($(date +%s) - $(stat -c %Y "$CACHE_FILE")))
if [ $AGE -lt $CACHE_AGE ]; then
cat "$CACHE_FILE"
exit 0
fi
fi
# Regenerate cache
voyager history stats --format json > "$CACHE_FILE"
cat "$CACHE_FILE"
Best Practices
1. Regular Monitoring
Check stats regularly:
# Weekly review
0 9 * * 1 /usr/local/bin/voyager history stats --since 7 | mail -s "Weekly Stats" team@company.com
2. Set Baselines
Establish normal ranges:
# Baseline metrics (example)
# Success rate: 90-95%
# Avg duration: 3-5 minutes
# Verify these regularly
3. Compare Time Periods
Track trends:
# This month vs last month
voyager history stats --after 2025-11-01
voyager history stats --after 2025-10-01 --before 2025-10-31
4. Use JSON for Automation
# Parse JSON in scripts
RATE=$(voyager history stats --format json | jq -r '.success_rate')
5. Combine with Other Tools
# Stats + details
voyager history stats --since 7
voyager history list --status failed --since 7
Next Steps
- History Listing - View individual verification records
- Filtering - Advanced history queries
- Rechecking Jobs - Update pending jobs
- Cleanup - Manage history database
- How History Works - Understanding the system
History Cleanup
Manage and clean old verification records from your local history database.
Overview
The history clean command allows you to:
- Remove old records - Delete verifications older than N days
- Free disk space - Reduce database size
- Maintain performance - Keep database queries fast
- Selective cleanup - Clean specific networks or statuses
- Safe deletion - Confirmation prompts for safety
Basic Usage
Clean Old Records
voyager history clean --older-than <DAYS>
Example:
# Remove records older than 90 days
voyager history clean --older-than 90
Output:
Cleaning History Records
════════════════════════════════════════════════════════
Found 47 records older than 90 days:
- 42 successful verifications
- 3 failed verifications
- 2 pending verifications
Total database size: 2.3 MB
Space to be freed: ~180 KB
⚠️ This action cannot be undone.
Proceed with cleanup? [y/N]: y
Deleting records...
✓ 47 records deleted
Database size after cleanup: 2.1 MB
Space freed: 200 KB
Command Options
Required: Time Period
Specify how old records must be to delete:
--older-than <DAYS>
Examples:
# 30 days old
voyager history clean --older-than 30
# 6 months old (180 days)
voyager history clean --older-than 180
# 1 year old
voyager history clean --older-than 365
Optional: Network Filter
Clean records for specific network only:
voyager history clean --older-than <DAYS> --network <NETWORK>
Example:
# Clean old sepolia testnet records
voyager history clean --older-than 30 --network sepolia
Optional: Status Filter
Clean records with specific status:
voyager history clean --older-than <DAYS> --status <STATUS>
Examples:
# Clean old successful verifications only
voyager history clean --older-than 90 --status success
# Clean old failed verifications
voyager history clean --older-than 30 --status failed
# Clean old pending verifications (likely abandoned)
voyager history clean --older-than 7 --status pending
Optional: Force (Skip Confirmation)
Skip confirmation prompt:
voyager history clean --older-than <DAYS> --force
Example:
# Clean without prompting (for scripts)
voyager history clean --older-than 90 --force
Optional: Dry Run
Preview what would be deleted without actually deleting:
voyager history clean --older-than <DAYS> --dry-run
Example:
# See what would be deleted
voyager history clean --older-than 90 --dry-run
Use Cases
Use Case 1: Monthly Cleanup
Regular monthly maintenance:
# Keep last 90 days of records
voyager history clean --older-than 90
Use Case 2: Testnet Cleanup
Clean testnet records more aggressively:
# Keep only 30 days of sepolia records
voyager history clean --older-than 30 --network sepolia
Use Case 3: Failed Verification Cleanup
Remove old failed verifications:
# Remove failed verifications older than 30 days
voyager history clean --older-than 30 --status failed
Use Case 4: Abandoned Pending Jobs
Clean old pending jobs that likely failed:
# Remove pending jobs older than 7 days
voyager history clean --older-than 7 --status pending
Use Case 5: Automated Cleanup
Set up automated cleanup via cron:
# Add to crontab - clean monthly
0 0 1 * * /usr/local/bin/voyager history clean --older-than 90 --force
Safety Features
Confirmation Prompt
By default, cleanup requires confirmation:
⚠️ This action cannot be undone.
Proceed with cleanup? [y/N]:
Type y to proceed, n or Enter to cancel.
Dry Run Mode
Preview deletions without making changes:
voyager history clean --older-than 90 --dry-run
Output:
DRY RUN - No changes will be made
════════════════════════════════════════════════════════
Would delete 47 records older than 90 days:
- 42 successful verifications
- 3 failed verifications
- 2 pending verifications
Estimated space to free: ~180 KB
No records were actually deleted.
No Deletion of Recent Records
Records newer than specified age are never deleted:
# Only deletes records >90 days old
# Keeps all records ≤90 days old
voyager history clean --older-than 90
Complete Examples
Example 1: Conservative Cleanup
Keep 180 days (6 months):
voyager history clean --older-than 180
Example 2: Aggressive Cleanup
Keep only 30 days:
voyager history clean --older-than 30
Example 3: Network-Specific Cleanup
Different retention per network:
# Mainnet: keep 180 days (production important)
voyager history clean --older-than 180 --network mainnet
# Sepolia: keep 30 days (testnet less important)
voyager history clean --older-than 30 --network sepolia
# Dev: keep 7 days (local testing)
voyager history clean --older-than 7 --network dev
Example 4: Status-Based Cleanup
Clean failures more aggressively:
# Keep successful for 180 days
voyager history clean --older-than 180 --status success
# Remove failed after 30 days
voyager history clean --older-than 30 --status failed
# Remove old pending after 7 days
voyager history clean --older-than 7 --status pending
Example 5: Scripted Cleanup
Automated cleanup without user interaction:
#!/bin/bash
# cleanup-history.sh
# Force flag skips confirmation
voyager history clean --older-than 90 --force
echo "History cleanup complete"
Database Maintenance
Vacuum Database
After cleanup, vacuum to reclaim space:
# Clean records
voyager history clean --older-than 90
# Vacuum database to reclaim space
sqlite3 ~/.voyager/history.db "VACUUM;"
Benefits:
- Defragments database
- Reclaims unused space
- Improves query performance
Check Database Size
Monitor database growth:
# Check size before cleanup
ls -lh ~/.voyager/history.db
# Clean
voyager history clean --older-than 90
# Check size after
ls -lh ~/.voyager/history.db
Database Statistics
Get record counts:
# Total records
sqlite3 ~/.voyager/history.db "SELECT COUNT(*) FROM verifications;"
# By status
sqlite3 ~/.voyager/history.db "SELECT status, COUNT(*) FROM verifications GROUP BY status;"
# By network
sqlite3 ~/.voyager/history.db "SELECT network, COUNT(*) FROM verifications GROUP BY network;"
Best Practices
1. Regular Schedule
Set up regular cleanup:
# Monthly via cron
0 0 1 * * voyager history clean --older-than 90 --force
# Or weekly for aggressive cleanup
0 0 * * 0 voyager history clean --older-than 30 --force
2. Backup Before Major Cleanup
Backup database before first cleanup:
# Backup
cp ~/.voyager/history.db ~/.voyager/history-backup-$(date +%Y%m%d).db
# Then clean
voyager history clean --older-than 180
3. Different Retention Per Network
Production vs testnet retention:
# Production: keep longer
voyager history clean --older-than 365 --network mainnet
# Testnet: shorter retention
voyager history clean --older-than 30 --network sepolia
4. Always Dry Run First
Preview before actual cleanup:
# See what would be deleted
voyager history clean --older-than 90 --dry-run
# If looks good, proceed
voyager history clean --older-than 90
5. Recheck Before Cleanup
Update pending jobs before cleaning:
# Recheck pending first
voyager history recheck --network mainnet
# Then clean old records
voyager history clean --older-than 90
Troubleshooting
Permission Denied
Problem: Cannot write to database.
Solution:
# Fix permissions
chmod 644 ~/.voyager/history.db
# Retry cleanup
voyager history clean --older-than 90
Database Locked
Problem: Database is locked by another process.
Solution:
# Check for other voyager processes
ps aux | grep voyager
# Kill if stuck
kill <PID>
# Retry cleanup
voyager history clean --older-than 90
No Records Deleted
Problem: Cleanup reports 0 records deleted.
Possible causes:
- No records older than specified age
- All records match filter criteria
Solution:
# Check what exists
voyager history list --limit 10
# Try broader age
voyager history clean --older-than 30
Space Not Freed
Problem: Database size didn’t decrease after cleanup.
Solution:
# Vacuum database to reclaim space
sqlite3 ~/.voyager/history.db "VACUUM;"
# Check size again
ls -lh ~/.voyager/history.db
Cleanup Strategies
Strategy 1: Fixed Retention
Keep fixed number of days:
# Always keep 90 days
voyager history clean --older-than 90 --force
Good for: Consistent history across time.
Strategy 2: Tiered Retention
Different retention by network:
#!/bin/bash
# tiered-cleanup.sh
# Production: 1 year
voyager history clean --older-than 365 --network mainnet --force
# Staging: 90 days
voyager history clean --older-than 90 --network staging --force
# Testnet: 30 days
voyager history clean --older-than 30 --network sepolia --force
# Dev: 7 days
voyager history clean --older-than 7 --network dev --force
Good for: Different importance levels per network.
Strategy 3: Status-Based Retention
Keep successes longer than failures:
#!/bin/bash
# status-retention.sh
# Successes: keep 180 days
voyager history clean --older-than 180 --status success --force
# Failures: keep 60 days
voyager history clean --older-than 60 --status failed --force
# Pending: keep 7 days
voyager history clean --older-than 7 --status pending --force
Good for: Optimizing disk space while keeping important records.
Strategy 4: Database Size Limit
Clean until database is under size limit:
#!/bin/bash
# size-based-cleanup.sh
TARGET_SIZE_MB=50
DB_PATH=~/.voyager/history.db
while true; do
SIZE_MB=$(du -m "$DB_PATH" | cut -f1)
if [ $SIZE_MB -le $TARGET_SIZE_MB ]; then
echo "Database size OK: ${SIZE_MB}MB"
break
fi
echo "Database too large: ${SIZE_MB}MB, cleaning..."
voyager history clean --older-than 30 --force
sqlite3 "$DB_PATH" "VACUUM;"
sleep 1
done
Good for: Systems with strict disk space limits.
Automation Examples
Cron Job
# Add to crontab
# Clean monthly, keep 90 days
0 0 1 * * /usr/local/bin/voyager history clean --older-than 90 --force >> /var/log/voyager-cleanup.log 2>&1
Systemd Timer
# /etc/systemd/system/voyager-cleanup.timer
[Unit]
Description=Clean old Voyager history records
[Timer]
OnCalendar=monthly
Persistent=true
[Install]
WantedBy=timers.target
# /etc/systemd/system/voyager-cleanup.service
[Unit]
Description=Clean old Voyager history records
[Service]
Type=oneshot
ExecStart=/usr/local/bin/voyager history clean --older-than 90 --force
ExecStartPost=/usr/bin/sqlite3 /home/user/.voyager/history.db "VACUUM;"
GitHub Actions
name: Cleanup History
on:
schedule:
- cron: '0 0 1 * *' # Monthly
workflow_dispatch: # Manual trigger
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- name: Install Voyager
run: cargo install voyager-verifier
- name: Clean Old Records
run: |
voyager history clean --older-than 90 --force
sqlite3 ~/.voyager/history.db "VACUUM;"
Recovery
Restore from Backup
If cleanup deleted too much:
# Stop any voyager processes
killall voyager
# Restore from backup
cp ~/.voyager/history-backup-20251106.db ~/.voyager/history.db
# Verify restoration
voyager history list --limit 10
Manual Deletion Undo
SQLite doesn’t support undo, but you can:
- Restore from backup (if available)
- Re-run verifications (if needed)
- Export/import from another machine
Next Steps
- History Listing - View verification records
- Filtering - Find specific records
- Rechecking Jobs - Update pending statuses
- Statistics - View verification stats
- How History Works - Understanding the system
Advanced Usage
This section is currently under development as part of Phase 3.
Advanced features for power users:
- Desktop Notifications - Get notified when verification completes
- Custom Endpoints - Use custom API endpoints
- Lock Files - Include Scarb.lock for reproducible builds
- Test Files - Include test files in verification
- Output Formats - JSON, table, and text formats
- CI/CD Integration - Automate verification in pipelines
Quick Start
For basic usage, see the Quickstart Guide.
Full advanced feature documentation will be added in Phase 3.
Desktop Notifications
Desktop notifications alert you when verification completes, allowing you to continue working while the verification runs in the background.
Overview
Desktop notifications provide:
- Automatic alerts when verification completes
- Status indication - Success ✅ or Failure ❌
- Non-intrusive - Only appears on completion
- Cross-platform - Works on Linux, macOS, and Windows
- Optional feature - Can be disabled during build
Requirements
Watch Mode Required
Desktop notifications require watch mode to be enabled:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken \
--watch \
--notify
Without --watch, the --notify flag has no effect because the tool exits immediately after submission.
Platform Requirements
Linux
Requirements:
- D-Bus service running
- Notification daemon (e.g.,
notify-send, GNOME Shell, KDE Plasma)
Verify setup:
# Test with notify-send
notify-send "Test" "Notification working"
Common notification daemons:
- GNOME Shell (GNOME desktop)
- KDE Plasma (KDE desktop)
- dunst (lightweight daemon)
- mako (Wayland compositor)
macOS
Requirements:
- macOS 10.14 (Mojave) or later
- No additional setup needed
Behavior:
- Uses native macOS notification system
- Appears in Notification Center
- Works out of the box
Windows
Requirements:
- Windows 10 or Windows 11
- No additional setup needed
Behavior:
- Uses Windows notification system
- Appears in Action Center
- Works out of the box
Usage
Basic Usage
Enable notifications with watch mode:
voyager verify --network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyToken \
--watch \
--notify
Workflow:
- Submit verification
- Watch mode monitors progress
- Notification appears when complete
- Continue working on other tasks
In Configuration File
Set as default in .voyager.toml:
[voyager]
watch = true
notify = true
Then run:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken
With Interactive Wizard
The wizard prompts for notification preference:
Monitor verification status until completion? [Y/n]: y
Enable desktop notifications? [y/N]: y
With Batch Verification
Enable for all contracts in a batch:
voyager verify --watch --notify
All contract verifications in the batch will trigger notifications.
Notification Content
Success Notification
Title: ✅ Verification Successful
Body:
Contract: MyToken
Class Hash: 0x044dc2b3...da18
Network: mainnet
Example:
┌─────────────────────────────────────┐
│ ✅ Verification Successful │
│ │
│ Contract: MyToken │
│ Class Hash: 0x044dc2b3...da18 │
│ Network: mainnet │
└─────────────────────────────────────┘
Failure Notification
Title: ❌ Verification Failed
Body:
Contract: MyToken
Class Hash: 0x044dc2b3...da18
Network: mainnet
Status: CompileFailed
Example:
┌─────────────────────────────────────┐
│ ❌ Verification Failed │
│ │
│ Contract: MyToken │
│ Class Hash: 0x044dc2b3...da18 │
│ Network: mainnet │
│ Status: CompileFailed │
└─────────────────────────────────────┘
Notification Timing
Notifications appear only for terminal states:
- ✅ Success - Verification successful
- ❌ Failed - Verification failed (mismatch)
- ❌ CompileFailed - Compilation failed
No notifications for intermediate states (Submitted, Compiling, etc.).
Configuration
Priority Order
Notification setting can be specified in multiple ways:
-
CLI flag (highest priority)
voyager verify --watch --notify -
Configuration file
[voyager] notify = true -
Default (lowest priority)
- Default:
false(disabled)
- Default:
Enabling by Default
Set in .voyager.toml:
[voyager]
watch = true
notify = true
All verification commands will now send notifications by default.
Disabling Temporarily
Override config file for a single command:
# Config has notify = true, but disable for this run
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--watch
# Omit --notify to disable
Use Cases
Long-Running Verifications
For contracts that take several minutes to verify:
voyager verify --network mainnet \
--class-hash 0x044... \
--contract-name MyToken \
--watch \
--notify
Benefit: Work on other tasks, get notified when complete.
Batch Verifications
Monitor multiple verifications:
voyager verify --watch --notify
Behavior: Notification appears when all verifications complete.
Development Workflow
Typical development cycle:
# Deploy contract
starkli declare ...
starkli deploy ...
# Submit verification with notification
voyager verify --network sepolia \
--class-hash <HASH> \
--contract-name MyContract \
--watch \
--notify
# Continue coding while verification runs
# Notification alerts when complete
Background Verification
Run in a separate terminal:
# Terminal 1: Verification with notifications
voyager verify --watch --notify
# Terminal 2: Continue development
vim src/contract.cairo
scarb build
scarb test
Building Without Notifications
Disable Feature During Build
If you don’t want notification support:
cargo build --release --no-default-features
or
cargo install voyager-verifier --no-default-features
Effect:
- Reduces dependencies
- Smaller binary size
--notifyflag will not be available
Check If Notifications Are Enabled
Run voyager --help and check for --notify:
With notifications:
voyager verify --help | grep notify
--notify Send desktop notifications when verification completes
Without notifications:
voyager verify --help | grep notify
# No output - flag not available
Troubleshooting
Notifications Not Appearing
On Linux
Check D-Bus:
# Verify D-Bus is running
ps aux | grep dbus
# Test with notify-send
notify-send "Test" "Hello"
Install notification daemon:
Ubuntu/Debian:
sudo apt-get install libnotify-bin
Arch:
sudo pacman -S libnotify
Fedora:
sudo dnf install libnotify
Check desktop environment:
- Ensure your desktop environment has a notification daemon
- Some minimal window managers require manual setup
On macOS
Check Notification Center settings:
- System Preferences → Notifications
- Ensure notifications are enabled
- Check “Do Not Disturb” is not active
Terminal permissions:
- macOS may require Terminal.app to have notification permissions
- System Preferences → Notifications → Terminal
On Windows
Check Windows settings:
- Settings → System → Notifications & actions
- Ensure notifications are enabled
- Check “Focus assist” settings
“notify” Flag Not Recognized
Cause: Built without notifications feature
Solution:
# Rebuild with notifications
cargo build --release
# Or reinstall with default features
cargo install voyager-verifier
Notification Appears But No Content
Cause: Platform-specific formatting issue
Workaround: Check terminal output for verification result
Report: File an issue with platform details
Watch Mode Required Error
Error: --notify requires --watch to be enabled
Solution: Add --watch flag:
voyager verify --watch --notify
Platform-Specific Notes
Linux
- Works with X11 and Wayland
- Requires D-Bus
- Notification daemon must be running
- Some window managers need manual configuration
Testing:
# Install notification tools
sudo apt-get install libnotify-bin
# Test notification
notify-send "Voyager Test" "Notifications working"
macOS
- Uses NSUserNotificationCenter
- Works on macOS 10.14+
- Appears in Notification Center
- Terminal.app may need notification permissions
Granting permissions:
- System Preferences → Security & Privacy → Privacy
- Select “Notifications” from the left sidebar
- Enable Terminal.app
Windows
- Uses Windows Toast notifications
- Works on Windows 10/11
- Appears in Action Center
- No special configuration needed
Best Practices
1. Use for Long Verifications
Enable notifications when verification takes >1 minute:
voyager verify --watch --notify
2. Disable in CI/CD
Don’t use notifications in automated environments:
# .voyager.toml for CI
[voyager]
watch = false
notify = false
3. Set as Default Locally
For local development, enable by default:
# .voyager.toml
[voyager]
watch = true
notify = true
4. Test Notification Setup
Verify notifications work before relying on them:
# On Linux
notify-send "Test" "Notification check"
# With voyager (quick verification)
voyager verify --network sepolia \
--class-hash <TEST_HASH> \
--contract-name Test \
--watch \
--notify
5. Combine with Background Execution
Run verification in background terminal:
# Terminal 1
voyager verify --watch --notify
# Terminal 2
# Continue working
Security Considerations
No Sensitive Data in Notifications
Notifications display:
- ✅ Contract name (safe - user-provided)
- ✅ Shortened class hash (safe - public blockchain data)
- ✅ Network (safe - public information)
- ✅ Status (safe - success/fail)
No sensitive information is included in notifications.
Notification Permissions
Notifications use standard OS APIs:
- No special permissions required (except on macOS)
- Cannot access other apps’ data
- Cannot perform privileged operations
See Also
- Watch Mode - Watch mode documentation
- verify command - verify command reference
- Configuration file - Configuration options
- Batch Verification - Batch notifications
Custom Endpoints
The voyager-verifier supports using custom API endpoints instead of the predefined networks, allowing you to verify contracts against development environments, staging servers, or self-hosted Voyager instances.
Overview
By default, the verifier connects to predefined networks:
- Mainnet:
https://api.voyager.online/beta - Sepolia:
https://sepolia-api.voyager.online/beta - Dev:
https://dev-api.voyager.online/beta
However, you can specify a custom API endpoint using the --url flag to connect to:
- Development/staging environments
- Self-hosted Voyager instances
- Custom verification services
- Testing servers
Basic Usage
Command-Line Flag
Use the --url flag instead of --network:
voyager verify --url https://custom-api.example.com/beta \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyContract
Configuration File
Set a default custom endpoint in your .voyager.toml:
[voyager]
url = "https://custom-api.example.com/beta"
license = "MIT"
watch = true
Then run verification without specifying the URL:
voyager verify --class-hash 0x044dc2b3... --contract-name MyContract
URL vs Network Flag
Mutual Exclusivity
You cannot use both --network and --url simultaneously:
# ❌ This will fail
voyager verify --network mainnet --url https://custom.com/beta \
--class-hash 0x044dc2b3... --contract-name MyContract
# ✅ Use one or the other
voyager verify --network mainnet --class-hash 0x044dc2b3... --contract-name MyContract
voyager verify --url https://custom.com/beta --class-hash 0x044dc2b3... --contract-name MyContract
Priority System
When both are configured, the priority order is:
- CLI flag (
--urlor--network) - Highest priority - Config file (
urlornetworkin.voyager.toml) - Default value (none - error if neither provided)
Common Use Cases
Development Environment
Test contract verification against a development instance:
voyager verify --url https://dev-api.internal.com/beta \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name DevContract \
--watch
Configuration file approach:
# .voyager.dev.toml
[voyager]
url = "https://dev-api.internal.com/beta"
license = "MIT"
watch = true
verbose = true
# Use custom config file
cp .voyager.dev.toml .voyager.toml
voyager verify --class-hash 0x044dc2b3... --contract-name DevContract
Staging Environment
Verify contracts before production deployment:
voyager verify --url https://staging-api.example.com/beta \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name StagingContract
Self-Hosted Voyager Instance
Use your own Voyager deployment:
voyager verify --url https://voyager.mycompany.io/api/beta \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyContract
Local Testing
Connect to a local Voyager instance for testing:
voyager verify --url http://localhost:3000/api/beta \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name TestContract
URL Format Requirements
Valid URL Structure
The URL must be a fully-qualified, valid URL:
# ✅ Valid URLs
https://api.example.com/beta
https://voyager.staging.internal:8443/api/v1
http://localhost:3000/api/beta
https://192.168.1.100:8080/beta
# ❌ Invalid URLs
example.com/api # Missing protocol
api.example.com # Missing protocol
https:// # Incomplete
custom-endpoint # Not a URL
Protocol Support
Both HTTP and HTTPS are supported:
- HTTPS - Recommended for production and public endpoints
- HTTP - Acceptable for local development and internal networks
# Production/staging - use HTTPS
voyager verify --url https://staging-api.example.com/beta \
--class-hash 0x044dc2b3... --contract-name MyContract
# Local development - HTTP is acceptable
voyager verify --url http://localhost:3000/api/beta \
--class-hash 0x044dc2b3... --contract-name MyContract
Port Specification
Include port numbers when using non-standard ports:
voyager verify --url https://voyager.internal:8443/api/beta \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyContract
Multi-Environment Workflows
Using Multiple Configuration Files
Maintain separate config files for each environment:
.voyager.dev.toml:
[voyager]
url = "https://dev-api.internal.com/beta"
license = "MIT"
watch = true
verbose = true
test-files = true
.voyager.staging.toml:
[voyager]
url = "https://staging-api.example.com/beta"
license = "MIT"
watch = true
lock-file = true
.voyager.prod.toml:
[voyager]
network = "mainnet" # Use predefined network for production
license = "Apache-2.0"
watch = false
lock-file = true
Workflow:
# Development
cp .voyager.dev.toml .voyager.toml
voyager verify --class-hash $DEV_HASH --contract-name MyContract
# Staging
cp .voyager.staging.toml .voyager.toml
voyager verify --class-hash $STAGING_HASH --contract-name MyContract
# Production
cp .voyager.prod.toml .voyager.toml
voyager verify --class-hash $PROD_HASH --contract-name MyContract
Environment-Based Selection
Use shell scripts to select endpoints based on environment:
#!/bin/bash
ENVIRONMENT=${1:-dev}
case $ENVIRONMENT in
dev)
API_URL="https://dev-api.internal.com/beta"
;;
staging)
API_URL="https://staging-api.example.com/beta"
;;
prod)
# Use predefined network for production
voyager verify --network mainnet \
--class-hash "$CLASS_HASH" \
--contract-name "$CONTRACT_NAME"
exit 0
;;
*)
echo "Unknown environment: $ENVIRONMENT"
exit 1
;;
esac
voyager verify --url "$API_URL" \
--class-hash "$CLASS_HASH" \
--contract-name "$CONTRACT_NAME"
Usage:
# Verify on development
./verify.sh dev
# Verify on staging
./verify.sh staging
# Verify on production
./verify.sh prod
Status Checking with Custom Endpoints
When checking verification status, use the same endpoint:
# Submit verification
voyager verify --url https://custom-api.example.com/beta \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyContract
# Output: Job ID: abc-123-def
# Check status (must use same endpoint)
voyager status --url https://custom-api.example.com/beta \
--job abc-123-def
Important: The job ID is specific to the API endpoint. You must use the same endpoint to check status that was used for submission.
Configuration File Discovery
The verifier searches for .voyager.toml in:
- Current working directory
- Parent directories (walking up until found)
This allows you to place environment-specific configs at different levels:
project/
├── .voyager.toml # Default (production)
├── environments/
│ ├── dev/
│ │ └── .voyager.toml # Development config with custom URL
│ └── staging/
│ └── .voyager.toml # Staging config with custom URL
└── contracts/
└── my_contract/
└── Scarb.toml
Run from the appropriate directory:
# Use development endpoint
cd environments/dev
voyager verify --class-hash $HASH --contract-name MyContract
# Use staging endpoint
cd environments/staging
voyager verify --class-hash $HASH --contract-name MyContract
# Use production (default)
cd project
voyager verify --class-hash $HASH --contract-name MyContract
API Compatibility
Endpoint Requirements
Custom endpoints must implement the Voyager API specification to work with the CLI tool:
Required functionality:
- Accept verification submissions through the CLI tool
- Return job ID on successful submission
- Provide status updates via job ID query
- Support the same status values (Submitted, Processing, Compiled, Success, Fail, CompileFailed)
Note: The CLI tool handles all API communication. Users should not make direct API calls.
Version Compatibility
Ensure your custom endpoint supports:
- Cairo versions your contracts use
- Scarb versions in your development environment
- Dojo versions (if applicable)
The verifier sends version information with each request, so the custom endpoint must handle these appropriately.
Troubleshooting
Connection Errors
Problem: Cannot connect to custom endpoint
Error: Connection failed
Solutions:
-
Check URL format:
# Ensure URL is valid curl -I https://custom-api.example.com/beta -
Verify network access:
# Can you reach the endpoint? ping custom-api.example.com -
Check firewall rules:
- Ensure outbound HTTPS (443) or HTTP (80) is allowed
- Verify custom ports are accessible if using non-standard ports
-
Validate SSL certificates:
# Test SSL connection openssl s_client -connect custom-api.example.com:443
Authentication Errors
Problem: Endpoint requires authentication
Error: 401 Unauthorized
Solutions:
Custom authentication is not currently supported via command-line flags. If your endpoint requires authentication:
- Use a reverse proxy - Set up nginx or similar to handle authentication
- VPN access - Connect to VPN before running verifier
- API gateway - Use an API gateway that handles authentication transparently
API Incompatibility
Problem: Endpoint returns unexpected response format
Error: Failed to parse response
Solutions:
- Verify endpoint implements Voyager API - Check that your custom endpoint follows the same API contract as official Voyager
- Check API version - Ensure compatibility between verifier version and endpoint API version
- Enable verbose mode:
voyager verify --url https://custom-api.example.com/beta \ --class-hash 0x044dc2b3... \ --contract-name MyContract \ --verbose
URL Validation Errors
Problem: URL is rejected as invalid
Error: Invalid URL format
Solutions:
# ✅ Include protocol
voyager verify --url https://api.example.com/beta ...
# ❌ Don't omit protocol
voyager verify --url api.example.com/beta ...
# ✅ Use valid characters
voyager verify --url https://api.example.com/beta ...
# ❌ Avoid special characters in URL
voyager verify --url https://api example com/beta ...
Security Considerations
HTTPS in Production
Always use HTTPS for production and staging environments:
# ✅ Production config
[voyager]
url = "https://voyager.production.com/api/beta"
# ⚠️ Only use HTTP for local development
[voyager]
url = "http://localhost:3000/api/beta"
URL Validation
The verifier validates URLs before use:
- Checks for valid URL format
- Ensures protocol is present (http:// or https://)
- Validates URL structure
However, it does not validate:
- SSL certificate authenticity (uses system default)
- Endpoint API compatibility
- Network reachability
Internal Networks
When using custom endpoints on internal networks:
- Use VPN for remote access
- Implement network segmentation
- Use firewall rules to restrict access
- Consider using mutual TLS for enhanced security
Best Practices
1. Environment-Specific Configs
Maintain separate configuration files for each environment:
.voyager.dev.toml
.voyager.staging.toml
.voyager.prod.toml (uses --network mainnet instead of custom URL)
2. Use HTTPS Where Possible
Prefer HTTPS for all non-local endpoints:
# ✅ Recommended
url = "https://staging-api.example.com/beta"
# ⚠️ Only for localhost
url = "http://localhost:3000/api/beta"
3. Document Your Endpoints
Maintain documentation of available endpoints:
# Available Endpoints
- **Development:** https://dev-api.internal.com/beta
- **Staging:** https://staging-api.example.com/beta
- **Production:** Use `--network mainnet` (default)
4. Test Connectivity First
Before running verification, test endpoint connectivity:
# Quick connectivity check
curl -I https://custom-api.example.com/beta
# If successful, proceed with verification
voyager verify --url https://custom-api.example.com/beta \
--class-hash 0x044dc2b3... --contract-name MyContract
5. Use Configuration Files
Prefer configuration files over CLI flags for custom endpoints:
# .voyager.toml
[voyager]
url = "https://custom-api.example.com/beta"
license = "MIT"
watch = true
# Cleaner command
voyager verify --class-hash 0x044dc2b3... --contract-name MyContract
See Also
- Configuration File Guide - Complete configuration system
- CLI Options Reference - All command-line flags
- Command-Line Verification - Direct CLI verification
- CI/CD Integration - Using custom endpoints in CI/CD pipelines
Lock Files
The --lock-file flag allows you to include your project’s Scarb.lock file in the verification submission, ensuring reproducible builds by locking dependency versions to exactly match your deployment.
Overview
What is Scarb.lock?
Scarb.lock is a lock file generated by Scarb (the Cairo/Starknet package manager) that records the exact versions of all dependencies used in your project. Similar to Cargo.lock in Rust or package-lock.json in Node.js, it ensures that everyone building your project uses identical dependency versions.
Example Scarb.lock:
# This file is automatically generated by Scarb.
# It is not intended for manual editing.
version = 1
[[package]]
name = "my_contract"
version = "0.1.0"
dependencies = [
"starknet",
]
[[package]]
name = "starknet"
version = "2.11.4"
source = "registry+https://scarb-registry.org/"
checksum = "abc123..."
Why Include Lock Files?
By default, the verifier excludes Scarb.lock from verification submissions. However, including it can be beneficial when:
- Reproducible Builds - Ensure the remote compiler uses the exact same dependency versions you used locally
- Version Pinning - Lock specific versions that are known to work with your contract
- Debugging - Eliminate dependency version differences as a source of verification failures
- Production Deployments - Guarantee that verified code matches deployed bytecode exactly
Usage
Command-Line Flag
Include Scarb.lock using the --lock-file flag:
voyager verify --network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyContract \
--lock-file
Configuration File
Set it as default in .voyager.toml:
[voyager]
network = "mainnet"
license = "MIT"
lock-file = true # Always include Scarb.lock
Then verify without the flag:
voyager verify --class-hash 0x044dc2b3... --contract-name MyContract
Priority System
The --lock-file flag follows the standard priority order:
- CLI flag (
--lock-file) - Highest priority - Config file (
lock-file = truein.voyager.toml) - Default value (
false- lock file not included)
When to Use Lock Files
Recommended Use Cases
1. Production Deployments
Always include lock files for production contracts:
voyager verify --network mainnet \
--class-hash $PROD_CLASS_HASH \
--contract-name ProductionContract \
--lock-file \
--watch
Why: Ensures verification uses the exact same dependencies as your deployment, preventing subtle differences that could cause verification to fail.
2. Reproducible Verification
When you need byte-for-byte reproducibility:
# .voyager.prod.toml
[voyager]
network = "mainnet"
license = "Apache-2.0"
lock-file = true # Guarantee reproducibility
watch = false
Why: Lock files eliminate any ambiguity about which versions of dependencies should be used.
3. Debugging Verification Failures
If verification fails with dependency-related errors:
# First attempt (failed without lock file)
voyager verify --network mainnet --class-hash $HASH --contract-name MyContract
# Error: Compilation failed
# Retry with lock file
voyager verify --network mainnet --class-hash $HASH --contract-name MyContract --lock-file
Why: Including the lock file can resolve version mismatch issues between local and remote compilation.
4. Specific Dependency Versions
When using specific versions to work around bugs:
# Scarb.toml
[dependencies]
starknet = "2.11.2" # Specific version due to known issue in 2.11.3
# Ensure remote uses same version
voyager verify --network mainnet \
--class-hash $HASH \
--contract-name MyContract \
--lock-file
Why: Forces the remote compiler to use the same workaround versions.
When Lock Files Are Optional
1. Development/Testing
During active development, lock files may not be necessary:
# Quick verification during development
voyager verify --network sepolia \
--class-hash $DEV_HASH \
--contract-name DevContract
# No --lock-file flag
Why: Development often uses latest compatible versions, and exact reproducibility is less critical.
2. Simple Contracts
For contracts with minimal dependencies:
# Scarb.toml - simple contract
[dependencies]
starknet = ">=2.11.0"
# Verification without lock file usually works fine
voyager verify --network mainnet \
--class-hash $HASH \
--contract-name SimpleContract
Why: Fewer dependencies mean less chance of version conflicts.
3. Latest Dependency Versions
When you want to test against the latest versions:
# Explicitly exclude lock file (default behavior)
voyager verify --network sepolia \
--class-hash $HASH \
--contract-name TestContract
Why: Lets the remote compiler resolve to the latest compatible versions.
How It Works
Without Lock File (Default)
When --lock-file is not specified:
- Verifier reads
Scarb.tomlto identify dependencies - Sends
Scarb.tomlto remote API - Remote compiler runs
scarb build, which:- Resolves dependencies to latest compatible versions
- Downloads dependencies from registry
- Compiles your contract
Result: May use different dependency versions than your local build.
With Lock File
When --lock-file is specified:
- Verifier reads both
Scarb.tomlandScarb.lock - Sends both files to remote API
- Remote compiler runs
scarb build, which:- Uses exact versions from
Scarb.lock - Downloads those specific versions
- Compiles your contract
- Uses exact versions from
Result: Uses identical dependency versions to your local build.
File Location
The verifier looks for Scarb.lock in the same directory as Scarb.toml:
my_project/
├── Scarb.toml # Always included
├── Scarb.lock # Included only with --lock-file
└── src/
└── lib.cairo
Workspace Projects
For workspace projects, the lock file is at the workspace root:
my_workspace/
├── Scarb.toml # Workspace manifest
├── Scarb.lock # Workspace lock file (included with --lock-file)
├── package1/
│ ├── Scarb.toml
│ └── src/
└── package2/
├── Scarb.toml
└── src/
Lock File Validation
Missing Lock File
If --lock-file is specified but Scarb.lock doesn’t exist:
voyager verify --network mainnet \
--class-hash $HASH \
--contract-name MyContract \
--lock-file
Warning: --lock-file specified but Scarb.lock not found
Continuing without lock file...
The verification proceeds without the lock file rather than failing.
Generating Lock Files
If you don’t have a Scarb.lock file, generate one:
# Generate lock file
scarb build
# Verify the lock file was created
ls Scarb.lock
# Now verify with lock file
voyager verify --network mainnet \
--class-hash $HASH \
--contract-name MyContract \
--lock-file
Best Practices
1. Commit Lock Files to Version Control
Always commit Scarb.lock to your repository:
git add Scarb.lock
git commit -m "Add Scarb.lock for reproducible builds"
Why: Ensures all team members and CI/CD systems use identical dependencies.
2. Update Lock Files Intentionally
Don’t update Scarb.lock accidentally:
# Update dependencies intentionally
scarb update
# Review changes to lock file
git diff Scarb.lock
# Commit if changes are acceptable
git add Scarb.lock
git commit -m "Update dependencies"
Why: Prevents unexpected version changes that could break your build.
3. Use Lock Files in Production
Always use --lock-file for production deployments:
# .voyager.prod.toml
[voyager]
network = "mainnet"
lock-file = true # Required for production
license = "Apache-2.0"
Why: Guarantees verification matches deployment.
4. Keep Lock Files Fresh
Periodically update dependencies to get security fixes:
# Update to latest compatible versions
scarb update
# Test locally
scarb test
# Deploy and verify with updated lock file
voyager verify --network mainnet \
--class-hash $NEW_HASH \
--contract-name MyContract \
--lock-file
Why: Keeps your dependencies secure while maintaining reproducibility.
5. Document Lock File Usage
Document in your README when lock files should be used:
## Verification
### Production
Always verify production deployments with the lock file:
```bash
voyager verify --network mainnet \
--class-hash $CLASS_HASH \
--contract-name MyContract \
--lock-file
Development
Lock file is optional during development.
## Configuration Examples
### Production Deployment
```toml
# .voyager.prod.toml
[voyager]
network = "mainnet"
license = "Apache-2.0"
lock-file = true # Reproducible builds
watch = false
verbose = false
Staging/Testing
# .voyager.staging.toml
[voyager]
network = "sepolia"
license = "MIT"
lock-file = true # Test with exact production dependencies
watch = true
verbose = true
Development
# .voyager.dev.toml
[voyager]
network = "sepolia"
license = "MIT"
lock-file = false # Optional during development
watch = true
verbose = true
test-files = true
Troubleshooting
Verification Fails Without Lock File
Problem: Verification succeeds locally but fails remotely without --lock-file
Error: Compilation failed
Solution: Include the lock file to use exact dependency versions:
voyager verify --network mainnet \
--class-hash $HASH \
--contract-name MyContract \
--lock-file \
--verbose
Lock File Out of Date
Problem: Lock file doesn’t match Scarb.toml dependencies
Warning: Scarb.lock is out of date
Solution: Regenerate the lock file:
# Remove old lock file
rm Scarb.lock
# Regenerate from Scarb.toml
scarb build
# Verify
voyager verify --network mainnet \
--class-hash $HASH \
--contract-name MyContract \
--lock-file
Dependency Version Conflicts
Problem: Lock file specifies versions incompatible with remote compiler
Error: Failed to resolve dependency: starknet = "2.8.0" (unsupported version)
Solution: Update dependencies to supported versions:
# Update dependencies
scarb update
# Verify compatible versions in Scarb.lock
cat Scarb.lock | grep -A 3 starknet
# Retry verification
voyager verify --network mainnet \
--class-hash $HASH \
--contract-name MyContract \
--lock-file
Comparison with Test Files
| Feature | Lock Files (--lock-file) | Test Files (--test-files) |
|---|---|---|
| Purpose | Pin dependency versions | Include test source files |
| Default | Excluded | Excluded |
| File | Scarb.lock | **/test*.cairo, **/tests/*.cairo |
| Use Case | Reproducible builds | Contracts depending on test utilities |
| Production | ✅ Recommended | ⚠️ Usually not needed |
| Development | ⚠️ Optional | ✅ Often needed |
See Also
- Test Files - Including test files in verification
- Configuration File Guide - Complete configuration system
- CLI Options Reference - All command-line flags
- Dry-Run Mode - Preview what files will be included
- Configuration Examples - Production configuration patterns
Test Files
The --test-files flag allows you to include test files from your project’s src/ directory in the verification submission, which is necessary when your contract code depends on test utilities or shared test code.
Overview
What Are Test Files?
Test files are Cairo source files that contain:
- Test functions (marked with
#[test]) - Test utilities and helper functions
- Mock implementations
- Shared test fixtures and setup code
Example test file (src/tests.cairo):
#[cfg(test)]
mod tests {
use super::{MyContract, IMyContractDispatcher};
#[test]
fn test_transfer() {
// Test implementation
}
// Test utility function
fn setup_contract() -> IMyContractDispatcher {
// Setup code
}
}
Why Are They Excluded by Default?
By default, the verifier excludes test files from verification submissions because:
- Smaller payloads - Test files can be large and aren’t needed for most contracts
- Faster verification - Less code to compile means faster verification
- Production focus - Only production code needs to be verified
- Privacy - Test files may contain internal implementation details
However, some contracts require test files to be included when they depend on test utilities.
Usage
Command-Line Flag
Include test files using the --test-files flag:
voyager verify --network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyContract \
--test-files
Configuration File
Set it as default in .voyager.toml:
[voyager]
network = "mainnet"
license = "MIT"
test-files = true # Always include test files
Then verify without the flag:
voyager verify --class-hash 0x044dc2b3... --contract-name MyContract
Priority System
The --test-files flag follows the standard priority order:
- CLI flag (
--test-files) - Highest priority - Config file (
test-files = truein.voyager.toml) - Default value (
false- test files excluded)
When to Use Test Files
Required Use Cases
1. Contract Depends on Test Utilities
When your main contract imports test utilities:
// lib.cairo
mod contract;
mod test_utils; // Test utilities used by contract
// contract.cairo
use crate::test_utils::setup_environment;
#[starknet::contract]
mod MyContract {
// Uses test utilities
}
Error without --test-files:
error[E0005]: Module file not found. Expected path: /tmp/targets/.../src/test_utils.cairo
Solution:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files
2. Tests Module Declared in lib.cairo
When lib.cairo declares a test module:
// lib.cairo
mod contract;
mod tests; // Module declaration
// tests.cairo
#[cfg(test)]
mod test_cases {
// Test implementations
}
Error without --test-files:
error[E0005]: Module file not found. Expected path: /tmp/targets/.../src/tests.cairo
Solution:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files
3. Shared Test Code Used Across Modules
When multiple contract modules share test utilities:
src/
├── lib.cairo
├── token.cairo
├── vault.cairo
└── test_helpers.cairo # Shared by token and vault
// lib.cairo
mod token;
mod vault;
mod test_helpers; // Shared test code
Solution:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files
Optional Use Cases
1. Development/Testing Verification
During development, you might want to verify with all files included:
voyager verify --network sepolia \
--class-hash $DEV_HASH \
--contract-name DevContract \
--test-files \
--verbose
Why: Ensures the entire codebase compiles remotely, not just production code.
2. Comprehensive Code Review
When you want reviewers to see the complete codebase:
# .voyager.dev.toml
[voyager]
network = "sepolia"
test-files = true
verbose = true
When Test Files Are NOT Needed
1. Production Deployments (Usually)
Most production contracts don’t need test files:
# Production verification - no test files
voyager verify --network mainnet \
--class-hash $PROD_HASH \
--contract-name ProductionContract
Why: Production code should not depend on test utilities.
2. Self-Contained Contracts
When your contract doesn’t import test modules:
// lib.cairo
mod contract; // No test module declarations
Why: No test files are referenced, so they’re not needed.
3. Tests in Dedicated Directory
When tests are in a tests/ directory (outside src/):
project/
├── src/
│ └── lib.cairo # No test references
└── tests/
└── integration.cairo # Separate test directory
Why: The verifier only collects from src/ directory, so tests/ is automatically excluded.
File Detection Patterns
What Gets Included
When --test-files is enabled, the verifier includes files matching these patterns within the src/ directory:
-
Files with “test” in the name:
test.cairotests.cairotest_utils.cairotest_helpers.cairomock_test.cairo
-
Files in “test” or “tests” directories within src/:
src/test/helpers.cairosrc/tests/fixtures.cairo
-
Files with “tests” in the path:
src/utils/tests.cairosrc/tests/unit.cairo
What Gets Excluded (Always)
Even with --test-files enabled, these are always excluded:
-
Directories outside src/:
tests/(root-level tests directory)test/(root-level test directory)
-
Build artifacts:
target/Scarb.lock(unless--lock-fileis used)
-
Hidden files:
.git/.gitignore
How It Works
Without Test Files (Default)
When --test-files is not specified:
- Verifier scans
src/directory - Excludes files matching test patterns:
- Files with “test” in name
- Files in “test” or “tests” subdirectories
- Collects remaining
.cairofiles - Sends to remote API
Example files collected:
src/lib.cairo ✅ Included
src/contract.cairo ✅ Included
src/tests.cairo ❌ Excluded (has "tests" in name)
src/test_utils.cairo ❌ Excluded (has "test" in name)
With Test Files
When --test-files is specified:
- Verifier scans
src/directory - Includes all
.cairofiles (including test patterns) - Collects all files
- Sends to remote API
Example files collected:
src/lib.cairo ✅ Included
src/contract.cairo ✅ Included
src/tests.cairo ✅ Included (test files enabled)
src/test_utils.cairo ✅ Included (test files enabled)
Common Scenarios
Scenario 1: Missing Test Module Error
Problem:
error[E0005]: Module file not found. Expected path: /tmp/targets/.../src/tests.cairo
Diagnosis:
Your lib.cairo declares a test module:
mod tests;
Solution: Either include test files OR remove the module declaration:
Option A - Include test files:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files
Option B - Remove module declaration:
// lib.cairo
// mod tests; // Comment out or remove
mod contract;
Scenario 2: Test Utilities Used in Contract
Problem: Your contract imports from a test utility file:
// contract.cairo
use crate::test_helpers::mock_environment;
Solution: Include test files or refactor to not depend on test utilities:
Option A - Include test files:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files
Option B - Refactor (recommended for production):
// Move mock_environment to production code or use conditional compilation
#[cfg(test)]
use crate::test_helpers::mock_environment;
Scenario 3: Development vs Production
During Development:
# .voyager.dev.toml
[voyager]
network = "sepolia"
test-files = true # Include everything during dev
verbose = true
For Production:
# .voyager.prod.toml
[voyager]
network = "mainnet"
test-files = false # Exclude test files in production
lock-file = true
Dry-Run Preview
Use --dry-run to see which files will be included:
Without Test Files
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--dry-run
Output:
Files to be included:
src/lib.cairo
src/contract.cairo
src/utils.cairo
Files excluded (test files):
src/tests.cairo
src/test_utils.cairo
With Test Files
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files \
--dry-run
Output:
Files to be included:
src/lib.cairo
src/contract.cairo
src/utils.cairo
src/tests.cairo
src/test_utils.cairo
Best Practices
1. Avoid Dependencies on Test Code
Recommended: Keep production code independent of test utilities:
// ✅ Good - no test dependencies
mod contract;
mod utils;
// ❌ Bad - depends on test code
mod contract;
mod test_helpers; // Used by contract
2. Use Conditional Compilation
For code that should only exist in tests:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_function() {
// Test code
}
}
Why: The #[cfg(test)] attribute ensures test code is only compiled during testing.
3. Separate Test Directories
Put tests outside src/ directory:
project/
├── src/
│ ├── lib.cairo
│ └── contract.cairo
└── tests/
└── integration.cairo # Automatically excluded
Why: Tests in tests/ directory are never collected, even with --test-files.
4. Use Test Files Only When Necessary
Development:
[voyager]
network = "sepolia"
test-files = true # OK for development
Production:
[voyager]
network = "mainnet"
test-files = false # Recommended for production
5. Document Test File Requirements
In your project README:
## Verification
If verification fails with "Module file not found" for test files:
```bash
voyager verify --network mainnet \
--class-hash $HASH \
--contract-name MyContract \
--test-files
Or remove test module declarations from lib.cairo.
## Configuration Examples
### Development Environment
```toml
# .voyager.dev.toml
[voyager]
network = "sepolia"
license = "MIT"
test-files = true # Include all test files
verbose = true
watch = true
Production Environment
# .voyager.prod.toml
[voyager]
network = "mainnet"
license = "Apache-2.0"
test-files = false # Exclude test files
lock-file = true
watch = false
Contract with Test Dependencies
# .voyager.toml
[voyager]
network = "mainnet"
license = "MIT"
test-files = true # Required for this contract
lock-file = true
Troubleshooting
Module Not Found Errors
Problem: Verification fails with module not found errors
error[E0005]: Module file not found. Expected path: /tmp/targets/.../src/tests.cairo
Solutions:
-
Include test files:
voyager verify --network mainnet \ --class-hash 0x044dc2b3... \ --contract-name MyContract \ --test-files -
Remove module declaration:
// lib.cairo - remove or comment out: // mod tests; -
Check file exists locally:
ls src/tests.cairo # Ensure the file exists
Test Files Not Helping
Problem: Including --test-files doesn’t fix compilation errors
Diagnosis: The error might not be related to test files:
# Run with verbose to see full error
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files \
--verbose
Common causes:
- Syntax errors in code
- Missing dependencies
- Incompatible Cairo version
- Wrong compiler settings
Too Many Files Included
Problem: Verification payload is very large with test files
Solution: Review what’s being included with dry-run:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files \
--dry-run | grep "src/"
Consider refactoring to reduce test file dependencies.
Comparison with Lock Files
| Feature | Test Files (--test-files) | Lock Files (--lock-file) |
|---|---|---|
| Purpose | Include test source files | Pin dependency versions |
| Default | Excluded | Excluded |
| Files | **/test*.cairo in src/ | Scarb.lock |
| Use Case | Contracts depending on test utilities | Reproducible builds |
| Production | ⚠️ Usually not needed | ✅ Recommended |
| Development | ✅ Often needed | ⚠️ Optional |
| File Size Impact | Can be large | Usually small |
See Also
- Lock Files - Including Scarb.lock for reproducible builds
- Dry-Run Mode - Preview what files will be included
- Configuration File Guide - Complete configuration system
- CLI Options Reference - All command-line flags
- Troubleshooting - Common error solutions
Output Formats
The voyager-verifier supports multiple output formats to suit different use cases, from human-readable terminal output to machine-parseable JSON for CI/CD pipelines. This guide covers all available formats and when to use each one.
Overview
Three output formats are available:
- Text - Human-readable format with enhanced formatting, progress bars, and colors (default)
- JSON - Machine-readable format for programmatic parsing and CI/CD integration
- Table - Structured table format for batch operations and quick status overview
Format Selection
Command-Line Flag
Use the --format flag to specify the output format:
voyager status --network mainnet --job <JOB_ID> --format json
Available format values:
text(default)jsontable
Configuration File
Set a default format in your .voyager.toml:
[voyager]
network = "mainnet"
format = "json" # Options: "text", "json", "table"
Priority System
Format selection follows this priority order:
- CLI flag (
--format) - Highest priority - Config file (
formatin.voyager.toml) - Default value (
text) - Lowest priority
Text Format (Default)
Description
The text format provides human-readable output with:
- Color-coded status indicators (✅ success, ❌ failure, ⏳ in progress)
- Progress bars with percentage for in-progress jobs
- Time estimation based on historical verification data
- Stage-aware status messages
- Enhanced error reporting
Use Cases
- Interactive terminal use - Ideal for developers running verifications manually
- Debugging - Easy to read status and error messages
- Learning - Clear presentation of verification workflow stages
- Watch mode - Live updates with progress indicators
Example Output
In-Progress Verification
voyager status --network mainnet --job abc-123-def --format text
⏳ Verification Status
Job ID: abc-123-def
Status: Processing
Progress: ████████░░░░░░░░░░░░ (40%)
Class Hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Contract: MyToken
Started: 2025-01-15 10:30:45 UTC
Last Updated: 2025-01-15 10:31:12 UTC
Elapsed: 27s
Estimated Remaining: ~13s
Cairo Version: 2.11.4
License: MIT
⏳ Verification is in progress...
Use the same command to check progress later.
Successful Verification
✅ Verification Status
Job ID: abc-123-def
Status: Success
Class Hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Contract: MyToken
Contract File: token.cairo
Started: 2025-01-15 10:30:45 UTC
Last Updated: 2025-01-15 10:31:23 UTC
Elapsed: 38s
Cairo Version: 2.11.4
License: MIT
✅ Verification successful!
The contract is now verified and visible on Voyager at:
https://voyager.online/class/0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Failed Verification
❌ Verification Status
Job ID: abc-123-def
Status: CompileFailed
Class Hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Contract: MyToken
Started: 2025-01-15 10:30:45 UTC
Last Updated: 2025-01-15 10:31:02 UTC
Elapsed: 17s
Cairo Version: 2.11.4
License: MIT
❌ Verification failed!
Reason: Compilation failed
Message: error[E0005]: Module file not found. Expected path: /tmp/targets/.../src/tests.cairo
Suggestion: Use --test-files flag to include test files, or remove the module declaration from lib.cairo
Progress Indicators
Text format includes dynamic progress bars showing verification stages:
| Status | Progress | Description |
|---|---|---|
| Submitted | 10% | Job created, waiting in queue |
| Processing | 40% | Picked up by worker, compiling source |
| Compiled | 85% | Compilation done, verifying bytecode |
| Success/Fail | 100% | Verification complete |
Time Estimation
The text format provides intelligent time estimates:
- History-based estimates - Uses average time from your last 10 successful verifications (requires minimum 3 samples)
- Fallback estimates - Conservative hardcoded estimates if no history available:
- Queue wait: 2-5 seconds
- Compilation: 15-30 seconds
- Verification: 2-5 seconds
- Total: ~40 seconds
JSON Format
Description
The JSON format provides structured, machine-readable output suitable for:
- Automated processing and parsing
- CI/CD pipeline integration
- Monitoring and alerting systems
- Programmatic status checking
- Log aggregation
Use Cases
- CI/CD pipelines - Parse verification results in GitHub Actions, GitLab CI, etc.
- Automation scripts - Integrate verification into deployment workflows
- Monitoring - Feed verification data into monitoring dashboards
- API integration - Use verification status in other tools
- Data analysis - Track verification metrics over time
Example Output
voyager status --network mainnet --job abc-123-def --format json
{
"job_id": "abc-123-def",
"status": "Success",
"status_code": 4,
"is_completed": true,
"has_failed": false,
"progress_percentage": 100,
"class_hash": "0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18",
"contract_name": "MyToken",
"contract_file": "token.cairo",
"status_description": null,
"message": null,
"error_category": null,
"created_at": "2025-01-15 10:30:45 UTC",
"updated_at": "2025-01-15 10:31:23 UTC",
"elapsed_seconds": 38,
"estimated_remaining_seconds": null,
"cairo_version": "2.11.4",
"dojo_version": null,
"license": "MIT",
"address": null,
"build_tool": "scarb"
}
JSON Schema
| Field | Type | Description |
|---|---|---|
job_id | string | Unique verification job identifier (UUID) |
status | string | Current status (Submitted, Processing, Compiled, Success, Fail, CompileFailed) |
status_code | integer | Numeric status code (0-4) |
is_completed | boolean | Whether verification has finished (success or failure) |
has_failed | boolean | Whether verification failed |
progress_percentage | integer | Progress from 0-100 |
class_hash | string | null | Contract class hash |
contract_name | string | null | Contract name |
contract_file | string | null | Main contract source file |
status_description | string | null | Detailed status message |
message | string | null | Error or informational message |
error_category | string | null | Error categorization |
created_at | string | null | Job creation timestamp (UTC) |
updated_at | string | null | Last update timestamp (UTC) |
elapsed_seconds | integer | null | Time elapsed since job creation |
estimated_remaining_seconds | integer | null | Estimated time until completion (for in-progress jobs) |
cairo_version | string | null | Cairo compiler version used |
dojo_version | string | null | Dojo version (for Dojo projects) |
license | string | null | SPDX license identifier |
address | string | null | Contract address (if available) |
build_tool | string | null | Build tool used (scarb, dojo) |
Status Code Reference
0 = Unknown
1 = Submitted
2 = Processing
3 = Compiled
4 = Success
5 = Fail
6 = CompileFailed
Parsing JSON Output
Using jq (Command Line)
Extract specific fields:
# Get job status
voyager status --network mainnet --job <JOB_ID> --format json | jq -r '.status'
# Check if completed
voyager status --network mainnet --job <JOB_ID> --format json | jq -r '.is_completed'
# Get elapsed time
voyager status --network mainnet --job <JOB_ID> --format json | jq -r '.elapsed_seconds'
# Get class hash if successful
voyager status --network mainnet --job <JOB_ID> --format json | jq -r 'select(.status == "Success") | .class_hash'
Python Example
import json
import subprocess
# Run verification status command
result = subprocess.run(
['voyager', 'status', '--network', 'mainnet', '--job', job_id, '--format', 'json'],
capture_output=True,
text=True
)
# Parse JSON output
status = json.loads(result.stdout)
if status['is_completed']:
if status['has_failed']:
print(f"❌ Verification failed: {status.get('message', 'Unknown error')}")
exit(1)
else:
print(f"✅ Verification successful!")
print(f" Class hash: {status['class_hash']}")
print(f" Voyager URL: https://voyager.online/class/{status['class_hash']}")
else:
progress = status['progress_percentage']
remaining = status.get('estimated_remaining_seconds', 0)
print(f"⏳ Verification in progress: {progress}% (est. {remaining}s remaining)")
JavaScript/Node.js Example
const { execSync } = require('child_process');
// Run verification status command
const output = execSync(
`voyager status --network mainnet --job ${jobId} --format json`,
{ encoding: 'utf-8' }
);
// Parse JSON output
const status = JSON.parse(output);
if (status.is_completed) {
if (status.has_failed) {
console.error(`❌ Verification failed: ${status.message || 'Unknown error'}`);
process.exit(1);
} else {
console.log(`✅ Verification successful!`);
console.log(` Contract: ${status.contract_name}`);
console.log(` Elapsed: ${status.elapsed_seconds}s`);
}
} else {
console.log(`⏳ ${status.status}: ${status.progress_percentage}%`);
}
Bash Script Example
#!/bin/bash
JOB_ID=$1
NETWORK=${2:-mainnet}
# Get verification status as JSON
STATUS=$(voyager status --network "$NETWORK" --job "$JOB_ID" --format json)
# Parse JSON using jq
IS_COMPLETED=$(echo "$STATUS" | jq -r '.is_completed')
HAS_FAILED=$(echo "$STATUS" | jq -r '.has_failed')
STATUS_TEXT=$(echo "$STATUS" | jq -r '.status')
if [ "$IS_COMPLETED" = "true" ]; then
if [ "$HAS_FAILED" = "true" ]; then
echo "❌ Verification failed with status: $STATUS_TEXT"
exit 1
else
CLASS_HASH=$(echo "$STATUS" | jq -r '.class_hash')
echo "✅ Verification successful!"
echo "Class hash: $CLASS_HASH"
echo "View on Voyager: https://voyager.online/class/$CLASS_HASH"
exit 0
fi
else
PROGRESS=$(echo "$STATUS" | jq -r '.progress_percentage')
echo "⏳ Verification in progress: $STATUS_TEXT ($PROGRESS%)"
exit 2 # Still in progress
fi
Table Format
Description
The table format provides structured output in a bordered ASCII table layout. It’s designed for:
- Quick visual scanning of status information
- Batch operation results
- Terminal-based dashboards
- Reports and logs
Use Cases
- Batch verification - Compact summary of multiple contract verifications
- Status overview - Quick glance at verification details
- Terminal UIs - Integration with terminal-based interfaces
- Log files - Structured output for log analysis
Example Output
voyager status --network mainnet --job abc-123-def --format table
┌─────────────────────────────────────────────────────────────────────────────┐
│ Verification Job Status │
├─────────────────────────┬───────────────────────────────────────────────────┤
│ Job ID │ abc-123-def │
│ Status │ Success │
│ Class Hash │ 0x044dc2b3...f1da18 │
│ Contract │ MyToken │
│ Started │ 2025-01-15 10:30:45 UTC │
│ Elapsed │ 38s │
│ Cairo Version │ 2.11.4 │
└─────────────────────────┴───────────────────────────────────────────────────┘
Features
- Fixed-width columns - Consistent formatting across different outputs
- Truncated class hashes - Long hashes are shortened for readability
- Progress percentage - Shown for in-progress verifications
- Clean borders - Unicode box-drawing characters for clear structure
Format Comparison
| Feature | Text | JSON | Table |
|---|---|---|---|
| Human-readable | ✅ Excellent | ❌ No | ✅ Good |
| Machine-parseable | ❌ No | ✅ Perfect | ⚠️ Limited |
| Progress bars | ✅ Yes | ❌ No | ⚠️ Percentage only |
| Color output | ✅ Yes | ❌ No | ❌ No |
| Time estimates | ✅ Yes | ✅ Yes (numeric) | ✅ Yes |
| Verbose errors | ✅ Yes | ✅ Yes | ⚠️ Limited |
| CI/CD friendly | ⚠️ No | ✅ Perfect | ⚠️ Moderate |
| Batch operations | ✅ Summary | ✅ Array of jobs | ✅ Good |
| File size | Medium | Larger | Compact |
Batch Verification Output
When verifying multiple contracts in batch mode, the output format displays a summary followed by individual contract results.
Batch Text Output
voyager verify # Reads contracts from .voyager.toml
During submission:
[1/3] Verifying: MyToken
✓ Submitted - Job ID: abc-123-def
[2/3] Verifying: MyNFT
⏳ Waiting 5 seconds before next submission...
✓ Submitted - Job ID: ghi-456-jkl
[3/3] Verifying: MyMarketplace
✓ Submitted - Job ID: mno-789-pqr
════════════════════════════════════════════════════════
Batch Verification Summary
════════════════════════════════════════════════════════
Total contracts: 3
Submitted: 3
Succeeded: 0
Failed: 0
Pending: 3
════════════════════════════════════════════════════════
Contract Details:
⏳ MyToken (0x044dc2b3...f1da18)
Status: Submitted
Job ID: abc-123-def
⏳ MyNFT (0x055dc2b3...f1da19)
Status: Submitted
Job ID: ghi-456-jkl
⏳ MyMarketplace (0x066dc2b3...f1da20)
Status: Submitted
Job ID: mno-789-pqr
With watch mode (final results):
voyager verify --watch
⏳ Watching 3 verification job(s)...
✓ 3 Succeeded | ⏳ 0 Pending | ✗ 0 Failed
=== Final Summary ===
════════════════════════════════════════════════════════
Batch Verification Summary
════════════════════════════════════════════════════════
Total contracts: 3
Submitted: 3
Succeeded: 3
Failed: 0
Pending: 0
════════════════════════════════════════════════════════
Contract Details:
✓ MyToken (0x044dc2b3...f1da18)
Status: Success
Job ID: abc-123-def
✓ MyNFT (0x055dc2b3...f1da19)
Status: Success
Job ID: ghi-456-jkl
✓ MyMarketplace (0x066dc2b3...f1da20)
Status: Success
Job ID: mno-789-pqr
Understanding Batch Symbols
| Symbol | Meaning |
|---|---|
| ✓ | Successfully verified |
| ✗ | Verification failed |
| ⏳ | In progress or pending |
CI/CD Integration Examples
GitHub Actions
name: Verify Contracts
on:
push:
branches: [main]
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install voyager-verifier
run: cargo install voyager-verifier
- name: Verify contract
id: verify
run: |
# Submit verification
OUTPUT=$(voyager verify \
--network mainnet \
--class-hash ${{ secrets.CLASS_HASH }} \
--contract-name MyContract \
--format json)
# Extract job ID
JOB_ID=$(echo "$OUTPUT" | jq -r '.job_id')
echo "job_id=$JOB_ID" >> $GITHUB_OUTPUT
- name: Wait for verification
run: |
# Poll until complete (with timeout)
TIMEOUT=300 # 5 minutes
ELAPSED=0
while [ $ELAPSED -lt $TIMEOUT ]; do
STATUS=$(voyager status \
--network mainnet \
--job ${{ steps.verify.outputs.job_id }} \
--format json)
IS_COMPLETED=$(echo "$STATUS" | jq -r '.is_completed')
if [ "$IS_COMPLETED" = "true" ]; then
HAS_FAILED=$(echo "$STATUS" | jq -r '.has_failed')
if [ "$HAS_FAILED" = "true" ]; then
echo "❌ Verification failed"
echo "$STATUS" | jq '.'
exit 1
else
echo "✅ Verification successful"
echo "$STATUS" | jq '.'
exit 0
fi
fi
echo "⏳ Still verifying... ($ELAPSED/$TIMEOUT seconds)"
sleep 10
ELAPSED=$((ELAPSED + 10))
done
echo "❌ Verification timed out"
exit 1
GitLab CI
verify-contract:
stage: deploy
script:
- cargo install voyager-verifier
# Submit with watch mode (blocks until complete)
- |
voyager verify \
--network mainnet \
--class-hash $CLASS_HASH \
--contract-name MyContract \
--watch \
--format json > result.json
# Check result
- |
if [ $(jq -r '.has_failed' result.json) = "true" ]; then
echo "Verification failed"
cat result.json
exit 1
fi
- echo "Verification successful"
- cat result.json
only:
- main
Jenkins Pipeline
pipeline {
agent any
environment {
CLASS_HASH = credentials('starknet-class-hash')
CONTRACT_NAME = 'MyContract'
}
stages {
stage('Verify Contract') {
steps {
script {
// Submit verification
def result = sh(
script: """
voyager verify \
--network mainnet \
--class-hash ${CLASS_HASH} \
--contract-name ${CONTRACT_NAME} \
--watch \
--format json
""",
returnStdout: true
).trim()
// Parse JSON result
def json = readJSON text: result
if (json.has_failed) {
error("Verification failed: ${json.message}")
}
echo "✅ Verification successful!"
echo "Job ID: ${json.job_id}"
echo "Class Hash: ${json.class_hash}"
}
}
}
}
}
Makefile Integration
.PHONY: verify verify-watch verify-check
# Submit verification
verify:
@echo "📤 Submitting verification..."
@voyager verify \
--network mainnet \
--class-hash $(CLASS_HASH) \
--contract-name $(CONTRACT_NAME) \
--format json | tee verify-result.json
@echo "Job ID: $$(jq -r '.job_id' verify-result.json)"
# Submit and wait for completion
verify-watch:
@echo "📤 Submitting verification with watch mode..."
@voyager verify \
--network mainnet \
--class-hash $(CLASS_HASH) \
--contract-name $(CONTRACT_NAME) \
--watch \
--format json | tee verify-result.json
@if [ $$(jq -r '.has_failed' verify-result.json) = "true" ]; then \
echo "❌ Verification failed"; \
exit 1; \
fi
@echo "✅ Verification successful"
# Check existing job status
verify-check:
@voyager status \
--network mainnet \
--job $(JOB_ID) \
--format json | jq '.'
Best Practices
Format Selection Guidelines
-
Use text format for:
- Interactive terminal sessions
- Manual verification during development
- Learning and debugging
- Watch mode with live progress updates
-
Use JSON format for:
- CI/CD pipelines
- Automated deployment scripts
- Integration with other tools
- Monitoring and alerting
- Data analysis and metrics
-
Use table format for:
- Quick status checks
- Batch operation overviews
- Terminal-based UIs
- Documentation and reports
Error Handling
Always check the completion status before examining results:
Good:
STATUS=$(voyager status --network mainnet --job $JOB_ID --format json)
if [ $(echo "$STATUS" | jq -r '.is_completed') = "true" ]; then
if [ $(echo "$STATUS" | jq -r '.has_failed') = "true" ]; then
echo "Failed: $(echo "$STATUS" | jq -r '.message')"
else
echo "Success!"
fi
else
echo "Still in progress"
fi
Bad:
# Don't assume verification is complete
voyager status --network mainnet --job $JOB_ID --format json | jq -r '.class_hash'
# This might return null if verification is still running
Verbose Mode with JSON
Combine --verbose with --format json to get detailed error information in structured format:
voyager status --network mainnet --job $JOB_ID --format json --verbose
This includes full compiler output in the message field when compilation fails.
Troubleshooting
JSON Parsing Errors
Problem: jq command fails with parse error
Solution: Check that the command succeeded first:
OUTPUT=$(voyager status --network mainnet --job $JOB_ID --format json 2>&1)
if echo "$OUTPUT" | jq -e . >/dev/null 2>&1; then
# Valid JSON, safe to parse
STATUS=$(echo "$OUTPUT" | jq -r '.status')
else
# Not valid JSON, probably an error message
echo "Error occurred: $OUTPUT"
exit 1
fi
Empty or Null Fields
Problem: JSON fields contain null values
Solution: Always check for null before using field values:
# Safe null handling with jq
CLASS_HASH=$(voyager status --network mainnet --job $JOB_ID --format json | \
jq -r '.class_hash // "not available"')
# Or check explicitly
if [ $(echo "$STATUS" | jq -r '.class_hash') != "null" ]; then
# Safe to use class_hash
fi
Table Format in Scripts
Problem: Table format is hard to parse programmatically
Solution: Don’t use table format for automated scripts. Use JSON instead:
# ❌ Don't do this
voyager status --network mainnet --job $JOB_ID --format table | grep "Status"
# ✅ Do this instead
voyager status --network mainnet --job $JOB_ID --format json | jq -r '.status'
See Also
- Command-Line Verification - Direct CLI verification syntax
- Batch Verification - Verifying multiple contracts
- Watch Mode - Monitoring verification progress
- Desktop Notifications - Getting notified on completion
- History Listing - Viewing verification history
CI/CD Integration
Integrate voyager-verifier into your Continuous Integration and Deployment pipelines to automatically verify contracts when they’re deployed to Starknet networks.
Overview
Automated contract verification in CI/CD:
- Ensures deployed contracts are always verified
- Prevents manual verification steps
- Provides verification status in deployment logs
- Enables deployment gates based on verification success
- Integrates with existing workflows
General Integration Pattern
All CI/CD integrations follow a similar pattern:
- Install voyager-verifier
- Build your contract with Scarb
- Deploy contract to Starknet (get class hash)
- Verify using voyager-verifier
- Check verification status
- Report results
Installation in CI
Using Cargo
The most reliable method across platforms:
cargo install voyager-verifier
Caching for Faster Builds
Cache the installation to speed up subsequent runs:
GitHub Actions:
- name: Cache cargo binaries
uses: actions/cache@v3
with:
path: ~/.cargo/bin
key: ${{ runner.os }}-cargo-bin-voyager-${{ hashFiles('**/Cargo.lock') }}
GitLab CI:
cache:
paths:
- ~/.cargo/bin/voyager
GitHub Actions
Basic Workflow
name: Deploy and Verify Contract
on:
push:
branches: [main]
workflow_dispatch:
jobs:
deploy-and-verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Scarb
uses: software-mansion/setup-scarb@v1
- name: Build Contract
run: scarb build
- name: Install voyager-verifier
run: cargo install voyager-verifier
- name: Deploy Contract
id: deploy
run: |
# Your deployment script here
# This should output the class hash
CLASS_HASH=$(starkli declare target/release/my_contract.sierra.json)
echo "class_hash=$CLASS_HASH" >> $GITHUB_OUTPUT
- name: Verify Contract
run: |
voyager verify \
--network mainnet \
--class-hash ${{ steps.deploy.outputs.class_hash }} \
--contract-name MyContract \
--watch \
--format json > verification-result.json
- name: Check Verification Result
run: |
if [ $(jq -r '.has_failed' verification-result.json) = "true" ]; then
echo "❌ Contract verification failed"
jq '.' verification-result.json
exit 1
fi
echo "✅ Contract verified successfully"
jq '.class_hash' verification-result.json
Advanced Workflow with Multiple Environments
name: Multi-Environment Deployment
on:
push:
branches: [main, staging, develop]
env:
CARGO_TERM_COLOR: always
jobs:
determine-environment:
runs-on: ubuntu-latest
outputs:
environment: ${{ steps.set-env.outputs.environment }}
network: ${{ steps.set-env.outputs.network }}
steps:
- id: set-env
run: |
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
echo "environment=production" >> $GITHUB_OUTPUT
echo "network=mainnet" >> $GITHUB_OUTPUT
elif [[ "${{ github.ref }}" == "refs/heads/staging" ]]; then
echo "environment=staging" >> $GITHUB_OUTPUT
echo "network=sepolia" >> $GITHUB_OUTPUT
else
echo "environment=development" >> $GITHUB_OUTPUT
echo "network=sepolia" >> $GITHUB_OUTPUT
fi
deploy-and-verify:
needs: determine-environment
runs-on: ubuntu-latest
environment: ${{ needs.determine-environment.outputs.environment }}
steps:
- uses: actions/checkout@v3
- name: Cache cargo installation
uses: actions/cache@v3
with:
path: |
~/.cargo/bin/voyager
~/.cargo/bin/scarb
key: ${{ runner.os }}-cargo-tools-${{ hashFiles('**/Cargo.lock') }}
- name: Install Scarb
uses: software-mansion/setup-scarb@v1
- name: Build Contract
run: scarb build --release
- name: Install voyager-verifier
run: |
if ! command -v voyager &> /dev/null; then
cargo install voyager-verifier
fi
- name: Deploy Contract
id: deploy
env:
NETWORK: ${{ needs.determine-environment.outputs.network }}
PRIVATE_KEY: ${{ secrets.STARKNET_PRIVATE_KEY }}
run: |
# Deploy using starkli or your preferred tool
CLASS_HASH=$(./scripts/deploy.sh $NETWORK)
echo "class_hash=$CLASS_HASH" >> $GITHUB_OUTPUT
- name: Verify Contract
env:
NETWORK: ${{ needs.determine-environment.outputs.network }}
CLASS_HASH: ${{ steps.deploy.outputs.class_hash }}
run: |
voyager verify \
--network $NETWORK \
--class-hash $CLASS_HASH \
--contract-name MyContract \
--lock-file \
--watch \
--format json \
--verbose > verification-result.json
- name: Parse Verification Result
id: verify
run: |
IS_COMPLETED=$(jq -r '.is_completed' verification-result.json)
HAS_FAILED=$(jq -r '.has_failed' verification-result.json)
JOB_ID=$(jq -r '.job_id' verification-result.json)
echo "is_completed=$IS_COMPLETED" >> $GITHUB_OUTPUT
echo "has_failed=$HAS_FAILED" >> $GITHUB_OUTPUT
echo "job_id=$JOB_ID" >> $GITHUB_OUTPUT
- name: Report Verification Status
run: |
if [ "${{ steps.verify.outputs.has_failed }}" = "true" ]; then
echo "::error::Contract verification failed"
jq '.' verification-result.json
exit 1
fi
echo "::notice::Contract verified successfully!"
echo "Class Hash: ${{ steps.deploy.outputs.class_hash }}"
echo "Job ID: ${{ steps.verify.outputs.job_id }}"
- name: Upload Verification Result
uses: actions/upload-artifact@v3
if: always()
with:
name: verification-result-${{ needs.determine-environment.outputs.environment }}
path: verification-result.json
- name: Comment on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
const result = JSON.parse(fs.readFileSync('verification-result.json', 'utf8'));
const comment = result.has_failed
? `❌ Contract verification failed\\n\`\`\`json\\n${JSON.stringify(result, null, 2)}\\n\`\`\``
: `✅ Contract verified successfully!\\n- Class Hash: \`${result.class_hash}\`\\n- Network: \`${{ needs.determine-environment.outputs.network }}\``;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.name,
body: comment
});
Batch Verification Workflow
name: Batch Contract Verification
on:
workflow_dispatch:
inputs:
network:
description: 'Network to verify on'
required: true
type: choice
options:
- mainnet
- sepolia
jobs:
verify-batch:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install voyager-verifier
run: cargo install voyager-verifier
- name: Verify All Contracts
env:
NETWORK: ${{ inputs.network }}
run: |
# .voyager.toml contains [[contracts]] array
voyager verify \
--network $NETWORK \
--watch \
--batch-delay 5 \
--format json > batch-result.json
- name: Check Batch Results
run: |
FAILED=$(jq '[.results[] | select(.has_failed == true)] | length' batch-result.json)
if [ "$FAILED" -gt 0 ]; then
echo "::error::$FAILED contract(s) failed verification"
jq '.results[] | select(.has_failed == true)' batch-result.json
exit 1
fi
echo "::notice::All contracts verified successfully"
- name: Generate Summary
run: |
echo "# Batch Verification Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
jq -r '.results[] | "- \(.contract_name): \(.status)"' batch-result.json >> $GITHUB_STEP_SUMMARY
GitLab CI
Basic Pipeline
stages:
- build
- deploy
- verify
variables:
CARGO_HOME: $CI_PROJECT_DIR/.cargo
cache:
paths:
- .cargo/bin
- target/
build:
stage: build
image: rust:latest
script:
- curl -L https://raw.githubusercontent.com/software-mansion/scarb/main/install.sh | bash
- export PATH="$HOME/.local/bin:$PATH"
- scarb build --release
artifacts:
paths:
- target/release/
expire_in: 1 hour
deploy:
stage: deploy
image: rust:latest
script:
- ./scripts/deploy.sh $CI_COMMIT_REF_NAME
artifacts:
reports:
dotenv: deploy.env
only:
- main
- staging
verify:
stage: verify
image: rust:latest
dependencies:
- deploy
script:
- cargo install voyager-verifier
- |
voyager verify \
--network ${NETWORK} \
--class-hash ${CLASS_HASH} \
--contract-name ${CONTRACT_NAME} \
--lock-file \
--watch \
--format json > verification.json
- |
if [ $(jq -r '.has_failed' verification.json) = "true" ]; then
echo "Contract verification failed"
cat verification.json
exit 1
fi
- echo "Contract verified successfully"
- jq '.class_hash' verification.json
artifacts:
paths:
- verification.json
reports:
junit: verification.json
only:
- main
- staging
Multi-Environment Pipeline
stages:
- build
- deploy
- verify
- report
.verify_template: &verify_template
stage: verify
image: rust:latest
script:
- cargo install voyager-verifier
- |
voyager verify \
--network $NETWORK \
--class-hash $CLASS_HASH \
--contract-name $CONTRACT_NAME \
--watch \
--format json > verification-$CI_ENVIRONMENT_NAME.json
- |
if [ $(jq -r '.has_failed' verification-$CI_ENVIRONMENT_NAME.json) = "true" ]; then
echo "Verification failed on $CI_ENVIRONMENT_NAME"
exit 1
fi
artifacts:
paths:
- verification-*.json
verify:production:
<<: *verify_template
environment:
name: production
variables:
NETWORK: mainnet
dependencies:
- deploy:production
only:
- main
verify:staging:
<<: *verify_template
environment:
name: staging
variables:
NETWORK: sepolia
dependencies:
- deploy:staging
only:
- staging
report:
stage: report
image: alpine:latest
script:
- apk add --no-cache jq
- |
for file in verification-*.json; do
ENV=$(echo $file | sed 's/verification-\(.*\)\.json/\1/')
STATUS=$(jq -r '.status' $file)
echo "$ENV: $STATUS"
done
when: always
Jenkins
Declarative Pipeline
pipeline {
agent any
environment {
NETWORK = 'mainnet'
CONTRACT_NAME = 'MyContract'
CLASS_HASH = credentials('starknet-class-hash')
}
stages {
stage('Install Tools') {
steps {
sh '''
# Install Scarb
curl -L https://raw.githubusercontent.com/software-mansion/scarb/main/install.sh | bash
export PATH="$HOME/.local/bin:$PATH"
# Install voyager-verifier
cargo install voyager-verifier
'''
}
}
stage('Build Contract') {
steps {
sh '''
export PATH="$HOME/.local/bin:$PATH"
scarb build --release
'''
}
}
stage('Deploy Contract') {
steps {
script {
env.CLASS_HASH = sh(
script: './scripts/deploy.sh',
returnStdout: true
).trim()
}
}
}
stage('Verify Contract') {
steps {
sh '''
voyager verify \
--network ${NETWORK} \
--class-hash ${CLASS_HASH} \
--contract-name ${CONTRACT_NAME} \
--watch \
--format json > verification-result.json
'''
}
}
stage('Check Verification') {
steps {
script {
def result = readJSON file: 'verification-result.json'
if (result.has_failed) {
error("Contract verification failed: ${result.message}")
}
echo "✅ Contract verified successfully!"
echo "Class Hash: ${result.class_hash}"
echo "Job ID: ${result.job_id}"
}
}
}
}
post {
always {
archiveArtifacts artifacts: 'verification-result.json', allowEmptyArchive: true
}
success {
echo 'Deployment and verification completed successfully'
}
failure {
echo 'Deployment or verification failed'
}
}
}
Scripted Pipeline with Parallel Verification
node {
stage('Checkout') {
checkout scm
}
stage('Install Dependencies') {
sh 'cargo install voyager-verifier'
}
stage('Build Contracts') {
sh 'scarb build --release'
}
stage('Deploy and Verify') {
def contracts = [
[name: 'TokenContract', classHash: env.TOKEN_CLASS_HASH],
[name: 'NFTContract', classHash: env.NFT_CLASS_HASH],
[name: 'MarketplaceContract', classHash: env.MARKETPLACE_CLASS_HASH]
]
def verificationSteps = contracts.collectEntries { contract ->
["Verify ${contract.name}": {
sh """
voyager verify \
--network mainnet \
--class-hash ${contract.classHash} \
--contract-name ${contract.name} \
--watch \
--format json > verification-${contract.name}.json
"""
def result = readJSON file: "verification-${contract.name}.json"
if (result.has_failed) {
error("Verification failed for ${contract.name}")
}
}]
}
parallel verificationSteps
}
stage('Report Results') {
sh '''
for file in verification-*.json; do
CONTRACT=$(echo $file | sed 's/verification-\\(.*\\)\\.json/\\1/')
STATUS=$(jq -r '.status' $file)
echo "$CONTRACT: $STATUS"
done
'''
}
}
CircleCI
Basic Configuration
version: 2.1
orbs:
rust: circleci/rust@1.6.0
jobs:
build-and-verify:
docker:
- image: cimg/rust:latest
steps:
- checkout
- restore_cache:
keys:
- cargo-cache-{{ checksum "Cargo.lock" }}
- cargo-cache-
- run:
name: Install Scarb
command: |
curl -L https://raw.githubusercontent.com/software-mansion/scarb/main/install.sh | bash
echo 'export PATH="$HOME/.local/bin:$PATH"' >> $BASH_ENV
- run:
name: Install voyager-verifier
command: cargo install voyager-verifier
- save_cache:
key: cargo-cache-{{ checksum "Cargo.lock" }}
paths:
- ~/.cargo/bin
- run:
name: Build Contract
command: scarb build --release
- run:
name: Deploy Contract
command: |
CLASS_HASH=$(./scripts/deploy.sh)
echo "export CLASS_HASH=$CLASS_HASH" >> $BASH_ENV
- run:
name: Verify Contract
command: |
voyager verify \
--network mainnet \
--class-hash $CLASS_HASH \
--contract-name MyContract \
--watch \
--format json | tee verification-result.json
- run:
name: Check Verification
command: |
if [ $(jq -r '.has_failed' verification-result.json) = "true" ]; then
echo "Contract verification failed"
jq '.' verification-result.json
exit 1
fi
echo "Contract verified successfully"
- store_artifacts:
path: verification-result.json
workflows:
build-deploy-verify:
jobs:
- build-and-verify:
filters:
branches:
only:
- main
- staging
Environment Variables and Secrets
GitHub Actions Secrets
env:
CLASS_HASH: ${{ secrets.STARKNET_CLASS_HASH }}
PRIVATE_KEY: ${{ secrets.STARKNET_PRIVATE_KEY }}
NETWORK: ${{ vars.NETWORK }} # Repository variable
GitLab CI Variables
variables:
NETWORK: mainnet # Project variable
CLASS_HASH: $CI_CLASS_HASH # Protected variable
Jenkins Credentials
environment {
CLASS_HASH = credentials('starknet-class-hash')
PRIVATE_KEY = credentials('starknet-private-key')
}
Best Practices for Secrets
-
Never commit secrets to version control
-
Use CI platform’s secret management:
- GitHub: Repository Secrets
- GitLab: CI/CD Variables (protected)
- Jenkins: Credentials Plugin
- CircleCI: Context/Project Environment Variables
-
Rotate secrets regularly
-
Use different secrets per environment:
production_class_hash: ${{ secrets.PROD_CLASS_HASH }} staging_class_hash: ${{ secrets.STAGING_CLASS_HASH }}
Error Handling Patterns
Retry Logic
#!/bin/bash
MAX_RETRIES=3
RETRY_COUNT=0
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
voyager verify \
--network mainnet \
--class-hash $CLASS_HASH \
--contract-name MyContract \
--watch \
--format json > verification.json
if [ $(jq -r '.is_completed' verification.json) = "true" ]; then
if [ $(jq -r '.has_failed' verification.json) = "false" ]; then
echo "Verification successful"
exit 0
else
echo "Verification failed"
exit 1
fi
fi
RETRY_COUNT=$((RETRY_COUNT + 1))
echo "Retry $RETRY_COUNT/$MAX_RETRIES"
sleep 30
done
echo "Verification timed out after $MAX_RETRIES retries"
exit 1
Timeout Handling
- name: Verify with Timeout
timeout-minutes: 10
run: |
voyager verify \
--network mainnet \
--class-hash $CLASS_HASH \
--contract-name MyContract \
--watch \
--format json
Failure Notifications
Slack notification (GitHub Actions):
- name: Notify on Failure
if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "Contract verification failed for ${{ github.repository }}",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "❌ Contract verification failed\\nBranch: ${{ github.ref }}\\nCommit: ${{ github.sha }}"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
Best Practices
1. Use Configuration Files
Create environment-specific configs:
- name: Select Config
run: |
if [ "$ENVIRONMENT" = "production" ]; then
cp .voyager.prod.toml .voyager.toml
else
cp .voyager.dev.toml .voyager.toml
fi
2. Cache Installation
- name: Cache voyager
uses: actions/cache@v3
with:
path: ~/.cargo/bin/voyager
key: voyager-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}
3. Use JSON Output
Always use --format json in CI for reliable parsing:
voyager verify --format json > result.json
4. Enable Watch Mode
Use --watch to wait for completion:
voyager verify --watch --format json
5. Include Lock Files for Production
voyager verify --lock-file --network mainnet
6. Use Verbose Mode for Debugging
- name: Verify (Debug)
if: runner.debug == '1'
run: |
voyager verify --verbose --format json
7. Separate Deployment and Verification
Don’t block deployment on verification failure (optional):
- name: Verify Contract
continue-on-error: true # Don't fail deployment
run: voyager verify ...
Complete Example: Production-Ready Workflow
name: Production Deployment
on:
push:
tags:
- 'v*'
env:
NETWORK: mainnet
CARGO_TERM_COLOR: always
jobs:
deploy-and-verify:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v3
- name: Extract version
id: version
run: echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
- name: Cache dependencies
uses: actions/cache@v3
with:
path: |
~/.cargo/bin
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Install Scarb
uses: software-mansion/setup-scarb@v1
- name: Install voyager-verifier
run: |
if ! command -v voyager &> /dev/null; then
cargo install voyager-verifier
fi
- name: Build Contract
run: scarb build --release
- name: Deploy to Mainnet
id: deploy
env:
PRIVATE_KEY: ${{ secrets.STARKNET_PRIVATE_KEY }}
run: |
CLASS_HASH=$(./scripts/deploy.sh mainnet)
echo "class_hash=$CLASS_HASH" >> $GITHUB_OUTPUT
- name: Verify Contract
timeout-minutes: 10
run: |
voyager verify \
--network mainnet \
--class-hash ${{ steps.deploy.outputs.class_hash }} \
--contract-name MyContract \
--lock-file \
--watch \
--format json > verification-result.json
- name: Validate Verification
id: validate
run: |
IS_COMPLETED=$(jq -r '.is_completed' verification-result.json)
HAS_FAILED=$(jq -r '.has_failed' verification-result.json)
if [ "$IS_COMPLETED" != "true" ]; then
echo "::error::Verification did not complete"
exit 1
fi
if [ "$HAS_FAILED" = "true" ]; then
echo "::error::Verification failed"
jq '.' verification-result.json
exit 1
fi
echo "::notice::✅ Contract verified successfully"
echo "verified=true" >> $GITHUB_OUTPUT
- name: Create Release
if: steps.validate.outputs.verified == 'true'
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ steps.version.outputs.version }}
body: |
## Contract Deployment
- **Network:** Mainnet
- **Class Hash:** `${{ steps.deploy.outputs.class_hash }}`
- **Verification:** ✅ Verified
- **Voyager:** [View on Voyager](https://voyager.online/class/${{ steps.deploy.outputs.class_hash }})
- name: Upload Artifacts
uses: actions/upload-artifact@v3
if: always()
with:
name: deployment-artifacts
path: |
verification-result.json
target/release/*.sierra.json
- name: Notify on Failure
if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "❌ Production deployment failed",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Deployment Failed*\\nTag: ${{ github.ref }}\\nWorkflow: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
See Also
- Output Formats - JSON output parsing for CI/CD
- Configuration Examples - Environment-specific configs
- Custom Endpoints - Using staging/dev endpoints in CI
- Lock Files - Reproducible builds for production
- Batch Verification - Verifying multiple contracts
Troubleshooting Guide
Having issues with Voyager Verifier? This guide helps you quickly diagnose and resolve problems.
Quick Problem Solver
Verification Failed?
↓
┌─────────────────────────────────┐
│ Check Error Code │
│ → See Error Codes Reference │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ Common Error? │
│ → See Common Errors Guide │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ Need More Details? │
│ → Use Verbose Mode │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ Still Stuck? │
│ → Follow Debugging Workflow │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ Need Help? │
│ → Contact Support │
└─────────────────────────────────┘
Troubleshooting Resources
1. Common Errors
Quick fixes for frequent problems
Start here if you’re encountering a common issue:
- Compilation errors
- Verification failures
- Configuration problems
- Network and API errors
- File and project errors
- Class hash issues
When to Use: You have an error and want a quick solution.
2. Debugging Guide
Systematic troubleshooting workflow
Follow the step-by-step debugging process:
- 6-step debugging workflow
- Debugging tools (dry-run, verbose, local testing, history)
- Common debugging scenarios
- Advanced debugging techniques
When to Use: Quick fixes didn’t work and you need a systematic approach.
3. Verbose Mode
Understanding detailed output
Learn how to use --verbose for detailed error information:
- Enabling verbose mode
- Interpreting verbose output
- Common verbose patterns
- Debugging with verbose mode
When to Use: You need more details about what’s failing.
4. Getting Support
How to get help
Find support resources:
- Self-help documentation
- Telegram community
- GitHub issues
- Bug reporting guidelines
When to Use: You’ve tried everything and need human assistance.
Quick Tips
Compilation Failed?
# Build locally first
scarb --release build
# Check for syntax errors
scarb check
Verification Failed?
# Use verbose mode to see details
voyager status --network mainnet --job <JOB_ID> --verbose
# Preview what will be submitted
voyager verify --dry-run ...
Module Not Found?
# Include test files if needed
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files
Class Hash Mismatch?
# Include Scarb.lock for reproducibility
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--lock-file
Network Issues?
# Check API status
curl https://api.voyager.online/api-docs
# Try a different network
voyager verify --network sepolia ...
Job Taking Too Long?
# Check job status
voyager status --network mainnet --job <JOB_ID>
# View recent jobs
voyager history --network mainnet --limit 5
Error Code Quick Reference
| Error Code | Category | Description |
|---|---|---|
| E001-E003 | Workspace | Package not found, no packages, workspace errors |
| E004-E009 | Verification | API submission, polling, job failures |
| E010-E014 | Dependencies | Resolution failures, missing dependencies |
| E015-E024 | Contract/Target | Invalid contract names, target not found |
| E025-E029 | File System | File not found, read errors, path issues |
| E030-E039 | Class Hash | Hash mismatch, parsing errors, format issues |
| E040-E042 | Config | Config file errors, parsing failures |
See Error Codes Reference for complete details.
Common Scenarios
Scenario 1: First-Time Verification
Problem: Not sure where to start?
Solution:
# 1. Build your contract
cd my-project
scarb --release build
# 2. Get your class hash from declaration
# Example: 0x044dc2b3...
# 3. Verify with basic command
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
# 4. Check status
voyager status --network mainnet --job <JOB_ID>
Learn More: Getting Started Guide
Scenario 2: Test Files Missing
Problem: Error E005 - Module file not found (test files)
Solution:
# Include test files in verification
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files
Learn More: Test Files Guide
Scenario 3: Class Hash Mismatch
Problem: Error E030 - Compiled hash doesn’t match expected
Solution:
# 1. Include Scarb.lock for reproducibility
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--lock-file
# 2. Ensure exact same versions
cat Scarb.toml # Check Cairo/Scarb versions
# 3. Use dry-run to debug
voyager verify --dry-run ... --verbose
Learn More: Lock Files Guide
Scenario 4: Multi-Package Workspace
Problem: Which package to verify in a workspace?
Solution:
# List available packages
scarb metadata
# Verify specific package
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--package my_package
Learn More: Multi-Package Guide
Scenario 5: Custom Network/Endpoint
Problem: Need to verify on custom network?
Solution:
# Use custom endpoint
voyager verify --network custom \
--endpoint https://api.custom.com \
--class-hash 0x044dc2b3... \
--contract-name MyContract
Learn More: Custom Endpoints Guide
Debugging Checklist
Before asking for help, complete this checklist:
- Read the error message - What error code (E###) are you seeing?
- Check Common Errors - Is your error listed?
- Use verbose mode - Run with
--verboseflag - Try dry-run - Use
--dry-runto preview submission - Verify locally - Can you build with
scarb build? - Check versions - Are Cairo/Scarb versions correct?
- Review command - Are all required flags present?
- Test network - Is the API endpoint responding?
- Check history - Have similar verifications succeeded before?
Troubleshooting Tools
1. Verbose Mode
Get detailed error information:
voyager verify --verbose ...
voyager status --verbose ...
See: Verbose Mode Guide
2. Dry-Run Mode
Preview submission without sending:
voyager verify --dry-run ...
See: Debugging Guide
3. History Command
Check previous verifications:
# Recent jobs
voyager history --network mainnet --limit 10
# Successful jobs only
voyager history --network mainnet --status verified
# Specific contract
voyager history --network mainnet --contract MyContract
4. Local Testing
Test before submitting:
# Build locally
scarb --release build
# Check for errors
scarb check
# Run tests
scarb test
Prevention Tips
✅ Best Practices
-
Always build locally first
scarb --release build -
Use lock files for reproducibility
# Commit Scarb.lock to version control git add Scarb.lock -
Test with dry-run before submitting
voyager verify --dry-run ... -
Use verbose mode when debugging
voyager verify --verbose ... -
Keep versions consistent
# In Scarb.toml [dependencies] starknet = "2.8.2" -
Include necessary files
# Include tests if they're imported voyager verify --test-files ...
Getting Help
Self-Help First
- Check Common Errors
- Review Error Codes Reference
- Use Debugging Workflow
- Try Verbose Mode
Community Support
- Telegram: https://t.me/StarknetVoyager
- GitHub Issues: https://github.com/NethermindEth/voyager-verifier/issues
See Also
Troubleshooting Resources
- Common Errors - Quick fixes for frequent problems
- Debugging Guide - Systematic troubleshooting workflow
- Verbose Mode - Understanding detailed output
- Getting Support - How to get help
Reference Material
- Error Codes - Complete error reference (E001-E042)
- Supported Versions - Version compatibility
- File Collection - What files are included
Feature Guides
- Core Features - Essential functionality
- Advanced Features - Advanced usage patterns
- Getting Started - Initial setup and usage
Common Errors
This page covers the most frequent errors users encounter when using voyager-verifier, with practical solutions and examples.
Quick Navigation:
- Compilation Errors
- Verification Failures
- Configuration Issues
- Network & API Errors
- File & Project Errors
- Class Hash Issues
For a complete error code reference, see Error Codes Reference.
Compilation Errors
Module File Not Found
Error:
error[E0005]: Module file not found. Expected path: /tmp/targets/.../src/tests.cairo
Common Cause:
Your lib.cairo declares a test module, but test files are excluded by default.
Quick Fix:
# Option 1: Include test files
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files
# Option 2: Remove the module declaration from lib.cairo
Edit lib.cairo:
// Before
mod contract;
mod tests; // ← Remove this line
// After
mod contract;
// mod tests; // Commented out or removed
Why This Happens:
The verifier excludes test files by default to reduce payload size. If your code references test modules, you need to either include them with --test-files or remove the references.
See Also: Test Files Guide
Remote Build Failed But Local Build Succeeds
Symptoms:
scarb --release buildworks locally- Remote verification fails with compilation errors
Common Causes:
-
Missing dependencies in
[profile.release]:# ❌ Wrong: Settings in dev profile only [profile.dev.cairo] sierra-replace-ids = true # ✅ Correct: Settings in release profile [profile.release.cairo] sierra-replace-ids = true -
Local dependencies not available remotely:
# ❌ Problem: Local path dependency [dependencies] utils = { path = "../utils" } # Not available on remote # ✅ Solution: Use git or registry dependency [dependencies] utils = { git = "https://github.com/org/utils" } -
Cairo version mismatch:
- Remote compiler may use different Cairo version
- Use
--lock-fileto pin versions
Solutions:
1. Check release profile:
# Test with release profile locally
scarb --release build
2. Use lock file:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--lock-file # Pin dependency versions
3. Use verbose mode to see full error:
voyager status --network mainnet --job <JOB_ID> --verbose
Syntax Errors After Submission
Error:
[E004] Compilation failed: syntax error
Quick Checklist:
- ✅ Does
scarb buildwork locally? - ✅ Does
scarb --release buildwork locally? - ✅ Are all files committed (not using uncommitted changes)?
- ✅ Are imports correct?
Common Issues:
1. Missing imports:
// ❌ Error: Missing import
mod MyContract {
fn transfer() {
ITokenDispatcher { ... } // ITokenDispatcher not imported
}
}
// ✅ Fixed: Add import
use token::ITokenDispatcher;
mod MyContract {
fn transfer() {
ITokenDispatcher { ... }
}
}
2. Incorrect module declarations:
// lib.cairo
// ❌ Wrong: Module file doesn't exist
mod utils;
// ✅ Check file exists:
// - src/utils.cairo OR
// - src/utils/mod.cairo
Verification Failures
Class Hash Mismatch
Error:
[E005] Verification failed: Compiled class hash does not match declared class hash
Cause: The source code you submitted doesn’t produce the same class hash as the declared contract class.
Most Common Reasons:
1. Wrong source code version:
# Check git history for deployed version
git log --oneline
git checkout <deployment-commit>
# Then verify
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
2. Different dependency versions:
# Use lock file to ensure same versions
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--lock-file
3. Different compiler settings:
# Scarb.toml - Ensure these match deployment
[profile.release.cairo]
sierra-replace-ids = true # Must match deployment settings
inlining-strategy = "default"
4. Code modified after deployment:
- Even whitespace changes can affect hash
- Use exact same source as deployment
Debugging Steps:
-
Verify you have correct source:
# Check current commit git log -1 # If using tags git checkout v1.0.0 # Or whatever tag was deployed -
Build locally and compare:
scarb --release build # Check the class hash in target/release/ cat target/release/my_project_MyContract.contract_class.json | grep class_hash -
Try with lock file:
# Ensure Scarb.lock exists ls Scarb.lock # Verify with lock file voyager verify --network mainnet \ --class-hash 0x044dc2b3... \ --contract-name MyContract \ --lock-file \ --verbose
Class Hash Not Declared
Error:
[E015] Class hash '<hash>' is not declared
Cause: The class hash hasn’t been declared on the network you’re verifying against.
Solutions:
1. Check correct network:
# Wrong network?
voyager verify --network mainnet \
--class-hash 0x044dc2b3... # But declared on sepolia
# Try sepolia
voyager verify --network sepolia \
--class-hash 0x044dc2b3...
2. Verify on block explorer:
3. Declare first if needed:
# Using starkli
starkli declare target/release/my_contract_MyContract.contract_class.json
# Wait for confirmation, then verify
voyager verify --network mainnet \
--class-hash <HASH_FROM_DECLARATION> \
--contract-name MyContract
Configuration Issues
Invalid TOML Syntax in .voyager.toml
Error:
[E031] Failed to parse config file
Common Mistakes:
1. Wrong field names:
# ❌ Wrong: Using underscores
[voyager]
test_files = true
lock_file = true
# ✅ Correct: Using hyphens
[voyager]
test-files = true
lock-file = true
2. Missing quotes for strings:
# ❌ Wrong: No quotes
[voyager]
network = mainnet
# ✅ Correct: Quotes for strings
[voyager]
network = "mainnet"
3. Extra quotes for booleans:
# ❌ Wrong: Quotes on boolean
[voyager]
watch = "true"
# ✅ Correct: No quotes for boolean
[voyager]
watch = true
4. Typos in field names:
# ❌ Wrong: Typo
[voyager]
netwrok = "mainnet"
# ✅ Correct
[voyager]
network = "mainnet"
Quick Fix:
# Use example file as template
cp .voyager.toml.example .voyager.toml
# Or validate online
# Copy your config to https://www.toml-lint.com/
Workspace Package Not Found
Error:
[E001] Package '<name>' not found in workspace
Quick Fix:
# List available packages
scarb metadata | grep name
# Use correct package name
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--package correct_name
Check Scarb.toml:
[workspace]
members = [
"package1",
"package2",
"package3", # Use these exact names with --package
]
No Contracts Selected
Error:
[E016] No contracts selected for verification
Cause: You didn’t specify which contract to verify.
Solution:
# Always specify contract name
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract # ← Required
Network & API Errors
Connection Failed / Timeout
Error:
[E999] Network error / Connection timeout
Quick Checks:
-
Test internet connection:
ping api.voyager.online -
Check DNS:
nslookup api.voyager.online -
Test API endpoint:
curl -I https://api.voyager.online/beta -
Check firewall:
- Ensure HTTPS (port 443) is allowed
- Check corporate firewall/proxy settings
Solutions:
# Retry request
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
# If using custom endpoint, verify URL
voyager verify --url https://api.voyager.online/beta \
--class-hash 0x044dc2b3... \
--contract-name MyContract
Payload Too Large (413)
Error:
[E002] HTTP request failed: returned status 413
Payload Too Large
Cause: Your project files exceed the 10MB API limit.
Solutions:
1. Check project size:
# Find large files
find . -type f -size +1M
# Check total source size
du -sh src/
2. Exclude test files:
# Don't use --test-files flag
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
# Removed --test-files
3. Exclude lock file:
# Don't use --lock-file flag
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
# Removed --lock-file
4. Remove unnecessary files:
# Check .gitignore
echo "target/" >> .gitignore
echo "*.bin" >> .gitignore
# Remove build artifacts
rm -rf target/
Invalid API URL
Error:
[E006] Invalid base URL: example.com
Cause: Custom URL is missing protocol or malformed.
Fix:
# ❌ Wrong: Missing protocol
voyager verify --url example.com/api/beta ...
# ✅ Correct: Include https://
voyager verify --url https://example.com/api/beta ...
# OR use predefined network
voyager verify --network mainnet ...
File & Project Errors
Scarb.toml Not Found
Error:
[E020] Scarb project manifest not found
Solutions:
1. Check current directory:
ls Scarb.toml # Should exist
pwd # Verify you're in project root
2. Specify correct path:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--path /path/to/project # Path containing Scarb.toml
3. Initialize new project:
scarb init my-project
cd my-project
Invalid File Type
Error:
[E024] File '<path>' has invalid file type (extension: .bin)
Cause: Binary or non-Cairo files in project directory.
Solution:
# Remove binary files
rm src/*.bin
rm src/*.exe
# Add to .gitignore
echo "*.bin" >> .gitignore
echo "*.exe" >> .gitignore
echo "*.so" >> .gitignore
echo "target/" >> .gitignore
Allowed Extensions:
.cairo- Cairo source.toml- Config files.lock- Lock files.md,.txt- Documentation.json- JSON files
File Size Limit Exceeded
Error:
[E019] File '<path>' exceeds maximum size limit
Solutions:
1. Split large files:
// Split into multiple modules
// Large file: src/contract.cairo (> 1MB)
// Split into:
// src/contract/core.cairo
// src/contract/helpers.cairo
// src/contract/mod.cairo
2. Exclude large test files:
# Don't include test files if they're large
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
# Without --test-files
3. Check for generated content:
# Find large files
find src -type f -size +500k
# Remove if they're generated/temporary
Class Hash Issues
Invalid Class Hash Format
Error:
[E010] Invalid class hash format: '044dc2b3...'
Cause:
Class hash is missing 0x prefix or contains invalid characters.
Common Mistakes:
1. Missing 0x prefix:
# ❌ Wrong
--class-hash 044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
# ✅ Correct
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
2. Invalid characters:
# ❌ Wrong: Contains 'z' (not hex)
--class-hash 0x044dc2b3z39382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
# ✅ Correct: Only hex (0-9, a-f)
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
3. Spaces or special characters:
# ❌ Wrong: Contains spaces
--class-hash "0x044dc2b3 239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18"
# ✅ Correct: No spaces
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Quick Troubleshooting Workflow
When encountering an error, follow these steps:
1. Check Local Build First
# Does it build locally?
scarb --release build
# If local build fails, fix that first
# The remote will have the same error
2. Use Dry-Run Mode
# Preview what will be sent
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--dry-run
# Check the file list is correct
3. Use Verbose Mode
# Get detailed error information
voyager status --network mainnet \
--job <JOB_ID> \
--verbose
# Read the full compiler output
4. Check Configuration
# Verify Scarb.toml
scarb metadata
# Check .voyager.toml if using
cat .voyager.toml
5. Verify Release Profile
# Check [profile.release] settings
cat Scarb.toml | grep -A 5 "\[profile.release\]"
Most Common Error Combinations
“Module not found” + Test File
Pattern:
error[E0005]: Module file not found. Expected path: .../tests.cairo
Solution:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files # ← Add this
Compilation Passes Locally But Fails Remotely
Checklist:
- ✅
scarb --release build(not justscarb build) - ✅ Settings in
[profile.release]not[profile.dev] - ✅ No local-only dependencies
- ✅ Consider using
--lock-file
Solution:
# Test release build
scarb --release build
# Verify with lock file
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--lock-file
Verification Fails But Compilation Succeeds
This means: Code compiles but produces wrong class hash.
Common causes:
- Wrong source version (not matching deployment)
- Different dependency versions
- Different compiler settings
Solution:
# 1. Check git version
git log -1
# 2. Use lock file
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--lock-file \
--verbose
Prevention Tips
1. Always Test Release Build Locally
# Before verifying
scarb --release build
2. Use Configuration File
# .voyager.toml
[voyager]
network = "mainnet"
license = "MIT"
lock-file = true
verbose = true
3. Commit Scarb.lock
git add Scarb.lock
git commit -m "Add Scarb.lock for reproducible builds"
4. Document Deployment Settings
# Scarb.toml - Document why settings are needed
[profile.release.cairo]
# Required for deployment compatibility
sierra-replace-ids = true
5. Use Dry-Run Before Submission
# Preview first
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--dry-run
Getting More Help
Still stuck?
-
Use verbose mode:
voyager status --network mainnet --job <JOB_ID> --verbose -
Check full error code reference:
-
Review debugging guide:
-
Contact support:
- Telegram: @StarknetVoyager
- GitHub: Open an issue
When asking for help, include:
- Error code and message
- Full command you ran
- Output with
--verboseflag - Your Scarb.toml (remove sensitive info)
- Output of
scarb --release build
See Also
- Error Codes Reference - Complete error code listing
- Debugging Guide - Systematic debugging workflow
- Verbose Mode - Using
--verbosefor detailed output - Test Files - Including test files in verification
- Lock Files - Using Scarb.lock for reproducible builds
Debugging
This guide provides a systematic approach to debugging verification issues with voyager-verifier.
Quick Navigation:
- Debugging Workflow
- Debugging Tools
- Common Debugging Scenarios
- Step-by-Step Debugging
- Advanced Techniques
- Prevention Strategies
Debugging Workflow
Follow this systematic approach when verification fails:
1. Identify the Problem
Verification Failed
↓
What stage failed?
- Submission?
- Compilation?
- Verification?
Questions to ask:
- Did the submission succeed?
- Did compilation succeed?
- Did verification fail after compilation?
2. Gather Information
# Get detailed error output
voyager status --network mainnet --job <JOB_ID> --verbose
# Check what was submitted
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--dry-run
3. Reproduce Locally
# Can you build locally?
scarb --release build
# Does it match your verification attempt?
4. Form Hypothesis
Based on the error and local testing:
- “The remote compiler can’t find a dependency”
- “Test files are missing”
- “Class hash doesn’t match because of version differences”
5. Test Hypothesis
# If hypothesis: "Test files are missing"
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files # Test the fix
6. Verify Fix
# Did it work?
voyager status --network mainnet --job <NEW_JOB_ID>
Debugging Tools
Tool 1: Dry-Run Mode
Purpose: Preview what will be submitted without actually submitting.
Usage:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--dry-run
What It Shows:
Dry run - would submit verification for:
Network: mainnet
Class Hash: 0x044dc2b3...
Contract Name: MyContract
Files to be included:
src/lib.cairo
src/contract.cairo
src/utils.cairo
Scarb.toml
Files excluded (test files):
src/tests.cairo
Total files: 4
Total size: 125 KB
When to Use:
- Before first submission
- To check which files will be included
- To verify configuration is correct
- To check file count/size
Example - Debugging Missing Files:
# Run dry-run
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--dry-run
# Output shows tests.cairo is excluded
# But your lib.cairo declares: mod tests;
# Solution: Add --test-files
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files \
--dry-run # Verify tests.cairo now included
Tool 2: Verbose Mode
Purpose: Get detailed error messages and compiler output.
Usage:
# Verbose status check
voyager status --network mainnet --job <JOB_ID> --verbose
# Verbose verification (immediate)
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--verbose
What It Shows:
- Full compiler output
- Detailed error messages
- Stack traces
- Build logs
Example Output:
Status: CompileFailed
Error: Compilation failed
Compiler Output:
error[E0005]: Module file not found. Expected path: /tmp/targets/release/src/tests.cairo
--> src/lib.cairo:2:5
|
2 | mod tests;
| ^^^^^
|
When to Use:
- Compilation failed
- Verification failed
- Need to see full compiler output
- Debugging unclear errors
Tool 3: Local Build Testing
Purpose: Test if the issue is local or remote.
Key Commands:
# Standard build (what you might run during development)
scarb build
# Release build (what remote compiler uses)
scarb --release build
# Check metadata
scarb metadata
# Validate project
scarb check
Critical: Always test with --release flag:
# ❌ Wrong: Testing dev build
scarb build # Uses dev profile
# ✅ Correct: Testing release build
scarb --release build # Uses release profile (same as remote)
Debugging with Local Build:
# 1. Try release build
scarb --release build
# 2. If it fails locally
# → Fix the local build first
# → Remote will have same error
# 3. If it succeeds locally but fails remotely
# → Check release profile settings
# → Check dependencies
# → Use --verbose to see remote error
Tool 4: History Commands
Purpose: Review past verification attempts.
Usage:
# List recent verifications
voyager history list --limit 10
# Check specific job
voyager history status --job <JOB_ID>
# Recheck failed jobs
voyager history recheck --failed
# View statistics
voyager history stats
When to Use:
- Compare successful vs failed attempts
- Track patterns in failures
- Verify same configuration
- Check past successful builds
Common Debugging Scenarios
Scenario 1: “Module Not Found” Error
Error:
error[E0005]: Module file not found. Expected path: .../src/tests.cairo
Debugging Process:
Step 1: Check what’s declared
cat src/lib.cairo
# Shows: mod tests;
Step 2: Check if file exists locally
ls src/tests.cairo
# File exists locally
Step 3: Check what’s being submitted
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--dry-run
# Output shows: Files excluded (test files): src/tests.cairo
Step 4: Hypothesis “Test files are excluded by default, but lib.cairo declares them”
Step 5: Test fix
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files # Include test files
Step 6: Verify
voyager status --network mainnet --job <JOB_ID>
# Success!
Scenario 2: Builds Locally But Fails Remotely
Symptom: scarb --release build works, remote compilation fails
Debugging Process:
Step 1: Get remote error
voyager status --network mainnet --job <JOB_ID> --verbose
Step 2: Check release profile
cat Scarb.toml | grep -A 10 "\[profile.release"
Step 3: Look for common issues
- Settings in
[profile.dev]instead of[profile.release] - Local path dependencies
- Missing dependencies
Example Issue:
# ❌ Problem: Settings in wrong profile
[profile.dev.cairo]
sierra-replace-ids = true
# ✅ Fix: Move to release profile
[profile.release.cairo]
sierra-replace-ids = true
Step 4: Test locally with exact release settings
# Clean build
rm -rf target/
scarb --release build
Step 5: Resubmit
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
Scenario 3: Class Hash Mismatch
Error:
[E005] Verification failed: Compiled class hash does not match
Debugging Process:
Step 1: Build locally and check hash
scarb --release build
# Find the contract class file
find target/release -name "*.contract_class.json"
# Check the class hash
cat target/release/my_project_MyContract.contract_class.json | jq -r '.class_hash'
Step 2: Compare hashes
# Expected (from deployment):
0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
# Actual (from local build):
0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19
# ↑ Different!
Step 3: Identify why hashes differ
Possible causes:
-
Wrong source version
git log --oneline git checkout <deployment-commit> -
Different dependencies
# Check if Scarb.lock exists ls Scarb.lock # Use lock file voyager verify --network mainnet \ --class-hash 0x044dc2b3... \ --contract-name MyContract \ --lock-file -
Different compiler settings
# Check deployment vs current settings [profile.release.cairo] sierra-replace-ids = true # Must match deployment
Step 4: Fix and verify
# After fixing issue, rebuild
scarb --release build
# Check hash matches now
cat target/release/my_project_MyContract.contract_class.json | jq -r '.class_hash'
# Should match: 0x044dc2b3...
# Submit verification
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--lock-file
Step-by-Step Debugging
Debug Checklist
Use this checklist for systematic debugging:
Phase 1: Local Validation
# ✅ 1. Does standard build work?
scarb build
# ✅ 2. Does release build work?
scarb --release build
# ✅ 3. Is project metadata valid?
scarb metadata
# ✅ 4. Are you in the right directory?
ls Scarb.toml
Phase 2: Configuration Check
# ✅ 5. Check release profile settings
cat Scarb.toml | grep -A 10 "\[profile.release"
# ✅ 6. Check dependencies
cat Scarb.toml | grep -A 20 "\[dependencies"
# ✅ 7. Check for local path dependencies
cat Scarb.toml | grep "path ="
# ✅ 8. Verify lock file if using
ls Scarb.lock
Phase 3: Dry-Run Validation
# ✅ 9. Preview submission
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--dry-run
# ✅ 10. Check file list is complete
# Look for missing files in output
Phase 4: Submission & Monitoring
# ✅ 11. Submit verification
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--verbose
# ✅ 12. Check status with verbose
voyager status --network mainnet --job <JOB_ID> --verbose
Phase 5: Error Analysis
# ✅ 13. Read error message carefully
# ✅ 14. Check error code in documentation
# ✅ 15. Compare with similar successful verifications
voyager history list --limit 5
Advanced Techniques
Technique 1: Comparing Builds
Compare successful vs failed attempts:
# List history
voyager history list --format json > history.json
# Find successful verification
jq '.[] | select(.status == "Success")' history.json
# Find failed verification
jq '.[] | select(.status == "CompileFailed")' history.json
# Compare parameters
Technique 2: Incremental Testing
Test changes incrementally:
# Baseline (minimal flags)
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
# Test with lock file
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--lock-file
# Test with test files
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files
# Test with both
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--lock-file \
--test-files
Technique 3: Binary Search Debugging
For large projects, isolate the problem:
Step 1: Divide
# Test minimal contract
# Comment out half the code
# Does it build?
Step 2: Conquer
# If minimal works:
# → Problem is in commented code
# If minimal fails:
# → Problem is in active code
Step 3: Repeat Keep dividing until you find the problematic code.
Technique 4: Environment Matching
Ensure local matches remote:
# Check Cairo version
scarb --version
# Check dependencies
cat Scarb.lock | grep -A 5 "starknet"
# Use exact same scarb version as remote
asdf install scarb 2.11.4
asdf local scarb 2.11.4
Prevention Strategies
1. Pre-Submission Checklist
Before every verification:
# 1. Local release build
scarb --release build
# 2. Dry-run preview
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--dry-run
# 3. Check file list makes sense
# 4. Verify class hash format
# 5. Confirm correct network
2. Configuration Best Practices
Use configuration file:
# .voyager.toml
[voyager]
network = "mainnet"
license = "MIT"
lock-file = true # Reproducible builds
verbose = true # Always get details
Document compiler settings:
# Scarb.toml
[profile.release.cairo]
# IMPORTANT: These settings must match deployment
sierra-replace-ids = true
inlining-strategy = "default"
3. Version Control Integration
Tag deployments:
# When deploying
git tag -a v1.0.0-mainnet -m "Mainnet deployment"
git push --tags
# When verifying
git checkout v1.0.0-mainnet
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
Commit lock files:
git add Scarb.lock
git commit -m "Add Scarb.lock for v1.0.0"
4. Testing in Stages
Stage 1: Development (Sepolia)
# Test verification process on testnet first
voyager verify --network sepolia \
--class-hash $DEV_HASH \
--contract-name MyContract \
--verbose
Stage 2: Production (Mainnet)
# Once process is proven, use on mainnet
voyager verify --network mainnet \
--class-hash $PROD_HASH \
--contract-name MyContract \
--lock-file
5. Automation & CI/CD
GitHub Actions Example:
- name: Test Verification (Dry-Run)
run: |
voyager verify \
--network sepolia \
--class-hash ${{ secrets.DEV_CLASS_HASH }} \
--contract-name MyContract \
--dry-run
This catches issues before actual deployment.
Debugging Command Reference
Quick Reference Table
| Scenario | Command | Purpose |
|---|---|---|
| Preview submission | --dry-run | See what files will be sent |
| Get full error | --verbose | See complete compiler output |
| Test local build | scarb --release build | Verify builds locally |
| Check history | voyager history list | Review past attempts |
| Recheck failed | voyager history recheck --failed | Update status of old jobs |
| Compare builds | voyager history list --format json | Analyze patterns |
| Test incrementally | Add flags one at a time | Isolate problematic flag |
| Check metadata | scarb metadata | Validate project structure |
Debugging Examples
Example 1: Full Debug Session
Problem: Verification fails with compilation error
# Step 1: Get error details
$ voyager status --network mainnet --job abc-123 --verbose
Status: CompileFailed
Error: Module file not found: src/tests.cairo
# Step 2: Check local
$ ls src/tests.cairo
src/tests.cairo # File exists locally!
# Step 3: Check what's submitted
$ voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--dry-run
Files excluded (test files):
src/tests.cairo # Aha! Excluded by default
# Step 4: Fix
$ voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files # Include test files
# Step 5: Verify fix
$ voyager status --network mainnet --job def-456
Status: Success ✅
Example 2: Hash Mismatch Debug
Problem: Verification fails - hash mismatch
# Step 1: Build locally
$ scarb --release build
# Step 2: Check local hash
$ cat target/release/my_project_MyContract.contract_class.json | jq -r '.class_hash'
0x055dc2b3... # Different from expected!
# Step 3: Check git history
$ git log --oneline
abc1234 (HEAD) Updated contract # Current
def5678 Deployed to mainnet # Deployment
# Step 4: Checkout deployment version
$ git checkout def5678
# Step 5: Rebuild
$ scarb --release build
# Step 6: Check hash again
$ cat target/release/my_project_MyContract.contract_class.json | jq -r '.class_hash'
0x044dc2b3... # Matches! ✅
# Step 7: Verify
$ voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--lock-file
# Success! ✅
Getting Help
If debugging doesn’t resolve your issue:
-
Document your debugging steps:
- What you tried
- What results you got
- Full error messages with
--verbose
-
Gather information:
# System info voyager --version scarb --version # Project info cat Scarb.toml # Error output voyager status --network mainnet --job <JOB_ID> --verbose -
Check resources:
-
Ask for help:
- Telegram: @StarknetVoyager
- GitHub: Create an issue
Include in your report:
- Full command you ran
- Output with
--verbose - Your Scarb.toml
- Output of
scarb --release build - Steps you’ve already tried
See Also
- Common Errors - Frequent problems and quick fixes
- Verbose Mode - Detailed guide to
--verboseflag - Error Codes Reference - Complete error listing
- Dry-Run Mode - Preview verification submissions
- Getting Support - How to get help
Verbose Mode
The --verbose flag provides detailed error messages and compiler output to help diagnose verification issues.
Quick Navigation:
- Overview
- Enabling Verbose Mode
- What Verbose Mode Shows
- Reading Verbose Output
- Common Scenarios
- Best Practices
Overview
What is Verbose Mode?
Verbose mode displays detailed information that is normally hidden, including:
- Full compiler output
- Complete error messages with context
- Stack traces
- Build process logs
- API response details
When to Use Verbose Mode
Use --verbose when:
- ✅ Compilation fails and you need to see the compiler error
- ✅ Verification fails and you need detailed information
- ✅ You want to understand what went wrong
- ✅ The default error message is unclear
- ✅ Reporting an issue and need complete logs
Don’t use verbose mode when:
- ❌ Everything is working fine (adds unnecessary output)
- ❌ You only need a quick status check
Enabling Verbose Mode
Method 1: Command-Line Flag
Add --verbose or -v to any command:
# Verbose verification
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--verbose
# Verbose status check
voyager status --network mainnet --job <JOB_ID> --verbose
# Short form with -v
voyager status --network mainnet --job <JOB_ID> -v
Method 2: Configuration File
Set as default in .voyager.toml:
[voyager]
network = "mainnet"
license = "MIT"
verbose = true # Always use verbose mode
Then run without the flag:
voyager verify --class-hash 0x044dc2b3... --contract-name MyContract
# Automatically uses verbose mode
Method 3: Environment-Specific Configs
Use verbose in development, not in production:
# .voyager.dev.toml
[voyager]
network = "sepolia"
verbose = true # Verbose for development
# .voyager.prod.toml
[voyager]
network = "mainnet"
verbose = false # Quiet for production
What Verbose Mode Shows
Standard Output vs Verbose Output
Without --verbose (default):
Status: CompileFailed
Error: Compilation failed
With --verbose:
Status: CompileFailed
Error: Compilation failed
Compiler Output:
error[E0005]: Module file not found. Expected path: /tmp/targets/release/src/tests.cairo
--> src/lib.cairo:2:5
|
2 | mod tests;
| ^^^^^
|
Compilation failed with exit code: 1
Information Displayed
1. Full Compiler Output
Compiler Output:
Compiling my_project v0.1.0 (/tmp/targets/release/Scarb.toml)
error[E0005]: Module file not found. Expected path: /tmp/targets/release/src/tests.cairo
--> src/lib.cairo:2:5
|
2 | mod tests;
| ^^^^^
|
2. Error Context
Error: Compilation failed
Context:
Working directory: /tmp/targets/release
Command: scarb --release build
Exit code: 1
3. Build Process Details
Build Information:
Cairo version: 2.11.4
Scarb version: 2.11.4
Profile: release
Target: starknet-contract
4. File Information
Files included:
src/lib.cairo (245 bytes)
src/contract.cairo (1,832 bytes)
Scarb.toml (412 bytes)
Total: 3 files, 2,489 bytes
5. API Response Details
API Response:
Status Code: 200
Job ID: abc-123-def-456
Estimated time: 2-3 minutes
Reading Verbose Output
Structure of Verbose Output
Verbose output follows this structure:
1. Status Summary
Status: CompileFailed
2. High-Level Error
Error: Compilation failed
3. Detailed Information
Compiler Output:
[Full compiler error messages]
4. Context Information
[Build settings, environment, etc.]
Identifying the Problem
Step 1: Read the status
Status: CompileFailed ← What stage failed?
Step 2: Read the high-level error
Error: Compilation failed ← What type of error?
Step 3: Find the specific error in compiler output
Compiler Output:
error[E0005]: Module file not found ← Specific error
Step 4: Locate the source
--> src/lib.cairo:2:5 ← File and line number
Step 5: Understand the context
2 | mod tests; ← The problematic code
| ^^^^^
Common Scenarios
Scenario 1: Module Not Found Error
Command:
voyager status --network mainnet --job abc-123 --verbose
Verbose Output:
Status: CompileFailed
Error: Compilation failed
Compiler Output:
error[E0005]: Module file not found. Expected path: /tmp/targets/release/src/tests.cairo
--> src/lib.cairo:2:5
|
2 | mod tests;
| ^^^^^
|
For more information about this error, try `rustc --explain E0005`.
error: could not compile `my_project` (lib) due to 1 previous error
Interpretation:
- Problem: Module
testsis declared inlib.cairobut file is missing - Location:
src/lib.cairoline 2, column 5 - File expected:
src/tests.cairo - Solution: Add
--test-filesflag or remove module declaration
Scenario 2: Syntax Error
Verbose Output:
Status: CompileFailed
Error: Compilation failed
Compiler Output:
error: expected ';', found `}`
--> src/contract.cairo:15:1
|
14 | let x = 5
| - help: add `;` here
15 | }
| ^
error: aborting due to previous error
Interpretation:
- Problem: Missing semicolon
- Location:
src/contract.cairoline 14 - Fix: Add semicolon after
let x = 5
Scenario 3: Import Error
Verbose Output:
Status: CompileFailed
Error: Compilation failed
Compiler Output:
error[E0433]: failed to resolve: use of undeclared crate or module `utils`
--> src/contract.cairo:1:5
|
1 | use utils::helpers;
| ^^^^^ use of undeclared crate or module `utils`
error: aborting due to previous error
Interpretation:
- Problem: Module
utilsdoesn’t exist or isn’t declared - Location:
src/contract.cairoline 1 - Solution: Check
lib.cairohasmod utils;or fix import path
Scenario 4: Dependency Error
Verbose Output:
Status: CompileFailed
Error: Compilation failed
Compiler Output:
error: failed to download dependency `starknet`
|
= note: unable to get packages from source
Caused by:
failed to parse manifest at `/tmp/targets/release/Scarb.toml`
Caused by:
could not resolve dependency: starknet = "2.99.0"
Interpretation:
- Problem: Dependency version doesn’t exist
- Version:
2.99.0is not available - Solution: Use valid version (e.g.,
2.11.4)
Scenario 5: Verification Failure (Hash Mismatch)
Verbose Output:
Status: VerifyFailed
Error: Verification failed
Details:
Expected class hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Compiled class hash: 0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19
The compiled contract does not match the declared class hash.
Possible causes:
- Source code doesn't match declared contract class
- Different dependency versions
- Different compiler settings
- Different Cairo/Scarb version
Interpretation:
- Problem: Compiled hash doesn’t match expected hash
- Root cause: Source code or environment mismatch
- Solution: Use
--lock-file, check git version, verify compiler settings
Verbose Output Examples
Example 1: Successful Verification
Command:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--verbose
Output:
Submitting verification request...
Files included:
src/lib.cairo (245 bytes)
src/contract.cairo (1,832 bytes)
src/utils.cairo (567 bytes)
Scarb.toml (412 bytes)
Total: 4 files, 3,056 bytes
API Request:
Endpoint: https://api.voyager.online/beta/verify
Network: mainnet
Class Hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Contract Name: MyContract
API Response:
Status: 200 OK
Job ID: abc-123-def-456
Estimated time: 2-3 minutes
✅ Verification request submitted successfully!
Job ID: abc-123-def-456
Use the following command to check status:
voyager status --network mainnet --job abc-123-def-456
Example 2: Failed Compilation with Stack Trace
Command:
voyager status --network mainnet --job abc-123 --verbose
Output:
Status: CompileFailed
Error: Compilation failed
Compiler Output:
Compiling my_project v0.1.0 (/tmp/targets/release/Scarb.toml)
error[E0425]: cannot find value `undefined_var` in this scope
--> src/contract.cairo:23:13
|
23 | let x = undefined_var;
| ^^^^^^^^^^^^^ not found in this scope
error[E0308]: mismatched types
--> src/contract.cairo:45:5
|
45 | return x + y
| ^^^^^^^^^^^^ expected `felt252`, found `()`
|
= note: expected type `felt252`
found unit type `()`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0425`.
error: could not compile `my_project` (lib) due to 2 previous errors
Build Information:
Cairo version: 2.11.4
Scarb version: 2.11.4
Profile: release
Working directory: /tmp/targets/release
Exit code: 1
Key Information:
- Two errors found
- First error: undefined variable (line 23)
- Second error: type mismatch (line 45)
- Cairo/Scarb versions shown
- Exit code indicates failure
Example 3: Network/API Error
Command:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--verbose
Output:
Submitting verification request...
Files included:
src/lib.cairo (245 bytes)
src/contract.cairo (1,832 bytes)
Scarb.toml (412 bytes)
Total: 3 files, 2,494 bytes
API Request:
Endpoint: https://api.voyager.online/beta/verify
Method: POST
Content-Type: multipart/form-data
Content-Length: 3,125 bytes
API Response:
Status: 413 Payload Too Large
Error: Request entity too large
Details:
Maximum allowed size: 10MB
Your payload size: 12.5MB
Suggestion:
- Remove test files (use verification without --test-files)
- Remove lock file (use verification without --lock-file)
- Check for large files in project
Error: [E002] HTTP request failed: https://api.voyager.online/beta/verify returned status 413
Key Information:
- Payload too large (12.5MB > 10MB limit)
- Detailed request information shown
- Suggestions for fixing the issue
Practical Use Cases
Use Case 1: Debugging Compilation Failures
Problem: Verification fails with “Compilation failed”
Without verbose:
$ voyager status --network mainnet --job abc-123
Status: CompileFailed
Error: Compilation failed
❌ Not helpful - what’s wrong?
With verbose:
$ voyager status --network mainnet --job abc-123 --verbose
Status: CompileFailed
Error: Compilation failed
Compiler Output:
error[E0005]: Module file not found. Expected path: /tmp/targets/release/src/tests.cairo
--> src/lib.cairo:2:5
✅ Clear! Missing tests.cairo file
Solution:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files
Use Case 2: Understanding Verification Failures
Problem: Verification fails - why?
With verbose:
$ voyager status --network mainnet --job abc-123 --verbose
Status: VerifyFailed
Error: Verification failed
Details:
Expected: 0x044dc2b3...
Compiled: 0x055dc2b3...
Possible causes:
- Different source code version
- Different dependencies
✅ Hash mismatch - need to check source version
Solution:
git checkout <deployment-commit>
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--lock-file
Use Case 3: Reporting Issues
Scenario: You need to report a bug or ask for help
Without verbose: Limited information
It fails with "Compilation failed"
With verbose: Complete information
$ voyager status --network mainnet --job abc-123 --verbose > error.log
# error.log contains:
# - Full compiler output
# - Error codes and line numbers
# - Build environment details
# - Version information
Share error.log with support team for faster resolution.
Use Case 4: Comparing Successful vs Failed Builds
Successful build with verbose:
$ voyager status --network mainnet --job success-job --verbose > success.log
Failed build with verbose:
$ voyager status --network mainnet --job failed-job --verbose > failed.log
Compare:
$ diff success.log failed.log
# Shows exactly what's different
Best Practices
1. Always Use Verbose for Failures
When something fails, immediately recheck with --verbose:
# Check failed without verbose
$ voyager status --network mainnet --job abc-123
Status: CompileFailed
# Immediately recheck with verbose
$ voyager status --network mainnet --job abc-123 --verbose
# Now you see the actual error!
2. Save Verbose Output to File
For complex issues, save output to a file:
# Save to file
voyager status --network mainnet --job abc-123 --verbose > debug.log
# Review at your leisure
cat debug.log
# Share with others
# Send debug.log to support
3. Use Verbose in Development
Set verbose in development config:
# .voyager.dev.toml
[voyager]
network = "sepolia"
verbose = true # Always verbose in dev
watch = true
# Automatically uses verbose
voyager verify --class-hash 0x044dc2b3... --contract-name MyContract
4. Combine with Other Debug Tools
Use verbose with dry-run for maximum information:
# Preview what will be sent
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--dry-run \
--verbose
# Shows:
# - All files that will be included
# - Full configuration
# - Detailed request preview
5. Don’t Use Verbose Unnecessarily
❌ Don’t: Use verbose for routine successful checks
# Unnecessary verbose for success
voyager status --network mainnet --job abc-123 --verbose
Status: Success
# ... lots of unnecessary output
✅ Do: Use verbose only when investigating issues
# Quick check first
voyager status --network mainnet --job abc-123
Status: CompileFailed
# Then use verbose to debug
voyager status --network mainnet --job abc-123 --verbose
# Now you see why it failed
Verbose Mode Checklist
When using verbose mode for debugging:
Before Using Verbose
- Try command without verbose first
- Note if it succeeded or failed
- Identify what stage failed (submission, compilation, verification)
With Verbose Output
- Read the status (CompileFailed, VerifyFailed, etc.)
- Find the specific error message
- Note the file and line number
- Check the compiler output for details
- Look for suggestions in the output
After Reviewing Verbose
- Understand the root cause
- Identify the fix needed
- Apply the fix
- Test again
- Save verbose output if issue persists
Troubleshooting Verbose Mode
Issue: Too Much Output
Problem: Verbose output is overwhelming
Solution:
# Save to file and search
voyager status --network mainnet --job abc-123 --verbose > output.log
grep "error" output.log
grep "Error" output.log
Issue: Output Not Showing
Problem: --verbose doesn’t seem to work
Check:
# Ensure you're using correct syntax
voyager status --network mainnet --job abc-123 --verbose
# Not:
voyager status --network mainnet --job abc-123 verbose # Missing --
Issue: Need Even More Detail
Problem: Verbose output still not detailed enough
Solution: Check source code or use debugging tools
# Get scarb's verbose output
scarb --release build --verbose
# Check metadata
scarb metadata
Common Verbose Patterns
Pattern 1: File Not Found
error[E0005]: Module file not found
--> src/lib.cairo:X:Y
Solution: Add --test-files or remove module declaration
Pattern 2: Syntax Error
error: expected ';', found `}`
--> src/contract.cairo:X:Y
Solution: Fix syntax in the specified file/line
Pattern 3: Type Mismatch
error[E0308]: mismatched types
--> src/contract.cairo:X:Y
expected `felt252`, found `u256`
Solution: Fix type mismatch
Pattern 4: Import Error
error[E0433]: failed to resolve: use of undeclared module
--> src/contract.cairo:X:Y
Solution: Check module declarations and imports
Pattern 5: Hash Mismatch
Expected class hash: 0x044dc2b3...
Compiled class hash: 0x055dc2b3...
Solution: Use --lock-file, check source version
Quick Reference
Enable Verbose
| Method | Command |
|---|---|
| CLI flag | --verbose or -v |
| Config file | verbose = true in .voyager.toml |
Common Commands
| Task | Command |
|---|---|
| Verbose status | voyager status --network mainnet --job <ID> --verbose |
| Verbose verify | voyager verify --network mainnet ... --verbose |
| Save to file | voyager status ... --verbose > output.log |
| Search output | voyager status ... --verbose | grep "error" |
What to Look For
- Status line - What stage failed?
- Error code - What type of error? (E0005, E0308, etc.)
- File location - Which file and line?
- Error message - What specifically went wrong?
- Suggestions - What does the output recommend?
See Also
- Debugging Guide - Systematic debugging workflow
- Common Errors - Frequent problems and solutions
- Error Codes Reference - Complete error listing
- Getting Support - How to get help
Getting Support
Need help with Voyager Verifier? This guide shows you where to get assistance and how to report issues effectively.
Quick Support Overview
Need Help?
↓
┌────────────────────────────────────────┐
│ Try Self-Help First │
│ • Check documentation │
│ • Review common errors │
│ • Use debugging tools │
└────────────────────────────────────────┘
↓
Still Stuck?
↓
┌────────────────────────────────────────┐
│ Community Support │
│ • Telegram for quick questions │
│ • GitHub for bug reports/features │
└────────────────────────────────────────┘
Self-Help Resources
Before reaching out for help, try these resources:
1. Documentation
Start Here:
# View documentation at:
# https://docs.voyager.nethermind.io
Key Sections:
- Common Errors - Quick fixes for frequent problems
- Debugging Guide - Systematic troubleshooting workflow
- Error Codes - Complete error reference
- Verbose Mode - Understanding detailed output
2. Built-in Help
# General help
voyager verify --help
# Status command help
voyager status --help
# History command help
voyager history --help
3. Dry-Run Mode
Test your command without submitting:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--dry-run
4. Verbose Output
Get detailed error information:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--verbose
Community Support
Telegram Community
Join the Starknet Voyager Telegram group for:
- Quick questions and answers
- Community discussions
- General usage help
- Tips and best practices
Link: https://t.me/StarknetVoyager
When to Use Telegram:
- ✅ Quick questions about usage
- ✅ Clarification on features
- ✅ General troubleshooting help
- ✅ Community discussions
- ❌ Detailed bug reports (use GitHub instead)
- ❌ Feature requests (use GitHub instead)
Tips for Getting Help on Telegram:
- Search First: Check if your question has been asked before
- Be Specific: Include error messages and what you tried
- Share Context: Network, contract details (redact sensitive info)
- Be Patient: Community members help voluntarily
Example Good Question:
I'm getting "Compilation failed" when verifying on mainnet.
Using voyager 0.5.0 with Scarb 2.8.2.
Error: error[E0005]: Module file not found. Expected path: /tmp/.../src/tests.cairo
I tried adding --test-files but still failing. Any ideas?
Example Poor Question:
It doesn't work. Help?
GitHub Issues
Repository: https://github.com/NethermindEth/voyager-verifier
Reporting Bugs
When to Report:
- Tool crashes or hangs
- Incorrect behavior
- Error messages that don’t make sense
- Verification fails when it should succeed
Before Reporting:
-
Search Existing Issues: Your bug might already be reported
- Check open issues:
is:issue is:open - Check closed issues:
is:issue is:closed
- Check open issues:
-
Verify It’s a Bug: Test with minimal reproduction
# Try with verbose mode voyager verify --verbose ... # Try with dry-run voyager verify --dry-run ... -
Gather Information: Collect diagnostic details
How to Report a Bug:
Create a GitHub issue with this template:
## Bug Description
[Clear, concise description of what went wrong]
## Steps to Reproduce
1. Command executed: `voyager verify --network mainnet ...`
2. Expected behavior: [What should happen]
3. Actual behavior: [What actually happened]
## Environment
- Voyager Version: [Run `voyager --version`]
- Operating System: [Linux/macOS/Windows]
- Scarb Version: [Run `scarb --version`]
- Cairo Version: [From Scarb.toml]
## Error Output
[Paste full error output, including –verbose output if available]
## Additional Context
- Config file used (if any)
- Network: mainnet/sepolia/custom
- Project structure (if relevant)
## Reproducible Example
[Link to minimal repository that reproduces the issue, if possible]
Example Bug Report:
## Bug Description
Verification fails with "Class hash mismatch" but hashes are identical
## Steps to Reproduce
1. Run: `voyager verify --network mainnet --class-hash 0x044dc2b3... --contract-name Counter`
2. Expected: Verification succeeds
3. Actual: Error E030: Class hash mismatch
## Environment
- Voyager Version: 0.5.0
- Operating System: Ubuntu 22.04
- Scarb Version: 2.8.2
- Cairo Version: 2.8.2
## Error Output
[E030] Class hash mismatch. Compiled: 0x044dc2b3…, Expected: 0x044dc2b3…
## Additional Context
- Using default config
- Network: mainnet
- Scarb.lock file is present and committed
## Reproducible Example
https://github.com/example/minimal-repro
Requesting Features
When to Request:
- New functionality ideas
- Improvements to existing features
- Better error messages
- Documentation enhancements
How to Request a Feature:
## Feature Description
[Clear description of the proposed feature]
## Use Case
[Why is this feature needed? What problem does it solve?]
## Proposed Solution
[How you envision this working]
## Alternatives Considered
[Other approaches you thought about]
## Additional Context
[Examples, mockups, or related features in other tools]
Example Feature Request:
## Feature Description
Add support for verifying multiple contracts in a single command
## Use Case
When deploying a project with multiple contracts, it's tedious to verify each one separately.
I want to verify all contracts in one command.
## Proposed Solution
```bash
voyager verify --network mainnet \
--batch contracts.json
Where contracts.json contains:
[
{"class_hash": "0x123...", "contract_name": "Counter"},
{"class_hash": "0x456...", "contract_name": "ERC20"}
]
Alternatives Considered
- Using shell scripts to loop through contracts (current workaround)
- Using the batch verification API endpoint directly
Additional Context
Similar to how scarb build handles multiple packages
---
## Before Asking for Help
Complete this checklist before reaching out:
### ✅ Pre-Support Checklist
- [ ] **Read the error message carefully**: What is it telling you?
- [ ] **Check the documentation**: Especially [Common Errors](common-errors.md)
- [ ] **Try verbose mode**: Get detailed output with `--verbose`
- [ ] **Use dry-run mode**: Preview what will be submitted with `--dry-run`
- [ ] **Verify your setup**: Check versions, network, config
- [ ] **Search existing issues**: Has someone else reported this?
- [ ] **Create minimal reproduction**: Simplify to the smallest failing case
- [ ] **Gather version information**: Voyager, Scarb, Cairo versions
---
## What Information to Include
When asking for help, always include:
### Essential Information
```bash
# 1. Voyager version
voyager --version
# 2. Scarb version
scarb --version
# 3. Full command you ran
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
# 4. Full error output (with --verbose)
voyager verify --verbose ...
# 5. Your environment
uname -a # Linux/macOS
# or
ver # Windows
Additional Context
- Network: mainnet, sepolia, or custom endpoint
- Config file: If using
.voyager.toml - Project structure: Multi-package workspace or single package?
- Recent changes: Did this work before? What changed?
- Workarounds tried: What have you attempted so far?
What NOT to Include
- ⚠️ Private keys or secrets
- ⚠️ API keys or tokens
- ⚠️ Sensitive contract code (unless necessary for reproduction)
Redact Sensitive Information:
# Good - Shows structure without exposing secrets
--class-hash 0x044dc2b3...
--endpoint https://api.custom.com
# Bad - Exposes full sensitive data
--class-hash 0x044dc2b3abc123def456789... (full hash when not needed)
--endpoint https://api.company-internal.com/secret-key-abc123
Getting Help Effectively
Do’s ✅
-
Be Specific
❌ "Verification doesn't work" ✅ "Verification fails with E030 (class hash mismatch) on mainnet" -
Provide Context
❌ "Getting an error" ✅ "Getting error E005 (module not found) when verifying a contract with test files in src/tests.cairo. Using --test-files flag." -
Show What You Tried
❌ "How do I fix this?" ✅ "I tried: 1. Adding --test-files flag - still failing 2. Checking file exists - it's there 3. Running with --verbose - shows file path is correct What else should I try?" -
Use Code Blocks
✅ Format commands and output in code blocks for readability -
Follow Up
- If solution works, confirm and thank
- If still stuck, provide additional details requested
- Close GitHub issues when resolved
Don’ts ❌
-
Don’t Spam Multiple Channels
- Choose one channel (Telegram OR GitHub)
- Don’t cross-post the same question immediately
-
Don’t Expect Instant Responses
- Community members help voluntarily
- GitHub issues may take time to triage
-
Don’t Post Huge Logs Without Context
- Provide relevant excerpts
- Use GitHub Gists for very long logs
-
Don’t Hijack Other Threads
- Create a new issue if your problem is different
- Don’t add unrelated questions to existing issues
-
Don’t Give Up Too Quickly
- Work through the debugging checklist
- Try the suggestions provided
Response Times
Typical response times:
| Channel | Type | Expected Response |
|---|---|---|
| Telegram | Quick Question | Minutes to hours |
| Telegram | Complex Issue | Hours to days |
| GitHub | Bug Report | Days to weeks |
| GitHub | Feature Request | Weeks to months |
Remember:
- These are community projects
- Contributors help voluntarily
- Response times vary by complexity and availability
Contributing
Found a bug? Want to improve the tool? Consider contributing!
How to Contribute:
- Report Issues: Detailed bug reports help improve the tool
- Documentation: Suggest improvements or fix typos
- Code: Submit pull requests for bug fixes or features
- Community: Help others on Telegram
See the repository for contribution guidelines: https://github.com/NethermindEth/voyager-verifier
Emergency Support
For critical production issues:
-
Check Status Page: Verify API status
curl https://api.voyager.online/api-docs -
Try Alternative Network: If mainnet fails, test on sepolia
voyager verify --network sepolia ... -
Use Dry-Run: Ensure your submission is correct
voyager verify --dry-run ... -
Report on GitHub: For critical bugs affecting many users
Additional Resources
Official Links
- Documentation: https://docs.voyager.nethermind.io
- GitHub: https://github.com/NethermindEth/voyager-verifier
- Telegram: https://t.me/StarknetVoyager
- Voyager Explorer: https://voyager.online
Related Resources
- Starknet Documentation: https://docs.starknet.io
- Scarb Documentation: https://docs.swmansion.com/scarb
- Cairo Documentation: https://book.cairo-lang.org
Support Quick Reference
| Need | Channel | When to Use |
|---|---|---|
| Quick question | Telegram | General usage, tips |
| Bug report | GitHub Issues | Tool defects |
| Feature request | GitHub Issues | New functionality |
| Documentation | Docs Site | Self-help first |
| API issues | GitHub Issues | API problems |
See Also
- Common Errors - Solutions to frequent problems
- Debugging Guide - Systematic troubleshooting
- Error Codes - Complete error reference
- Verbose Mode - Understanding detailed output
Examples
This section provides practical, end-to-end examples demonstrating how to use voyager-verifier in real-world scenarios. Each example walks through a complete verification workflow, from project setup to successful verification.
Overview
The examples are organized from simple to complex:
- Simple Contract - Basic single-contract verification
- Workspace Project - Multi-package Scarb workspace
- Dojo Project - Dojo project verification
- Multi-Contract Batch - Batch verification for multiple contracts
- CI/CD Pipeline - Automated verification in CI/CD
What You’ll Learn
Each example includes:
- Project Setup - Complete Scarb.toml configuration
- Contract Code - Sample contract implementation
- Verification Steps - Detailed command-line instructions
- Expected Output - What you should see at each step
- Troubleshooting - Common issues and solutions
- Best Practices - Recommended approaches
Prerequisites
Before working through these examples, ensure you have:
- Scarb installed (version 2.x+)
- voyager-verifier installed (see Installation)
- Basic understanding of Cairo and Starknet development
- A Starknet contract class hash (for verification examples)
For Dojo examples, you’ll also need:
- Dojo installed (version 1.x+)
Example Projects
All examples use realistic project structures:
Simple Contract
A basic Starknet contract demonstrating core verification features:
- Single contract file
- Standard Scarb project structure
- Basic storage and external functions
Workspace Project
A multi-package workspace showing:
- Multiple Cairo packages in one repository
- Shared dependencies
- Package selection during verification
Dojo Project
A Dojo world with models and systems:
- Dojo-specific dependencies
- Multiple contracts and components
- Dojo version detection
Batch Verification
Verifying multiple contracts at once:
- Configuration file setup
- Batch submission workflow
- Progress monitoring
CI/CD Integration
Automated verification in continuous integration:
- GitHub Actions workflow
- GitLab CI pipeline
- Environment configuration
Using These Examples
For Learning
If you’re new to voyager-verifier, we recommend following the examples in order:
- Start with Simple Contract to understand the basics
- Progress to Workspace Project for multi-package setups
- Try Dojo Project if you’re using the Dojo framework
- Learn Multi-Contract Batch for efficient bulk verification
- Implement CI/CD Pipeline to automate your workflow
For Reference
If you’re looking for a specific use case:
- “How do I verify my first contract?” → Simple Contract
- “My project has multiple packages” → Workspace Project
- “I’m building with Dojo” → Dojo Project
- “I need to verify many contracts” → Multi-Contract Batch
- “I want to automate verification” → CI/CD Pipeline
For Copy-Paste
Each example includes complete, working code that you can:
- Copy directly into your project
- Modify to fit your needs
- Use as a template for similar scenarios
Example Structure
Each example follows a consistent format:
## Overview
Brief description of what you'll build
## Project Structure
Directory layout and file organization
## Setup
Step-by-step project setup instructions
## Contract Code
Complete contract implementation
## Configuration
Scarb.toml and .voyager.toml setup
## Verification
Detailed verification workflow
## Expected Output
What success looks like
## Troubleshooting
Common issues and solutions
## Next Steps
Where to go from here
Additional Resources
- Command Reference - Complete command documentation
- Configuration Guide - Configuration options
- Troubleshooting - Error resolution
- Best Practices - Recommended workflows
Interactive Learning
For an interactive verification experience, try the wizard mode:
voyager verify --wizard
The wizard guides you through the verification process step-by-step, making it perfect for learning and experimentation.
Getting Help
If you get stuck while working through an example:
- Check the Troubleshooting section in each example
- Review the Troubleshooting Guide
- Use
--verboseflag to see detailed error messages - Try
--dry-runto preview what will be submitted - Reach out to @StarknetVoyager on Telegram
Contributing Examples
Have a useful verification scenario that’s not covered here? Contributions are welcome! See Contributing to Documentation for guidelines.
Ready to start? Begin with the Simple Contract Example →
Simple Contract Example
This example walks through verifying a basic Starknet contract from scratch. It’s perfect for first-time users or as a quick reference for standard verification workflows.
Overview
You’ll learn how to:
- Set up a basic Scarb project
- Write a simple Cairo contract
- Deploy and get a class hash
- Verify the contract using voyager-verifier
- Check verification status
Time Required: 10-15 minutes
Difficulty: Beginner
Project Structure
We’ll create a simple balance contract with this structure:
hello-starknet/
├── Scarb.toml # Project configuration
├── Scarb.lock # Dependency lock file (auto-generated)
├── .voyager.toml # Optional: Verification config
└── src/
└── lib.cairo # Contract implementation
Step 1: Create the Project
Initialize a new Scarb project:
scarb new hello-starknet
cd hello-starknet
This creates a new Cairo project with the basic structure.
Step 2: Configure Scarb.toml
Update your Scarb.toml with the following configuration:
[package]
name = "hello_starknet"
version = "0.1.0"
edition = "2024_07"
license = "MIT" # Add your SPDX license identifier
[dependencies]
starknet = ">=2.8.0"
[[target.starknet-contract]]
sierra = true
[profile.release.cairo]
# Add any compiler configurations needed for deployment here
# sierra-replace-ids = true
# inlining-strategy = "avoid"
Important Notes:
- The
licensefield is optional but recommended - Any compiler configuration for deployment must be under
[profile.release] - The remote verifier uses
scarb --release build
Step 3: Write the Contract
Replace src/lib.cairo with this simple balance contract:
/// Interface representing `HelloStarknet` contract.
/// This interface allows modification and retrieval of the contract balance.
#[starknet::interface]
pub trait IHelloStarknet<TContractState> {
/// Increase contract balance.
fn increase_balance(ref self: TContractState, amount: felt252);
/// Retrieve contract balance.
fn get_balance(self: @TContractState) -> felt252;
}
/// Simple contract for managing balance.
#[starknet::contract]
mod HelloStarknet {
use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess};
#[storage]
struct Storage {
balance: felt252,
}
#[abi(embed_v0)]
impl HelloStarknetImpl of super::IHelloStarknet<ContractState> {
fn increase_balance(ref self: ContractState, amount: felt252) {
assert(amount != 0, 'Amount cannot be 0');
self.balance.write(self.balance.read() + amount);
}
fn get_balance(self: @ContractState) -> felt252 {
self.balance.read()
}
}
}
This contract:
- Stores a
balancevalue - Provides
increase_balance()to increment it - Provides
get_balance()to retrieve it - Includes basic validation
Step 4: Build the Contract
Verify your contract compiles correctly:
scarb build
Expected Output:
Compiling hello_starknet v0.1.0 (~/hello-starknet/Scarb.toml)
Finished release target(s) in 2 seconds
The compiled Sierra JSON will be in target/dev/hello_starknet_HelloStarknet.contract_class.json.
Step 5: Deploy the Contract
Before verifying, you need to deploy your contract and obtain the class hash. There are several ways to deploy:
Option A: Using Starkli
# Declare the contract class
starkli declare target/dev/hello_starknet_HelloStarknet.contract_class.json \
--network mainnet \
--account ~/.starkli-wallets/deployer/account.json \
--keystore ~/.starkli-wallets/deployer/keystore.json
# This will return a class hash like:
# Class hash declared: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Option B: Using Starknet Foundry
sncast declare \
--contract-name HelloStarknet \
--url https://rpc.starknet.lava.build \
--account myaccount
# Save the returned class hash
Option C: Using a Deployment Script
Use your preferred deployment tooling (starknet.py, starknet.js, etc.) and note the class hash from the transaction receipt.
Save Your Class Hash! You’ll need it for verification. For this example, let’s assume:
Class Hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Step 6: Verify the Contract
Now verify your deployed contract using voyager-verifier.
Method 1: Interactive Wizard (Recommended for Beginners)
voyager verify --wizard
The wizard will guide you through:
- Network selection: Choose
mainnet - Class hash: Enter your class hash
- Contract name: Enter
HelloStarknet - License: Confirm
MIT(auto-detected from Scarb.toml) - Optional features: Choose any extras (watch mode, notifications, etc.)
Method 2: Command-Line (Recommended for Automation)
voyager verify \
--network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name HelloStarknet \
--license MIT \
--watch
Flag Explanation:
--network mainnet- Verify on Starknet mainnet--class-hash- The class hash from declaring your contract--contract-name- Contract name from your Cairo code--license MIT- SPDX license identifier (optional if in Scarb.toml)--watch- Wait and display verification progress
Method 3: Using Configuration File
Create .voyager.toml in your project root:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
verbose = false
Then run:
voyager verify \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name HelloStarknet
Step 7: Monitor Verification Status
With Watch Mode
If you used --watch, you’ll see real-time progress:
✓ Verification job submitted
Job ID: abc-123-def-456
⏳ Checking verification status...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% ⏱ 00:45
✓ Verification successful!
╭─────────────────────────────────────────╮
│ Verification Status │
├─────────────────────────────────────────┤
│ Status: Success │
│ Job ID: abc-123-def-456 │
│ Class Hash: 0x044dc2b3... │
│ Contract: HelloStarknet │
│ Network: mainnet │
╰─────────────────────────────────────────╯
View on Voyager: https://voyager.online/class/0x044dc2b3...
Without Watch Mode
If you didn’t use --watch, check status manually:
# Check status
voyager status --network mainnet --job abc-123-def-456
# Or check from history
voyager history status --job abc-123-def-456 --refresh
Step 8: Verify on Voyager Website
Once verification succeeds, visit Voyager and search for your class hash. You should see:
- ✅ Verified badge next to your contract
- Full source code visible
- Contract name and license information
- Compile-time metadata
Expected Output Summary
Successful Verification
✓ Files collected: 1 file (src/lib.cairo)
✓ Project built successfully
✓ Verification job submitted: abc-123-def-456
✓ Status: Success
✓ Contract verified on Voyager
Verification Record in History
voyager history list --limit 1
Output:
╭──────────────────────────────────────────────────────────╮
│ Recent Verifications │
├──────────────────────────────────────────────────────────┤
│ [1] HelloStarknet │
│ Status: ✓ Success │
│ Job: abc-123-def-456 │
│ Network: mainnet │
│ Submitted: 2025-11-06 14:30:00 │
│ Class: 0x044dc2b3... │
╰──────────────────────────────────────────────────────────╯
Troubleshooting
Error: “Compilation failed”
Problem: Remote build failed
Solutions:
- Verify local build works:
scarb --release build - Check
[profile.release]configuration in Scarb.toml - Use
--verboseto see full compiler output:voyager status --network mainnet --job <JOB_ID> --verbose
Error: “Class hash not found”
Problem: Class hash doesn’t exist on the network
Solutions:
- Verify the contract class was actually declared on the network
- Check you’re using the correct network (mainnet vs sepolia)
- Confirm the class hash is correct (no typos)
Error: “License not specified”
Problem: No license provided
Solutions:
- Add
license = "MIT"to[package]in Scarb.toml - Or provide via CLI:
--license MIT - Use a valid SPDX identifier from spdx.org/licenses
Verification Pending for Too Long
Problem: Status stuck at “Pending” or “Compiling”
Solutions:
- Wait a few more minutes (complex contracts take longer)
- Check status with
--verbosefor details - Verify the network isn’t experiencing issues
Best Practices
1. Always Test Build Locally First
Before submitting verification:
# Test release build (same as remote verifier)
scarb --release build
# Verify it builds without errors
echo $? # Should output: 0
2. Use Configuration Files for Consistent Settings
Create .voyager.toml for your project:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
verbose = true
Commit this to version control for your team.
3. Enable Watch Mode for Immediate Feedback
Always use --watch during development:
voyager verify --network sepolia \
--class-hash <HASH> \
--contract-name MyContract \
--watch \
--verbose
4. Use Dry-Run to Preview Submission
Before actual verification:
voyager verify --network mainnet \
--class-hash <HASH> \
--contract-name HelloStarknet \
--dry-run
This shows exactly what files will be sent.
5. Keep Verification Records
The history database tracks all verifications:
# View recent verifications
voyager history list --limit 10
# Filter by status
voyager history list --status success
# Generate statistics
voyager history stats
6. Specify License Explicitly
Even if your Scarb.toml has a license, be explicit:
voyager verify \
--network mainnet \
--class-hash <HASH> \
--contract-name HelloStarknet \
--license MIT # Always explicit
7. Use Desktop Notifications for Long Verifications
For contracts that take time to verify:
voyager verify \
--network mainnet \
--class-hash <HASH> \
--contract-name HelloStarknet \
--watch \
--notify # Get desktop notification when done
Continue working on other tasks and get notified when complete.
Common Variations
Verifying on Sepolia (Testnet)
voyager verify \
--network sepolia \
--class-hash <YOUR_SEPOLIA_CLASS_HASH> \
--contract-name HelloStarknet \
--watch
Using Custom API Endpoint
voyager verify \
--url https://custom-api.example.com/beta \
--class-hash <HASH> \
--contract-name HelloStarknet
Including Lock File
For reproducible builds:
voyager verify \
--network mainnet \
--class-hash <HASH> \
--contract-name HelloStarknet \
--lock-file # Include Scarb.lock
Verbose Output for Debugging
voyager verify \
--network mainnet \
--class-hash <HASH> \
--contract-name HelloStarknet \
--verbose # Show detailed logs
Next Steps
Congratulations! You’ve successfully verified your first contract. Here’s what to explore next:
- Workspace Projects - Learn to verify multi-package projects
- Batch Verification - Verify multiple contracts at once
- CI/CD Integration - Automate verification in your pipeline
- Configuration Guide - Deep dive into all configuration options
- History Tracking - Manage verification history
Additional Resources
- Installation Guide - Install voyager-verifier
- Quickstart - Quick reference guide
- Command Reference - Complete verify command options
- Troubleshooting Guide - Comprehensive error resolution
- Supported Versions - Cairo/Scarb compatibility
FAQ
Q: Do I need to verify on both mainnet and sepolia?
A: No. Contracts verified on mainnet automatically appear verified on sepolia.
Q: How long does verification take?
A: Typically 30-60 seconds for simple contracts, longer for complex ones.
Q: Can I verify an already-verified contract?
A: Yes, but it’s unnecessary. The verification status persists.
Q: What if I update my contract?
A: Deploy the new version (new class hash) and verify it separately. Each class hash is unique.
Q: Is verification free?
A: Yes, verification through Voyager is completely free.
Q: Can I verify private/proprietary contracts?
A: Verification makes source code public. Use license = "All Rights Reserved" for proprietary code, but note the source will still be visible.
Have questions? Check the Troubleshooting Guide or reach out on Telegram.
Workspace Project Example
This example demonstrates how to verify contracts in a Scarb workspace containing multiple packages. Workspaces are common in larger projects where you organize related contracts, libraries, and shared code into separate Cairo packages.
Overview
You’ll learn how to:
- Set up a Scarb workspace with multiple packages
- Configure workspace settings for verification
- Specify which package to verify
- Use default package configuration
- Verify different contracts from the same workspace
Time Required: 15-20 minutes
Difficulty: Intermediate
What is a Scarb Workspace?
A Scarb workspace is a collection of one or more Cairo packages that share:
- Common dependencies
- Single
Scarb.lockfile - Unified build configuration
- Shared workspace root
Workspaces are ideal for:
- Protocol suites - Multiple interconnected contracts
- Shared libraries - Common utilities used across contracts
- Modular architecture - Separating concerns into packages
- Monorepo organization - Managing related projects together
Project Structure
We’ll create a DeFi protocol workspace with this structure:
defi-protocol/
├── Scarb.toml # Workspace root configuration
├── Scarb.lock # Shared dependency lock file
├── .voyager.toml # Verification configuration
├── packages/
│ ├── token/ # ERC20 token package
│ │ ├── Scarb.toml
│ │ └── src/
│ │ └── lib.cairo
│ ├── staking/ # Staking contract package
│ │ ├── Scarb.toml
│ │ └── src/
│ │ └── lib.cairo
│ └── common/ # Shared utilities package
│ ├── Scarb.toml
│ └── src/
│ └── lib.cairo
└── README.md
Step 1: Create Workspace Root
Create the workspace directory and root Scarb.toml:
mkdir defi-protocol
cd defi-protocol
Create Scarb.toml in the root directory:
[workspace]
members = [
"packages/common",
"packages/token",
"packages/staking"
]
[workspace.package]
version = "1.0.0"
authors = ["Your Name <your.email@example.com>"]
license = "MIT"
edition = "2024_07"
[workspace.dependencies]
starknet = "2.13.1"
Key Points:
[workspace]defines the workspace structurememberslists all packages in the workspace[workspace.package]sets default metadata for all packages[workspace.dependencies]defines shared dependencies
Step 2: Create Common Utilities Package
Create the shared utilities package:
mkdir -p packages/common/src
Create packages/common/Scarb.toml:
[package]
name = "common"
version.workspace = true
edition.workspace = true
license.workspace = true
[dependencies]
starknet.workspace = true
[[target.starknet-contract]]
sierra = true
Create packages/common/src/lib.cairo:
/// Common utilities and constants used across the protocol
use starknet::ContractAddress;
/// Protocol-wide constants
pub mod constants {
pub const SCALE_FACTOR: u256 = 1000000; // 6 decimals
pub const MAX_FEE_BPS: u16 = 1000; // 10% max fee
}
/// Utility functions
pub trait Math<T> {
fn mul_div(a: T, b: T, c: T) -> T;
}
/// Address validation utilities
pub fn is_valid_address(addr: ContractAddress) -> bool {
addr.into() != 0
}
Step 3: Create Token Package
Create the ERC20 token package:
mkdir -p packages/token/src
Create packages/token/Scarb.toml:
[package]
name = "token"
version.workspace = true
edition.workspace = true
license.workspace = true
[dependencies]
starknet.workspace = true
common = { path = "../common" }
[[target.starknet-contract]]
sierra = true
[profile.release.cairo]
sierra-replace-ids = true
Create packages/token/src/lib.cairo:
use starknet::ContractAddress;
use common::constants::SCALE_FACTOR;
#[starknet::interface]
pub trait IERC20<TContractState> {
fn name(self: @TContractState) -> ByteArray;
fn symbol(self: @TContractState) -> ByteArray;
fn decimals(self: @TContractState) -> u8;
fn total_supply(self: @TContractState) -> u256;
fn balance_of(self: @TContractState, account: ContractAddress) -> u256;
fn transfer(ref self: TContractState, recipient: ContractAddress, amount: u256) -> bool;
}
#[starknet::contract]
pub mod Token {
use starknet::{ContractAddress, get_caller_address};
use starknet::storage::{
Map, StorageMapReadAccess, StorageMapWriteAccess,
StoragePointerReadAccess, StoragePointerWriteAccess
};
#[storage]
struct Storage {
name: ByteArray,
symbol: ByteArray,
decimals: u8,
total_supply: u256,
balances: Map<ContractAddress, u256>,
}
#[constructor]
fn constructor(
ref self: ContractState,
name: ByteArray,
symbol: ByteArray,
initial_supply: u256,
recipient: ContractAddress
) {
self.name.write(name);
self.symbol.write(symbol);
self.decimals.write(18);
self.total_supply.write(initial_supply);
self.balances.write(recipient, initial_supply);
}
#[abi(embed_v0)]
impl ERC20Impl of super::IERC20<ContractState> {
fn name(self: @ContractState) -> ByteArray {
self.name.read()
}
fn symbol(self: @ContractState) -> ByteArray {
self.symbol.read()
}
fn decimals(self: @ContractState) -> u8 {
self.decimals.read()
}
fn total_supply(self: @ContractState) -> u256 {
self.total_supply.read()
}
fn balance_of(self: @ContractState, account: ContractAddress) -> u256 {
self.balances.read(account)
}
fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool {
let sender = get_caller_address();
let sender_balance = self.balances.read(sender);
assert(sender_balance >= amount, 'Insufficient balance');
self.balances.write(sender, sender_balance - amount);
self.balances.write(recipient, self.balances.read(recipient) + amount);
true
}
}
}
Step 4: Create Staking Package
Create the staking contract package:
mkdir -p packages/staking/src
Create packages/staking/Scarb.toml:
[package]
name = "staking"
version.workspace = true
edition.workspace = true
license.workspace = true
[dependencies]
starknet.workspace = true
common = { path = "../common" }
token = { path = "../token" }
[[target.starknet-contract]]
sierra = true
[profile.release.cairo]
sierra-replace-ids = true
Create packages/staking/src/lib.cairo:
use starknet::ContractAddress;
#[starknet::interface]
pub trait IStaking<TContractState> {
fn stake(ref self: TContractState, amount: u256);
fn unstake(ref self: TContractState, amount: u256);
fn get_staked_balance(self: @TContractState, account: ContractAddress) -> u256;
}
#[starknet::contract]
pub mod Staking {
use starknet::{ContractAddress, get_caller_address};
use starknet::storage::{
Map, StorageMapReadAccess, StorageMapWriteAccess,
StoragePointerReadAccess, StoragePointerWriteAccess
};
use common::is_valid_address;
#[storage]
struct Storage {
token_address: ContractAddress,
staked_balances: Map<ContractAddress, u256>,
total_staked: u256,
}
#[constructor]
fn constructor(ref self: ContractState, token_address: ContractAddress) {
assert(is_valid_address(token_address), 'Invalid token address');
self.token_address.write(token_address);
}
#[abi(embed_v0)]
impl StakingImpl of super::IStaking<ContractState> {
fn stake(ref self: ContractState, amount: u256) {
let caller = get_caller_address();
assert(amount > 0, 'Amount must be positive');
let current_stake = self.staked_balances.read(caller);
self.staked_balances.write(caller, current_stake + amount);
self.total_staked.write(self.total_staked.read() + amount);
}
fn unstake(ref self: ContractState, amount: u256) {
let caller = get_caller_address();
let current_stake = self.staked_balances.read(caller);
assert(current_stake >= amount, 'Insufficient staked balance');
self.staked_balances.write(caller, current_stake - amount);
self.total_staked.write(self.total_staked.read() - amount);
}
fn get_staked_balance(self: @ContractState, account: ContractAddress) -> u256 {
self.staked_balances.read(account)
}
}
}
Step 5: Build the Workspace
Build all packages in the workspace:
scarb build
Expected Output:
Compiling common v1.0.0 (~/defi-protocol/packages/common/Scarb.toml)
Compiling token v1.0.0 (~/defi-protocol/packages/token/Scarb.toml)
Compiling staking v1.0.0 (~/defi-protocol/packages/staking/Scarb.toml)
Finished release target(s) in 3 seconds
All three packages are built together, with dependencies resolved correctly.
Step 6: Deploy Contracts
Deploy the contracts you want to verify. For this example, let’s assume you’ve deployed:
Token Contract:
Class Hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Staking Contract:
Class Hash: 0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19
Step 7: Verify Workspace Contracts
Method 1: Verify with Explicit Package Selection
When verifying workspace contracts, you must specify which package to verify using --package:
# Verify the token contract
voyager verify \
--network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name Token \
--package token \
--watch
# Verify the staking contract
voyager verify \
--network mainnet \
--class-hash 0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19 \
--contract-name Staking \
--package staking \
--watch
Important: Without --package, voyager-verifier won’t know which package to verify in a workspace.
Method 2: Using Configuration File with Default Package
Create .voyager.toml in the workspace root to set a default package:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
verbose = false
[workspace]
default-package = "token" # Set default package for verification
Now you can omit --package for the default:
# Verifies the default package (token)
voyager verify \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name Token
# Still need to specify non-default packages
voyager verify \
--class-hash 0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19 \
--contract-name Staking \
--package staking
Method 3: Batch Verification for Workspace
For multiple contracts in a workspace, use batch verification:
Create .voyager.toml:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
[workspace]
default-package = "token"
# Define all contracts to verify
[[contracts]]
class-hash = "0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18"
contract-name = "Token"
package = "token"
[[contracts]]
class-hash = "0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19"
contract-name = "Staking"
package = "staking"
Then run batch verification:
voyager verify
This verifies both contracts automatically.
Expected Output
Single Package Verification
✓ Workspace detected: 3 packages found
✓ Selected package: token
✓ Building package: token (includes dependency: common)
✓ Files collected: 2 files
- packages/token/src/lib.cairo
- packages/common/src/lib.cairo
✓ Verification job submitted: abc-123-def-456
⏳ Waiting for verification...
✓ Verification successful!
View on Voyager: https://voyager.online/class/0x044dc2b3...
Batch Workspace Verification
[1/2] Verifying: Token (package: token)
✓ Submitted - Job ID: abc-123-def
[2/2] Verifying: Staking (package: staking)
✓ Submitted - Job ID: ghi-456-jkl
════════════════════════════════════════
Batch Verification Summary
════════════════════════════════════════
Total contracts: 2
Submitted: 2
Succeeded: 0
Failed: 0
Pending: 2
════════════════════════════════════════
⏳ Watching verification jobs...
✓ All verifications completed successfully!
Troubleshooting
Error: “Package must be specified for workspace projects”
Problem: Didn’t specify --package flag
Solution:
# Add --package flag
voyager verify \
--network mainnet \
--class-hash <HASH> \
--contract-name Token \
--package token # Required for workspaces!
Or set default-package in .voyager.toml:
[workspace]
default-package = "token"
Error: “Package ‘xyz’ not found in workspace”
Problem: Specified package doesn’t exist or typo in package name
Solutions:
- Check package name matches
[package]name inpackages/xyz/Scarb.toml - Verify package is listed in workspace
membersin rootScarb.toml - Ensure package directory structure is correct
Error: “Dependency resolution failed”
Problem: Package dependencies not found or misconfigured
Solutions:
- Verify
[dependencies]in package Scarb.toml:common = { path = "../common" } # Correct relative path - Check all workspace members are listed in root Scarb.toml
- Run
scarb buildto test dependency resolution
Files from Wrong Package Included
Problem: Incorrect package selected
Solution: Use --dry-run to verify correct files:
voyager verify \
--network mainnet \
--class-hash <HASH> \
--contract-name Token \
--package token \
--dry-run # Preview which files will be sent
Best Practices
1. Use Workspace-Level Configuration
Create .voyager.toml at workspace root:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
lock-file = true # Include Scarb.lock for reproducible builds
[workspace]
default-package = "token" # Most frequently verified package
[[contracts]]
class-hash = "0x044dc2..."
contract-name = "Token"
package = "token"
[[contracts]]
class-hash = "0x055dc2..."
contract-name = "Staking"
package = "staking"
2. Use Workspace Dependencies
Define shared dependencies at workspace level:
# Root Scarb.toml
[workspace.dependencies]
starknet = "2.13.1"
openzeppelin = "0.15.0"
# Package Scarb.toml
[dependencies]
starknet.workspace = true
openzeppelin.workspace = true
This ensures consistent versions across packages.
3. Set Default Package for Primary Contract
If you have a main contract that’s verified often:
[workspace]
default-package = "token" # Your primary contract package
4. Verify All Packages After Changes
When updating shared code (like common), re-verify all dependent contracts:
# Use batch verification
voyager verify # Verifies all contracts in .voyager.toml
5. Use Consistent Naming
Match package names to contract purposes:
packages/
├── token/ # Contains Token contract
├── staking/ # Contains Staking contract
└── governance/ # Contains Governance contract
6. Include Lock File for Workspaces
For workspace projects, always include Scarb.lock:
voyager verify \
--network mainnet \
--class-hash <HASH> \
--contract-name Token \
--package token \
--lock-file # Ensures exact dependency versions
7. Test Individual Package Builds
Before verification, test each package builds correctly:
# Build specific package
scarb build --package token
# Build all packages
scarb build
Common Workspace Patterns
Pattern 1: Shared Library Package
workspace/
├── Scarb.toml
├── packages/
│ ├── lib/ # Shared utilities (not a contract)
│ │ └── src/
│ │ └── lib.cairo
│ ├── token/ # Uses lib
│ └── staking/ # Uses lib
Only verify token and staking (not lib).
Pattern 2: Multiple Contract Implementations
workspace/
├── Scarb.toml
├── packages/
│ ├── erc20/ # ERC20 implementation
│ ├── erc721/ # ERC721 implementation
│ └── erc1155/ # ERC1155 implementation
Verify each contract independently:
[[contracts]]
package = "erc20"
# ...
[[contracts]]
package = "erc721"
# ...
Pattern 3: Protocol Suite
workspace/
├── Scarb.toml
├── packages/
│ ├── core/ # Core protocol logic
│ ├── periphery/ # Helper contracts
│ ├── governance/ # Governance contracts
│ └── utils/ # Shared utilities
Use batch verification for the entire suite.
Next Steps
Now that you understand workspace verification:
- Dojo Projects - Learn Dojo-specific verification
- Batch Verification - Master batch verification for multiple contracts
- CI/CD Integration - Automate workspace verification
- Configuration Guide - Deep dive into workspace configuration
Additional Resources
- Workspace Configuration - Complete workspace settings reference
- Batch Verification - Multiple contract verification
- Scarb Workspaces - Official Scarb workspace documentation
- Project Types - Understanding different project structures
Ready for more advanced examples? Continue to Dojo Project Verification →
Dojo Project Example
This example walks through verifying a Dojo project that includes models and systems. Dojo is a provable game engine built on Starknet, and verifying Dojo contracts requires special handling that voyager-verifier automatically detects and manages.
Overview
You’ll learn how to:
- Set up a Dojo project with models and systems
- Configure Scarb.toml with Dojo-specific settings
- Understand key differences from standard Scarb projects
- Verify Dojo contracts using voyager-verifier
- Handle Dojo world contracts and dependencies
- Troubleshoot Dojo-specific issues
Time Required: 20-25 minutes
Difficulty: Intermediate
What is Dojo?
Dojo is a provable game engine built on Starknet. It provides:
- Entity Component System (ECS) - Efficient game state management
- Models - On-chain data structures with
#[dojo::model]decorator - Systems - Game logic contracts with
#[dojo::contract]decorator - World Contract - Central registry connecting models and systems
- Sozo - Dojo’s build and deployment tool
How Verification Works with Dojo
Voyager-verifier automatically detects Dojo projects by checking for:
dojodependency inScarb.toml- Dojo-specific imports (
use dojo::...) - Dojo decorators (
#[dojo::model],#[dojo::contract])
When detected, it uses sozo build instead of scarb build to ensure proper compilation.
Project Structure
We’ll create a simple game with player movement:
dojo-game/
├── Scarb.toml # Dojo project configuration
├── Scarb.lock # Dependency lock file
├── .voyager.toml # Optional: Verification config
├── dojo_dev.toml # Dojo development config
├── manifest_dev.json # Dojo deployment manifest
└── src/
├── lib.cairo # Module declarations
├── models.cairo # Game models (Position, Moves)
└── systems/
└── actions.cairo # Game systems (spawn, move)
Key Differences from Standard Scarb
1. Cairo Version Specification
Dojo projects must specify an exact Cairo version:
[package]
cairo-version = "2.12.2" # Required for Dojo
2. Sierra Replace IDs
Dojo requires this setting for deterministic builds:
[cairo]
sierra-replace-ids = true # Required for Dojo
3. Dojo Dependencies
Use the dojo dependency instead of individual Dojo packages:
[dependencies]
starknet = "2.12.2"
dojo = "1.7.2" # Single unified dependency
4. World Contract Build
Dojo projects must build the world contract:
[[target.starknet-contract]]
build-external-contracts = ["dojo::world::world_contract::world"]
5. Dojo Macros and Decorators
Models and contracts use special Dojo decorators:
#[dojo::model] // Marks a struct as a Dojo model
pub struct Position { ... }
#[dojo::contract] // Marks a module as a Dojo system
pub mod actions { ... }
Step 1: Create the Project
Initialize a new Dojo project:
# Using Dojo's project initializer
sozo init dojo-game
cd dojo-game
# Or create manually:
mkdir dojo-game
cd dojo-game
Step 2: Configure Scarb.toml
Create or update Scarb.toml with Dojo-specific configuration:
[package]
cairo-version = "2.12.2"
name = "dojo_game"
version = "1.7.2"
edition = "2024_07"
license = "MIT"
[cairo]
sierra-replace-ids = true
[dependencies]
starknet = "2.12.2"
dojo = "1.7.2"
[tool.scarb]
allow-prebuilt-plugins = ["dojo_cairo_macros"]
[[target.starknet-contract]]
build-external-contracts = ["dojo::world::world_contract::world"]
[dev-dependencies]
cairo_test = "2.12.2"
dojo_cairo_test = "1.7.2"
Critical Settings:
cairo-version- Must match your Dojo version’s Cairo requirementsierra-replace-ids = true- Required for deterministic buildsdojodependency - Version should match your Dojo installationbuild-external-contracts- Ensures world contract is built
Step 3: Create the Module Structure
Create src/lib.cairo to declare modules:
pub mod models;
pub mod systems {
pub mod actions;
}
This organizes your models and systems into separate files.
Step 4: Create Game Models
Create src/models.cairo with your game data structures:
use starknet::ContractAddress;
use core::num::traits::{SaturatingAdd, SaturatingSub};
/// Direction enum for player movement
#[derive(Serde, Copy, Drop, Default, Introspect)]
pub enum Direction {
#[default]
Left, // Serialized as 0
Right, // Serialized as 1
Up, // Serialized as 2
Down, // Serialized as 3
}
/// Player position on the game board
#[derive(Copy, Drop, Serde)]
#[dojo::model]
pub struct Position {
#[key]
pub player: ContractAddress,
pub x: u32,
pub y: u32,
}
/// Remaining moves for a player
#[derive(Copy, Drop, Serde)]
#[dojo::model]
pub struct Moves {
#[key]
pub player: ContractAddress,
pub remaining: u8,
}
/// Implementation for applying direction to position
#[generate_trait]
pub impl PositionImpl of PositionTrait {
fn apply_direction(ref self: Position, direction: Direction) {
match direction {
Direction::Left => { self.x = self.x.saturating_sub(1) },
Direction::Right => { self.x = self.x.saturating_add(1) },
Direction::Up => { self.y = self.y.saturating_add(1) },
Direction::Down => { self.y = self.y.saturating_sub(1) },
}
}
}
Key Points:
#[dojo::model]- Registers struct as a Dojo model#[key]- Marks the field used for indexingIntrospect- Required derive for Dojo models
Step 5: Create Game Systems
Create src/systems/actions.cairo with game logic:
use crate::models::Direction;
use starknet::ContractAddress;
#[starknet::interface]
pub trait IActions<T> {
fn spawn(ref self: T);
fn move(ref self: T, direction: Direction);
}
#[dojo::contract]
pub mod actions {
use super::IActions;
use crate::models::{Direction, Moves, Position, PositionTrait};
use core::num::traits::SaturatingSub;
use dojo::model::ModelStorage;
pub const INIT_COORD: u32 = 10;
pub const INIT_REMAINING_MOVES: u8 = 100;
#[abi(embed_v0)]
impl ActionsImpl of IActions<ContractState> {
fn spawn(ref self: ContractState) {
let mut world = self.world_default();
let player = starknet::get_caller_address();
// Create initial position
let position = Position {
player,
x: INIT_COORD,
y: INIT_COORD,
};
// Create initial moves
let moves = Moves {
player,
remaining: INIT_REMAINING_MOVES,
};
// Write to world state
world.write_model(@position);
world.write_model(@moves);
}
fn move(ref self: ContractState, direction: Direction) {
let mut world = self.world_default();
let player = starknet::get_caller_address();
// Update position
let mut position: Position = world.read_model(player);
position.apply_direction(direction);
world.write_model(@position);
// Decrement moves
let mut moves: Moves = world.read_model(player);
moves.remaining = moves.remaining.saturating_sub(1);
world.write_model(@moves);
}
}
#[generate_trait]
impl InternalImpl of InternalTrait {
fn world_default(self: @ContractState) -> dojo::world::WorldStorage {
self.world(@"di")
}
}
}
Key Points:
#[dojo::contract]- Registers module as a Dojo systemworld.read_model()/write_model()- Access Dojo world stateModelStorage- Dojo’s storage interface
Step 6: Build with Dojo
Build your Dojo project using sozo:
sozo build
Expected Output:
Compiling dojo_game v1.7.2 (~/dojo-game/Scarb.toml)
Compiling dojo::world::world_contract v1.7.2
Finished release target(s) in 5 seconds
Dojo builds both your contracts and the world contract.
Step 7: Deploy to Starknet
Deploy your Dojo world to get the contract class hashes:
# Initialize Dojo world on Sepolia testnet
sozo build
sozo migrate --network sepolia
# This creates manifest_dev.json with deployed addresses
The manifest file contains class hashes for:
- World contract - The central world registry
- Models - Position, Moves
- Systems - actions (spawn, move)
Example Class Hashes:
actions contract: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Position model: 0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19
Moves model: 0x066dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da20
World contract: 0x077dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da21
Step 8: Verify Dojo Contracts
Now verify your deployed contracts using voyager-verifier.
Method 1: Automatic Detection (Recommended)
Voyager automatically detects Dojo projects:
voyager verify \
--network sepolia \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name actions \
--watch
Detection Process:
✓ Detected Dojo project (dojo = "1.7.2")
✓ Using sozo build tool
✓ Files collected: 3 files
- src/lib.cairo
- src/models.cairo
- src/systems/actions.cairo
Method 2: Explicit Dojo Type
Explicitly specify Dojo project type:
voyager verify \
--network sepolia \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name actions \
--project-type dojo \
--watch
Method 3: Interactive Mode
Use the wizard for guided verification:
voyager verify --wizard
Select “Dojo project” when prompted for project type.
Method 4: Configuration File
Create .voyager.toml for repeated verifications:
[voyager]
network = "sepolia"
license = "MIT"
watch = true
project-type = "dojo" # Explicitly set Dojo type
# Verify the actions system
[[contracts]]
class-hash = "0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18"
contract-name = "actions"
Then run:
voyager verify
Step 9: Verify Multiple Dojo Contracts
Verify all contracts from your Dojo world at once:
Using Batch Configuration
Create .voyager.toml:
[voyager]
network = "sepolia"
license = "MIT"
watch = true
project-type = "dojo"
# Actions system
[[contracts]]
class-hash = "0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18"
contract-name = "actions"
# Position model contract
[[contracts]]
class-hash = "0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19"
contract-name = "Position"
# Moves model contract
[[contracts]]
class-hash = "0x066dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da20"
contract-name = "Moves"
Run batch verification:
voyager verify
Expected Output:
[1/3] Verifying: actions
✓ Detected Dojo project (dojo = "1.7.2")
✓ Submitted - Job ID: abc-123-def
[2/3] Verifying: Position
✓ Using cached build
✓ Submitted - Job ID: ghi-456-jkl
[3/3] Verifying: Moves
✓ Using cached build
✓ Submitted - Job ID: mno-789-pqr
════════════════════════════════════════
Batch Verification Summary
════════════════════════════════════════
Total contracts: 3
Submitted: 3
Succeeded: 0
Failed: 0
Pending: 3
════════════════════════════════════════
⏳ Watching verification jobs...
✓ All verifications completed successfully!
Expected Output
Successful Dojo Verification
✓ Detected Dojo project automatically
Dojo version: 1.7.2
Cairo version: 2.12.2
Build tool: sozo
✓ Files collected: 3 files
- src/lib.cairo
- src/models.cairo
- src/systems/actions.cairo
✓ Project built successfully (sozo build)
✓ Verification job submitted: abc-123-def-456
⏳ Checking verification status...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% ⏱ 01:15
✓ Verification successful!
╭─────────────────────────────────────────╮
│ Verification Status │
├─────────────────────────────────────────┤
│ Status: Success │
│ Job ID: abc-123-def-456 │
│ Class Hash: 0x044dc2b3... │
│ Contract: actions │
│ Network: sepolia │
│ Build Tool: sozo │
╰─────────────────────────────────────────╯
View on Voyager: https://sepolia.voyager.online/class/0x044dc2b3...
Verification on Voyager Website
Visit Voyager to see:
- Full source code for models and systems
- Dojo version information
- World contract relationships
- Model schemas
- System interfaces
Troubleshooting
Error: “Dojo version not found”
Problem: Cannot detect Dojo version from Scarb.toml
Solutions:
-
Add explicit Dojo dependency:
[dependencies] dojo = "1.7.2" # Explicit version -
Or use
--project-type dojoflag:voyager verify \ --network sepolia \ --class-hash <HASH> \ --contract-name actions \ --project-type dojo -
Check Dojo installation:
sozo --version
Error: “sierra-replace-ids not enabled”
Problem: Build fails because sierra-replace-ids is missing
Solution: Add to Scarb.toml:
[cairo]
sierra-replace-ids = true
This is required for all Dojo projects.
Error: “Cairo version mismatch”
Problem: Cairo version incompatible with Dojo version
Solutions:
-
Check compatibility:
- Dojo 1.7.x requires Cairo 2.12.x
- Dojo 2.0.x requires Cairo 2.13.x+
-
Update
cairo-versioninScarb.toml:[package] cairo-version = "2.12.2" # Match Dojo requirements -
Verify locally first:
sozo build # Should succeed without errors
Error: “sozo command not found”
Problem: Dojo not installed or not in PATH
Solutions:
-
Install Dojo:
curl -L https://install.dojoengine.org | bash dojoup -
Verify installation:
sozo --version -
Note: Voyager can still verify Dojo projects even if sozo isn’t installed locally (remote build handles it)
Error: “World contract verification failed”
Problem: Trying to verify the world contract itself
Solution: You typically don’t need to verify the world contract separately. Focus on verifying:
- Your game systems (contracts)
- Your models (if deployed as separate contracts)
The world contract is a standard Dojo component that doesn’t need individual verification.
Error: “Build-external-contracts missing”
Problem: World contract not being built
Solution: Add to Scarb.toml:
[[target.starknet-contract]]
build-external-contracts = ["dojo::world::world_contract::world"]
Verification Takes Longer Than Expected
Problem: Dojo projects have more dependencies and take longer to compile
Expected Times:
- Simple Dojo project: 1-2 minutes
- Complex Dojo world: 3-5 minutes
Tips:
- Always use
--watchto monitor progress - Use
--verboseto see build output - Check status with
voyager history status --job <JOB_ID>
Error: “Dojo plugin version mismatch”
Problem: Cairo macros plugin version doesn’t match Dojo version
Solution: Ensure versions match in Scarb.toml:
[package]
version = "1.7.2" # Match Dojo version
[dependencies]
dojo = "1.7.2" # Same version
[tool.scarb]
allow-prebuilt-plugins = ["dojo_cairo_macros"]
Best Practices
1. Always Specify Cairo Version
Dojo requires exact Cairo versions:
[package]
cairo-version = "2.12.2" # Required, not optional
2. Use sierra-replace-ids
Always enable this for Dojo:
[cairo]
sierra-replace-ids = true
3. Keep Dojo and Dependencies in Sync
All versions should align:
[package]
version = "1.7.2"
cairo-version = "2.12.2"
[dependencies]
starknet = "2.12.2"
dojo = "1.7.2"
[dev-dependencies]
cairo_test = "2.12.2"
dojo_cairo_test = "1.7.2"
4. Verify Systems, Not Models
Focus verification on:
- Systems (game logic contracts) - Important to verify
- Complex models - If they have custom logic
Skip verification for:
- Simple data models without logic
- Standard Dojo components
5. Use Batch Verification for Worlds
Verify all your game contracts together:
[voyager]
project-type = "dojo"
[[contracts]]
contract-name = "actions"
class-hash = "0x..."
[[contracts]]
contract-name = "items"
class-hash = "0x..."
6. Test Locally Before Verification
Always ensure local build succeeds:
# Clean build
sozo clean
sozo build
# Should complete without errors
echo $? # Should output: 0
7. Use Configuration Files for Complex Worlds
For projects with many contracts, use .voyager.toml:
[voyager]
network = "sepolia"
license = "MIT"
project-type = "dojo"
watch = true
verbose = false
[[contracts]]
# ... all your contracts
Commit this to version control for your team.
8. Verify on Testnet First
Always test on Sepolia before mainnet:
# Deploy to testnet
sozo migrate --network sepolia
# Verify on testnet
voyager verify \
--network sepolia \
--class-hash <SEPOLIA_HASH> \
--contract-name actions
# Only after success, deploy and verify on mainnet
9. Monitor Verification Progress
Use watch mode for immediate feedback:
voyager verify \
--network sepolia \
--class-hash <HASH> \
--contract-name actions \
--watch \
--verbose # See detailed build output
10. Document Your World Structure
Include verification info in your project README:
## Verified Contracts
- **actions**: [View on Voyager](https://sepolia.voyager.online/class/0x044dc2...)
- **items**: [View on Voyager](https://sepolia.voyager.online/class/0x055dc2...)
Common Dojo Patterns
Pattern 1: Simple Game World
dojo-world/
├── Scarb.toml
└── src/
├── lib.cairo
├── models.cairo # All models in one file
└── systems/
└── actions.cairo # Single actions system
Verification:
voyager verify --class-hash <HASH> --contract-name actions
Pattern 2: Complex Multi-System World
dojo-world/
├── Scarb.toml
└── src/
├── lib.cairo
├── models/
│ ├── player.cairo
│ ├── items.cairo
│ └── map.cairo
└── systems/
├── player_actions.cairo
├── combat.cairo
└── trading.cairo
Verification: Use batch .voyager.toml for all systems
Pattern 3: Dojo with External Dependencies
[dependencies]
starknet = "2.12.2"
dojo = "1.7.2"
openzeppelin = "0.15.0" # Additional dependencies work fine
Voyager handles all dependencies automatically.
Next Steps
Congratulations! You’ve successfully verified a Dojo project. Here’s what to explore next:
- Multi-Contract Batch - Efficient batch verification for complex worlds
- CI/CD Integration - Automate Dojo verification in your deployment pipeline
- Workspace Projects - Learn about multi-package Scarb workspaces
- Configuration Guide - Deep dive into all configuration options
- History Tracking - Track verification history for your Dojo world
Additional Resources
- Dojo Book - Official Dojo documentation
- Dojo Installation - Install Dojo and sozo
- Supported Versions - Dojo/Cairo compatibility matrix
- Troubleshooting Guide - Comprehensive error resolution
- Command Reference - Complete verify command options
- Dojo Discord - Get help from the Dojo community
- Voyager Telegram - Voyager support channel
FAQ
Q: Do I need to verify the world contract?
A: No, the world contract is a standard Dojo component. Focus on verifying your custom systems and models.
Q: Can I verify Dojo projects without sozo installed?
A: Yes! Voyager handles the build remotely. Local sozo is optional but recommended for testing.
Q: How long does Dojo verification take?
A: Typically 1-2 minutes for simple projects, 3-5 minutes for complex worlds with many models/systems.
Q: What if my Dojo version isn’t detected?
A: Use --project-type dojo to explicitly specify. Voyager will still verify successfully.
Q: Can I use Dojo with workspaces?
A: Yes! Use --package <name> to specify which package in your workspace is the Dojo project.
Q: Should I verify every model?
A: Focus on systems (game logic). Simple data models don’t need verification unless they have complex logic.
Q: What about Dojo plugins and custom macros?
A: Voyager handles standard Dojo macros automatically. Custom plugins should work if they’re in your dependencies.
Q: Can I verify Dojo contracts on mainnet?
A: Yes, use --network mainnet. Always test on Sepolia first to ensure everything works.
Q: How do I verify contracts from older Dojo versions?
A: Specify the exact versions in Scarb.toml. Voyager supports older Dojo versions (check Supported Versions).
Q: What if verification fails with “compilation error”?
A: First verify that sozo build works locally. Check that all versions match and sierra-replace-ids is enabled.
Building a Dojo game? Join the Dojo Discord to connect with other provable game developers!
Multi-Contract Deployment
This example demonstrates batch verification of multiple contracts in a single command. Batch verification is ideal for protocol suites, multi-contract dApps, and team workflows where you need to verify many contracts efficiently.
Overview
You’ll learn how to:
- Configure batch verification with multiple contracts
- Submit and monitor multiple verifications simultaneously
- Use fail-fast mode for critical deployments
- Apply rate limiting with batch delays
- Handle partial failures gracefully
- Combine batch mode with workspace projects
Time Required: 15-20 minutes
Difficulty: Intermediate
What is Batch Verification?
Batch verification allows you to verify multiple contracts in a single command by defining them in your .voyager.toml configuration file. Instead of running separate verify commands for each contract, batch mode:
- Submits multiple contracts sequentially - Processes contracts one by one
- Tracks all jobs individually - Each contract gets its own job ID
- Continues on error by default - Optional fail-fast mode available
- Supports rate limiting - Configurable delays between submissions
- Provides comprehensive summaries - Complete batch status at end
- Integrates with watch mode - Real-time monitoring of all jobs
Use Cases
Protocol Suite Deployment
Deploy an entire DeFi protocol with interconnected contracts:
- Core protocol contract
- Token contracts (ERC20, governance tokens)
- Staking and rewards contracts
- Treasury and timelock contracts
- Governance modules
Multi-Contract dApp
Verify all contracts for a complex application:
- NFT collection contracts
- Marketplace contracts
- Royalty distributor
- Metadata registry
- Access control contracts
Mass Verification After Network Migration
Re-verify all contracts after:
- Network upgrades
- API changes
- Source code updates
- License changes
Team Workflows
Streamline team verification processes:
- Shared configuration in version control
- Consistent verification settings across team
- Automated batch verification in CI/CD
- Simplified deployment workflows
Project Structure
We’ll create a comprehensive DeFi protocol with multiple interconnected contracts:
defi-protocol/
├── Scarb.toml # Project configuration
├── Scarb.lock # Dependency lock file
├── .voyager.toml # Batch verification config
└── src/
├── lib.cairo # Module declarations
├── token.cairo # ERC20 token contract
├── staking.cairo # Staking contract
├── rewards.cairo # Rewards distribution
├── governance.cairo # Governance contract
└── treasury.cairo # Treasury management
Step 1: Create the Project
Initialize a new Scarb project for our protocol:
scarb new defi-protocol
cd defi-protocol
Step 2: Configure Scarb.toml
Update your Scarb.toml:
[package]
name = "defi_protocol"
version = "1.0.0"
edition = "2024_07"
license = "MIT"
[dependencies]
starknet = ">=2.8.0"
[[target.starknet-contract]]
sierra = true
[profile.release.cairo]
sierra-replace-ids = true
Step 3: Create Multiple Contracts
For brevity, we’ll show simplified contract examples. In practice, these would be full implementations.
Token Contract (src/token.cairo)
use starknet::ContractAddress;
#[starknet::interface]
pub trait IToken<TContractState> {
fn name(self: @TContractState) -> ByteArray;
fn symbol(self: @TContractState) -> ByteArray;
fn total_supply(self: @TContractState) -> u256;
fn balance_of(self: @TContractState, account: ContractAddress) -> u256;
fn transfer(ref self: TContractState, recipient: ContractAddress, amount: u256) -> bool;
}
#[starknet::contract]
pub mod Token {
use starknet::{ContractAddress, get_caller_address};
use starknet::storage::{
Map, StorageMapReadAccess, StorageMapWriteAccess,
StoragePointerReadAccess, StoragePointerWriteAccess
};
#[storage]
struct Storage {
name: ByteArray,
symbol: ByteArray,
total_supply: u256,
balances: Map<ContractAddress, u256>,
}
#[constructor]
fn constructor(
ref self: ContractState,
name: ByteArray,
symbol: ByteArray,
initial_supply: u256,
recipient: ContractAddress
) {
self.name.write(name);
self.symbol.write(symbol);
self.total_supply.write(initial_supply);
self.balances.write(recipient, initial_supply);
}
#[abi(embed_v0)]
impl TokenImpl of super::IToken<ContractState> {
fn name(self: @ContractState) -> ByteArray {
self.name.read()
}
fn symbol(self: @ContractState) -> ByteArray {
self.symbol.read()
}
fn total_supply(self: @ContractState) -> u256 {
self.total_supply.read()
}
fn balance_of(self: @ContractState, account: ContractAddress) -> u256 {
self.balances.read(account)
}
fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool {
let sender = get_caller_address();
let sender_balance = self.balances.read(sender);
assert(sender_balance >= amount, 'Insufficient balance');
self.balances.write(sender, sender_balance - amount);
self.balances.write(recipient, self.balances.read(recipient) + amount);
true
}
}
}
Staking Contract (src/staking.cairo)
use starknet::ContractAddress;
#[starknet::interface]
pub trait IStaking<TContractState> {
fn stake(ref self: TContractState, amount: u256);
fn unstake(ref self: TContractState, amount: u256);
fn get_staked_balance(self: @TContractState, account: ContractAddress) -> u256;
fn total_staked(self: @TContractState) -> u256;
}
#[starknet::contract]
pub mod Staking {
use starknet::{ContractAddress, get_caller_address};
use starknet::storage::{
Map, StorageMapReadAccess, StorageMapWriteAccess,
StoragePointerReadAccess, StoragePointerWriteAccess
};
#[storage]
struct Storage {
token_address: ContractAddress,
staked_balances: Map<ContractAddress, u256>,
total_staked: u256,
}
#[constructor]
fn constructor(ref self: ContractState, token_address: ContractAddress) {
self.token_address.write(token_address);
}
#[abi(embed_v0)]
impl StakingImpl of super::IStaking<ContractState> {
fn stake(ref self: ContractState, amount: u256) {
let caller = get_caller_address();
assert(amount > 0, 'Amount must be positive');
let current_stake = self.staked_balances.read(caller);
self.staked_balances.write(caller, current_stake + amount);
self.total_staked.write(self.total_staked.read() + amount);
}
fn unstake(ref self: ContractState, amount: u256) {
let caller = get_caller_address();
let current_stake = self.staked_balances.read(caller);
assert(current_stake >= amount, 'Insufficient staked balance');
self.staked_balances.write(caller, current_stake - amount);
self.total_staked.write(self.total_staked.read() - amount);
}
fn get_staked_balance(self: @ContractState, account: ContractAddress) -> u256 {
self.staked_balances.read(account)
}
fn total_staked(self: @ContractState) -> u256 {
self.total_staked.read()
}
}
}
Rewards Contract (src/rewards.cairo)
use starknet::ContractAddress;
#[starknet::interface]
pub trait IRewards<TContractState> {
fn distribute_rewards(ref self: TContractState, amount: u256);
fn claim_rewards(ref self: TContractState);
fn get_pending_rewards(self: @TContractState, account: ContractAddress) -> u256;
}
#[starknet::contract]
pub mod Rewards {
use starknet::{ContractAddress, get_caller_address};
use starknet::storage::{
Map, StorageMapReadAccess, StorageMapWriteAccess,
StoragePointerReadAccess, StoragePointerWriteAccess
};
#[storage]
struct Storage {
staking_contract: ContractAddress,
pending_rewards: Map<ContractAddress, u256>,
total_distributed: u256,
}
#[constructor]
fn constructor(ref self: ContractState, staking_contract: ContractAddress) {
self.staking_contract.write(staking_contract);
}
#[abi(embed_v0)]
impl RewardsImpl of super::IRewards<ContractState> {
fn distribute_rewards(ref self: ContractState, amount: u256) {
assert(amount > 0, 'Amount must be positive');
self.total_distributed.write(self.total_distributed.read() + amount);
}
fn claim_rewards(ref self: ContractState) {
let caller = get_caller_address();
let rewards = self.pending_rewards.read(caller);
assert(rewards > 0, 'No rewards to claim');
self.pending_rewards.write(caller, 0);
}
fn get_pending_rewards(self: @ContractState, account: ContractAddress) -> u256 {
self.pending_rewards.read(account)
}
}
}
Governance Contract (src/governance.cairo)
use starknet::ContractAddress;
#[starknet::interface]
pub trait IGovernance<TContractState> {
fn propose(ref self: TContractState, description: ByteArray);
fn vote(ref self: TContractState, proposal_id: u256, support: bool);
fn execute(ref self: TContractState, proposal_id: u256);
}
#[starknet::contract]
pub mod Governance {
use starknet::{ContractAddress, get_caller_address};
use starknet::storage::{
Map, StorageMapReadAccess, StorageMapWriteAccess,
StoragePointerReadAccess, StoragePointerWriteAccess
};
#[storage]
struct Storage {
token_address: ContractAddress,
proposal_count: u256,
proposals: Map<u256, ByteArray>,
}
#[constructor]
fn constructor(ref self: ContractState, token_address: ContractAddress) {
self.token_address.write(token_address);
}
#[abi(embed_v0)]
impl GovernanceImpl of super::IGovernance<ContractState> {
fn propose(ref self: ContractState, description: ByteArray) {
let proposal_id = self.proposal_count.read() + 1;
self.proposals.write(proposal_id, description);
self.proposal_count.write(proposal_id);
}
fn vote(ref self: ContractState, proposal_id: u256, support: bool) {
assert(proposal_id <= self.proposal_count.read(), 'Invalid proposal ID');
// Vote logic here
}
fn execute(ref self: ContractState, proposal_id: u256) {
assert(proposal_id <= self.proposal_count.read(), 'Invalid proposal ID');
// Execution logic here
}
}
}
Treasury Contract (src/treasury.cairo)
use starknet::ContractAddress;
#[starknet::interface]
pub trait ITreasury<TContractState> {
fn deposit(ref self: TContractState, amount: u256);
fn withdraw(ref self: TContractState, amount: u256, recipient: ContractAddress);
fn get_balance(self: @TContractState) -> u256;
}
#[starknet::contract]
pub mod Treasury {
use starknet::{ContractAddress, get_caller_address};
use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess};
#[storage]
struct Storage {
governance_address: ContractAddress,
balance: u256,
}
#[constructor]
fn constructor(ref self: ContractState, governance_address: ContractAddress) {
self.governance_address.write(governance_address);
}
#[abi(embed_v0)]
impl TreasuryImpl of super::ITreasury<ContractState> {
fn deposit(ref self: ContractState, amount: u256) {
assert(amount > 0, 'Amount must be positive');
self.balance.write(self.balance.read() + amount);
}
fn withdraw(ref self: ContractState, amount: u256, recipient: ContractAddress) {
let caller = get_caller_address();
assert(caller == self.governance_address.read(), 'Only governance can withdraw');
assert(amount <= self.balance.read(), 'Insufficient balance');
self.balance.write(self.balance.read() - amount);
}
fn get_balance(self: @ContractState) -> u256 {
self.balance.read()
}
}
}
Module Declaration (src/lib.cairo)
pub mod token;
pub mod staking;
pub mod rewards;
pub mod governance;
pub mod treasury;
Step 4: Build the Project
Verify all contracts compile correctly:
scarb build
Expected Output:
Compiling defi_protocol v1.0.0 (~/defi-protocol/Scarb.toml)
Finished release target(s) in 4 seconds
Step 5: Declare All Contract Classes
Declare each contract class to Starknet and save the class hashes. Note: Verification requires the class hash from declaration, not contract deployment.
Starknet Distinction:
- Declare - Uploads contract class code to network → produces class hash
- Deploy - Creates instance of a class → produces contract address
- Verification verifies the contract class, not deployed instances
For this example, assume you’ve declared the classes and received:
Token Contract:
Class Hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Staking Contract:
Class Hash: 0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19
Rewards Contract:
Class Hash: 0x066dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da20
Governance Contract:
Class Hash: 0x077dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da21
Treasury Contract:
Class Hash: 0x088dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da22
Setting Up Batch Verification
Method 1: Configuration File Approach (Recommended)
Create .voyager.toml in your project root with all contracts defined:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
lock-file = true
verbose = false
# Define all contracts to verify
[[contracts]]
class-hash = "0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18"
contract-name = "Token"
[[contracts]]
class-hash = "0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19"
contract-name = "Staking"
[[contracts]]
class-hash = "0x066dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da20"
contract-name = "Rewards"
[[contracts]]
class-hash = "0x077dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da21"
contract-name = "Governance"
[[contracts]]
class-hash = "0x088dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da22"
contract-name = "Treasury"
Key Configuration Options:
[voyager]- Global settings applied to all contracts[[contracts]]- Array of contracts to verify (double brackets create array elements)class-hash- Required for each contractcontract-name- Required for each contractpackage- Optional, for workspace projects (see Method 3)
Method 2: Programmatic Approach
For dynamic batch verification, use a script to generate the config:
#!/bin/bash
# generate-batch-config.sh
# Read class hashes from deployment manifest
TOKEN_HASH=$(jq -r '.contracts.token' deployment.json)
STAKING_HASH=$(jq -r '.contracts.staking' deployment.json)
REWARDS_HASH=$(jq -r '.contracts.rewards' deployment.json)
GOVERNANCE_HASH=$(jq -r '.contracts.governance' deployment.json)
TREASURY_HASH=$(jq -r '.contracts.treasury' deployment.json)
# Generate .voyager.toml
cat > .voyager.toml <<EOF
[voyager]
network = "mainnet"
license = "MIT"
watch = true
[[contracts]]
class-hash = "$TOKEN_HASH"
contract-name = "Token"
[[contracts]]
class-hash = "$STAKING_HASH"
contract-name = "Staking"
[[contracts]]
class-hash = "$REWARDS_HASH"
contract-name = "Rewards"
[[contracts]]
class-hash = "$GOVERNANCE_HASH"
contract-name = "Governance"
[[contracts]]
class-hash = "$TREASURY_HASH"
contract-name = "Treasury"
EOF
echo "Generated .voyager.toml for batch verification"
Usage:
chmod +x generate-batch-config.sh
./generate-batch-config.sh
voyager verify
Method 3: Workspace Batch Verification
For workspace projects with multiple packages:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
[workspace]
default-package = "core"
# Contracts from different packages
[[contracts]]
class-hash = "0x044dc2..."
contract-name = "Token"
package = "token" # Specify package explicitly
[[contracts]]
class-hash = "0x055dc2..."
contract-name = "Staking"
package = "staking"
[[contracts]]
class-hash = "0x066dc2..."
contract-name = "CoreLogic"
# Uses default-package = "core"
Configuration Options
Batch-Specific Flags
--fail-fast
Stop batch verification on first failure:
voyager verify --fail-fast
Default behavior (without --fail-fast):
- Continues with remaining contracts if one fails
- All results shown in final summary
- Maximum verification coverage
With --fail-fast:
- Stops immediately when a contract fails
- Remaining contracts are not submitted
- Useful for critical deployment pipelines where order matters
Example:
# Development: continue on error to see all issues
voyager verify --watch
# Production: stop on first failure
voyager verify --fail-fast --watch
--batch-delay <SECONDS>
Add delay between contract submissions for rate limiting:
voyager verify --batch-delay 5
Use cases:
- API rate limiting (avoid overwhelming the verification service)
- Server load management
- Staggered deployments for monitoring
- Large batches (10+ contracts)
Recommended delays:
- Small batches (2-5 contracts): 0-3 seconds
- Medium batches (6-15 contracts): 3-5 seconds
- Large batches (16+ contracts): 5-10 seconds
Example:
# Verify 10 contracts with 5 second delay
voyager verify --batch-delay 5 --watch
--watch
Monitor all verification jobs until completion:
voyager verify --watch
Behavior:
- Submits all contracts first
- Then monitors all jobs concurrently
- Shows real-time progress updates
- Displays final summary when all complete
Output shows:
- Number of succeeded verifications
- Number of pending verifications
- Number of failed verifications
- Updates every 2 seconds
--notify
Get desktop notifications when batch completes:
voyager verify --watch --notify
Requires: --watch flag must be enabled
Notifications:
- Success: “Batch verification completed: 5/5 succeeded”
- Partial: “Batch verification completed: 3/5 succeeded, 2 failed”
- Failure: “Batch verification failed: 0/5 succeeded”
Per-Contract Configuration
Each contract in the [[contracts]] array can have individual settings:
[[contracts]]
class-hash = "0x123..."
contract-name = "Token"
package = "token" # For workspace projects
[[contracts]]
class-hash = "0x456..."
contract-name = "NFT"
package = "nft" # Different package
[[contracts]]
class-hash = "0x789..."
contract-name = "Marketplace"
# package omitted - uses workspace.default-package or auto-detect
Overriding Global Settings
CLI arguments override config file settings:
# Config has network = "mainnet", but verify on sepolia
voyager verify --network sepolia
# Config has watch = false, but enable watch mode
voyager verify --watch
# Override license for this batch
voyager verify --license Apache-2.0
Step-by-Step Batch Verification
Step 1: Create the Configuration File
Create .voyager.toml in your project root:
touch .voyager.toml
Step 2: Define All Contracts to Verify
Edit .voyager.toml:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
lock-file = true
[[contracts]]
class-hash = "0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18"
contract-name = "Token"
[[contracts]]
class-hash = "0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19"
contract-name = "Staking"
[[contracts]]
class-hash = "0x066dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da20"
contract-name = "Rewards"
[[contracts]]
class-hash = "0x077dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da21"
contract-name = "Governance"
[[contracts]]
class-hash = "0x088dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da22"
contract-name = "Treasury"
Step 3: Run Batch Verification
Execute the batch:
voyager verify
That’s it! No additional arguments needed. The tool automatically detects batch mode from the [[contracts]] array.
Step 4: Monitor Progress
With watch = true in config (or --watch flag), you’ll see real-time progress:
[1/5] Verifying: Token
✓ Submitted - Job ID: abc-123-def
[2/5] Verifying: Staking
✓ Submitted - Job ID: ghi-456-jkl
[3/5] Verifying: Rewards
✓ Submitted - Job ID: mno-789-pqr
[4/5] Verifying: Governance
✓ Submitted - Job ID: stu-012-vwx
[5/5] Verifying: Treasury
✓ Submitted - Job ID: yza-345-bcd
════════════════════════════════════════
Batch Verification Summary
════════════════════════════════════════
Total contracts: 5
Submitted: 5
Succeeded: 0
Failed: 0
Pending: 5
════════════════════════════════════════
⏳ Watching 5 verification job(s)...
✓ 2 Succeeded | ⏳ 3 Pending | ✗ 0 Failed
[Updates every 2 seconds...]
Step 5: Handle Failures
If a contract fails, you’ll see it in the summary:
[1/5] Verifying: Token
✗ Failed - Error: Invalid class hash format
[2/5] Verifying: Staking
✓ Submitted - Job ID: ghi-456-jkl
[Continues with remaining contracts...]
To retry failed verifications:
- Fix the issue (e.g., correct class hash)
- Update
.voyager.toml - Run
voyager verifyagain
To verify only specific contracts:
# Remove failed contracts from [[contracts]] array temporarily
# Or comment them out:
# [[contracts]]
# class-hash = "0x044dc2..." # Failed, will fix later
# contract-name = "Token"
Step 6: Verify Results
Once complete, check the final summary:
✓ 5 Succeeded | ⏳ 0 Pending | ✗ 0 Failed
════════════════════════════════════════
Batch Verification Summary
════════════════════════════════════════
Total contracts: 5
Submitted: 5
Succeeded: 5
Failed: 0
Pending: 0
════════════════════════════════════════
Contract Details:
✓ Success Token (Job: abc-123-def)
✓ Success Staking (Job: ghi-456-jkl)
✓ Success Rewards (Job: mno-789-pqr)
✓ Success Governance (Job: stu-012-vwx)
✓ Success Treasury (Job: yza-345-bcd)
Visit Voyager to confirm all contracts show verified badges.
Running Batch Verification
Basic Batch
Simple batch verification with default settings:
voyager verify
Requirements:
.voyager.tomlexists with[[contracts]]arraynetworkspecified in config or via--networkflag- No
--class-hashor--contract-nameflags (these conflict with batch mode)
With Watch Mode
Monitor until completion:
voyager verify --watch
Output:
- Real-time status updates
- Progress bar for each contract
- Final summary when complete
- Exit code 0 on success, non-zero on failure
With Verbose Output
See detailed logs:
voyager verify --watch --verbose
Shows:
- File collection details
- Build output
- API requests/responses
- Detailed error messages
- Useful for debugging failures
With Rate Limiting
Add delays between submissions:
voyager verify --watch --batch-delay 5
Output:
[1/5] Verifying: Token
✓ Submitted - Job ID: abc-123-def
[2/5] Verifying: Staking
⏳ Waiting 5 seconds before next submission...
✓ Submitted - Job ID: ghi-456-jkl
[3/5] Verifying: Rewards
⏳ Waiting 5 seconds before next submission...
✓ Submitted - Job ID: mno-789-pqr
With Fail-Fast Mode
Stop on first failure:
voyager verify --fail-fast --watch
Behavior:
[1/5] Verifying: Token
✗ Failed - Error: Compilation failed
Batch verification stopped due to failure (--fail-fast enabled)
════════════════════════════════════════
Batch Verification Summary
════════════════════════════════════════
Total contracts: 5
Submitted: 1
Succeeded: 0
Failed: 1
Pending: 0
════════════════════════════════════════
Remaining contracts not processed: 4
Combined Options
Use multiple flags together:
voyager verify --watch --batch-delay 3 --verbose --notify
This enables:
- Real-time monitoring (
--watch) - 3-second delays between submissions (
--batch-delay 3) - Detailed logging (
--verbose) - Desktop notification when complete (
--notify)
Output Examples
Submission Phase
As each contract is submitted:
[1/5] Verifying: Token
✓ Files collected: 5 files
✓ Project built successfully
✓ Submitted - Job ID: abc-123-def-456
[2/5] Verifying: Staking
✓ Using cached build
✓ Submitted - Job ID: ghi-789-jkl-012
[3/5] Verifying: Rewards
✓ Using cached build
✓ Submitted - Job ID: mno-345-pqr-678
[4/5] Verifying: Governance
✓ Using cached build
✓ Submitted - Job ID: stu-901-vwx-234
[5/5] Verifying: Treasury
✓ Using cached build
✓ Submitted - Job ID: yza-567-bcd-890
Note: “Using cached build” appears when all contracts use the same source code (common in batch mode).
Watch Phase
Real-time monitoring output:
════════════════════════════════════════
Batch Verification Summary
════════════════════════════════════════
Total contracts: 5
Submitted: 5
Succeeded: 0
Failed: 0
Pending: 5
════════════════════════════════════════
⏳ Watching 5 verification job(s)...
✓ 0 Succeeded | ⏳ 5 Pending | ✗ 0 Failed
[2 seconds later...]
✓ 2 Succeeded | ⏳ 3 Pending | ✗ 0 Failed
[4 seconds later...]
✓ 4 Succeeded | ⏳ 1 Pending | ✗ 0 Failed
[6 seconds later...]
✓ 5 Succeeded | ⏳ 0 Pending | ✗ 0 Failed
✓ All verifications completed successfully!
Summary Output
Final batch summary:
════════════════════════════════════════
Batch Verification Summary
════════════════════════════════════════
Total contracts: 5
Submitted: 5
Succeeded: 5
Failed: 0
Pending: 0
════════════════════════════════════════
Contract Details:
✓ Success Token (Job: abc-123-def)
View: https://voyager.online/class/0x044dc2b3...
✓ Success Staking (Job: ghi-789-jkl)
View: https://voyager.online/class/0x055dc2b3...
✓ Success Rewards (Job: mno-345-pqr)
View: https://voyager.online/class/0x066dc2b3...
✓ Success Governance (Job: stu-901-vwx)
View: https://voyager.online/class/0x077dc2b3...
✓ Success Treasury (Job: yza-567-bcd)
View: https://voyager.online/class/0x088dc2b3...
All verifications completed in 1m 23s
Partial Failure Output
When some contracts fail:
════════════════════════════════════════
Batch Verification Summary
════════════════════════════════════════
Total contracts: 5
Submitted: 5
Succeeded: 3
Failed: 2
Pending: 0
════════════════════════════════════════
Contract Details:
✗ Failed Token - Compilation failed: cannot find 'unknown_module' in 'starknet'
Job ID: abc-123-def
✓ Success Staking (Job: ghi-789-jkl)
View: https://voyager.online/class/0x055dc2b3...
✓ Success Rewards (Job: mno-345-pqr)
View: https://voyager.online/class/0x066dc2b3...
✗ Failed Governance - Class hash not found on network
Job ID: stu-901-vwx
✓ Success Treasury (Job: yza-567-bcd)
View: https://voyager.online/class/0x088dc2b3...
⚠ 2 contracts failed verification. Run with --verbose for details.
Monitoring Batch Progress
Real-Time Monitoring with Watch Mode
Enable watch mode for live updates:
[voyager]
watch = true # In config
Or via CLI:
voyager verify --watch
Output shows:
- Submission progress (1/5, 2/5, etc.)
- Live status counts
- Progress updates every 2 seconds
- Final summary
Manual Status Checks
Check individual job status:
# Check specific job from batch
voyager status --network mainnet --job abc-123-def-456
# Or use history commands
voyager history status --job abc-123-def-456 --refresh
Progress Tracking with History
View batch in history:
# List recent verifications
voyager history list --limit 10
# Filter by status
voyager history list --status success
voyager history list --status fail
# Generate statistics
voyager history stats
Example output:
╭──────────────────────────────────────────────────────────╮
│ Recent Verifications │
├──────────────────────────────────────────────────────────┤
│ [1] Token │
│ Status: ✓ Success │
│ Job: abc-123-def │
│ Network: mainnet │
│ Submitted: 2025-11-06 14:30:00 │
│ │
│ [2] Staking │
│ Status: ✓ Success │
│ Job: ghi-789-jkl │
│ Network: mainnet │
│ Submitted: 2025-11-06 14:30:05 │
│ │
│ [3] Rewards │
│ Status: ✓ Success │
│ Job: mno-345-pqr │
│ Network: mainnet │
│ Submitted: 2025-11-06 14:30:10 │
╰──────────────────────────────────────────────────────────╯
Understanding Progress Indicators
Submission Phase:
[1/5]- Contract 1 of 5 being submitted✓ Submitted- Successfully submitted to verification service✗ Failed- Submission failed (e.g., invalid class hash)
Watch Phase:
✓ N Succeeded- N contracts verified successfully⏳ N Pending- N contracts still compiling/verifying✗ N Failed- N contracts failed verification
Final Status:
✓ Success- Contract verified successfully✗ Failed- Contract verification failed⏳ Pending- Still in progress (shouldn’t happen in final state)
Handling Failures
Continue-on-Error (Default)
By default, batch verification continues even when contracts fail:
voyager verify --watch
Behavior:
- All contracts are attempted
- Failures are logged
- Summary shows all results
- Exit code non-zero if any failed
Use when:
- You want maximum coverage
- Failures are independent
- You’ll fix issues after reviewing all results
Example:
[1/5] Verifying: Token
✗ Failed - Compilation error
[2/5] Verifying: Staking
✓ Submitted - Job ID: ghi-789-jkl
[3/5] Verifying: Rewards
✓ Submitted - Job ID: mno-345-pqr
[4/5] Verifying: Governance
✓ Submitted - Job ID: stu-901-vwx
[5/5] Verifying: Treasury
✓ Submitted - Job ID: yza-567-bcd
Final: 4 succeeded, 1 failed
Fail-Fast Mode
Stop on first failure:
voyager verify --fail-fast --watch
Behavior:
- Stops immediately when a contract fails
- Remaining contracts are NOT submitted
- Useful for ordered deployments
- Exit code non-zero immediately
Use when:
- Contracts have dependencies
- Order matters (e.g., Token must verify before Staking)
- You want to fix issues before continuing
- In CI/CD where you want fast failures
Example:
[1/5] Verifying: Token
✗ Failed - Compilation error
Batch verification stopped due to failure (--fail-fast enabled)
Remaining contracts not processed:
- Staking
- Rewards
- Governance
- Treasury
Retry Strategies
Strategy 1: Fix and Re-run Entire Batch
# Fix the issue in code
vim src/token.cairo
# Rebuild
scarb build
# Run batch again
voyager verify --watch
Note: Previously verified contracts will show “already verified” and skip quickly.
Strategy 2: Verify Failed Contracts Only
# Edit .voyager.toml to remove successful contracts
# Keep only failed ones
[[contracts]]
class-hash = "0x044dc2..."
contract-name = "Token" # This one failed
# Run batch with only failed contracts
voyager verify --watch
Strategy 3: Individual Retry
# Verify failed contract individually
voyager verify \
--network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name Token \
--watch --verbose
Debugging Failed Contracts
Use verbose mode to see detailed errors:
voyager verify --watch --verbose
Verbose output shows:
[1/5] Verifying: Token
✓ Files collected: 5 files
- src/lib.cairo
- src/token.cairo
- src/staking.cairo
- src/rewards.cairo
- src/governance.cairo
Building project...
Error: Compilation failed
Compiler output:
error: Type `unknown_module::UnknownType` not found.
--> src/token.cairo:2:5
|
2 | use unknown_module::UnknownType;
| ^^^^^^^^^^^^^^^
✗ Failed - Compilation failed
Common failure causes:
- Compilation errors - Syntax errors, missing imports
- Invalid class hash - Typo or wrong network
- Class hash not found - Contract class not declared yet
- Network errors - API timeouts, connectivity issues
- License errors - Invalid SPDX identifier
Advanced Patterns
Rate-Limited Batch
For large batches, add delays to avoid overwhelming the API:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
# 20 contracts to verify
[[contracts]]
class-hash = "0x001..."
contract-name = "Contract01"
[[contracts]]
class-hash = "0x002..."
contract-name = "Contract02"
# ... (18 more)
[[contracts]]
class-hash = "0x020..."
contract-name = "Contract20"
Run with rate limiting:
voyager verify --batch-delay 10 --watch
This will:
- Submit one contract
- Wait 10 seconds
- Submit next contract
- Repeat until all submitted
- Then monitor all jobs concurrently
Recommended delays for API rate limiting:
- 10+ contracts: 5-10 second delay
- 20+ contracts: 10-15 second delay
- 50+ contracts: 15-20 second delay
Conditional Verification
Verify only specific contracts from a batch using temporary config:
# Create temporary config for subset
cat > .voyager.tmp.toml <<EOF
[voyager]
network = "mainnet"
license = "MIT"
watch = true
[[contracts]]
class-hash = "0x044dc2..."
contract-name = "Token"
[[contracts]]
class-hash = "0x055dc2..."
contract-name = "Staking"
# Only these two
EOF
# Verify subset
cp .voyager.tmp.toml .voyager.toml
voyager verify
rm .voyager.tmp.toml
Multi-Network Batches
Verify same contracts on different networks:
Mainnet config (.voyager.mainnet.toml):
[voyager]
network = "mainnet"
license = "MIT"
[[contracts]]
class-hash = "0x044dc2..." # Mainnet hash
contract-name = "Token"
[[contracts]]
class-hash = "0x055dc2..." # Mainnet hash
contract-name = "Staking"
Sepolia config (.voyager.sepolia.toml):
[voyager]
network = "sepolia"
license = "MIT"
[[contracts]]
class-hash = "0x066dc2..." # Sepolia hash
contract-name = "Token"
[[contracts]]
class-hash = "0x077dc2..." # Sepolia hash
contract-name = "Staking"
Usage:
# Verify on testnet first
cp .voyager.sepolia.toml .voyager.toml
voyager verify --watch
# Then on mainnet
cp .voyager.mainnet.toml .voyager.toml
voyager verify --watch
Workspace + Batch
Combine workspace projects with batch verification:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
[workspace]
default-package = "core"
# Contracts from different packages
[[contracts]]
class-hash = "0x044dc2..."
contract-name = "CoreToken"
package = "core"
[[contracts]]
class-hash = "0x055dc2..."
contract-name = "CoreGovernance"
package = "core"
[[contracts]]
class-hash = "0x066dc2..."
contract-name = "UtilsHelper"
package = "utils"
[[contracts]]
class-hash = "0x077dc2..."
contract-name = "NFTCollection"
package = "nft"
[[contracts]]
class-hash = "0x088dc2..."
contract-name = "Marketplace"
# Uses default-package = "core"
Project structure:
workspace/
├── .voyager.toml # Batch config above
├── Scarb.toml # Workspace root
└── packages/
├── core/
│ ├── Scarb.toml
│ └── src/
├── utils/
│ ├── Scarb.toml
│ └── src/
└── nft/
├── Scarb.toml
└── src/
Verification:
voyager verify --watch
All contracts from all packages verified in one batch!
Best Practices
1. Test Individually First
Before batch verification, verify one contract works:
# Test single contract first
voyager verify \
--network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name Token \
--watch --verbose
# If successful, proceed with batch
voyager verify
Why: Catches configuration issues early without wasting time on entire batch.
2. Use –dry-run to Preview
Preview batch before submission:
voyager verify --dry-run
Output shows:
- Which contracts will be verified
- What files will be included
- Configuration summary
- No actual submission
3. Enable Watch Mode
Always use watch mode to see final results:
voyager verify --watch
Benefits:
- Real-time progress updates
- Immediate feedback on failures
- Don’t need to manually check status later
- See full summary at end
4. Add Delays for Rate Limiting
For large batches, use delays:
# 10+ contracts: use 5-10 second delay
voyager verify --batch-delay 5 --watch
# 20+ contracts: use 10-15 second delay
voyager verify --batch-delay 10 --watch
Prevents:
- API rate limiting errors
- Server overload
- Network timeouts
5. Use Fail-Fast During Development
During development, stop on first failure:
voyager verify --fail-fast --watch
Benefits:
- Quick feedback on issues
- Don’t waste time submitting bad contracts
- Fix one issue at a time
6. Continue-on-Error in Production
For production deployments, get maximum coverage:
voyager verify --watch
Benefits:
- All contracts attempted
- See all failures at once
- Maximum verification coverage
7. Track with History
Use history commands to monitor batch:
# View batch in history
voyager history list --limit 10
# Check specific contract
voyager history status --job abc-123-def
# Generate statistics
voyager history stats
8. Desktop Notifications
Get notified when batch completes:
voyager verify --watch --notify
Benefits:
- Continue working on other tasks
- Get notification when complete
- No need to monitor terminal
Setup notifications: See Desktop Notifications
9. Version Control Your Config
Commit .voyager.toml to share with team:
git add .voyager.toml
git commit -m "Add batch verification config for DeFi protocol"
git push
Benefits:
- Team consistency
- Reproducible verifications
- Track changes over time
- Easy onboarding for new team members
10. Document Class Hashes
Keep track of deployments in comments:
[voyager]
network = "mainnet"
license = "MIT"
# Token contract - deployed 2025-11-06
[[contracts]]
class-hash = "0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18"
contract-name = "Token"
# Staking contract - deployed 2025-11-06
[[contracts]]
class-hash = "0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19"
contract-name = "Staking"
# Rewards contract - deployed 2025-11-06
[[contracts]]
class-hash = "0x066dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da20"
contract-name = "Rewards"
Troubleshooting
Rate Limiting Errors
Problem: “Rate limit exceeded” or “Too many requests”
Solution:
# Add delays between submissions
voyager verify --batch-delay 10 --watch
Prevention:
- Use
--batch-delayfor large batches - Recommended: 5-10 seconds for 10+ contracts
Partial Failures
Problem: Some contracts verify, others fail
Solution:
# Use verbose mode to see why some failed
voyager verify --watch --verbose
# Check failed contracts individually
voyager verify \
--network mainnet \
--class-hash 0x<FAILED_HASH> \
--contract-name FailedContract \
--watch --verbose
Then:
- Fix issues in failed contracts
- Update
.voyager.tomlto include only failed contracts - Re-run batch
Configuration Errors
Problem: “No contracts defined” or “Invalid configuration”
Solution:
- Check
.voyager.tomlsyntax:
# Correct
[[contracts]]
class-hash = "0x123..."
contract-name = "Token"
# Wrong - single bracket
[contracts] # ❌ Should be [[contracts]]
- Validate TOML:
cat .voyager.toml | toml-lint
- Use example config:
cp .voyager.toml.example .voyager.toml
Network Timeouts
Problem: “Request timeout” or “Network error”
Solution:
# Add delays to reduce load
voyager verify --batch-delay 10 --watch
# Verify smaller batches
# Split large batch into multiple runs
Mixed Success/Failure Handling
Problem: How to handle batch with both successes and failures?
Solution:
View summary:
voyager verify --watch
# See which succeeded and which failed
Retry only failures:
- Note which contracts failed from summary
- Edit
.voyager.tomlto include only failed contracts - Run batch again
Example:
# Original batch: 5 contracts
# 3 succeeded, 2 failed (Token and Governance)
# Updated config with only failures:
[voyager]
network = "mainnet"
license = "MIT"
[[contracts]]
class-hash = "0x044dc2..."
contract-name = "Token" # Failed, retry
[[contracts]]
class-hash = "0x077dc2..."
contract-name = "Governance" # Failed, retry
Batch Mode Not Detected
Problem: Running single verification instead of batch
Solution:
Check:
.voyager.tomlhas[[contracts]]array- Not using
--class-hashor--contract-nameflags - File is in current or parent directory
Verify:
# Should show batch mode
voyager verify --dry-run
Complete Working Example
Here’s a full end-to-end example with all files:
Project Structure
defi-protocol/
├── Scarb.toml
├── Scarb.lock
├── .voyager.toml
├── deployment.json
└── src/
├── lib.cairo
├── token.cairo
├── staking.cairo
├── rewards.cairo
├── governance.cairo
└── treasury.cairo
Full .voyager.toml
[voyager]
# Network configuration
network = "mainnet"
# License (SPDX identifier)
license = "MIT"
# Enable watch mode for real-time monitoring
watch = true
# Include Scarb.lock for reproducible builds
lock-file = true
# Verbose output for debugging
verbose = false
# Desktop notifications when batch completes
notify = true
# Token Contract
[[contracts]]
class-hash = "0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18"
contract-name = "Token"
# Staking Contract
[[contracts]]
class-hash = "0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19"
contract-name = "Staking"
# Rewards Contract
[[contracts]]
class-hash = "0x066dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da20"
contract-name = "Rewards"
# Governance Contract
[[contracts]]
class-hash = "0x077dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da21"
contract-name = "Governance"
# Treasury Contract
[[contracts]]
class-hash = "0x088dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da22"
contract-name = "Treasury"
All Contracts Listed
See Step 3 above for full contract implementations.
Expected Output from Start to Finish
$ voyager verify
Output:
Starting batch verification for 5 contracts...
[1/5] Verifying: Token
✓ Files collected: 5 files
- src/lib.cairo
- src/token.cairo
- src/staking.cairo
- src/rewards.cairo
- src/governance.cairo
- src/treasury.cairo
✓ Project built successfully
✓ Verification job submitted
Job ID: abc-123-def-456
Class Hash: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
[2/5] Verifying: Staking
✓ Using cached build
✓ Verification job submitted
Job ID: ghi-789-jkl-012
Class Hash: 0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19
[3/5] Verifying: Rewards
✓ Using cached build
✓ Verification job submitted
Job ID: mno-345-pqr-678
Class Hash: 0x066dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da20
[4/5] Verifying: Governance
✓ Using cached build
✓ Verification job submitted
Job ID: stu-901-vwx-234
Class Hash: 0x077dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da21
[5/5] Verifying: Treasury
✓ Using cached build
✓ Verification job submitted
Job ID: yza-567-bcd-890
Class Hash: 0x088dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da22
════════════════════════════════════════════════════════════════
Batch Verification Summary
════════════════════════════════════════════════════════════════
Total contracts: 5
Submitted: 5
Succeeded: 0
Failed: 0
Pending: 5
════════════════════════════════════════════════════════════════
Contract Details:
⏳ Submitted Token (Job: abc-123-def-456)
⏳ Submitted Staking (Job: ghi-789-jkl-012)
⏳ Submitted Rewards (Job: mno-345-pqr-678)
⏳ Submitted Governance (Job: stu-901-vwx-234)
⏳ Submitted Treasury (Job: yza-567-bcd-890)
⏳ Watching 5 verification job(s)...
✓ 0 Succeeded | ⏳ 5 Pending | ✗ 0 Failed
[Updating every 2 seconds...]
✓ 1 Succeeded | ⏳ 4 Pending | ✗ 0 Failed
✓ 2 Succeeded | ⏳ 3 Pending | ✗ 0 Failed
✓ 3 Succeeded | ⏳ 2 Pending | ✗ 0 Failed
✓ 4 Succeeded | ⏳ 1 Pending | ✗ 0 Failed
✓ 5 Succeeded | ⏳ 0 Pending | ✗ 0 Failed
✓ All verifications completed successfully!
════════════════════════════════════════════════════════════════
Final Batch Verification Summary
════════════════════════════════════════════════════════════════
Total contracts: 5
Submitted: 5
Succeeded: 5
Failed: 0
Pending: 0
════════════════════════════════════════════════════════════════
Contract Details:
✓ Success Token (Job: abc-123-def-456)
Class: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
View: https://voyager.online/class/0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
✓ Success Staking (Job: ghi-789-jkl-012)
Class: 0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19
View: https://voyager.online/class/0x055dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da19
✓ Success Rewards (Job: mno-345-pqr-678)
Class: 0x066dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da20
View: https://voyager.online/class/0x066dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da20
✓ Success Governance (Job: stu-901-vwx-234)
Class: 0x077dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da21
View: https://voyager.online/class/0x077dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da21
✓ Success Treasury (Job: yza-567-bcd-890)
Class: 0x088dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da22
View: https://voyager.online/class/0x088dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da22
════════════════════════════════════════════════════════════════
All 5 contracts verified successfully in 1m 47s
════════════════════════════════════════════════════════════════
Desktop notification sent: "Batch verification completed: 5/5 succeeded"
Verification complete! Visit Voyager to see all contracts with verified badges.
Next Steps
Now that you’ve mastered batch verification:
- CI/CD Integration - Automate batch verification in your deployment pipeline
- Configuration Reference - Deep dive into all configuration options
- History Management - Track and analyze verification history
- Workspace Projects - Combine workspaces with batch verification
- Desktop Notifications - Setup notifications for batch completion
Additional Resources
- Batch Verification Reference - Complete batch mode documentation
- Configuration File Guide - Configuration file reference
- CLI Options Reference - All command-line flags
- Troubleshooting Guide - Comprehensive error resolution
- Simple Contract Example - Basic single-contract verification
- Workspace Example - Multi-package project verification
- Dojo Example - Dojo project verification
Ready to automate? Continue to CI/CD Integration to learn how to integrate batch verification into your deployment pipeline.
CI/CD Pipeline Integration
This example demonstrates how to integrate voyager-verifier into CI/CD pipelines for automated contract verification. Automate verification to ensure every deployment is verified consistently, without manual intervention.
Overview
You’ll learn how to:
- Integrate verification into GitHub Actions, GitLab CI, CircleCI, and Jenkins
- Deploy and verify contracts automatically
- Handle verification failures in CI
- Configure secrets and environment variables
- Use batch verification in CI
- Set up notifications and status reporting
- Implement deployment gates and approval workflows
Time Required: 25-30 minutes
Difficulty: Advanced
Why Automate Verification in CI/CD?
Benefits of Automated Verification
Consistency - Every deployment is verified using the same process, eliminating human error.
Speed - Verification happens automatically during deployment, no manual steps needed.
Transparency - Team can see verification status in CI logs and pull requests.
Quality Gate - Treat verification as a required step, failing builds if verification fails.
Audit Trail - CI systems provide complete logs and history of all verifications.
Team Efficiency - Developers don’t need to remember to verify manually.
When to Verify
After Deployment to Testnet - Verify every testnet deployment to catch issues early.
After Deployment to Mainnet - Critical - ensure mainnet contracts are always verified.
On PR Merges - Verify when code is merged to main/production branches.
On Tagged Releases - Verify official releases automatically.
After Successful Tests - Only verify if deployment tests pass.
Prerequisites
Before setting up CI/CD verification, ensure you have:
- voyager-verifier CLI installed in your CI environment
- Starknet deployment tooling (starkli, sncast, or custom scripts)
- Class hashes from deployment (captured in deployment step)
- Repository secrets/environment variables configured:
- Network selection (mainnet/sepolia)
- Deployment credentials (if needed)
- Class hashes or deployment manifest
Key Concepts
CI/CD Workflow Design
Deploy → Verify Pattern - Most common approach:
- Build contracts with Scarb
- Deploy to Starknet
- Capture class hash from deployment
- Verify with voyager-verifier
- Report results
Verification as Quality Gate - Fail the build if verification fails:
- Use
--watchto wait for completion - Check exit code (0 = success, non-zero = failure)
- Display verification status in logs
- Send notifications on failure
Parallel vs Sequential - Design considerations:
- Sequential: Deploy → Wait → Verify → Complete (safer, slower)
- Parallel: Deploy multiple contracts → Verify all in batch (faster)
Configuration Management
Using .voyager.toml - Commit configuration to repository:
[voyager]
network = "mainnet"
license = "MIT"
watch = true
verbose = true
Environment-Specific Configs - Different configs for dev/staging/prod:
.voyager.dev.toml- For development.voyager.staging.toml- For staging.voyager.prod.toml- For production
Dynamic Configuration - Generate config from deployment output:
- Parse deployment manifest
- Extract class hashes
- Create temporary .voyager.toml
- Run verification
Example 1: GitHub Actions
GitHub Actions is the most popular CI/CD platform for open-source projects. This example shows a complete workflow for deploying and verifying Starknet contracts.
Complete Workflow File
Create .github/workflows/verify-contracts.yml:
name: Deploy and Verify Contracts
on:
push:
branches:
- main
- production
tags:
- 'v*'
pull_request:
branches:
- main
workflow_dispatch:
inputs:
network:
description: 'Network to deploy to'
required: true
default: 'sepolia'
type: choice
options:
- sepolia
- mainnet
env:
SCARB_VERSION: '2.8.4'
VOYAGER_VERSION: '2.0.0'
jobs:
build:
name: Build Contracts
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Scarb
uses: software-mansion/setup-scarb@v1
with:
scarb-version: ${{ env.SCARB_VERSION }}
- name: Build contracts
run: |
scarb --release build
echo "Build completed successfully"
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: compiled-contracts
path: |
target/release/*.json
target/release/*.sierra.json
retention-days: 7
deploy:
name: Deploy Contracts
needs: build
runs-on: ubuntu-latest
environment:
name: ${{ github.event.inputs.network || (github.ref == 'refs/heads/production' && 'mainnet' || 'sepolia') }}
outputs:
class_hash: ${{ steps.deploy.outputs.class_hash }}
network: ${{ steps.set_network.outputs.network }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: compiled-contracts
path: target/release/
- name: Set network
id: set_network
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
echo "network=${{ github.event.inputs.network }}" >> $GITHUB_OUTPUT
elif [ "${{ github.ref }}" == "refs/heads/production" ]; then
echo "network=mainnet" >> $GITHUB_OUTPUT
else
echo "network=sepolia" >> $GITHUB_OUTPUT
fi
- name: Setup Starkli
run: |
curl https://get.starkli.sh | sh
export PATH="$HOME/.starkli/bin:$PATH"
starkliup -v 0.3.5
- name: Deploy contract
id: deploy
env:
STARKNET_ACCOUNT: ${{ secrets.STARKNET_ACCOUNT }}
STARKNET_KEYSTORE: ${{ secrets.STARKNET_KEYSTORE }}
NETWORK: ${{ steps.set_network.outputs.network }}
run: |
export PATH="$HOME/.starkli/bin:$PATH"
# Set RPC URL based on network
if [ "$NETWORK" == "mainnet" ]; then
RPC_URL="https://starknet-mainnet.public.blastapi.io"
else
RPC_URL="https://starknet-sepolia.public.blastapi.io"
fi
# Deploy contract and capture class hash
OUTPUT=$(starkli declare \
target/release/my_contract_MyContract.contract_class.json \
--rpc $RPC_URL \
--account ~/.starkli-wallets/deployer/account.json \
--keystore ~/.starkli-wallets/deployer/keystore.json 2>&1)
echo "$OUTPUT"
# Extract class hash from output
CLASS_HASH=$(echo "$OUTPUT" | grep -oP "Class hash declared: \K0x[0-9a-fA-F]+")
if [ -z "$CLASS_HASH" ]; then
echo "Error: Failed to extract class hash from deployment output"
exit 1
fi
echo "Deployed class hash: $CLASS_HASH"
echo "class_hash=$CLASS_HASH" >> $GITHUB_OUTPUT
# Save deployment info
echo "{\"class_hash\": \"$CLASS_HASH\", \"network\": \"$NETWORK\", \"timestamp\": \"$(date -Iseconds)\"}" > deployment.json
- name: Upload deployment info
uses: actions/upload-artifact@v4
with:
name: deployment-info
path: deployment.json
retention-days: 30
verify:
name: Verify Contracts
needs: deploy
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Scarb
uses: software-mansion/setup-scarb@v1
with:
scarb-version: ${{ env.SCARB_VERSION }}
- name: Install voyager-verifier
run: |
curl -L https://raw.githubusercontent.com/NethermindEth/voyager-verify/main/install.sh | bash
echo "$HOME/.voyager/bin" >> $GITHUB_PATH
- name: Verify version
run: voyager --version
- name: Download deployment info
uses: actions/download-artifact@v4
with:
name: deployment-info
- name: Verify contract
env:
CLASS_HASH: ${{ needs.deploy.outputs.class_hash }}
NETWORK: ${{ needs.deploy.outputs.network }}
run: |
echo "Verifying contract on $NETWORK"
echo "Class hash: $CLASS_HASH"
voyager verify \
--network $NETWORK \
--class-hash $CLASS_HASH \
--contract-name MyContract \
--license MIT \
--watch \
--verbose
VERIFY_EXIT=$?
if [ $VERIFY_EXIT -eq 0 ]; then
echo "✓ Verification successful!"
echo "View on Voyager: https://voyager.online/class/$CLASS_HASH"
else
echo "✗ Verification failed with exit code $VERIFY_EXIT"
exit 1
fi
- name: Comment on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const classHash = '${{ needs.deploy.outputs.class_hash }}';
const network = '${{ needs.deploy.outputs.network }}';
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `### ✅ Contract Verification Complete
**Network:** ${network}
**Class Hash:** \`${classHash}\`
**Status:** Verified ✓
[View on Voyager](https://voyager.online/class/${classHash})`
});
- name: Create verification badge
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/production'
run: |
mkdir -p .github/badges
echo '{"schemaVersion": 1, "label": "contract", "message": "verified", "color": "success"}' > .github/badges/verification.json
notify:
name: Send Notifications
needs: [deploy, verify]
runs-on: ubuntu-latest
if: always()
steps:
- name: Notify Slack
if: success()
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "✅ Contract verified successfully",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Contract Verification Successful*\n\n*Network:* ${{ needs.deploy.outputs.network }}\n*Class Hash:* `${{ needs.deploy.outputs.class_hash }}`\n*Branch:* ${{ github.ref_name }}\n\n<https://voyager.online/class/${{ needs.deploy.outputs.class_hash }}|View on Voyager>"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
- name: Notify on failure
if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "❌ Contract verification failed",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Contract Verification Failed*\n\n*Network:* ${{ needs.deploy.outputs.network }}\n*Branch:* ${{ github.ref_name }}\n\n<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Logs>"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
Features Demonstrated
Matrix Builds - Verify multiple contracts in parallel:
verify:
name: Verify Contracts
needs: deploy
runs-on: ubuntu-latest
strategy:
matrix:
contract:
- name: Token
class_hash: ${{ needs.deploy.outputs.token_hash }}
- name: Staking
class_hash: ${{ needs.deploy.outputs.staking_hash }}
- name: Governance
class_hash: ${{ needs.deploy.outputs.governance_hash }}
steps:
- name: Verify ${{ matrix.contract.name }}
run: |
voyager verify \
--network mainnet \
--class-hash ${{ matrix.contract.class_hash }} \
--contract-name ${{ matrix.contract.name }} \
--watch --verbose
Conditional Verification - Only verify on specific branches:
verify:
name: Verify Contracts
needs: deploy
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')
steps:
- name: Verify contract
run: voyager verify --network mainnet --class-hash $CLASS_HASH --contract-name MyContract --watch
Secrets Management - Secure handling of sensitive data:
- name: Verify contract
env:
# Reference secrets securely
VOYAGER_NETWORK: ${{ secrets.NETWORK }}
CLASS_HASH: ${{ secrets.CLASS_HASH }}
run: |
voyager verify \
--network $VOYAGER_NETWORK \
--class-hash $CLASS_HASH \
--contract-name MyContract \
--watch
Setting Up GitHub Secrets
Configure secrets in your repository:
- Go to Settings → Secrets and variables → Actions
- Add the following secrets:
STARKNET_ACCOUNT- Your Starknet account JSONSTARKNET_KEYSTORE- Your keystore fileSLACK_WEBHOOK_URL- (Optional) For notifications
- Add environment variables (optional):
VOYAGER_NETWORK- Default network (mainnet/sepolia)
Expected Output
Successful Verification:
Run voyager verify \
--network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyContract \
--watch \
--verbose
✓ Files collected: 3 files
✓ Project built successfully
✓ Verification job submitted
Job ID: abc-123-def-456
⏳ Checking verification status...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% ⏱ 00:47
✓ Verification successful!
╭─────────────────────────────────────────╮
│ Verification Status │
├─────────────────────────────────────────┤
│ Status: Success │
│ Job ID: abc-123-def-456 │
│ Class Hash: 0x044dc2b3... │
│ Contract: MyContract │
│ Network: mainnet │
╰─────────────────────────────────────────╯
View on Voyager: https://voyager.online/class/0x044dc2b3...
✓ Verification successful!
View on Voyager: https://voyager.online/class/0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Example 2: GitLab CI
GitLab CI provides built-in CI/CD with powerful pipeline features. This example shows how to integrate verification into GitLab pipelines.
Complete .gitlab-ci.yml
Create .gitlab-ci.yml:
# GitLab CI Pipeline for Starknet Contract Verification
variables:
SCARB_VERSION: "2.8.4"
VOYAGER_VERSION: "2.0.0"
CARGO_HOME: "${CI_PROJECT_DIR}/.cargo"
stages:
- build
- deploy
- verify
- report
# Cache dependencies for faster builds
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- .cargo/
- target/
before_script:
- echo "Starting pipeline for $CI_COMMIT_REF_NAME"
build:contracts:
stage: build
image: ubuntu:22.04
before_script:
- apt-get update && apt-get install -y curl git
script:
- echo "Installing Scarb"
- curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | sh -s -- -v $SCARB_VERSION
- export PATH="$HOME/.local/bin:$PATH"
- echo "Building contracts"
- scarb --version
- scarb --release build
- echo "Build completed successfully"
- ls -la target/release/
artifacts:
name: "compiled-contracts-$CI_COMMIT_SHORT_SHA"
paths:
- target/release/*.json
- target/release/*.sierra.json
expire_in: 1 week
only:
- main
- production
- merge_requests
- tags
deploy:testnet:
stage: deploy
image: ubuntu:22.04
variables:
NETWORK: "sepolia"
environment:
name: testnet
url: https://sepolia.voyager.online
before_script:
- apt-get update && apt-get install -y curl jq
script:
- echo "Deploying to $NETWORK"
# Install starkli
- curl https://get.starkli.sh | sh
- export PATH="$HOME/.starkli/bin:$PATH"
- starkliup -v 0.3.5
# Deploy contract
- |
OUTPUT=$(starkli declare \
target/release/my_contract_MyContract.contract_class.json \
--rpc https://starknet-sepolia.public.blastapi.io \
--account $STARKNET_ACCOUNT_FILE \
--keystore $STARKNET_KEYSTORE_FILE 2>&1)
- echo "$OUTPUT"
# Extract class hash
- CLASS_HASH=$(echo "$OUTPUT" | grep -oP "Class hash declared: \K0x[0-9a-fA-F]+")
- echo "Deployed class hash: $CLASS_HASH"
# Save for next stage
- echo $CLASS_HASH > class_hash.txt
- echo "{\"class_hash\":\"$CLASS_HASH\",\"network\":\"$NETWORK\",\"commit\":\"$CI_COMMIT_SHA\"}" > deployment.json
artifacts:
paths:
- class_hash.txt
- deployment.json
expire_in: 1 month
only:
- main
- merge_requests
deploy:mainnet:
stage: deploy
image: ubuntu:22.04
variables:
NETWORK: "mainnet"
environment:
name: production
url: https://voyager.online
before_script:
- apt-get update && apt-get install -y curl jq
script:
- echo "Deploying to $NETWORK"
# Install starkli
- curl https://get.starkli.sh | sh
- export PATH="$HOME/.starkli/bin:$PATH"
- starkliup -v 0.3.5
# Deploy contract
- |
OUTPUT=$(starkli declare \
target/release/my_contract_MyContract.contract_class.json \
--rpc https://starknet-mainnet.public.blastapi.io \
--account $STARKNET_ACCOUNT_FILE \
--keystore $STARKNET_KEYSTORE_FILE 2>&1)
- echo "$OUTPUT"
# Extract class hash
- CLASS_HASH=$(echo "$OUTPUT" | grep -oP "Class hash declared: \K0x[0-9a-fA-F]+")
- echo "Deployed class hash: $CLASS_HASH"
# Save for next stage
- echo $CLASS_HASH > class_hash.txt
- echo "{\"class_hash\":\"$CLASS_HASH\",\"network\":\"$NETWORK\",\"commit\":\"$CI_COMMIT_SHA\"}" > deployment.json
artifacts:
paths:
- class_hash.txt
- deployment.json
expire_in: 1 month
only:
- production
- tags
when: manual # Require manual approval for mainnet
verify:testnet:
stage: verify
image: ubuntu:22.04
dependencies:
- build:contracts
- deploy:testnet
before_script:
- apt-get update && apt-get install -y curl
script:
- echo "Installing voyager-verifier"
- curl -L https://raw.githubusercontent.com/NethermindEth/voyager-verify/main/install.sh | bash
- export PATH="$HOME/.voyager/bin:$PATH"
- echo "Verifying voyager-verifier installation"
- voyager --version
# Read class hash from artifact
- CLASS_HASH=$(cat class_hash.txt)
- echo "Verifying class hash: $CLASS_HASH"
# Verify contract
- |
voyager verify \
--network sepolia \
--class-hash $CLASS_HASH \
--contract-name MyContract \
--license MIT \
--watch \
--verbose
- |
if [ $? -eq 0 ]; then
echo "✓ Verification successful!"
echo "View on Voyager: https://sepolia.voyager.online/class/$CLASS_HASH"
else
echo "✗ Verification failed"
exit 1
fi
only:
- main
- merge_requests
verify:mainnet:
stage: verify
image: ubuntu:22.04
dependencies:
- build:contracts
- deploy:mainnet
before_script:
- apt-get update && apt-get install -y curl
script:
- echo "Installing voyager-verifier"
- curl -L https://raw.githubusercontent.com/NethermindEth/voyager-verify/main/install.sh | bash
- export PATH="$HOME/.voyager/bin:$PATH"
- echo "Verifying voyager-verifier installation"
- voyager --version
# Read class hash from artifact
- CLASS_HASH=$(cat class_hash.txt)
- echo "Verifying class hash: $CLASS_HASH"
# Verify contract
- |
voyager verify \
--network mainnet \
--class-hash $CLASS_HASH \
--contract-name MyContract \
--license MIT \
--watch \
--verbose
- |
if [ $? -eq 0 ]; then
echo "✓ Verification successful!"
echo "View on Voyager: https://voyager.online/class/$CLASS_HASH"
else
echo "✗ Verification failed"
exit 1
fi
only:
- production
- tags
report:verification:
stage: report
image: alpine:latest
dependencies:
- deploy:mainnet
before_script:
- apk add --no-cache curl jq
script:
- CLASS_HASH=$(cat class_hash.txt)
- NETWORK=$(jq -r '.network' deployment.json)
- echo "Verification Report"
- echo "==================="
- echo "Network: $NETWORK"
- echo "Class Hash: $CLASS_HASH"
- echo "Commit: $CI_COMMIT_SHA"
- echo "Branch: $CI_COMMIT_REF_NAME"
- echo "View: https://voyager.online/class/$CLASS_HASH"
# Create badge
- mkdir -p badges
- echo '{"schemaVersion": 1, "label": "contract", "message": "verified", "color": "success"}' > badges/verification.json
artifacts:
paths:
- badges/
expire_in: 1 year
only:
- production
- tags
Variables & Secrets
Configure in GitLab: Settings → CI/CD → Variables
Protected Variables (only available on protected branches):
STARKNET_ACCOUNT_FILE- Account configurationSTARKNET_KEYSTORE_FILE- Keystore file- Type: File
Regular Variables:
SCARB_VERSION- Scarb version to useVOYAGER_VERSION- voyager-verifier version
Pipeline Status Reporting
GitLab provides built-in status reporting:
# Add status badge to README.md
[](https://gitlab.com/your-username/your-project/-/pipelines)
[](https://voyager.online)
Example 3: CircleCI
CircleCI provides powerful workflow orchestration. This example shows how to verify contracts in CircleCI.
Complete config.yml
Create .circleci/config.yml:
# CircleCI Configuration for Starknet Contract Verification
version: 2.1
orbs:
slack: circleci/slack@4.12.0
executors:
ubuntu-executor:
docker:
- image: ubuntu:22.04
resource_class: medium
working_directory: ~/project
commands:
install-scarb:
description: "Install Scarb"
parameters:
version:
type: string
default: "2.8.4"
steps:
- run:
name: Install Scarb
command: |
apt-get update && apt-get install -y curl
curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | sh -s -- -v << parameters.version >>
echo 'export PATH="$HOME/.local/bin:$PATH"' >> $BASH_ENV
install-voyager:
description: "Install voyager-verifier"
steps:
- run:
name: Install voyager-verifier
command: |
curl -L https://raw.githubusercontent.com/NethermindEth/voyager-verify/main/install.sh | bash
echo 'export PATH="$HOME/.voyager/bin:$PATH"' >> $BASH_ENV
install-starkli:
description: "Install Starkli"
steps:
- run:
name: Install Starkli
command: |
curl https://get.starkli.sh | sh
echo 'export PATH="$HOME/.starkli/bin:$PATH"' >> $BASH_ENV
source $HOME/.starkli/env
starkliup -v 0.3.5
jobs:
build:
executor: ubuntu-executor
steps:
- checkout
- install-scarb:
version: "2.8.4"
- restore_cache:
keys:
- scarb-cache-v1-{{ checksum "Scarb.toml" }}
- scarb-cache-v1-
- run:
name: Build contracts
command: |
scarb --version
scarb --release build
ls -la target/release/
- save_cache:
key: scarb-cache-v1-{{ checksum "Scarb.toml" }}
paths:
- target/
- ~/.cargo/
- persist_to_workspace:
root: .
paths:
- target/release/*.json
- target/release/*.sierra.json
- store_artifacts:
path: target/release/
destination: compiled-contracts
deploy-testnet:
executor: ubuntu-executor
steps:
- checkout
- attach_workspace:
at: .
- install-starkli
- run:
name: Deploy to Sepolia
command: |
OUTPUT=$(starkli declare \
target/release/my_contract_MyContract.contract_class.json \
--rpc https://starknet-sepolia.public.blastapi.io \
--account ~/.starkli-wallets/deployer/account.json \
--keystore ~/.starkli-wallets/deployer/keystore.json 2>&1)
echo "$OUTPUT"
CLASS_HASH=$(echo "$OUTPUT" | grep -oP "Class hash declared: \K0x[0-9a-fA-F]+")
if [ -z "$CLASS_HASH" ]; then
echo "Failed to extract class hash"
exit 1
fi
echo "Deployed class hash: $CLASS_HASH"
echo "$CLASS_HASH" > class_hash.txt
echo "{\"class_hash\":\"$CLASS_HASH\",\"network\":\"sepolia\"}" > deployment.json
- persist_to_workspace:
root: .
paths:
- class_hash.txt
- deployment.json
- store_artifacts:
path: deployment.json
destination: deployment-info
verify-testnet:
executor: ubuntu-executor
steps:
- checkout
- attach_workspace:
at: .
- install-scarb
- install-voyager
- run:
name: Verify contract on Sepolia
command: |
CLASS_HASH=$(cat class_hash.txt)
echo "Verifying class hash: $CLASS_HASH"
voyager verify \
--network sepolia \
--class-hash $CLASS_HASH \
--contract-name MyContract \
--license MIT \
--watch \
--verbose
VERIFY_EXIT=$?
if [ $VERIFY_EXIT -eq 0 ]; then
echo "✓ Verification successful!"
echo "VERIFICATION_STATUS=success" >> verification_result.txt
echo "VOYAGER_URL=https://sepolia.voyager.online/class/$CLASS_HASH" >> verification_result.txt
else
echo "✗ Verification failed"
echo "VERIFICATION_STATUS=failed" >> verification_result.txt
exit 1
fi
- persist_to_workspace:
root: .
paths:
- verification_result.txt
- slack/notify:
event: pass
custom: |
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "✅ *Contract Verified Successfully*\n\n*Network:* Sepolia\n*Class Hash:* `$(cat class_hash.txt)`\n\n<https://sepolia.voyager.online/class/$(cat class_hash.txt)|View on Voyager>"
}
}
]
}
- slack/notify:
event: fail
custom: |
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "❌ *Contract Verification Failed*\n\n*Network:* Sepolia\n*Branch:* $CIRCLE_BRANCH\n\n<$CIRCLE_BUILD_URL|View Logs>"
}
}
]
}
deploy-mainnet:
executor: ubuntu-executor
steps:
- checkout
- attach_workspace:
at: .
- install-starkli
- run:
name: Deploy to Mainnet
command: |
OUTPUT=$(starkli declare \
target/release/my_contract_MyContract.contract_class.json \
--rpc https://starknet-mainnet.public.blastapi.io \
--account ~/.starkli-wallets/deployer/account.json \
--keystore ~/.starkli-wallets/deployer/keystore.json 2>&1)
echo "$OUTPUT"
CLASS_HASH=$(echo "$OUTPUT" | grep -oP "Class hash declared: \K0x[0-9a-fA-F]+")
if [ -z "$CLASS_HASH" ]; then
echo "Failed to extract class hash"
exit 1
fi
echo "Deployed class hash: $CLASS_HASH"
echo "$CLASS_HASH" > class_hash.txt
echo "{\"class_hash\":\"$CLASS_HASH\",\"network\":\"mainnet\"}" > deployment.json
- persist_to_workspace:
root: .
paths:
- class_hash.txt
- deployment.json
verify-mainnet:
executor: ubuntu-executor
steps:
- checkout
- attach_workspace:
at: .
- install-scarb
- install-voyager
- run:
name: Verify contract on Mainnet
command: |
CLASS_HASH=$(cat class_hash.txt)
echo "Verifying class hash: $CLASS_HASH"
voyager verify \
--network mainnet \
--class-hash $CLASS_HASH \
--contract-name MyContract \
--license MIT \
--watch \
--verbose
VERIFY_EXIT=$?
if [ $VERIFY_EXIT -eq 0 ]; then
echo "✓ Verification successful!"
echo "VERIFICATION_STATUS=success" >> verification_result.txt
echo "VOYAGER_URL=https://voyager.online/class/$CLASS_HASH" >> verification_result.txt
else
echo "✗ Verification failed"
echo "VERIFICATION_STATUS=failed" >> verification_result.txt
exit 1
fi
- persist_to_workspace:
root: .
paths:
- verification_result.txt
- slack/notify:
event: pass
custom: |
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "✅ *Contract Verified Successfully*\n\n*Network:* Mainnet\n*Class Hash:* `$(cat class_hash.txt)`\n\n<https://voyager.online/class/$(cat class_hash.txt)|View on Voyager>"
}
}
]
}
workflows:
version: 2
deploy-and-verify:
jobs:
- build
- deploy-testnet:
requires:
- build
filters:
branches:
only:
- main
- develop
- verify-testnet:
requires:
- deploy-testnet
- hold-mainnet-deploy:
type: approval
requires:
- verify-testnet
filters:
branches:
only: main
- deploy-mainnet:
requires:
- hold-mainnet-deploy
- verify-mainnet:
requires:
- deploy-mainnet
Approval Workflows
CircleCI’s hold jobs require manual approval:
- hold-mainnet-deploy:
type: approval
requires:
- verify-testnet
filters:
branches:
only: main
This creates a pause in the workflow where a team member must click “Approve” before mainnet deployment proceeds.
Example 4: Jenkins
Jenkins provides flexible pipeline-as-code with Groovy. This example shows a complete Jenkinsfile for verification.
Jenkinsfile
Create Jenkinsfile:
// Jenkins Pipeline for Starknet Contract Verification
pipeline {
agent any
environment {
SCARB_VERSION = '2.8.4'
VOYAGER_VERSION = '2.0.0'
PATH = "${env.HOME}/.local/bin:${env.HOME}/.voyager/bin:${env.HOME}/.starkli/bin:${env.PATH}"
}
parameters {
choice(
name: 'NETWORK',
choices: ['sepolia', 'mainnet'],
description: 'Network to deploy to'
)
booleanParam(
name: 'SKIP_VERIFICATION',
defaultValue: false,
description: 'Skip verification step'
)
}
stages {
stage('Setup') {
steps {
script {
echo "Setting up environment"
sh 'which curl || apt-get update && apt-get install -y curl'
}
}
}
stage('Install Dependencies') {
parallel {
stage('Install Scarb') {
steps {
script {
sh '''
if ! command -v scarb &> /dev/null; then
curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | sh -s -- -v ${SCARB_VERSION}
fi
scarb --version
'''
}
}
}
stage('Install voyager-verifier') {
steps {
script {
sh '''
if ! command -v voyager &> /dev/null; then
curl -L https://raw.githubusercontent.com/NethermindEth/voyager-verify/main/install.sh | bash
fi
voyager --version
'''
}
}
}
stage('Install Starkli') {
steps {
script {
sh '''
if ! command -v starkli &> /dev/null; then
curl https://get.starkli.sh | sh
starkliup -v 0.3.5
fi
starkli --version
'''
}
}
}
}
}
stage('Build Contracts') {
steps {
script {
echo "Building contracts with Scarb"
sh '''
scarb clean
scarb --release build
ls -la target/release/
'''
}
}
}
stage('Deploy Contract') {
steps {
script {
echo "Deploying to ${params.NETWORK}"
withCredentials([
file(credentialsId: 'starknet-account', variable: 'ACCOUNT_FILE'),
file(credentialsId: 'starknet-keystore', variable: 'KEYSTORE_FILE')
]) {
sh '''
# Set RPC URL based on network
if [ "${NETWORK}" == "mainnet" ]; then
RPC_URL="https://starknet-mainnet.public.blastapi.io"
else
RPC_URL="https://starknet-sepolia.public.blastapi.io"
fi
# Deploy contract
OUTPUT=$(starkli declare \
target/release/my_contract_MyContract.contract_class.json \
--rpc $RPC_URL \
--account $ACCOUNT_FILE \
--keystore $KEYSTORE_FILE 2>&1)
echo "$OUTPUT"
# Extract class hash
CLASS_HASH=$(echo "$OUTPUT" | grep -oP "Class hash declared: \\K0x[0-9a-fA-F]+")
if [ -z "$CLASS_HASH" ]; then
echo "Error: Failed to extract class hash"
exit 1
fi
echo "Deployed class hash: $CLASS_HASH"
echo "$CLASS_HASH" > class_hash.txt
# Save deployment info
echo "{\\"class_hash\\":\\"$CLASS_HASH\\",\\"network\\":\\"${NETWORK}\\",\\"timestamp\\":\\"$(date -Iseconds)\\"}" > deployment.json
'''
}
// Archive deployment artifacts
archiveArtifacts artifacts: 'deployment.json,class_hash.txt', fingerprint: true
// Read class hash for next stage
env.CLASS_HASH = readFile('class_hash.txt').trim()
echo "CLASS_HASH=${env.CLASS_HASH}"
}
}
}
stage('Verify Contract') {
when {
expression { !params.SKIP_VERIFICATION }
}
steps {
script {
echo "Verifying contract on ${params.NETWORK}"
echo "Class hash: ${env.CLASS_HASH}"
sh """
voyager verify \\
--network ${params.NETWORK} \\
--class-hash ${env.CLASS_HASH} \\
--contract-name MyContract \\
--license MIT \\
--watch \\
--verbose
VERIFY_EXIT=\$?
if [ \$VERIFY_EXIT -eq 0 ]; then
echo "✓ Verification successful!"
echo "View on Voyager: https://voyager.online/class/${env.CLASS_HASH}"
echo "success" > verification_status.txt
else
echo "✗ Verification failed with exit code \$VERIFY_EXIT"
echo "failed" > verification_status.txt
exit 1
fi
"""
// Archive verification result
archiveArtifacts artifacts: 'verification_status.txt', fingerprint: true
}
}
}
stage('Generate Report') {
steps {
script {
def classHash = env.CLASS_HASH
def network = params.NETWORK
def voyagerUrl = "https://voyager.online/class/${classHash}"
echo """
╔═══════════════════════════════════════════════════════════╗
║ Deployment Report ║
╠═══════════════════════════════════════════════════════════╣
║ Network: ${network}
║ Class Hash: ${classHash}
║ Branch: ${env.BRANCH_NAME}
║ Build: ${env.BUILD_NUMBER}
║ Status: ✓ Verified
║ Voyager URL: ${voyagerUrl}
╚═══════════════════════════════════════════════════════════╝
"""
// Create badge
sh 'mkdir -p badges'
sh 'echo \'{"schemaVersion": 1, "label": "contract", "message": "verified", "color": "success"}\' > badges/verification.json'
archiveArtifacts artifacts: 'badges/verification.json', fingerprint: true
}
}
}
}
post {
success {
script {
echo "✅ Pipeline completed successfully"
// Send Slack notification
slackSend(
color: 'good',
message: """
✅ Contract Verified Successfully
Network: ${params.NETWORK}
Class Hash: `${env.CLASS_HASH}`
Branch: ${env.BRANCH_NAME}
<https://voyager.online/class/${env.CLASS_HASH}|View on Voyager>
""",
channel: '#deployments'
)
}
}
failure {
script {
echo "❌ Pipeline failed"
// Send Slack notification
slackSend(
color: 'danger',
message: """
❌ Contract Verification Failed
Network: ${params.NETWORK}
Branch: ${env.BRANCH_NAME}
Build: ${env.BUILD_NUMBER}
<${env.BUILD_URL}|View Logs>
""",
channel: '#deployments'
)
}
}
always {
// Clean up workspace
cleanWs()
}
}
}
Credential Binding
Configure credentials in Jenkins:
- Go to Manage Jenkins → Credentials
- Add credentials:
starknet-account- File credential with account JSONstarknet-keystore- File credential with keystore
- Reference in pipeline with
withCredentials
Common Patterns
Pattern 1: Deploy-then-Verify (Sequential)
Most straightforward approach - deploy then verify:
# GitHub Actions
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy contract
run: deploy_script.sh
- name: Save class hash
run: echo $CLASS_HASH > class_hash.txt
verify:
needs: deploy
runs-on: ubuntu-latest
steps:
- name: Read class hash
run: CLASS_HASH=$(cat class_hash.txt)
- name: Verify
run: voyager verify --class-hash $CLASS_HASH --watch
Pros:
- Simple and straightforward
- Easy to debug
- Clear separation of concerns
Cons:
- Slower (sequential execution)
- Blocks on verification
Pattern 2: Parallel Verification
Verify multiple contracts simultaneously:
# GitHub Actions
jobs:
deploy:
runs-on: ubuntu-latest
outputs:
token_hash: ${{ steps.deploy-token.outputs.hash }}
staking_hash: ${{ steps.deploy-staking.outputs.hash }}
governance_hash: ${{ steps.deploy-governance.outputs.hash }}
steps:
- name: Deploy all contracts
run: deploy_all.sh
verify:
needs: deploy
runs-on: ubuntu-latest
strategy:
matrix:
include:
- name: Token
hash: ${{ needs.deploy.outputs.token_hash }}
- name: Staking
hash: ${{ needs.deploy.outputs.staking_hash }}
- name: Governance
hash: ${{ needs.deploy.outputs.governance_hash }}
steps:
- name: Verify ${{ matrix.name }}
run: |
voyager verify \
--network mainnet \
--class-hash ${{ matrix.hash }} \
--contract-name ${{ matrix.name }} \
--watch
Pros:
- Faster (parallel execution)
- Efficient for multiple contracts
Cons:
- More complex setup
- Harder to debug failures
Pattern 3: Conditional Verification
Only verify on specific branches or tags:
# GitHub Actions
jobs:
verify:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')
steps:
- name: Verify on main or release tags only
run: voyager verify --watch
Use cases:
- Production deployments only
- Release tags
- Protected branches
Pattern 4: Manual Approval
Require human approval before verification:
# GitHub Actions (using environments)
jobs:
verify:
runs-on: ubuntu-latest
environment:
name: production
# Configure required reviewers in repo settings
steps:
- name: Verify after approval
run: voyager verify --watch
Or CircleCI:
workflows:
deploy:
jobs:
- deploy-mainnet
- hold-verification:
type: approval
requires:
- deploy-mainnet
- verify-mainnet:
requires:
- hold-verification
Configuration Management
Using .voyager.toml in CI
Commit configuration to repository for consistency:
# .voyager.toml
[voyager]
network = "mainnet"
license = "MIT"
watch = true
verbose = true
notify = false # Disable in CI
In CI pipeline:
- name: Verify with config file
run: |
# Config is automatically detected
voyager verify --class-hash $CLASS_HASH --contract-name MyContract
Environment-Specific Configs
Maintain separate configs for different environments:
# Directory structure
.
├── .voyager.dev.toml # Development config
├── .voyager.staging.toml # Staging config
└── .voyager.prod.toml # Production config
In CI:
- name: Select config based on environment
run: |
if [ "$ENV" == "production" ]; then
cp .voyager.prod.toml .voyager.toml
elif [ "$ENV" == "staging" ]; then
cp .voyager.staging.toml .voyager.toml
else
cp .voyager.dev.toml .voyager.toml
fi
- name: Verify
run: voyager verify --class-hash $CLASS_HASH --contract-name MyContract
Dynamic Configuration
Generate config from deployment output:
- name: Generate verification config
run: |
# Read deployment manifest
TOKEN_HASH=$(jq -r '.contracts.token.class_hash' deployment.json)
STAKING_HASH=$(jq -r '.contracts.staking.class_hash' deployment.json)
# Generate .voyager.toml
cat > .voyager.toml <<EOF
[voyager]
network = "mainnet"
license = "MIT"
watch = true
[[contracts]]
class-hash = "$TOKEN_HASH"
contract-name = "Token"
[[contracts]]
class-hash = "$STAKING_HASH"
contract-name = "Staking"
EOF
- name: Batch verify
run: voyager verify
Secrets Management
GitHub Secrets
Configure:
- Repository Settings → Secrets and variables → Actions
- Add secrets:
STARKNET_ACCOUNTSTARKNET_KEYSTORESLACK_WEBHOOK_URL
Use:
- name: Verify contract
env:
ACCOUNT: ${{ secrets.STARKNET_ACCOUNT }}
KEYSTORE: ${{ secrets.STARKNET_KEYSTORE }}
run: |
echo "$ACCOUNT" > account.json
echo "$KEYSTORE" > keystore.json
# Use in deployment/verification
GitLab CI Variables
Configure: Settings → CI/CD → Variables
Types:
- Protected: Only available on protected branches
- Masked: Hidden in logs
- File: Stored as file (use for JSON configs)
Use:
verify:
script:
- echo "Using protected variable: $STARKNET_ACCOUNT_FILE"
- voyager verify --class-hash $CLASS_HASH --watch
Environment Variables Best Practices
- Never commit secrets to version control
- Use file-type secrets for JSON configs
- Mark secrets as protected for production
- Rotate secrets regularly
- Use different secrets for different environments
- Audit secret usage in logs
Error Handling
Verification Failures in CI
Handle verification failures gracefully:
- name: Verify contract
id: verify
continue-on-error: true
run: |
voyager verify \
--network mainnet \
--class-hash $CLASS_HASH \
--contract-name MyContract \
--watch \
--verbose
- name: Handle failure
if: steps.verify.outcome == 'failure'
run: |
echo "❌ Verification failed!"
echo "Check logs above for details"
# Send notification
curl -X POST $SLACK_WEBHOOK \
-H 'Content-Type: application/json' \
-d '{"text":"Verification failed for '$CLASS_HASH'"}'
# Fail the build
exit 1
Timeout Handling
Set appropriate timeouts for verification:
- name: Verify with timeout
timeout-minutes: 10
run: |
voyager verify \
--network mainnet \
--class-hash $CLASS_HASH \
--contract-name MyContract \
--watch
Recommended timeouts:
- Simple contracts: 5-10 minutes
- Complex contracts: 10-15 minutes
- Batch verification: 15-30 minutes
Retry Logic
Implement retries for transient failures:
- name: Verify with retry
uses: nick-invision/retry@v2
with:
timeout_minutes: 10
max_attempts: 3
retry_wait_seconds: 60
command: |
voyager verify \
--network mainnet \
--class-hash $CLASS_HASH \
--contract-name MyContract \
--watch
Or in shell script:
#!/bin/bash
MAX_ATTEMPTS=3
ATTEMPT=1
while [ $ATTEMPT -le $MAX_ATTEMPTS ]; do
echo "Verification attempt $ATTEMPT of $MAX_ATTEMPTS"
if voyager verify --network mainnet --class-hash $CLASS_HASH --contract-name MyContract --watch; then
echo "✓ Verification successful"
exit 0
else
echo "✗ Attempt $ATTEMPT failed"
if [ $ATTEMPT -lt $MAX_ATTEMPTS ]; then
echo "Retrying in 60 seconds..."
sleep 60
fi
ATTEMPT=$((ATTEMPT + 1))
fi
done
echo "❌ Verification failed after $MAX_ATTEMPTS attempts"
exit 1
Notification Strategies
Slack Notifications:
- name: Notify Slack on success
if: success()
run: |
curl -X POST ${{ secrets.SLACK_WEBHOOK_URL }} \
-H 'Content-Type: application/json' \
-d '{
"text": "✅ Contract verified successfully",
"blocks": [{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Contract Verified*\n\nClass Hash: `'$CLASS_HASH'`\nNetwork: mainnet\n\n<https://voyager.online/class/'$CLASS_HASH'|View on Voyager>"
}
}]
}'
- name: Notify Slack on failure
if: failure()
run: |
curl -X POST ${{ secrets.SLACK_WEBHOOK_URL }} \
-H 'Content-Type: application/json' \
-d '{
"text": "❌ Contract verification failed",
"blocks": [{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Verification Failed*\n\nBranch: '${{ github.ref_name }}'\n\n<'${{ github.server_url }}'/'${{ github.repository }}'/actions/runs/'${{ github.run_id }}'|View Logs>"
}
}]
}'
Email Notifications:
- name: Send email notification
if: always()
uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.gmail.com
server_port: 465
username: ${{ secrets.EMAIL_USERNAME }}
password: ${{ secrets.EMAIL_PASSWORD }}
subject: "Contract Verification: ${{ job.status }}"
to: team@example.com
from: ci@example.com
body: |
Verification Status: ${{ job.status }}
Network: mainnet
Class Hash: ${{ env.CLASS_HASH }}
Branch: ${{ github.ref_name }}
View on Voyager: https://voyager.online/class/${{ env.CLASS_HASH }}
Best Practices
1. Always Verify in CI
Automate verification - Don’t rely on manual steps:
# ✓ Good - automated
- name: Verify automatically after deploy
run: voyager verify --class-hash $CLASS_HASH --watch
# ✗ Bad - manual step
# "Remember to verify the contract on Voyager website"
2. Use –watch in CI
Wait for completion - Don’t submit and forget:
# ✓ Good - waits for result
voyager verify --network mainnet --class-hash $HASH --watch
# ✗ Bad - doesn't wait
voyager verify --network mainnet --class-hash $HASH
3. Set Reasonable Timeouts
Account for network delays - Verification can take several minutes:
- name: Verify with timeout
timeout-minutes: 10 # ✓ Good
run: voyager verify --watch
4. Fail the Build on Verification Failure
Make verification a quality gate:
- name: Verify contract
run: |
voyager verify --watch
# Exit with error if verification failed
if [ $? -ne 0 ]; then
echo "❌ Verification failed - failing build"
exit 1
fi
5. Use Configuration Files
Don’t hardcode in workflows:
# .voyager.toml - committed to repo
[voyager]
network = "mainnet"
license = "MIT"
watch = true
verbose = true
# Workflow uses config file
- name: Verify
run: voyager verify --class-hash $CLASS_HASH --contract-name MyContract
6. Manage Secrets Properly
Never commit sensitive data:
# ✓ Good - using secrets
env:
ACCOUNT: ${{ secrets.STARKNET_ACCOUNT }}
# ✗ Bad - hardcoded
env:
ACCOUNT: '{"version":1,"private_key":"0x..."}'
7. Cache Dependencies
Speed up CI runs:
- name: Cache Scarb
uses: actions/cache@v4
with:
path: |
~/.cargo
target/
key: scarb-${{ hashFiles('Scarb.toml') }}
8. Test Verification on Testnet First
Catch issues early:
jobs:
test-testnet:
runs-on: ubuntu-latest
steps:
- name: Deploy to sepolia
run: deploy_sepolia.sh
- name: Verify on sepolia
run: voyager verify --network sepolia --watch
deploy-mainnet:
needs: test-testnet # Only proceed if testnet succeeds
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- name: Deploy to mainnet
run: deploy_mainnet.sh
- name: Verify on mainnet
run: voyager verify --network mainnet --watch
9. Tag Releases with Verification Status
Track what’s verified:
- name: Tag release
if: success()
run: |
git tag -a "v$VERSION-verified" -m "Verified on Voyager: $CLASS_HASH"
git push --tags
10. Send Notifications
Alert team of verification status:
- name: Notify team
if: always()
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "Verification ${{ job.status }}: ${{ env.CLASS_HASH }}"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
Debugging CI Verification
Common Issues
Issue 1: Permission Errors
Error: Permission denied when accessing deployment files
Solution:
- name: Fix permissions
run: |
chmod +x deploy.sh
chmod 600 keystore.json
Issue 2: Network Timeouts
Error: Request timeout while verifying
Solution:
- name: Increase timeout
timeout-minutes: 15
run: voyager verify --watch
Issue 3: Missing Dependencies
Error: scarb: command not found
Solution:
- name: Install Scarb
run: |
curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | sh
echo "$HOME/.local/bin" >> $GITHUB_PATH
Issue 4: Configuration Errors
Error: No contracts defined in .voyager.toml
Solution:
- name: Validate config
run: |
if [ ! -f .voyager.toml ]; then
echo "Error: .voyager.toml not found"
exit 1
fi
cat .voyager.toml # Print for debugging
Using –verbose in CI
Capture detailed logs:
- name: Verify with verbose output
run: |
voyager verify \
--network mainnet \
--class-hash $CLASS_HASH \
--contract-name MyContract \
--watch \
--verbose 2>&1 | tee verification.log
- name: Upload logs
if: always()
uses: actions/upload-artifact@v4
with:
name: verification-logs
path: verification.log
Artifact Collection
Save verification results:
- name: Verify and save results
run: |
voyager verify --watch > verification_output.txt 2>&1
echo $? > exit_code.txt
- name: Upload verification artifacts
uses: actions/upload-artifact@v4
with:
name: verification-results
path: |
verification_output.txt
exit_code.txt
deployment.json
retention-days: 30
Complete Example: Full GitHub Actions Workflow
Here’s a complete, production-ready GitHub Actions workflow demonstrating all concepts:
name: Production Deploy and Verify
on:
push:
branches: [main, production]
tags: ['v*']
pull_request:
branches: [main]
workflow_dispatch:
env:
SCARB_VERSION: '2.8.4'
VOYAGER_VERSION: '2.0.0'
jobs:
build:
name: Build Contracts
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Scarb
uses: software-mansion/setup-scarb@v1
with:
scarb-version: ${{ env.SCARB_VERSION }}
- name: Cache dependencies
uses: actions/cache@v4
with:
path: |
~/.cargo
target/
key: scarb-${{ hashFiles('Scarb.toml') }}
- name: Build
run: scarb --release build
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: contracts
path: target/release/*.json
deploy-testnet:
name: Deploy to Testnet
needs: build
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
environment: testnet
outputs:
token_hash: ${{ steps.deploy.outputs.token_hash }}
staking_hash: ${{ steps.deploy.outputs.staking_hash }}
governance_hash: ${{ steps.deploy.outputs.governance_hash }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: contracts
path: target/release/
- name: Setup Starkli
run: |
curl https://get.starkli.sh | sh
echo "$HOME/.starkli/bin" >> $GITHUB_PATH
starkliup
- name: Deploy contracts
id: deploy
env:
ACCOUNT: ${{ secrets.SEPOLIA_ACCOUNT }}
KEYSTORE: ${{ secrets.SEPOLIA_KEYSTORE }}
run: |
# Deploy Token
TOKEN_OUTPUT=$(starkli declare target/release/token_Token.contract_class.json --rpc https://starknet-sepolia.public.blastapi.io 2>&1)
TOKEN_HASH=$(echo "$TOKEN_OUTPUT" | grep -oP "Class hash declared: \K0x[0-9a-fA-F]+")
echo "token_hash=$TOKEN_HASH" >> $GITHUB_OUTPUT
# Deploy Staking
STAKING_OUTPUT=$(starkli declare target/release/staking_Staking.contract_class.json --rpc https://starknet-sepolia.public.blastapi.io 2>&1)
STAKING_HASH=$(echo "$STAKING_OUTPUT" | grep -oP "Class hash declared: \K0x[0-9a-fA-F]+")
echo "staking_hash=$STAKING_HASH" >> $GITHUB_OUTPUT
# Deploy Governance
GOV_OUTPUT=$(starkli declare target/release/governance_Governance.contract_class.json --rpc https://starknet-sepolia.public.blastapi.io 2>&1)
GOV_HASH=$(echo "$GOV_OUTPUT" | grep -oP "Class hash declared: \K0x[0-9a-fA-F]+")
echo "governance_hash=$GOV_HASH" >> $GITHUB_OUTPUT
verify-testnet:
name: Verify on Testnet
needs: deploy-testnet
runs-on: ubuntu-latest
strategy:
matrix:
contract:
- name: Token
hash_var: token_hash
- name: Staking
hash_var: staking_hash
- name: Governance
hash_var: governance_hash
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Scarb
uses: software-mansion/setup-scarb@v1
with:
scarb-version: ${{ env.SCARB_VERSION }}
- name: Install voyager-verifier
run: |
curl -L https://raw.githubusercontent.com/NethermindEth/voyager-verify/main/install.sh | bash
echo "$HOME/.voyager/bin" >> $GITHUB_PATH
- name: Verify ${{ matrix.contract.name }}
timeout-minutes: 10
run: |
HASH="${{ needs.deploy-testnet.outputs[matrix.contract.hash_var] }}"
voyager verify \
--network sepolia \
--class-hash $HASH \
--contract-name ${{ matrix.contract.name }} \
--license MIT \
--watch \
--verbose
- name: Comment on PR
uses: actions/github-script@v7
with:
script: |
const hash = '${{ needs.deploy-testnet.outputs[matrix.contract.hash_var] }}';
const name = '${{ matrix.contract.name }}';
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `✅ **${name}** verified on Sepolia\n\nClass Hash: \`${hash}\`\n\n[View on Voyager](https://sepolia.voyager.online/class/${hash})`
});
deploy-mainnet:
name: Deploy to Mainnet
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')
environment: production
outputs:
token_hash: ${{ steps.deploy.outputs.token_hash }}
staking_hash: ${{ steps.deploy.outputs.staking_hash }}
governance_hash: ${{ steps.deploy.outputs.governance_hash }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: contracts
path: target/release/
- name: Setup Starkli
run: |
curl https://get.starkli.sh | sh
echo "$HOME/.starkli/bin" >> $GITHUB_PATH
starkliup
- name: Deploy contracts
id: deploy
env:
ACCOUNT: ${{ secrets.MAINNET_ACCOUNT }}
KEYSTORE: ${{ secrets.MAINNET_KEYSTORE }}
run: |
# Deploy all contracts and capture hashes
# (Same as testnet but with mainnet RPC)
TOKEN_OUTPUT=$(starkli declare target/release/token_Token.contract_class.json --rpc https://starknet-mainnet.public.blastapi.io 2>&1)
TOKEN_HASH=$(echo "$TOKEN_OUTPUT" | grep -oP "Class hash declared: \K0x[0-9a-fA-F]+")
echo "token_hash=$TOKEN_HASH" >> $GITHUB_OUTPUT
STAKING_OUTPUT=$(starkli declare target/release/staking_Staking.contract_class.json --rpc https://starknet-mainnet.public.blastapi.io 2>&1)
STAKING_HASH=$(echo "$STAKING_OUTPUT" | grep -oP "Class hash declared: \K0x[0-9a-fA-F]+")
echo "staking_hash=$STAKING_HASH" >> $GITHUB_OUTPUT
GOV_OUTPUT=$(starkli declare target/release/governance_Governance.contract_class.json --rpc https://starknet-mainnet.public.blastapi.io 2>&1)
GOV_HASH=$(echo "$GOV_OUTPUT" | grep -oP "Class hash declared: \K0x[0-9a-fA-F]+")
echo "governance_hash=$GOV_HASH" >> $GITHUB_OUTPUT
verify-mainnet:
name: Verify on Mainnet
needs: deploy-mainnet
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Scarb
uses: software-mansion/setup-scarb@v1
with:
scarb-version: ${{ env.SCARB_VERSION }}
- name: Install voyager-verifier
run: |
curl -L https://raw.githubusercontent.com/NethermindEth/voyager-verify/main/install.sh | bash
echo "$HOME/.voyager/bin" >> $GITHUB_PATH
- name: Create batch config
run: |
cat > .voyager.toml <<EOF
[voyager]
network = "mainnet"
license = "MIT"
watch = true
verbose = true
[[contracts]]
class-hash = "${{ needs.deploy-mainnet.outputs.token_hash }}"
contract-name = "Token"
[[contracts]]
class-hash = "${{ needs.deploy-mainnet.outputs.staking_hash }}"
contract-name = "Staking"
[[contracts]]
class-hash = "${{ needs.deploy-mainnet.outputs.governance_hash }}"
contract-name = "Governance"
EOF
- name: Batch verify
timeout-minutes: 30
run: |
voyager verify --batch-delay 5
- name: Upload verification results
if: always()
uses: actions/upload-artifact@v4
with:
name: verification-results
path: .voyager.toml
notify:
name: Send Notifications
needs: [deploy-mainnet, verify-mainnet]
runs-on: ubuntu-latest
if: always()
steps:
- name: Notify success
if: needs.verify-mainnet.result == 'success'
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "✅ Mainnet deployment verified",
"blocks": [{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Deployment Complete*\n\n• Token: `${{ needs.deploy-mainnet.outputs.token_hash }}`\n• Staking: `${{ needs.deploy-mainnet.outputs.staking_hash }}`\n• Governance: `${{ needs.deploy-mainnet.outputs.governance_hash }}`\n\nAll contracts verified on Voyager"
}
}]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
- name: Notify failure
if: needs.verify-mainnet.result == 'failure'
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "❌ Verification failed",
"blocks": [{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Verification Failed*\n\nBranch: ${{ github.ref_name }}\n\n<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Logs>"
}
}]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
Expected Output from Full Workflow
Build Stage:
Run scarb --release build
Compiling my_contracts v1.0.0 (~/project/Scarb.toml)
Finished release target(s) in 5 seconds
✓ Build completed
Deploy Stage:
Run starkli declare target/release/token_Token.contract_class.json
Declaring contract class...
Class hash declared: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
✓ All contracts deployed
Verify Stage:
Starting batch verification for 3 contracts...
[1/3] Verifying: Token
✓ Files collected: 5 files
✓ Project built successfully
✓ Verification job submitted (Job ID: abc-123)
[2/3] Verifying: Staking
✓ Using cached build
✓ Verification job submitted (Job ID: def-456)
[3/3] Verifying: Governance
✓ Using cached build
✓ Verification job submitted (Job ID: ghi-789)
⏳ Watching 3 verification job(s)...
✓ 3 Succeeded | ⏳ 0 Pending | ✗ 0 Failed
✓ All verifications completed successfully!
════════════════════════════════════════
Batch Verification Summary
════════════════════════════════════════
Total contracts: 3
Succeeded: 3
Failed: 0
════════════════════════════════════════
Security Considerations
API Keys & Secrets
Best practices:
- Never commit secrets to repository
- Use repository secrets for sensitive data
- Rotate secrets regularly
- Limit secret access to necessary jobs
- Audit secret usage in workflow logs
Example:
# ✓ Good
env:
ACCOUNT: ${{ secrets.STARKNET_ACCOUNT }}
# ✗ Bad
env:
ACCOUNT: '{"private_key":"0x123..."}'
Network Selection
Testnet vs Mainnet:
# Deploy to testnet for testing
- name: Deploy testnet
if: github.event_name == 'pull_request'
run: deploy.sh --network sepolia
# Deploy to mainnet only on main branch
- name: Deploy mainnet
if: github.ref == 'refs/heads/main'
environment: production # Requires approval
run: deploy.sh --network mainnet
Class Hash Validation
Ensure correctness:
- name: Validate class hash
run: |
if [[ ! $CLASS_HASH =~ ^0x[0-9a-fA-F]{64}$ ]]; then
echo "Error: Invalid class hash format: $CLASS_HASH"
exit 1
fi
echo "✓ Class hash validated: $CLASS_HASH"
Advanced Patterns
Multi-Environment Deployment
Deploy through dev → staging → production:
jobs:
deploy-dev:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/develop'
steps:
- name: Deploy to dev
run: deploy.sh --network sepolia --env dev
- name: Verify dev
run: voyager verify --network sepolia --watch
deploy-staging:
needs: deploy-dev
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
environment: staging
steps:
- name: Deploy to staging
run: deploy.sh --network sepolia --env staging
- name: Verify staging
run: voyager verify --network sepolia --watch
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment: production # Requires approval
steps:
- name: Deploy to production
run: deploy.sh --network mainnet
- name: Verify production
run: voyager verify --network mainnet --watch
Approval Gates
Require manual approval for critical steps:
# GitHub Actions (using environments)
deploy-mainnet:
runs-on: ubuntu-latest
environment:
name: production
# Configure required reviewers in repo settings
# CircleCI
workflows:
deploy:
jobs:
- hold-approval:
type: approval
- deploy-mainnet:
requires:
- hold-approval
Rollback on Failure
Handle verification failures with rollback:
- name: Verify deployment
id: verify
run: voyager verify --watch
- name: Rollback on failure
if: steps.verify.outcome == 'failure'
run: |
echo "❌ Verification failed - rolling back"
./rollback.sh --to-previous-version
exit 1
Integration Testing
Verify after deployment tests pass:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy
run: deploy.sh
integration-tests:
needs: deploy
runs-on: ubuntu-latest
steps:
- name: Run tests
run: pytest tests/integration/
verify:
needs: integration-tests # Only verify if tests pass
runs-on: ubuntu-latest
steps:
- name: Verify
run: voyager verify --watch
Monitoring & Reporting
CI Status Badges
Add verification status to README:
GitHub Actions:
[](https://github.com/username/repo/actions/workflows/verify.yml)
GitLab CI:
[](https://gitlab.com/username/repo/-/pipelines)
CircleCI:
[](https://circleci.com/gh/username/repo)
Notification Integration
Slack Integration:
- name: Notify Slack
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "Verification complete",
"attachments": [{
"color": "good",
"fields": [
{"title": "Network", "value": "mainnet", "short": true},
{"title": "Status", "value": "✓ Verified", "short": true},
{"title": "Class Hash", "value": "'$CLASS_HASH'"}
]
}]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
Discord Integration:
- name: Notify Discord
run: |
curl -X POST "${{ secrets.DISCORD_WEBHOOK_URL }}" \
-H "Content-Type: application/json" \
-d '{
"content": "✅ Contract verified",
"embeds": [{
"title": "Verification Complete",
"description": "Class Hash: `'$CLASS_HASH'`",
"color": 65280,
"url": "https://voyager.online/class/'$CLASS_HASH'"
}]
}'
Email Notifications:
- name: Send email
uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.gmail.com
server_port: 465
username: ${{ secrets.EMAIL_USERNAME }}
password: ${{ secrets.EMAIL_PASSWORD }}
subject: "Verification Status: ${{ job.status }}"
to: team@example.com
from: ci@example.com
body: |
Verification completed with status: ${{ job.status }}
Network: mainnet
Class Hash: ${{ env.CLASS_HASH }}
View: https://voyager.online/class/${{ env.CLASS_HASH }}
Verification History
Track verifications across deployments:
- name: Record verification
run: |
# Use voyager history commands
voyager history list --limit 10 > verification_history.txt
voyager history stats > verification_stats.txt
- name: Upload history
uses: actions/upload-artifact@v4
with:
name: verification-history
path: |
verification_history.txt
verification_stats.txt
Next Steps
Congratulations! You’ve learned how to integrate voyager-verifier into CI/CD pipelines. Here’s what to explore next:
- Configuration Reference - Deep dive into configuration options
- History Management - Track verification history
- Batch Verification - Verify multiple contracts efficiently
- Troubleshooting Guide - Resolve common issues
- Advanced Features - Desktop notifications, custom workflows
Additional Resources
- GitHub Actions Documentation - GitHub Actions reference
- GitLab CI Documentation - GitLab CI/CD guide
- CircleCI Documentation - CircleCI configuration
- Jenkins Pipeline - Jenkins pipeline syntax
- Starkli Documentation - Starknet CLI tool
- Scarb Documentation - Cairo package manager
Conclusion
Automating contract verification in CI/CD pipelines ensures:
- Consistency - Every deployment is verified the same way
- Reliability - No forgotten manual steps
- Transparency - Team visibility into verification status
- Quality - Verification as a required quality gate
- Efficiency - Save time with automation
Start with a simple deployment → verification workflow, then gradually add features like batch verification, notifications, and approval gates as your needs grow.
Ready for advanced features? Continue to Advanced Configuration or Troubleshooting Guide.
Reference
Technical reference documentation for Voyager Verifier, including error codes, version support, file collection rules, and API endpoints.
Reference Material
Error Codes
Complete error code reference (E001-E042, E999)
Comprehensive listing of all error codes with descriptions, causes, solutions, and examples.
- Workspace & Package Errors (E001-E003)
- Verification API Errors (E004-E009)
- Dependency Errors (E010-E014)
- Contract & Target Errors (E015-E024)
- File System Errors (E025-E029)
- Class Hash Errors (E030-E039)
- Config File Errors (E040-E042)
- General Errors (E999)
Use when: You encounter an error code and need detailed information.
Supported Versions
Cairo, Scarb, and Dojo version compatibility
Version support matrix and upgrade guidance.
- Cairo Version Support: Server-determined, up to 2.13.1 (Oct 2025)
- Scarb Version Support: 1.x - 2.x
- Dojo Version Support: Auto-detected from Scarb.toml, up to 1.8.0 (Oct 2025)
- Upgrade Guidance: Step-by-step upgrade procedures
Use when: Planning upgrades or checking version compatibility.
File Collection
What files are included/excluded in verification
Detailed rules for file collection and validation.
- Source Files: .cairo files (excluding tests by default)
- Manifest Files: Scarb.toml, workspace manifests
- Lock Files: Scarb.lock (optional with
--lock-file) - Test Files: Excluded by default (
--test-filesto include) - File Types: Allowed extensions and size limits (20MB)
- Contract Detection: How the main contract file is found
Use when: Understanding what will be submitted for verification.
API Reference
Job status endpoint and response formats
API documentation for checking verification job status.
- Status Endpoint: Get job status by job ID
- Response Formats: JSON schemas and examples
- Job Status Codes: 0-5 and their meanings
- Job Lifecycle: State transitions and typical timing
- Network Endpoints: Mainnet, Sepolia, Dev, Custom
- Error Handling: API error responses and recovery
Use when: Understanding job statuses and response formats.
Quick Reference Tables
Networks
| Network | Base URL | Usage |
|---|---|---|
| Mainnet | https://api.voyager.online | Production contracts |
| Sepolia | https://sepolia-api.voyager.online | Testnet contracts |
| Dev | https://dev-api.voyager.online | Development testing |
| Custom | User-specified | Custom deployments |
Job Status Codes
| Code | Name | Description | Terminal |
|---|---|---|---|
0 | Submitted | Job queued | No |
1 | Compiled | Compilation success | No |
2 | CompileFailed | Compilation failed | Yes |
3 | Fail | Verification failed | Yes |
4 | Success | Verified successfully | Yes |
5 | Processing | Being processed | No |
File Types
| Type | Included | Flag Required | Max Size |
|---|---|---|---|
| Cairo source (.cairo) | ✅ Yes | None | 20MB |
| Scarb.toml | ✅ Yes | None | 20MB |
| Scarb.lock | ❌ No | --lock-file | 20MB |
| Test files | ❌ No | --test-files | 20MB |
| Documentation (.md) | ✅ If found | None | 20MB |
Version Support
| Component | Support Model | Current |
|---|---|---|
| Cairo | Server-determined | Up to 2.13.1 (Oct 2025) |
| Scarb | Client + Server | 1.x - 2.x |
| Dojo | Auto-detected | Up to 1.8.0 (Oct 2025) |
| Client | Semantic Versioning | v2.0.1 |
Error Code Quick Lookup
Most Common Errors
| Code | Error | Quick Fix |
|---|---|---|
| E005 | Module not found | Add --test-files if importing tests |
| E007 | Verification failed | Check Troubleshooting Guide |
| E015 | Invalid contract name | Verify contract name matches #[starknet::contract] mod |
| E030 | Class hash mismatch | Use --lock-file for reproducibility |
| E999 | Unexpected error | Check logs with --verbose |
By Category
Workspace Issues (E001-E003):
- Package not found
- No packages in workspace
- Workspace errors
API Issues (E004-E009):
- Job submission failed
- Job not found
- Verification failed
Dependency Issues (E010-E014):
- Resolution failures
- Missing dependencies
- Dependency conflicts
Contract Issues (E015-E024):
- Invalid contract names
- Target not found
- Multiple contracts found
File Issues (E025-E029):
- File not found
- File read errors
- Invalid file types
Hash Issues (E030-E039):
- Hash mismatch
- Parsing errors
- Format issues
Config Issues (E040-E042):
- Config file errors
- Parse failures
- Invalid settings
File Collection Rules
Always Included
✅ All .cairo files in src/ (except tests)
✅ Package Scarb.toml
✅ Workspace Scarb.toml (if workspace)
✅ Documentation files (LICENSE, README.md, etc.)
Optional (Requires Flags)
❌ Scarb.lock → Use --lock-file
❌ Test files (src/tests/) → Use --test-files
Never Included
❌ Files outside src/ (except manifests)
❌ Test directories outside src/ (tests/, test/)
❌ Build artifacts (target/)
❌ Hidden files (.git/, .env)
❌ Unsupported file types (.yaml, .png, etc.)
File Size Limits
Maximum: 20MB per file
Validation:
- File type checking (cairo, toml, lock, md, txt, json)
- Size checking (max 20MB)
- Path validation
Version Compatibility
Cairo Versions
Supported: Up to 2.13.1 (as of October 2025)
Compatibility:
- ✅ Cairo 2.13.x - Fully supported (latest)
- ✅ Cairo 2.12.x - Fully supported
- ✅ Cairo 2.11.x - Fully supported
- ✅ Cairo 2.10.x - Fully supported
- ✅ Cairo 2.9.x - Maintained
- ✅ Cairo 2.8.x - Maintained
- ⚠️ Cairo 1.x - Limited support
- 🔄 Newer versions - Check API or request via GitHub/Telegram
Version Agnostic: Client doesn’t impose version restrictions; server determines support.
Scarb Versions
Recommended: 2.8.x
Compatibility:
- ✅ Scarb 2.8.x - Fully tested
- ✅ Scarb 2.7.x - Stable
- ✅ Scarb 2.6.x - Supported
- ⚠️ Scarb 1.x - Limited
- ❌ Scarb 0.x - Not supported
Dojo Support
Detection: Automatic from Scarb.toml
Formats Supported:
# Simple string
dojo = "1.7.1"
# Git tag
dojo = { tag = "v0.7.0" }
# Version table
dojo = { version = "2.0.0" }
All Dojo versions with valid Scarb.toml format are supported.
Common Reference Scenarios
Scenario 1: Error Code Lookup
Problem: Getting error code E005
Steps:
- Go to Error Codes
- Find E005 in the list
- Read cause, solutions, and examples
- Apply suggested fix
Scenario 2: Version Check
Problem: Unsure if Cairo 2.12.0 is supported
Steps:
- Go to Supported Versions
- Check Cairo version compatibility matrix
- See note about server-side support
- Test with
--dry-runon Sepolia first
Scenario 3: File Not Included
Problem: File missing from submission
Steps:
- Go to File Collection
- Check if file type is allowed
- Verify file location (must be in src/ or manifest)
- Use
--dry-runto preview collection - Check if flag needed (
--lock-file,--test-files)
Scenario 4: Understanding Job Status
Problem: Understanding what status codes mean
Steps:
- Go to API Reference
- Review job status codes documentation
- Check response formats
- Understand state transitions
- Learn about typical timing
Scenario 5: Hash Mismatch
Problem: Class hash mismatch error
Steps:
- Check Error Codes E030
- Review File Collection for lock files
- Use
--lock-fileflag - Check Supported Versions for compatibility
- Verify exact versions match deployment
Reference FAQs
Q: Where can I find error code E030?
A: See Error Codes for detailed information on class hash mismatch errors.
Q: Which files are submitted for verification?
A: See File Collection for complete rules. By default: all .cairo files in src/ (except tests) + Scarb.toml + workspace manifest (if applicable).
Q: What Cairo version should I use?
A: See Supported Versions. As of 2025, Cairo up to 2.11.4 is fully supported. Newer versions are added with a slight lag.
Q: How do I check job status?
A: Use the voyager status command. See Status Command for usage details.
Q: What does status code 2 mean?
A: See API Reference. Status 2 = CompileFailed (compilation error, terminal state).
Q: Are test files included by default?
A: No. See File Collection. Use --test-files flag to include them.
Q: How long does verification take?
A: See API Reference. Simple contracts: 5-15 seconds. Complex contracts: 15-60 seconds.
Q: Can I use a custom API endpoint?
A: Yes. See API Reference for using --network custom --endpoint <URL>.
Reference Navigation
By Topic
Errors & Troubleshooting:
- Error Codes - Complete error reference
- Common Errors - Solutions for frequent issues
- Debugging - Systematic troubleshooting
Versions & Compatibility:
- Supported Versions - Version matrices
- Upgrade Guide - How to upgrade
Files & Collection:
- File Collection - What gets included
- Test Files - Using
--test-files - Lock Files - Using
--lock-file
API & Integration:
- API Reference - Complete API docs
- Custom Endpoints - Custom deployments
By Task
I want to…
…understand an error code → Error Codes
…check version compatibility → Supported Versions
…know what files are submitted → File Collection
…understand job status codes → API Reference
…fix a verification failure → Common Errors
…upgrade Cairo/Scarb → Version Upgrade Guide
…debug compilation errors → Debugging
See Also
Related Documentation
- Getting Started - Initial setup and first verification
- Core Features - Essential commands and workflows
- Advanced Features - Advanced usage patterns
- Troubleshooting - Problem-solving guides
External Resources
- Cairo Documentation: https://book.cairo-lang.org
- Scarb Documentation: https://docs.swmansion.com/scarb
- Dojo Documentation: https://book.dojoengine.org
- Starknet Documentation: https://docs.starknet.io
- Voyager Explorer: https://voyager.online
Community Support
- Telegram: https://t.me/StarknetVoyager
- GitHub Issues: https://github.com/NethermindEth/voyager-verifier/issues
- GitHub Releases: https://github.com/NethermindEth/voyager-verifier/releases
Error Codes
This page provides a complete reference of all error codes in voyager-verifier with descriptions, causes, and solutions.
Error Code Format
All error codes follow the format [EXXX] where XXX is a three-digit number. Error codes help you quickly identify and resolve issues.
Quick Navigation:
- Workspace & Package Errors (E001-E003)
- Verification Errors (E004-E009)
- Class Hash Errors (E010-E011)
- Dependency & Resolution Errors (E012-E014)
- Contract & Target Errors (E015-E017)
- File System Errors (E018-E019, E022-E024)
- Project Configuration Errors (E020-E021, E025-E028)
- Config File Errors (E030-E032)
- History Database Errors (E040-E042)
- General Errors (E999)
Workspace & Package Errors
E001: Package Not Found in Workspace
Error Message:
[E001] Package '<name>' not found in workspace.
Cause: You specified a package name that doesn’t exist in the current workspace.
Common Scenarios:
- Typo in package name
- Package not listed in workspace members
- Wrong directory (not in workspace root)
Solutions:
-
Check available packages:
scarb metadata -
List workspace members in Scarb.toml:
[workspace] members = ["package1", "package2"] -
Use correct package name:
voyager verify --network mainnet \ --class-hash 0x044dc2b3... \ --contract-name MyContract \ --package correct_package_name -
Verify you’re in the workspace root directory
Example:
# Error: Trying to use non-existent package
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--package my_contrct # Typo: should be "my_contract"
# ✅ Solution: Fix package name
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--package my_contract
E002: HTTP Request Failed
Error Message:
[E002] HTTP request failed: <url> returned status <code>
Cause: An HTTP request to the Voyager API failed.
Common Status Codes:
400 Bad Request:
- Invalid parameters
- Malformed request
Solution:
# Check all required parameters are provided
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--license MIT
401 Unauthorized:
- Invalid authentication (rare - most endpoints are public)
403 Forbidden:
- Insufficient permissions
- Account access issues
404 Not Found:
- Wrong API endpoint
- Service not available
- Invalid URL
Solution:
# Verify the network/URL is correct
voyager verify --network mainnet ... # Use predefined network
# OR
voyager verify --url https://api.voyager.online/beta ... # Check custom URL
413 Payload Too Large:
- Project files exceed 10MB limit
Solution:
# Remove unnecessary files or try without optional files
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
# Don't use --test-files or --lock-file if not needed
429 Too Many Requests:
- Rate limiting triggered
Solution:
# Wait before retrying, or use batch delay
voyager verify --batch-delay 10 # For batch verification
500-599 Server Errors:
- Voyager API experiencing issues
Solution:
- Wait a few minutes and retry
- Check Voyager service status
Example:
# Error: Wrong URL
voyager verify --url https://api.wrong-domain.com/beta ...
# [E002] HTTP request failed: https://api.wrong-domain.com/beta returned status 404
# ✅ Solution: Use correct URL
voyager verify --network mainnet ...
E003: Contract Not Found in Manifest
Error Message:
[E003] Contract '<name>' not found in manifest file.
Cause:
The specified contract name doesn’t exist in the [tool.voyager] section of Scarb.toml or couldn’t be auto-detected.
Common Scenarios:
- Typo in contract name
- Contract not defined in manifest
- Missing
[tool.voyager]section
Solutions:
-
Check available contracts in Scarb.toml:
[tool.voyager.contracts] MyToken = "0x044dc2b3..." MyNFT = "0x055dc2b3..." -
Use correct contract name:
voyager verify --network mainnet \ --class-hash 0x044dc2b3... \ --contract-name MyToken # Must match manifest -
Add contract to manifest if missing:
[tool.voyager.contracts] MyContract = "0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18"
Example:
# Error: Contract name doesn't match manifest
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyTokin # Typo
# ✅ Solution: Use exact name from manifest
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyToken
Verification Errors
E004: Compilation Failed
Error Message:
[E004] Compilation failed: <details>
Cause: The remote compiler failed to build your contract.
Common Causes:
- Syntax errors in Cairo code
- Missing dependencies
- Import errors
- Module not found
- Incompatible Cairo version
Solutions:
-
Test local build first:
scarb --release buildThe remote compiler uses the same command. If it fails locally, it will fail remotely.
-
Check dependencies:
[dependencies] starknet = ">=2.11.0" # Ensure all deps are declared -
Verify imports and modules:
// In lib.cairo mod contract; // Ensure this file exists // mod tests; // Remove if tests.cairo isn't included -
Include test files if needed:
voyager verify --network mainnet \ --class-hash 0x044dc2b3... \ --contract-name MyContract \ --test-files # Include if contract depends on test utilities -
Check release profile settings:
[profile.release.cairo] sierra-replace-ids = true # Any compiler settings must be here -
Use verbose mode for details:
voyager status --network mainnet --job <JOB_ID> --verbose
Example:
error[E0005]: Module file not found. Expected path: /tmp/targets/.../src/tests.cairo
Solution:
# Include test files OR remove module declaration
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files
E005: Verification Failed
Error Message:
[E005] Verification failed: <details>
Cause: The contract compiled successfully, but the resulting class hash doesn’t match the declared class hash.
Common Causes:
- Wrong source code (doesn’t match deployed contract)
- Different compiler settings
- Incorrect dependencies or versions
- Modified code after deployment
Solutions:
-
Verify class hash is correct:
# Double-check the class hash from deployment voyager verify --network mainnet \ --class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \ --contract-name MyContract -
Ensure source matches deployment:
- Use the exact same code that was deployed
- Check out the correct git commit if using version control
- Verify no changes were made after deployment
-
Use lock file for reproducible builds:
voyager verify --network mainnet \ --class-hash 0x044dc2b3... \ --contract-name MyContract \ --lock-file # Ensure same dependency versions -
Match compiler settings:
[profile.release.cairo] # Ensure these match deployment settings sierra-replace-ids = true inlining-strategy = "default" -
Check Cairo version compatibility:
- Ensure the same Cairo/Scarb version was used for deployment
Example:
# If verification fails, try with lock file
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--lock-file \
--verbose
E006: Invalid Base URL
Error Message:
[E006] Invalid base URL: <url>
Cause: The provided custom API URL is invalid or cannot be used as a base URL.
Solutions:
-
Use valid HTTP/HTTPS URL:
# ✅ Correct format voyager verify --url https://api.example.com/beta \ --class-hash 0x044dc2b3... \ --contract-name MyContract # ❌ Wrong: Missing protocol voyager verify --url api.example.com/beta ... -
Use predefined network instead:
voyager verify --network mainnet \ --class-hash 0x044dc2b3... \ --contract-name MyContract -
Check URL format:
- Must start with
http://orhttps:// - Must be a valid URL structure
- Include proper path if required
- Must start with
Example:
# Error: Invalid URL
voyager verify --url example.com ...
# [E006] Invalid base URL: example.com
# ✅ Solution: Add protocol
voyager verify --url https://example.com/api/beta ...
E007: Verification Job Still in Progress
Error Message:
[E007] Verification job is still in progress
Cause: You checked the status of a verification job that hasn’t completed yet.
Solutions:
-
Wait and check again:
# Wait a few seconds/minutes sleep 30 voyager status --network mainnet --job <JOB_ID> -
Use watch mode to wait automatically:
voyager verify --network mainnet \ --class-hash 0x044dc2b3... \ --contract-name MyContract \ --watch # Automatically waits for completion -
Check status with auto-refresh:
# Polls every few seconds until complete voyager status --network mainnet --job <JOB_ID> --wait
Note: This is not an error - it just means the job is still being processed.
E008: Job Not Found
Error Message:
[E008] Job '<job_id>' not found
Cause: The specified job ID doesn’t exist or has expired from the server.
Solutions:
-
Check job ID is correct:
# Copy the full job ID from verification output voyager status --network mainnet --job abc-123-def-456 -
Verify using same network/URL:
# Job ID is tied to the specific API endpoint # Must use same network or URL as verification voyager status --network mainnet --job <JOB_ID> -
Check history for recent jobs:
voyager history list --limit 10 -
Job may have expired:
- Jobs may be removed after a certain period
- Submit a new verification request
Example:
# Error: Wrong network for job ID
voyager verify --network mainnet ... # Submitted to mainnet
# Output: Job ID: abc-123
voyager status --network sepolia --job abc-123 # Wrong network!
# [E008] Job 'abc-123' not found
# ✅ Solution: Use same network
voyager status --network mainnet --job abc-123
E009: Invalid URL Format
Error Message:
[E009] Invalid URL format: <url>
Cause: The custom URL provided has an invalid format.
Solutions:
-
Use proper URL format:
# ✅ Correct voyager verify --url https://api.example.com/beta ... # ❌ Wrong formats # Missing protocol: api.example.com # Invalid characters: https://api example com # Incomplete: https:// -
Encode special characters:
- Ensure proper URL encoding
- Avoid spaces and special characters
-
Use predefined networks:
# Simpler and less error-prone voyager verify --network mainnet ...
Class Hash Errors
E010: Invalid Class Hash Format
Error Message:
[E010] Invalid class hash format: '<hash>'
Expected format: 0x followed by up to 64 hexadecimal characters
Example: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
Cause: The provided class hash doesn’t match the required format.
Valid Format:
- Must start with
0x - Followed by 1-64 hexadecimal characters (0-9, a-f, A-F)
- Maximum 66 characters total (including
0xprefix)
Solutions:
-
Check hash format:
# ✅ Valid --class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 # ❌ Invalid: Missing 0x prefix --class-hash 044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 # ❌ Invalid: Contains non-hex characters --class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da1z -
Ensure correct characters:
- Only hexadecimal: 0-9, a-f, A-F
- No spaces or special characters
-
Verify hash from deployment:
# Get hash from Starknet deployment output # Or from block explorer
Example:
# Error: Missing 0x prefix
voyager verify --network mainnet \
--class-hash 044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyContract
# [E010] Invalid class hash format
# ✅ Solution: Add 0x prefix
voyager verify --network mainnet \
--class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
--contract-name MyContract
E011: Internal Regex Compilation Error
Error Message:
[E011] Internal regex compilation error
This is an internal error. Please report this issue.
Cause: An internal error occurred when compiling regular expressions for class hash validation.
Solution: This is a bug in the verifier. Please:
- Report the issue on GitHub
- Include the full command you ran
- Include your environment details (OS, voyager-verifier version)
Dependency & Resolution Errors
E012: Invalid Dependency Path
Error Message:
[E012] Invalid dependency path for '<name>': <path>
Cause: A path dependency in Scarb.toml points to an invalid or inaccessible location.
Common Scenarios:
- Path doesn’t exist
- Incorrect relative path
- Permission issues
Solutions:
-
Check path exists:
ls ../my-dependency # Verify path -
Use correct relative path:
[dependencies] my_lib = { path = "../my-dependency" } # Relative from Scarb.toml location -
Verify path format:
# ✅ Correct my_lib = { path = "../dependency" } my_lib = { path = "./local-lib" } # ❌ Wrong my_lib = { path = "~/dependency" } # Don't use ~
Example:
# Error: Path doesn't exist
[dependencies]
utils = { path = "../utils" } # But ../utils doesn't exist
# ✅ Solution: Fix path
[dependencies]
utils = { path = "../common-utils" } # Correct path
E013: Failed to Read Metadata
Error Message:
[E013] Failed to read metadata for '<name>' at path: <path>
Cause: Cannot read or parse Scarb.toml metadata for a path dependency.
Solutions:
-
Check Scarb.toml exists:
ls ../my-dependency/Scarb.toml -
Validate Scarb.toml:
cd ../my-dependency scarb metadata # Test if metadata can be read -
Verify file permissions:
chmod 644 ../my-dependency/Scarb.toml -
Ensure valid TOML:
# Check dependency's Scarb.toml is valid [package] name = "my_dependency" version = "0.1.0"
E014: Path Contains Invalid UTF-8
Error Message:
[E014] Path contains invalid UTF-8 characters
Cause: A file path contains characters that aren’t valid UTF-8.
Solutions:
-
Use ASCII characters only:
- Avoid special characters in file names
- Avoid spaces in directory names
- Use standard English letters and numbers
-
Check for hidden characters:
- Look for control characters or special Unicode
-
Rename files/directories:
# Example: Rename directory with special chars mv "dir with spaces" dir-with-dashes
Contract & Target Errors
E015: Class Hash Not Declared
Error Message:
[E015] Class hash '<hash>' is not declared
Cause: The specified class hash hasn’t been declared on the network.
Solutions:
-
Verify class hash:
# Check on block explorer (Voyager, Starkscan, etc.) # Ensure hash is declared on the network -
Check correct network:
# Ensure using the right network voyager verify --network mainnet ... # Or sepolia -
Declare class before verification:
- Use
starklior deployment tool to declare - Wait for transaction confirmation
- Then verify
- Use
Example:
# Error: Hash not declared on mainnet
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
# [E015] Class hash not declared
# ✅ Solution: Check if declared on sepolia instead
voyager verify --network sepolia \
--class-hash 0x044dc2b3... \
--contract-name MyContract
E016: No Contracts Selected
Error Message:
[E016] No contracts selected for verification
Cause: No contract was specified and none could be auto-detected.
Solutions:
-
Specify contract name:
voyager verify --network mainnet \ --class-hash 0x044dc2b3... \ --contract-name MyContract # Required -
Define in manifest:
[tool.voyager.contracts] MyContract = "0x044dc2b3..." -
Use batch verification:
[[contracts]] class-hash = "0x044dc2b3..." contract-name = "MyContract"
E017: Multiple Contracts Found
Error Message:
[E017] Multiple contracts found - only single contract verification is supported
Cause: Multiple contracts were detected, but you can only verify one at a time (unless using batch mode).
Solutions:
-
Specify which contract:
voyager verify --network mainnet \ --class-hash 0x044dc2b3... \ --contract-name MyToken # Choose one -
Use batch verification for multiple:
# .voyager.toml [[contracts]] class-hash = "0x044dc2b3..." contract-name = "MyToken" [[contracts]] class-hash = "0x055dc2b3..." contract-name = "MyNFT"voyager verify # Verifies all in batch
File System Errors
E018: Path Processing Error
Error Message:
[E018] Path processing error: cannot strip '<prefix>' from '<path>'
This is an internal error. Please report this issue.
Cause: Internal error when processing file paths.
Solution: This is a bug. Please report with:
- Full command
- Project structure
- Scarb.toml contents
E019: File Size Limit Exceeded
Error Message:
[E019] File '<path>' exceeds maximum size limit of <max> bytes (actual: <actual> bytes)
Cause: A file in your project is too large (exceeds individual file size limit).
Solutions:
-
Reduce file size:
- Split large files into smaller modules
- Remove unnecessary code or comments
- Check for generated content
-
Exclude large files:
- Add to
.gitignore - Don’t use
--test-filesif tests are large
- Add to
-
Check for unexpected files:
# Find large files find src -type f -size +1M
Example:
# Error: Large test file
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files # Includes large tests.cairo
# ✅ Solution: Don't include test files
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
E022: File System Error
Error Message:
[E022] File system error
Cause: General file system error (permissions, access issues).
Solutions:
-
Check file permissions:
chmod 644 Scarb.toml chmod 755 src/ -
Verify path exists:
ls -la <path> -
Check disk space:
df -h
E023: Path Contains Invalid UTF-8
Error Message:
[E023] Path contains invalid UTF-8 characters
Cause: File path contains invalid UTF-8 characters.
Solution: Same as E014 - use ASCII characters only in file paths.
E024: Invalid File Type
Error Message:
[E024] File '<path>' has invalid file type (extension: <ext>)
Cause: A file with an unsupported extension was included.
Allowed Extensions:
.cairo- Cairo source files.toml- Configuration files (Scarb.toml).lock- Lock files (Scarb.lock).md- Documentation.txt- Text files.json- JSON files
Solutions:
-
Remove binary/executable files:
# Don't include in project directory rm src/binary_file -
Check for unexpected files:
find src -type f ! -name "*.cairo" -
Add to .gitignore:
*.bin *.exe *.so
Project Configuration Errors
E020: Scarb Manifest Not Found
Error Message:
[E020] Scarb project manifest not found at: <path>
Cause: Scarb.toml file doesn’t exist at the specified path.
Solutions:
-
Check you’re in project directory:
ls Scarb.toml # Should exist -
Use correct path:
voyager verify --network mainnet \ --class-hash 0x044dc2b3... \ --contract-name MyContract \ --path /correct/path/to/project -
Create new project:
scarb init my-project cd my-project
E021: Failed to Read Project Metadata
Error Message:
[E021] Failed to read project metadata: <error>
Cause: Cannot parse Scarb.toml or read project metadata.
Solutions:
-
Validate Scarb.toml:
scarb metadata --format-version 1 -
Check TOML syntax:
# Ensure valid TOML format [package] name = "my_project" version = "0.1.0" [dependencies] starknet = ">=2.11.0" -
Run scarb check:
scarb check -
Update scarb:
asdf install scarb latest
E025: Invalid Project Type
Error Message:
[E025] Invalid project type specified
Specified: <specified>
Detected: <detected>
Cause: Mismatch between specified project type and detected type.
Solutions:
-
Use auto-detection:
# Don't specify project type, let it auto-detect voyager verify --network mainnet \ --class-hash 0x044dc2b3... \ --contract-name MyContract -
Specify correct type:
# For Dojo projects voyager verify --network mainnet \ --class-hash 0x044dc2b3... \ --contract-name MyContract \ --project-type dojo # For Scarb projects voyager verify --network mainnet \ --class-hash 0x044dc2b3... \ --contract-name MyContract \ --project-type scarb
E026: Dojo Project Validation Failed
Error Message:
[E026] Dojo project validation failed
Cause: Project specified as Dojo, but doesn’t meet Dojo requirements.
Solutions:
-
Ensure dojo-core dependency:
[dependencies] dojo = { git = "https://github.com/dojoengine/dojo" } -
Check Dojo project structure:
project/ ├── Scarb.toml ├── src/ │ └── lib.cairo -
Test with sozo:
sozo build -
Use correct project type:
# If not actually Dojo, use scarb voyager verify --network mainnet \ --class-hash 0x044dc2b3... \ --contract-name MyContract \ --project-type scarb
E027: Interactive Prompt Failed
Error Message:
[E027] Interactive prompt failed
Cause: Failed to display interactive wizard prompt.
Solutions:
-
Use CLI arguments instead:
voyager verify --network mainnet \ --class-hash 0x044dc2b3... \ --contract-name MyContract \ --license MIT -
Specify project type:
voyager verify --network mainnet \ --class-hash 0x044dc2b3... \ --contract-name MyContract \ --project-type scarb # Skip prompt -
Check terminal supports interactive input:
- Ensure running in proper terminal
- Check stdin is available
- Not running in non-interactive environment
E028: Internal Error
Error Message:
[E028] Internal error: <message>
This is an internal error that should not occur.
Cause: Unexpected internal error.
Solution: Please report this issue with:
- Full command you ran
- Context/what you were doing
- Any relevant logs or output
Config File Errors
E030: Failed to Read Config File
Error Message:
[E030] Failed to read config file: <error>
Cause:
Cannot read .voyager.toml configuration file.
Solutions:
-
Check file permissions:
chmod 644 .voyager.toml -
Verify file exists:
ls -la .voyager.toml -
Check file is accessible:
cat .voyager.toml # Should display contents
E031: Failed to Parse Config File
Error Message:
[E031] Failed to parse config file: <error>
Cause:
.voyager.toml file has invalid TOML syntax.
Solutions:
-
Validate TOML syntax:
# Ensure proper format [voyager] network = "mainnet" # String values in quotes watch = true # Boolean without quotes -
Check field names:
# ✅ Correct field names [voyager] network = "mainnet" test-files = true # Use hyphens, not underscores # ❌ Wrong [voyager] netwrk = "mainnet" # Typo test_files = true # Underscore instead of hyphen -
Use TOML validator:
- Online TOML validator
- Or use example file as template
-
Check example file:
cp .voyager.toml.example .voyager.toml # Edit as needed
E032: Invalid UTF-8 Path in Config
Error Message:
[E032] Invalid UTF-8 path: <error>
Cause: A path in the config file contains invalid UTF-8 characters.
Solution:
Use ASCII characters only in paths configured in .voyager.toml.
History Database Errors
E040: Failed to Access History Database
Error Message:
[E040] Failed to access history database: <error>
Cause:
Cannot access or open the history database at ~/.voyager/history.db.
Solutions:
-
Check directory exists:
mkdir -p ~/.voyager -
Check permissions:
chmod 755 ~/.voyager chmod 644 ~/.voyager/history.db # If exists -
Check disk space:
df -h ~ -
Remove corrupted database:
# Backup first if needed mv ~/.voyager/history.db ~/.voyager/history.db.bak # Will be recreated automatically
E041: Failed to Create History Directory
Error Message:
[E041] Failed to create history directory: <error>
Cause:
Cannot create ~/.voyager directory.
Solutions:
-
Check home directory permissions:
chmod 755 ~ -
Check disk space:
df -h ~ -
Manual creation:
mkdir -p ~/.voyager chmod 755 ~/.voyager
E042: Unable to Determine Home Directory
Error Message:
[E042] Unable to determine home directory
Cause: Cannot find user’s home directory (HOME environment variable not set).
Solutions:
-
Check HOME variable:
echo $HOME # Should show /home/username -
Set HOME if missing:
export HOME=/home/username -
Check user has home directory:
ls -ld ~
General Errors
E999: General/Network Errors
Error Code:
[E999] <Various error messages>
Cause: Generic error code for network errors, I/O errors, or other uncategorized issues.
Common Causes:
- Network connectivity issues
- Request timeout
- DNS resolution failures
- SSL/TLS errors
- Generic I/O errors
Solutions:
-
Check internet connection:
ping api.voyager.online -
Verify DNS resolution:
nslookup api.voyager.online -
Check firewall/proxy:
- Ensure HTTPS (port 443) is allowed
- Configure proxy if needed
-
Retry the request:
# Sometimes transient network issues resolve on retry voyager verify --network mainnet \ --class-hash 0x044dc2b3... \ --contract-name MyContract -
Use verbose mode:
voyager verify --network mainnet \ --class-hash 0x044dc2b3... \ --contract-name MyContract \ --verbose
Getting Help
If you encounter an error that isn’t resolved by this guide:
-
Use verbose mode to get detailed error information:
voyager status --network mainnet --job <JOB_ID> --verbose -
Check the troubleshooting guide: Troubleshooting
-
Search for similar issues on GitHub
-
Contact support:
- Telegram: @StarknetVoyager
- GitHub: Create an issue
When reporting errors, include:
- Error code and full error message
- Full command you ran
- Output with
--verboseflag - Your environment (OS, voyager-verifier version, scarb version)
- Relevant configuration files (Scarb.toml, .voyager.toml)
See Also
- Common Errors - Frequent problems and solutions
- Debugging Guide - Debugging workflow
- Verbose Mode - Using
--verboseflag - Getting Support - How to get help
Supported Versions
This reference documents version compatibility for Voyager Verifier, including Cairo, Scarb, and Dojo version support.
Quick Reference
| Component | Support Model | Current Support | Notes |
|---|---|---|---|
| Cairo/Scarb | Server-determined | Up to 2.13.1 (Oct 2025) | Version agnostic client |
| Dojo | Auto-detected | Up to 1.8.0 (Oct 2025) | Extracted from dependencies |
| Client | Independent versioning | v2.0.1 | Update via asdf |
Note: Voyager version and supported toolchain versions are independent. The Voyager team continuously works to support the latest Scarb and Dojo releases.
Cairo Version Support
Version-Agnostic Design
Voyager Verifier is version-agnostic - it does not impose Cairo version restrictions. Version support is determined by the Voyager API server.
# Your Scarb.toml
[package]
name = "my_contract"
version = "0.1.0"
[dependencies]
starknet = "2.13.1" # Server determines if supported
Current Support (October 2025)
As of October 2025, the Voyager API supports:
- Cairo/Scarb 2.x: Full support up to 2.13.1
- Newer versions: The Voyager team works to keep up with Scarb releases
- Older versions: Cairo 1.x and 2.x versions maintained
If you need a newer version:
- Check if it’s already supported by testing with
--dry-run - If not available, open an issue on GitHub
- Reach out on Telegram for faster response
Check Current Support:
# The API will inform you if your version is unsupported
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
# If version is unsupported, you'll see:
# Error: Cairo version 2.99.0 is not supported by the API
Version Compatibility Matrix
| Cairo/Scarb Version | Support Status | Notes |
|---|---|---|
| 2.13.x | ✅ Fully Supported | Latest stable (as of Oct 2025) |
| 2.12.x | ✅ Fully Supported | Previous stable |
| 2.11.x | ✅ Fully Supported | Stable |
| 2.10.x | ✅ Fully Supported | Stable |
| 2.9.x | ✅ Fully Supported | Maintained |
| 2.8.x | ✅ Fully Supported | Maintained |
| 2.7.x and older | ✅ Maintained | Legacy support |
| 1.x | ⚠️ Limited Support | Cairo 1.0 era |
| 2.14.x+ | 🔄 Check API / Request | Open GitHub issue if needed |
Note: Version support updates are managed server-side. The client does not require updates for new Cairo versions. The Voyager team continuously works to keep up with the latest Scarb releases.
Scarb Version Support
Client Requirements
Voyager Verifier requires Scarb to be installed and accessible:
# Check your Scarb version
scarb --version
# Example output:
# scarb 2.8.4 (ab1234cd 2024-12-15)
# cairo: 2.8.4 (https://crates.io/crates/cairo-lang-compiler/2.8.4)
Compatible Versions
| Scarb Version | Support Status | Notes |
|---|---|---|
| 2.13.x | ✅ Fully Supported | Latest (as of Oct 2025) |
| 2.12.x | ✅ Fully Supported | Previous stable |
| 2.11.x | ✅ Fully Supported | Stable |
| 2.10.x | ✅ Fully Supported | Stable |
| 2.9.x | ✅ Fully Supported | Maintained |
| 2.8.x | ✅ Fully Supported | Maintained |
| 2.7.x and older | ✅ Maintained | Legacy support |
| 1.x | ⚠️ Limited | Legacy |
| 0.x | ❌ Not Supported | Too old |
Version Detection
The tool automatically detects your Scarb version:
# Voyager reads from scarb metadata
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
# Output includes:
# 📦 Using Scarb 2.8.4
# 🏗️ Using Cairo 2.8.4
Dojo Version Support
Auto-Detection
For Dojo projects, Voyager automatically detects the Dojo version from your Scarb.toml:
# Scarb.toml
[dependencies]
dojo = "1.7.1" # Simple string format
# Or:
[dependencies]
dojo = { tag = "v0.7.0" } # Git tag format
# Or:
[dependencies]
dojo = { version = "2.0.0" } # Table format
Detection Behavior
Voyager searches for Dojo version in this order:
- Package Scarb.toml (if in workspace)
- Workspace root Scarb.toml (fallback)
# Voyager will log:
🔍 Checking for dojo version in package Scarb.toml: /path/to/package/Scarb.toml
✅ Found dojo version in package Scarb.toml: 1.7.1
Supported Dojo Versions
| Dojo Version | Support Status | Project Type |
|---|---|---|
| 1.8.x | ✅ Fully Supported | Latest (as of Oct 2025) |
| 1.7.x | ✅ Fully Supported | sozo build |
| 1.6.x and older | ✅ Supported | sozo build |
| 0.7.x | ✅ Supported | sozo build |
| 0.6.x and older | ⚠️ Limited | May work |
Note: The Voyager team works to keep up with Dojo releases. If you need support for a newer version, open a GitHub issue or reach out on Telegram.
Manual Project Type Selection
If auto-detection fails, specify manually:
# Specify Dojo project explicitly
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--project-type dojo
# Or use interactive prompt:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--project-type auto
Version Upgrade Guide
Upgrading Cairo/Scarb
Check Compatibility First:
- Review Release Notes: https://github.com/starkware-libs/cairo/releases
- Test Locally: Ensure your project builds with the new version
- Verify on Testnet: Test verification on Sepolia before mainnet
Upgrade Steps:
# 1. Install new Scarb version (includes Cairo) via asdf
asdf install scarb latest
asdf global scarb latest
# Verify installation
scarb --version
# 2. Update Scarb.toml
# Edit your Scarb.toml:
[dependencies]
starknet = "2.13.1" # Update to new version
# 3. Verify build works
scarb clean
scarb build --release
# 4. Test verification
voyager verify --network sepolia \
--class-hash 0x... \
--contract-name MyContract
# 5. If successful, proceed with mainnet
voyager verify --network mainnet \
--class-hash 0x... \
--contract-name MyContract
Upgrading Dojo
Upgrade Dojo Projects:
# 1. Update Dojo dependency in Scarb.toml
[dependencies]
dojo = "2.0.0" # New version
# 2. Update sozo
curl -L https://install.dojoengine.org | bash
dojoup
# 3. Rebuild project
sozo clean
sozo build
# 4. Verify detection works
voyager verify --network sepolia \
--class-hash 0x... \
--contract-name MyContract \
--project-type dojo --dry-run
# Should see:
# ✅ Successfully extracted Dojo version: 2.0.0
# 🔨 Build tool: sozo
Upgrading Voyager Client
Keep the client updated using asdf:
# Check current version
voyager --version
# Update to latest version via asdf
asdf install voyager latest
# Set as global default
asdf global voyager latest
# Verify update
voyager --version
Note: Voyager version and supported toolchain (Cairo/Scarb/Dojo) versions are independent. You can update Voyager without worrying about toolchain compatibility - version support is managed server-side.
Alternative: Download from GitHub
Latest releases are also available at: https://github.com/NethermindEth/voyager-verifier/releases
Version-Related Issues
Issue 1: Cairo Version Not Supported
Problem:
Error: Cairo version 2.99.0 is not supported by the API
Solutions:
-
Request Support: The Voyager team works to keep up with Scarb releases
- Open a GitHub issue requesting the version
- Reach out on Telegram for faster response
-
Test with dry-run: Check if the version is already supported
voyager verify --dry-run --network sepolia \ --class-hash 0x044dc2b3... \ --contract-name MyContract -
Use latest supported version (temporary):
# Scarb.toml [dependencies] starknet = "2.13.1" # Use latest supported (as of Oct 2025)
Issue 2: Scarb Metadata Error
Problem:
Error: Failed to parse scarb metadata
Solutions:
-
Update Scarb:
asdf install scarb latest asdf global scarb latest -
Verify Scarb Works:
scarb metadata --format-version 1 -
Clean and Rebuild:
scarb clean scarb build
Issue 3: Dojo Version Not Detected
Problem:
⚠️ Could not extract Dojo version from Scarb.toml - proceeding without version
Solutions:
-
Check Dependency Format:
# ✅ Correct formats: [dependencies] dojo = "1.7.1" # OR dojo = { version = "1.7.1" } # OR dojo = { tag = "v0.7.0" } -
Specify Project Type Explicitly:
voyager verify --project-type dojo ... -
Verify Dojo is Installed:
sozo --version
Issue 4: Version Mismatch
Problem:
Error: Class hash mismatch
Solution: Use Lock File for Reproducibility:
# Include Scarb.lock to ensure exact dependency versions
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--lock-file
# Commit lock file to version control
git add Scarb.lock
git commit -m "Add lock file for reproducible builds"
Version Checking Tools
Check All Versions
#!/bin/bash
# version-check.sh - Check all component versions
echo "=== Voyager Verifier Version Check ==="
echo
echo "📦 Voyager Client:"
voyager --version
echo
echo "🏗️ Scarb:"
scarb --version
echo
echo "🔧 Cairo:"
scarb --version | grep cairo
echo
echo "🎮 Sozo (if installed):"
sozo --version 2>/dev/null || echo "Not installed"
echo
echo "📄 Project Starknet Version (from Scarb.toml):"
grep "starknet = " Scarb.toml | head -1
echo
echo "🔗 Dojo Version (from Scarb.toml):"
grep "dojo = " Scarb.toml || echo "Not a Dojo project"
Version Compatibility Check
# Quick compatibility check
voyager verify --dry-run \
--network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--verbose
# Dry-run will validate versions without submitting
API Version Support
Server-Side Version Management
The Voyager API manages version support server-side:
Version Checking:
The CLI tool automatically validates version compatibility when submitting verification jobs. Unsupported versions will be rejected with an appropriate error message.
Version Update Timeline
Typical Timeline for New Cairo Releases:
- Day 0: Cairo version released by Starkware
- Days 1-7: Testing and integration
- Week 2: Voyager API updated with support
- Ongoing: Version available for verification
Stay Updated:
- GitHub Releases: https://github.com/NethermindEth/voyager-verifier/releases
- Telegram: https://t.me/StarknetVoyager
- API Documentation: Updated with supported versions
Best Practices
✅ Version Management Best Practices
-
Pin Cairo Versions in Production
# Scarb.toml - Use specific versions [dependencies] starknet = "2.8.4" # Not "^2.8" or ">=2.8" -
Commit Lock Files
git add Scarb.lock -
Test Before Upgrading
# Always test on Sepolia first voyager verify --network sepolia ... -
Keep Voyager Updated
# Update regularly for bug fixes asdf install voyager latest asdf global voyager latestNote: Voyager version is independent of toolchain versions - you can safely update without compatibility concerns.
-
Document Your Versions
# Add to your README.md: # Cairo: 2.8.4 # Scarb: 2.8.4 # Dojo: 1.7.1 (if applicable) -
Monitor API Changes
- Watch for announcements on Telegram
- Review GitHub release notes
- Test periodically on testnet
Version FAQ
Q: What Cairo version should I use?
A: Use the latest stable version that’s supported by the API. As of October 2025, Cairo/Scarb 2.13.1 is fully supported. Check the compatibility matrix above.
Q: Do I need to upgrade Voyager for new Cairo versions?
A: No. Voyager version and toolchain versions are independent. Version support is determined by the API server, not the client. You can safely update Voyager without worrying about Cairo/Scarb compatibility.
Q: How do I request support for a newer version?
A: If a newer version of Cairo/Scarb or Dojo is not yet supported:
- Test with
--dry-runfirst to confirm it’s unsupported - Open a GitHub issue
- Reach out on Telegram for faster response
The Voyager team continuously works to support the latest releases.
Q: Can I use different Cairo versions in a workspace?
A: Yes, each package in a workspace can specify its own starknet dependency version in its Scarb.toml.
Q: How do I check if my version is supported?
A: Run a verification with --dry-run to check compatibility without submitting:
voyager verify --dry-run ...
Q: What if my Dojo version isn’t detected?
A: Manually specify --project-type dojo. The version is optional; verification works without it.
Q: Can I verify contracts built with older Cairo versions?
A: Yes, the API maintains support for older Cairo versions. Version 1.x and 2.x contracts can be verified.
See Also
- Error Codes - Version-related error codes (E010-E014)
- File Collection - Which files are included in verification
- Common Errors - Version-related issues
- Cairo Documentation - Official Cairo docs
- Scarb Documentation - Scarb documentation
- Dojo Documentation - Dojo documentation
File Collection
This reference documents which files are collected and included when submitting contract verification requests.
Quick Reference
| File Type | Included by Default | Flag Required | Max Size | Notes |
|---|---|---|---|---|
| Cairo source files (.cairo) | ✅ Yes | None | 20MB each | Excluding tests by default |
| Scarb.toml (package) | ✅ Yes | None | 20MB | Always included |
| Scarb.toml (workspace) | ✅ Yes (if workspace) | None | 20MB | Auto-detected |
| Scarb.lock | ❌ No | --lock-file | 20MB | Optional for reproducibility |
| Test files (.cairo in tests/) | ❌ No | --test-files | 20MB each | In src/ directory only |
| Documentation (.md, .txt) | ✅ Yes (if found) | None | 20MB each | LICENSE, README, etc. |
| Rust files (.rs) | ✅ Yes (proc-macro only) | None | 20MB each | For procedural macro packages |
Collection Overview
Collection Process
Start Verification
↓
1. Collect Source Files
└─ All .cairo files in src/
└─ Exclude tests/* by default
└─ Include tests if --test-files
↓
2. Add Manifest Files
└─ Package Scarb.toml
└─ Workspace Scarb.toml (if workspace)
↓
3. Add Optional Files
└─ Scarb.lock (if --lock-file)
└─ Documentation files
↓
4. Validate Files
└─ Check file types
└─ Check file sizes (max 20MB)
↓
5. Find Contract File
└─ Search for #[starknet::contract]
└─ Fallback to heuristics
↓
Submit to API
Source Files
Cairo Source Files (.cairo)
Default Behavior:
All .cairo files in the src/ directory are collected:
my-project/
├── src/
│ ├── lib.cairo ✅ Included
│ ├── contract.cairo ✅ Included
│ ├── utils.cairo ✅ Included
│ └── tests/
│ └── test_contract.cairo ❌ Excluded (by default)
Collection Rules:
- Recursive Search: All Cairo files under
src/are found recursively - Test Exclusion: Files in
test/ortests/directories are excluded by default - Target Filtering: Only files relevant to the specified package are included
Example:
# Collect only production Cairo files
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
# Files collected:
# ✅ src/lib.cairo
# ✅ src/contract.cairo
# ✅ src/utils.cairo
# ❌ src/tests/test_contract.cairo (excluded)
Manifest Files
Package Scarb.toml
Always Included:
The package’s Scarb.toml is always included in verification submissions.
# Scarb.toml - Always included
[package]
name = "my_contract"
version = "0.1.0"
[dependencies]
starknet = "2.8.4"
Why It’s Needed:
- Defines package metadata (name, version, license)
- Specifies Cairo version
- Lists dependencies
- Contains Dojo version (if applicable)
Workspace Scarb.toml
Included for Workspace Projects:
If your project is part of a Scarb workspace, both manifests are included:
my-workspace/
├── Scarb.toml ✅ Workspace manifest (included)
└── packages/
└── my_contract/
└── Scarb.toml ✅ Package manifest (included)
Workspace Detection:
Voyager automatically detects workspace setups by comparing manifest paths:
#![allow(unused)]
fn main() {
// From file_collector.rs
let is_workspace = workspace_manifest != manifest_path;
}
Example Workspace:
# Workspace Scarb.toml (root)
[workspace]
members = [
"packages/contracts",
"packages/tokens",
]
[workspace.package]
version = "0.1.0"
Lock File
Scarb.lock
Optional - Requires --lock-file Flag:
The lock file is only included when explicitly requested:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--lock-file
When to Use Lock Files:
✅ Use when:
- You want reproducible builds
- Dependency versions matter
- You’re getting class hash mismatches
- You’ve committed Scarb.lock to version control
❌ Don’t use when:
- Testing with latest dependencies
- Lock file doesn’t exist
- You want flexible dependency resolution
Lock File Behavior:
# If --lock-file is set but file doesn't exist:
⚠️ --lock-file flag enabled but Scarb.lock not found at /path/to/Scarb.lock
# If file exists:
✅ Including Scarb.lock file: /path/to/Scarb.lock
Example Lock File:
# Scarb.lock
version = 1
[[package]]
name = "my_contract"
version = "0.1.0"
dependencies = [
"starknet 2.8.4 (registry+https://...)",
]
[[package]]
name = "starknet"
version = "2.8.4"
source = "registry+https://..."
Test Files
Test File Detection
Excluded by Default:
Test files in src/test/ or src/tests/ are excluded unless --test-files is specified:
my-project/
├── src/
│ ├── lib.cairo ✅ Included
│ ├── contract.cairo ✅ Included
│ ├── tests/
│ │ └── test_contract.cairo ❌ Excluded (default)
│ └── test/
│ └── test_utils.cairo ❌ Excluded (default)
Including Test Files
Use --test-files Flag:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--test-files
# Now includes:
# ✅ src/lib.cairo
# ✅ src/contract.cairo
# ✅ src/tests/test_contract.cairo
# ✅ src/test/test_utils.cairo
When Test Files Are Required:
Test files must be included if:
-
Your contract imports test modules:
// src/lib.cairo mod contract; #[cfg(test)] mod tests; // Error E005 without --test-files -
Test code is referenced in production:
// src/lib.cairo use my_contract::tests::TestHelper; // Requires --test-files -
Compilation fails with E005:
Error[E005]: Module file not found. Expected path: /tmp/.../src/tests.cairo Solution: Add --test-files flag
Test File Location Rules
Only src/ Tests Are Included:
my-project/
├── src/
│ └── tests/
│ └── test_contract.cairo ✅ Included with --test-files
├── tests/
│ └── integration_test.cairo ❌ Never included
└── test/
└── e2e_test.cairo ❌ Never included
Detection Logic:
#![allow(unused)]
fn main() {
// From resolver.rs
let is_in_src = path_str.contains("/src/");
let has_test_in_path = path_str.contains("/test") || path_str.contains("/tests/");
if is_in_src && has_test_in_path {
return include_test_files; // Only if --test-files flag is set
}
}
Procedural Macro Packages
Rust Files for Proc Macros
Special Case for Cairo Proc Macro Packages:
If your package is a procedural macro package (defined with cairo-plugin = true in Cargo.toml), Rust files are also collected:
my-proc-macro/
├── Cargo.toml ✅ Included
├── Scarb.toml ✅ Included
└── src/
├── lib.rs ✅ Included
└── utils.rs ✅ Included
Cargo.toml Validation:
# Cargo.toml
[package]
name = "my_proc_macro"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"] # Required
proc-macro = true # Required
[dependencies]
cairo-lang-macro = "*" # Required
Files Collected:
- Cargo.toml - Rust package manifest
- Cargo.lock - Rust dependency lock file (if exists)
- All .rs files in src/
- Scarb.toml - Cairo package manifest
File Type Validation
Allowed File Types
Voyager validates file types before submission:
#![allow(unused)]
fn main() {
// From file_collector.rs
let allowed_extensions = ["cairo", "toml", "lock", "md", "txt", "json"];
}
Valid File Extensions:
| Extension | Type | Example |
|---|---|---|
.cairo | Cairo source | src/contract.cairo |
.toml | Configuration | Scarb.toml, Cargo.toml |
.lock | Lock files | Scarb.lock, Cargo.lock |
.md | Documentation | README.md, CHANGELOG.md |
.txt | Text files | LICENSE.txt, NOTICE.txt |
.json | JSON data | metadata.json |
.rs | Rust source | src/lib.rs (proc-macro only) |
Files Without Extensions:
These common project files are allowed without extensions:
LICENSEREADMECHANGELOGNOTICEAUTHORSCONTRIBUTORS
Example:
my-project/
├── LICENSE ✅ Allowed (no extension)
├── README ✅ Allowed (no extension)
├── README.md ✅ Allowed (.md)
├── Scarb.toml ✅ Allowed (.toml)
├── notes.txt ✅ Allowed (.txt)
├── config.yaml ❌ Rejected (.yaml not allowed)
└── image.png ❌ Rejected (.png not allowed)
Error on Invalid Type:
Error[E026]: Invalid file type '.yaml' for file: config.yaml
Allowed extensions: cairo, toml, lock, md, txt, json
Allowed files without extension: LICENSE, README, CHANGELOG, NOTICE, AUTHORS, CONTRIBUTORS
File Size Limits
Maximum File Size: 20MB
All files are validated against a 20MB size limit:
#![allow(unused)]
fn main() {
// From file_collector.rs
const MAX_FILE_SIZE: usize = 1024 * 1024 * 20; // 20MB limit
}
Size Validation:
# Files under 20MB pass validation
✅ src/contract.cairo (145 KB)
✅ Scarb.toml (2 KB)
✅ README.md (15 KB)
# Files over 20MB are rejected
❌ src/huge_contract.cairo (25 MB)
Error on Size Limit:
Error[E027]: File size exceeds limit
File: src/huge_contract.cairo
Size: 25 MB
Maximum allowed: 20 MB
Suggestion: Split large files into smaller modules
Best Practices:
- Keep contracts modular: Split large contracts into smaller files
- Avoid generated code: Don’t include large auto-generated files
- Remove unnecessary documentation: Keep docs concise
Contract File Detection
Finding the Main Contract
Voyager automatically finds the main contract file:
Detection Strategy
1. Pattern-Based Search (Primary):
Searches for the actual contract definition:
#[starknet::contract]
mod MyContract {
// ...
}
2. Heuristic Fallback:
If pattern search fails, tries these paths (case-insensitive):
src/mycontract.cairo
src/contract.cairo
src/lib.cairo
src/main.cairo
<first .cairo file found>
Example:
# Contract name: MyToken
# Search order:
1. Find #[starknet::contract] + mod MyToken ✅ src/token.cairo
2. If not found: src/mytoken.cairo
3. If not found: src/contract.cairo
4. If not found: src/lib.cairo
5. If not found: src/main.cairo
6. If not found: first .cairo file
Explicit Contract File Location:
// src/token.cairo
#[starknet::contract]
mod MyToken {
// Voyager will find this even if filename doesn't match
// because it searches for the pattern
}
Common File Collection Scenarios
Scenario 1: Simple Single Package
my-contract/
├── Scarb.toml
├── src/
│ ├── lib.cairo
│ └── contract.cairo
└── Scarb.lock
# Default collection:
voyager verify --network mainnet \
--class-hash 0x... \
--contract-name MyContract
# Files included:
✅ Scarb.toml
✅ src/lib.cairo
✅ src/contract.cairo
❌ Scarb.lock (not included by default)
Scenario 2: Workspace Project
my-workspace/
├── Scarb.toml (workspace manifest)
└── packages/
└── my_contract/
├── Scarb.toml (package manifest)
└── src/
└── lib.cairo
# Default collection:
voyager verify --network mainnet \
--class-hash 0x... \
--contract-name MyContract \
--package my_contract
# Files included:
✅ Scarb.toml (workspace)
✅ packages/my_contract/Scarb.toml
✅ packages/my_contract/src/lib.cairo
Scenario 3: Contract with Tests
my-contract/
├── Scarb.toml
└── src/
├── lib.cairo
├── contract.cairo
└── tests/
└── test_contract.cairo
# Without --test-files:
voyager verify --network mainnet \
--class-hash 0x... \
--contract-name MyContract
# Files included:
✅ Scarb.toml
✅ src/lib.cairo
✅ src/contract.cairo
❌ src/tests/test_contract.cairo
# With --test-files:
voyager verify --network mainnet \
--class-hash 0x... \
--contract-name MyContract \
--test-files
# Files included:
✅ Scarb.toml
✅ src/lib.cairo
✅ src/contract.cairo
✅ src/tests/test_contract.cairo
Scenario 4: Reproducible Build with Lock File
my-contract/
├── Scarb.toml
├── Scarb.lock
└── src/
└── lib.cairo
# With --lock-file:
voyager verify --network mainnet \
--class-hash 0x... \
--contract-name MyContract \
--lock-file
# Files included:
✅ Scarb.toml
✅ Scarb.lock
✅ src/lib.cairo
Scenario 5: Procedural Macro Package
my-proc-macro/
├── Cargo.toml
├── Cargo.lock
├── Scarb.toml
└── src/
├── lib.rs
└── utils.rs
# Default collection (auto-detected as proc-macro):
voyager verify --network mainnet \
--class-hash 0x... \
--contract-name MyMacro
# Files included:
✅ Cargo.toml
✅ Cargo.lock
✅ Scarb.toml
✅ src/lib.rs
✅ src/utils.rs
Dry-Run: Preview File Collection
Using –dry-run Flag
Preview which files will be collected:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract \
--dry-run
Output Shows:
📦 Files to be submitted:
✅ Scarb.toml
✅ src/lib.cairo
✅ src/contract.cairo
✅ src/utils.cairo
📊 Summary:
Total files: 4
Total size: 47.3 KB
Contract file: src/contract.cairo
🔍 Validation:
✅ All files under 20MB
✅ All file types valid
✅ Contract file found
✨ Dry-run successful - no files were submitted
File Collection Errors
E005: Module File Not Found
Error:
Error[E005]: Module file not found. Expected path: /tmp/.../src/tests.cairo
Cause: Contract imports a test module but --test-files flag not set
Solution:
voyager verify --test-files ...
See: Error Codes E005
E026: Invalid File Type
Error:
Error[E026]: Invalid file type '.yaml' for file: config.yaml
Cause: File has an unsupported extension
Solution: Only include files with allowed extensions (cairo, toml, lock, md, txt, json)
E027: File Size Limit Exceeded
Error:
Error[E027]: File size exceeds limit
File: src/huge_contract.cairo
Size: 25 MB
Maximum allowed: 20 MB
Cause: Individual file exceeds 20MB limit
Solution:
- Split large files into modules
- Remove unnecessary code or comments
- Refactor into smaller components
E028: File Not Found
Error:
Error[E028]: File not found: src/contract.cairo
Cause: Expected file doesn’t exist at the specified path
Solution:
- Verify file path is correct
- Check file was created
- Ensure proper casing (case-sensitive)
Best Practices
✅ File Collection Best Practices
-
Commit Lock Files
git add Scarb.lock git commit -m "Add lock file for reproducibility" -
Use –test-files Only When Needed
# Only if tests are actually imported voyager verify --test-files ... -
Keep Files Under 20MB
// Split large contracts: mod contract_part1; mod contract_part2; -
Use Dry-Run to Preview
# Always check before submitting voyager verify --dry-run ... -
Organize Source Files
src/ ├── lib.cairo # Main entry ├── contract.cairo # Contract code ├── utils.cairo # Utilities └── tests/ # Tests (separate) -
Include Minimal Documentation
# Included documentation: ✅ LICENSE ✅ README.md (keep concise) ❌ docs/ (not submitted) ❌ examples/ (not submitted)
FAQ
Q: Are test files included by default?
A: No. Test files in src/test/ or src/tests/ are excluded by default. Use --test-files to include them.
Q: Is Scarb.lock included automatically?
A: No. Use --lock-file flag to include it. Recommended for reproducible builds.
Q: What files are always included?
A:
- All
.cairofiles insrc/(except tests) - Package
Scarb.toml - Workspace
Scarb.toml(if workspace)
Q: Can I include custom configuration files?
A: Only files with allowed extensions (.cairo, .toml, .lock, .md, .txt, .json) are accepted.
Q: What’s the maximum file size?
A: 20MB per file. Split larger files into modules.
Q: How do I see which files will be submitted?
A: Use --dry-run flag to preview file collection without submitting.
Q: Are files outside src/ included?
A: Only manifest files (Scarb.toml) and optional files (Scarb.lock, LICENSE, README.md) are included from the project root.
See Also
- Error Codes - File collection errors (E005, E025-E029)
- Test Files Guide - Using
--test-filesflag - Lock Files Guide - Using
--lock-fileflag - Common Errors - File-related issues
- Multi-Package Guide - Workspace file collection
API Reference
This reference documents the API interactions used by the Voyager CLI for contract verification.
Overview
The Voyager CLI communicates with the Voyager verification service to submit contracts for verification and check their status. All API interactions are handled internally by the CLI - users don’t need to make direct API calls.
CLI Commands
Verify Command
Submit a contract for verification:
voyager verify --network mainnet \
--class-hash 0x044dc2b3... \
--contract-name MyContract
Status Command
Check verification job status:
voyager status --network mainnet --job abc123def456
Check Command
Check if a class is already verified:
voyager check --network mainnet --class-hash 0x044dc2b3...
Job Status Codes
Status Values
| Code | Name | Description | Terminal |
|---|---|---|---|
0 | Submitted | Job submitted, waiting to be processed | No |
1 | Compiled | Contract compiled successfully | No |
2 | CompileFailed | Compilation failed | Yes |
3 | Fail | Verification failed | Yes |
4 | Success | Contract verified successfully | Yes |
5 | Processing | Job is being processed | No |
Unknown | Unknown | Unknown status | No |
Terminal States:
Jobs in these states are considered complete and won’t change:
CompileFailed(2)Fail(3)Success(4)
Non-Terminal States:
Jobs in these states are still in progress:
Submitted(0)Compiled(1)Processing(5)
Status Meanings
0 - Submitted: Job has been received and is waiting in the queue.
1 - Compiled: Contract compiled successfully, now comparing class hash.
2 - CompileFailed:
Compilation failed. Use --verbose flag for compiler error details.
3 - Fail: Verification failed. Common causes:
- Class hash mismatch
- Build configuration mismatch
- Missing dependencies
4 - Success: Verification completed successfully! Contract is now verified on the explorer.
5 - Processing: Job is actively being processed by the server.
Job Lifecycle
Typical Successful Flow
1. Submitted (0)
↓
[Job received]
↓
2. Processing (5)
↓
[Server compiles contract]
↓
3. Compiled (1)
↓
[Server verifies hash]
↓
4. Success (4)
[Verification complete!]
Typical Failure Flow
1. Submitted (0)
↓
[Job received]
↓
2. Processing (5)
↓
[Server attempts compilation]
↓
3. CompileFailed (2)
[Compilation errors found]
OR
3. Compiled (1)
↓
[Server verifies hash]
↓
4. Fail (3)
[Hash mismatch]
State Transition Diagram
Submitted (0)
↓
Processing (5)
↙ ↘
CompileFailed Compiled (1)
(2) ↓
Verifying...
↙ ↘
Fail (3) Success (4)
Networks
Predefined Networks
1. Mainnet (Default)
voyager verify --network mainnet --class-hash 0x...
voyager status --network mainnet --job abc123
voyager check --network mainnet --class-hash 0x...
2. Sepolia Testnet
voyager verify --network sepolia --class-hash 0x...
voyager status --network sepolia --job abc123
voyager check --network sepolia --class-hash 0x...
3. Dev Environment
voyager verify --network dev --class-hash 0x...
voyager status --network dev --job abc123
voyager check --network dev --class-hash 0x...
Custom Endpoints
For staging/internal environments, use the --url flag:
voyager verify --url https://custom-api.example.com/beta \
--class-hash 0x... \
--contract-name MyContract
Polling and Watch Mode
Watch Mode
Use --watch to automatically poll until verification completes:
voyager verify --network mainnet \
--class-hash 0x... \
--contract-name MyContract \
--watch
The CLI uses exponential backoff when polling:
- Initial delay: 2 seconds
- Maximum delay: 10 seconds
- Maximum total time: ~30 minutes
Typical Timing
| Job Result | Typical Duration |
|---|---|
| Success (simple contract) | 5-15 seconds |
| Success (complex contract) | 15-60 seconds |
| CompileFailed | 10-30 seconds |
| Fail (hash mismatch) | 15-45 seconds |
Error Handling
Common Errors
Job Not Found (E008):
[E008] Job 'abc123' not found
Suggestions:
• Check that the job ID is correct
• Verify the job was submitted successfully
• The job may have expired from the server
Class Not Found (E012):
[E012] Class '0x...' not found on-chain
Suggestions:
• Check that the class hash is correct
• Verify the class has been declared on the network
• Ensure you're using the correct network
Verbose Mode
Use --verbose for detailed error information:
voyager status --network mainnet --job abc123 --verbose
See Also
- Error Codes - Complete list of error codes
- Custom Endpoints Guide - Using custom API endpoints
- Status Command - Checking job status
- Check Command - Checking verification status
- Troubleshooting - Common issues and solutions
Contributing
Thank you for your interest in contributing to Voyager Verifier! This guide will help you get started.
Table of Contents
- Code of Conduct
- How to Contribute
- Opening an Issue
- Submitting a Pull Request
- Development Setup
- Coding Standards
- Documentation
- Community
Code of Conduct
By participating in this project, you agree to maintain a respectful and inclusive environment. Be considerate, professional, and constructive in all interactions.
How to Contribute
There are many ways to contribute to Voyager Verifier:
- Report bugs - Found a bug? Let us know by opening an issue
- Suggest features - Have an idea? Open an issue to discuss it
- Fix issues - Browse open issues and submit a fix
- Improve documentation - Help make our docs better
- Write tests - Increase code coverage and reliability
Opening an Issue
Before opening a pull request, please open an issue first. This allows us to:
- Discuss the proposed changes
- Ensure the approach aligns with project goals
- Avoid duplicate work
- Provide feedback early in the process
Bug Reports
When reporting a bug, please include:
- Clear title - Summarize the issue concisely
- Description - Detailed explanation of the problem
- Steps to reproduce - Specific steps to trigger the bug
- Expected behavior - What should happen
- Actual behavior - What actually happens
- Environment - OS, Rust version, dependency versions
- Error messages - Full error output or stack traces
- Screenshots - If applicable
Feature Requests
When suggesting a feature, please include:
- Use case - Why is this feature needed?
- Proposed solution - How should it work?
- Alternatives - Other approaches you’ve considered
- Implementation details - Technical considerations if applicable
Submitting a Pull Request
Workflow
- Open an issue first to discuss the changes
- Fork the repository and create a branch from
main - Make your changes following our coding standards
- Write or update tests to cover your changes
- Update documentation as needed
- Ensure tests pass with
cargo test - Run linting with
cargo lint - Format code with
cargo fmt - Commit your changes with clear, descriptive messages
- Push to your fork and submit a pull request
Pull Request Guidelines
- Reference the issue - Link to the issue your PR addresses
- Clear description - Explain what changes you made and why
- Small, focused PRs - Keep changes atomic and easy to review
- One feature per PR - Don’t bundle unrelated changes
- Tests included - All new code should have tests
- Documentation updated - Keep docs in sync with code changes
- CI must pass - All checks must be green before merge
Commit Messages
Write clear, descriptive commit messages:
Short summary (50 chars or less)
More detailed explanation if needed. Wrap at 72 characters.
Explain the problem this commit solves and why this approach
was chosen.
Fixes #123
Development Setup
Prerequisites
- Rust 1.70 or later
- Cargo
- Git
Getting Started
-
Clone your fork:
git clone https://github.com/YOUR_USERNAME/voyager-verifier.git cd voyager-verifier -
Add upstream remote:
git remote add upstream https://github.com/NethermindEth/voyager-verifier.git -
Install dependencies:
cargo build -
Run tests:
cargo test -
Run the project:
cargo run
Keeping Your Fork Updated
git fetch upstream
git checkout main
git merge upstream/main
Coding Standards
Rust Style
- Follow standard Rust conventions and idioms
- Use
cargo fmtto format code - Address all
cargo lintwarnings - Write idiomatic Rust code
Code Quality
- Write tests - Aim for high test coverage
- Handle errors properly - Use
Resultand proper error types - Document public APIs - Add doc comments to public items
- Avoid unwrap/expect - Handle errors gracefully
- Keep functions focused - Single responsibility principle
- Use meaningful names - Clear, descriptive variable and function names
Testing
- Write unit tests for individual functions
- Add integration tests for workflows
- Test edge cases and error conditions
- Ensure all tests pass before submitting
Documentation
See Documentation Guidelines for detailed information on:
- Writing and updating documentation
- Building documentation locally
- Documentation structure and style
Community
Quick Links
Getting Help
- Check existing documentation
- Search closed issues for similar problems
- Open a new issue if you need help
Review Process
- Maintainers will review your PR as soon as possible
- Be responsive to feedback and questions
- Changes may be requested before merging
- Once approved, a maintainer will merge your PR
License
By contributing to Voyager Verifier, you agree that your contributions will be licensed under the same license as the project.
Documentation
This guide covers how to contribute to Voyager Verifier’s documentation.
Overview
Good documentation is crucial for project success. We welcome contributions that:
- Fix typos and grammatical errors
- Clarify confusing explanations
- Add missing information
- Improve code examples
- Update outdated content
- Add tutorials and guides
Documentation Structure
Our documentation is organized as follows:
docs/
├── src/
│ ├── SUMMARY.md # Table of contents
│ ├── introduction.md # Getting started
│ ├── architecture/ # System design docs
│ ├── api/ # API reference
│ ├── guides/ # How-to guides
│ └── contributing/ # Contribution guidelines
Making Changes
1. Open an Issue First
Before making documentation changes, please open an issue to:
- Discuss significant restructuring or additions
- Get feedback on your proposed changes
- Ensure the changes align with documentation goals
For minor fixes (typos, formatting), you can skip this step.
2. Build Documentation Locally
We use mdBook for documentation.
Install mdBook:
cargo install mdbook
Build and serve locally:
cd docs
mdbook serve
Then open http://localhost:3000 in your browser to preview changes.
3. Make Your Changes
Edit the Markdown files in docs/src/. As you save, mdBook will automatically rebuild and refresh your browser.
Writing Guidelines
Style and Tone
- Clear and concise - Use simple, direct language
- Active voice - “The verifier checks” instead of “The check is performed”
- Present tense - “The function returns” not “The function will return”
- Second person - Address the reader as “you”
- Technical but accessible - Explain concepts without oversimplifying
Structure
- Start with overview - Begin each section with a summary
- Progressive detail - Go from simple to complex
- Use headings - Break content into scannable sections
- Include examples - Show concrete usage
- Add context - Explain the “why” not just the “how”
Code Examples
- Complete and runnable - Examples should work as-is
- Realistic - Use meaningful variable names and scenarios
- Commented - Explain non-obvious parts
- Tested - Ensure examples actually work
Example format:
// Verify a Cairo contract on Starknet
use voyager_verifier::Verifier;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let verifier = Verifier::new("https://api.voyager.online");
// Submit verification request
let result = verifier.verify(
"0x1234...", // Contract address
"path/to/source.cairo"
)?;
println!("Verification: {:?}", result);
Ok(())
}
Markdown Best Practices
- Use fenced code blocks with language hints:
```rust - Use relative links for internal pages:
[Guide](../guides/quickstart.md) - Add alt text to images:
 - Use tables for structured data
- Use admonitions for warnings/notes if supported
API Documentation
When documenting APIs:
- Function signature - Show the full signature
- Parameters - List all parameters with types and descriptions
- Return value - Describe what is returned
- Errors - Document possible error conditions
- Examples - Provide usage examples
- Related - Link to related functions/types
Common Documentation Tasks
Adding a New Page
- Create the Markdown file in the appropriate directory
- Add it to
docs/src/SUMMARY.mdin the correct section - Link to it from related pages
Updating API Documentation
- Update the relevant Rust doc comments in source code
- Update the corresponding API reference page if it exists
- Update any examples that reference the changed API
Adding Code Examples
- Write the example code
- Test that it compiles and runs correctly
- Add explanatory comments
- Include it in the documentation with context
Fixing Broken Links
- Use
mdbook buildto check for broken links - Update links to point to the correct location
- Use relative paths for internal links
Documentation Checklist
Before submitting your documentation changes:
- Spell check and grammar check completed
- Code examples tested and working
- Links verified (no broken links)
- Documentation builds without errors:
mdbook build - Preview looks correct:
mdbook serve - Changes reviewed in browser at
http://localhost:3000 - SUMMARY.md updated if new pages added
- Related pages updated to cross-reference new content
Review Process
- Submit your PR referencing the related issue
- Maintainers will review for:
- Technical accuracy
- Clarity and readability
- Consistency with existing docs
- Proper formatting and structure
- Address any feedback
- Once approved, your changes will be merged and published
Style Reference
Headings
# Page Title (H1 - one per page)
## Major Section (H2)
### Subsection (H3)
#### Minor Section (H4)
Emphasis
**Bold** for emphasis and UI elements
*Italic* for introducing new terms
`code` for inline code and commands
Lists
- Unordered list item
- Another item
- Nested item
1. Ordered list item
2. Second item
Code Blocks
```rust
// Rust code
fn main() {
println!("Hello, world!");
}
```
```bash
# Shell commands
cargo build
```
Links
[Link text](https://example.com)
[Internal link](../other-page.md)
[Heading link](#heading-anchor)
Questions?
If you have questions about documentation:
- Check existing documentation pages as examples
- Review the mdBook documentation
- Open an issue to discuss your plans
- Ask in your pull request
Thank you for helping improve Voyager Verifier’s documentation!