Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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.toml config 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:

  1. Prepare Your Project - Ensure your Scarb project builds successfully
  2. Submit for Verification - Use the CLI to submit your contract class hash and source code
  3. Monitor Progress - Track the verification status with built-in polling
  4. 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:

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 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:

  1. Make sure asdf is properly configured in your shell profile (.bashrc, .zshrc, etc.)
  2. Restart your terminal or run source ~/.bashrc (or your shell’s config file)
  3. Verify asdf is working: asdf --version

Plugin Installation Fails

If adding the plugin fails:

  1. Ensure you have git installed
  2. Check your network connection
  3. 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:

  1. Ensure Rust is properly installed
  2. Make sure ~/.cargo/bin is in your PATH
  3. Restart your terminal
  4. 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:

  1. Check your internet connection
  2. Check if you’re behind a proxy (configure cargo proxy settings)
  3. Try using a VPN if crates.io is blocked

Permission Errors

If you get permission errors during installation:

  • Never use sudo with cargo install
  • Ensure ~/.cargo/bin is 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) or openssl-devel (Fedora/RHEL)
    • macOS: pkg-config, openssl (via Homebrew)
    • Windows: Visual Studio Build Tools

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 git or Xcode Command Line Tools
  • Windows: Git for Windows

asdf

Only required for asdf installation method.

See asdf installation guide.

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 your Scarb.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:

  1. In Scarb.toml:

    [package]
    license = "MIT"
    
  2. Via CLI flag:

    --license MIT
    
  3. In .voyager.toml config 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 --url flag

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.toml if needed
  • Network connectivity to Voyager API
  • (Optional) License identifier is specified

Next Steps

Once you’ve verified all requirements are met:

Troubleshooting

If you’re missing requirements:

  • Scarb not found: Install from Scarb documentation
  • Build fails: Check your Scarb.toml configuration 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:

The easiest way to verify your contract with guided prompts.

Jump to Wizard Method →

⌨️ Command Line (For Experienced Users)

Direct command-line verification for those who know what they’re doing.

Jump to CLI Method →

📦 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:

  1. Network Selection

    • Choose: Mainnet, Sepolia, Dev, or Custom
    • Example: mainnet
  2. Class Hash

    • The class hash of your declared contract class
    • Example: 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
  3. Package (for workspace projects only)

    • Select the package to verify
    • Auto-detected for single-package projects
  4. Contract Name

    • The name of your contract
    • Example: MyToken
  5. License (optional)

    • Auto-detected from Scarb.toml if present
    • Can specify manually (e.g., MIT, Apache-2.0)
  6. 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 --verbose for details) ❌
  • CompileFailed - Compilation error (use --verbose for 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:

  1. Visit Voyager Explorer
  2. Search for your class hash
  3. You’ll see the verified badge ✓
  4. 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:


Quick Reference

Minimal Command

voyager verify --network mainnet \
  --class-hash <HASH> \
  --contract-name <NAME>
voyager verify --network mainnet \
  --class-hash <HASH> \
  --contract-name <NAME> \
  --license MIT \
  --watch
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 verification

    The 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 status

    Query 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 verified

    Query whether a contract class is already verified on Voyager before submitting a verification request. Useful for CI/CD pipelines.

  • history - Manage verification history

    View, 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:

  1. CLI arguments (highest priority)
  2. .voyager.toml configuration file
  3. 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:

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 mainnet
  • sepolia - Sepolia testnet
  • dev - 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:

  1. Value from Scarb.toml if specified
  2. Value from .voyager.toml if specified
  3. “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 project
  • dojo - 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 JSON
  • table - 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

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

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 mainnet
  • sepolia - Sepolia testnet
  • dev - 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 --verbose for details

CompileFailed

  • Compilation failed on remote server
  • Build error in your source code
  • Use --verbose to 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:

  1. Historical data - Average time from your last 10 successful verifications (requires minimum 3 samples)
  2. 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 (--network or --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

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

OptionShortDescription
--networkNetwork to check (mainnet, sepolia, dev)
--urlCustom API endpoint URL
--class-hashClass hash to check (0x-prefixed hex)
--json-jOutput result as JSON
--verbose-vShow 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:

FieldDescription
verifiedWhether the class is verified (true/false)
class_hashThe class hash that was checked
nameContract name (if verified)
versionPackage version (if verified)
licenseSPDX license identifier (if verified)
verified_timestampUnix timestamp of verification (if verified)
contract_fileMain contract file path (if verified)

Exit Codes

CodeMeaning
0Success (class found, verified or not)
1Class not found on-chain
Non-zeroOther 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

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 verifications
  • fail - Show only failed verifications
  • pending - 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

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

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.toml if 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:

  • MIT
  • Apache-2.0
  • GPL-3.0
  • BSD-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.lock for 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:

  1. Detect “MIT” from Scarb.toml
  2. Prompt for confirmation
  3. Allow override if needed

Package Detection

For workspace projects, reads from Scarb.toml:

[workspace]
members = ["token", "nft", "marketplace"]

The wizard will:

  1. List all packages
  2. Provide numbered selection
  3. 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

  1. Review Summary: Always review the summary before confirming
  2. Use Watch Mode: Enable watch mode to see final results
  3. Save Settings: For repeated verifications, consider using a config file
  4. Keep Info Handy: Have class hash and contract name ready before starting
  5. Test on Sepolia: Verify on Sepolia first before mainnet

See Also

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.toml to 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:

  1. --license CLI flag (highest priority)
  2. license in .voyager.toml config
  3. license in Scarb.toml package section
  4. “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

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

AspectCommand LineWizard (--wizard)
Best forExperienced users, automationFirst-time users, occasional use
SpeedFast (one command)Slower (interactive prompts)
AutomationExcellentNot suitable
Learning curveRequires knowing all flagsGuided, self-explanatory
Config supportFull config file integrationLimited
Batch verificationSupportedNot supported
CI/CDPerfectNot recommended
Error preventionManual validationBuilt-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

  1. Use --dry-run first to preview file collection
  2. Add --verbose to see detailed error messages
  3. Check local build with scarb --release build
  4. Verify network connectivity to API endpoints
  5. Review history with voyager history list to check past attempts

See Troubleshooting Guide for comprehensive debugging help.

Next Steps

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:

  1. Use workspace.default-package if configured
  2. Auto-detect the package
  3. 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-hash or --contract-name arguments 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

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:

StageEstimated 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:

  1. Submit verification
  2. Display job ID
  3. Start polling immediately
  4. Show live progress
  5. Display final result
  6. 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:

  1. Submit verification
  2. Display job ID
  3. 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:

  1. CLI flag (highest priority)

    voyager verify --watch  # Enables
    voyager verify --no-watch  # Disables (if supported)
    
  2. Configuration file

    [voyager]
    watch = true
    
  3. Default value (lowest priority)

    • Default: false (watch mode disabled)

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:

  1. Check status later:

    voyager status --network mainnet --job abc-123-def-456
    
  2. Use verbose mode to see detailed errors:

    voyager status --network mainnet --job abc-123-def-456 --verbose
    
  3. 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

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:

FieldDescription
NetworkTarget network (mainnet/sepolia/dev)
API EndpointFull API URL being used
Class HashContract class hash
ContractContract name
LicenseSPDX license identifier
PackagePackage name (for workspace projects)
Lock FileWhether Scarb.lock is included
Test FilesWhether test files are included

Project Details Section

Shows detected project information:

FieldDescription
Project TypeScarb, Dojo, or Unknown
Project PathAbsolute path to project root
Scarb VersionDetected Scarb version
Cairo VersionDetected Cairo version
Package NamePackage identifier from Scarb.toml
PackagesList of packages (workspace only)
SelectedSelected 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

  1. Server-side validation - Can’t catch API-specific errors
  2. Compilation check - Doesn’t verify code compiles on server
  3. Network testing - Doesn’t test API connectivity
  4. Authentication - Doesn’t validate API credentials
  5. 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

Configuration Overview

This section is currently under development as part of Phase 2.

Learn how to configure Voyager Verifier using:

  • Configuration Files - .voyager.toml for 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.toml to 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:

  1. Current working directory - ./voyager.toml
  2. Parent directories - Walks up the directory tree until found
  3. 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:

  1. /home/user/projects/my-contract/packages/token/.voyager.toml
  2. /home/user/projects/my-contract/packages/.voyager.toml
  3. /home/user/projects/my-contract/.voyager.toml
  4. /home/user/projects/.voyager.toml
  5. /home/user/.voyager.toml

The first file found is used.

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:

  • mainnethttps://api.voyager.online/beta
  • sepoliahttps://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:

  1. --license CLI flag
  2. license in .voyager.toml
  3. license in Scarb.toml
  4. “All Rights Reserved” (default)

Common licenses:

  • MIT
  • Apache-2.0
  • GPL-3.0
  • BSD-3-Clause
  • AGPL-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:

  1. Checks for Scarb.toml with [tool.dojo] section → Dojo
  2. Checks for Scarb.toml → Scarb
  3. 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:

  1. Verify file exists: ls -la .voyager.toml
  2. Check file location (current or parent directory)
  3. Use --dry-run to 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 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 detection
  • dojo - 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:

  1. --license CLI flag
  2. license in .voyager.toml
  3. license in Scarb.toml
  4. “All Rights Reserved” (default)

Common licenses:

  • MIT
  • Apache-2.0
  • GPL-3.0
  • BSD-3-Clause
  • AGPL-3.0
  • ISC
  • MPL-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.lock in 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

  1. CLI flags (highest)
  2. Config file (.voyager.toml)
  3. Scarb.toml (license only)
  4. 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

FlagTypeRequiredDefaultConfig Equivalent
--networkStringYes*Nonevoyager.network
--urlStringYes*Nonevoyager.url
--class-hashStringYes**NoneN/A
--contract-nameStringYes**NoneN/A
--pathStringNo.N/A
--packageStringSometimesNoneworkspace.default-package
--project-typeStringNoautovoyager.project-type
--licenseStringNoSee docsvoyager.license
--lock-fileFlagNofalsevoyager.lock-file
--test-filesFlagNofalsevoyager.test-files
--watchFlagNofalsevoyager.watch
--notifyFlagNofalsevoyager.notify
--verbose, -vFlagNofalsevoyager.verbose
--dry-runFlagNofalseN/A
--wizardFlagNofalseN/A
--fail-fastFlagNofalseN/A
--batch-delayIntegerNo0N/A

* Either --network or --url required ** Not required in batch mode or wizard mode

Next Steps

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 --package every 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 --package every 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

  1. Reads root Scarb.toml - Looks for [workspace] section
  2. Parses workspace members - Gets list of package paths
  3. Validates packages - Ensures each package has valid Scarb.toml
  4. 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 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

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:

  1. On submission - When voyager verify is executed
  2. During watch - When using --watch mode
  3. On status check - When checking status manually
  4. 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:

  1. Check if ~/.voyager/ directory exists
  2. Create directory if needed
  3. Check if history.db exists
  4. Create database with schema if needed
  5. Insert first record
  6. 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:

  1. Submitted → recorded
  2. Pending → updated
  3. In Progress → updated
  4. Compiling → updated
  5. 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:

  1. Fetches current status from API
  2. Updates record in history.db
  3. Displays updated status

Batch Updates

Update all pending jobs:

voyager history recheck --network mainnet

This:

  1. Finds all pending jobs
  2. Checks status for each from API
  3. Updates all records in database
  4. 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

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 successfully
  • failed - Failed verification
  • pending - 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:

  1. No verification history exists
  2. Filters too restrictive
  3. 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

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 successfully
  • failed - Failed verification
  • pending - 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:

  1. Filters too restrictive
  2. Incorrect date format
  3. Typo in contract name
  4. 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

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:

  • mainnet
  • sepolia
  • dev
  • 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 = pending are 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:

  1. Jobs are legitimately still processing
  2. API is slow
  3. 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

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:

  1. Pending verifications not updated
  2. 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 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:

  1. No records older than specified age
  2. 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:

  1. Restore from backup (if available)
  2. Re-run verifications (if needed)
  3. Export/import from another machine

Next Steps

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:

  1. Submit verification
  2. Watch mode monitors progress
  3. Notification appears when complete
  4. 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:

  1. CLI flag (highest priority)

    voyager verify --watch --notify
    
  2. Configuration file

    [voyager]
    notify = true
    
  3. Default (lowest priority)

    • Default: false (disabled)

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
  • --notify flag 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:

  1. System Preferences → Notifications
  2. Ensure notifications are enabled
  3. 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:

  1. Settings → System → Notifications & actions
  2. Ensure notifications are enabled
  3. 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:

  1. System Preferences → Security & Privacy → Privacy
  2. Select “Notifications” from the left sidebar
  3. 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

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:

  1. CLI flag (--url or --network) - Highest priority
  2. Config file (url or network in .voyager.toml)
  3. 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:

  1. Current working directory
  2. 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:

  1. Check URL format:

    # Ensure URL is valid
    curl -I https://custom-api.example.com/beta
    
  2. Verify network access:

    # Can you reach the endpoint?
    ping custom-api.example.com
    
  3. Check firewall rules:

    • Ensure outbound HTTPS (443) or HTTP (80) is allowed
    • Verify custom ports are accessible if using non-standard ports
  4. 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:

  1. Use a reverse proxy - Set up nginx or similar to handle authentication
  2. VPN access - Connect to VPN before running verifier
  3. API gateway - Use an API gateway that handles authentication transparently

API Incompatibility

Problem: Endpoint returns unexpected response format

Error: Failed to parse response

Solutions:

  1. Verify endpoint implements Voyager API - Check that your custom endpoint follows the same API contract as official Voyager
  2. Check API version - Ensure compatibility between verifier version and endpoint API version
  3. 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

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:

  1. Reproducible Builds - Ensure the remote compiler uses the exact same dependency versions you used locally
  2. Version Pinning - Lock specific versions that are known to work with your contract
  3. Debugging - Eliminate dependency version differences as a source of verification failures
  4. 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:

  1. CLI flag (--lock-file) - Highest priority
  2. Config file (lock-file = true in .voyager.toml)
  3. Default value (false - lock file not included)

When to Use Lock Files

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:

  1. Verifier reads Scarb.toml to identify dependencies
  2. Sends Scarb.toml to remote API
  3. 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:

  1. Verifier reads both Scarb.toml and Scarb.lock
  2. Sends both files to remote API
  3. Remote compiler runs scarb build, which:
    • Uses exact versions from Scarb.lock
    • Downloads those specific versions
    • Compiles your contract

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

FeatureLock Files (--lock-file)Test Files (--test-files)
PurposePin dependency versionsInclude test source files
DefaultExcludedExcluded
FileScarb.lock**/test*.cairo, **/tests/*.cairo
Use CaseReproducible buildsContracts depending on test utilities
Production✅ Recommended⚠️ Usually not needed
Development⚠️ Optional✅ Often needed

See Also

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:

  1. Smaller payloads - Test files can be large and aren’t needed for most contracts
  2. Faster verification - Less code to compile means faster verification
  3. Production focus - Only production code needs to be verified
  4. 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:

  1. CLI flag (--test-files) - Highest priority
  2. Config file (test-files = true in .voyager.toml)
  3. 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:

  1. Files with “test” in the name:

    • test.cairo
    • tests.cairo
    • test_utils.cairo
    • test_helpers.cairo
    • mock_test.cairo
  2. Files in “test” or “tests” directories within src/:

    • src/test/helpers.cairo
    • src/tests/fixtures.cairo
  3. Files with “tests” in the path:

    • src/utils/tests.cairo
    • src/tests/unit.cairo

What Gets Excluded (Always)

Even with --test-files enabled, these are always excluded:

  1. Directories outside src/:

    • tests/ (root-level tests directory)
    • test/ (root-level test directory)
  2. Build artifacts:

    • target/
    • Scarb.lock (unless --lock-file is used)
  3. Hidden files:

    • .git/
    • .gitignore

How It Works

Without Test Files (Default)

When --test-files is not specified:

  1. Verifier scans src/ directory
  2. Excludes files matching test patterns:
    • Files with “test” in name
    • Files in “test” or “tests” subdirectories
  3. Collects remaining .cairo files
  4. 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:

  1. Verifier scans src/ directory
  2. Includes all .cairo files (including test patterns)
  3. Collects all files
  4. 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:

  1. Include test files:

    voyager verify --network mainnet \
      --class-hash 0x044dc2b3... \
      --contract-name MyContract \
      --test-files
    
  2. Remove module declaration:

    // lib.cairo - remove or comment out:
    // mod tests;
    
  3. 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

FeatureTest Files (--test-files)Lock Files (--lock-file)
PurposeInclude test source filesPin dependency versions
DefaultExcludedExcluded
Files**/test*.cairo in src/Scarb.lock
Use CaseContracts depending on test utilitiesReproducible builds
Production⚠️ Usually not needed✅ Recommended
Development✅ Often needed⚠️ Optional
File Size ImpactCan be largeUsually small

See Also

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)
  • json
  • table

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:

  1. CLI flag (--format) - Highest priority
  2. Config file (format in .voyager.toml)
  3. 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:

StatusProgressDescription
Submitted10%Job created, waiting in queue
Processing40%Picked up by worker, compiling source
Compiled85%Compilation done, verifying bytecode
Success/Fail100%Verification complete

Time Estimation

The text format provides intelligent time estimates:

  1. History-based estimates - Uses average time from your last 10 successful verifications (requires minimum 3 samples)
  2. 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

FieldTypeDescription
job_idstringUnique verification job identifier (UUID)
statusstringCurrent status (Submitted, Processing, Compiled, Success, Fail, CompileFailed)
status_codeintegerNumeric status code (0-4)
is_completedbooleanWhether verification has finished (success or failure)
has_failedbooleanWhether verification failed
progress_percentageintegerProgress from 0-100
class_hashstring | nullContract class hash
contract_namestring | nullContract name
contract_filestring | nullMain contract source file
status_descriptionstring | nullDetailed status message
messagestring | nullError or informational message
error_categorystring | nullError categorization
created_atstring | nullJob creation timestamp (UTC)
updated_atstring | nullLast update timestamp (UTC)
elapsed_secondsinteger | nullTime elapsed since job creation
estimated_remaining_secondsinteger | nullEstimated time until completion (for in-progress jobs)
cairo_versionstring | nullCairo compiler version used
dojo_versionstring | nullDojo version (for Dojo projects)
licensestring | nullSPDX license identifier
addressstring | nullContract address (if available)
build_toolstring | nullBuild 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

FeatureTextJSONTable
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 sizeMediumLargerCompact

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

SymbolMeaning
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

  1. Use text format for:

    • Interactive terminal sessions
    • Manual verification during development
    • Learning and debugging
    • Watch mode with live progress updates
  2. Use JSON format for:

    • CI/CD pipelines
    • Automated deployment scripts
    • Integration with other tools
    • Monitoring and alerting
    • Data analysis and metrics
  3. 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

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:

  1. Install voyager-verifier
  2. Build your contract with Scarb
  3. Deploy contract to Starknet (get class hash)
  4. Verify using voyager-verifier
  5. Check verification status
  6. 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

  1. Never commit secrets to version control

  2. Use CI platform’s secret management:

    • GitHub: Repository Secrets
    • GitLab: CI/CD Variables (protected)
    • Jenkins: Credentials Plugin
    • CircleCI: Context/Project Environment Variables
  3. Rotate secrets regularly

  4. 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

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 CodeCategoryDescription
E001-E003WorkspacePackage not found, no packages, workspace errors
E004-E009VerificationAPI submission, polling, job failures
E010-E014DependenciesResolution failures, missing dependencies
E015-E024Contract/TargetInvalid contract names, target not found
E025-E029File SystemFile not found, read errors, path issues
E030-E039Class HashHash mismatch, parsing errors, format issues
E040-E042ConfigConfig 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 --verbose flag
  • Try dry-run - Use --dry-run to 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

See: History Command Guide

4. Local Testing

Test before submitting:

# Build locally
scarb --release build

# Check for errors
scarb check

# Run tests
scarb test

Prevention Tips

✅ Best Practices

  1. Always build locally first

    scarb --release build
    
  2. Use lock files for reproducibility

    # Commit Scarb.lock to version control
    git add Scarb.lock
    
  3. Test with dry-run before submitting

    voyager verify --dry-run ...
    
  4. Use verbose mode when debugging

    voyager verify --verbose ...
    
  5. Keep versions consistent

    # In Scarb.toml
    [dependencies]
    starknet = "2.8.2"
    
  6. Include necessary files

    # Include tests if they're imported
    voyager verify --test-files ...
    

Getting Help

Self-Help First

  1. Check Common Errors
  2. Review Error Codes Reference
  3. Use Debugging Workflow
  4. Try Verbose Mode

Community Support

See: Getting Support Guide


See Also

Troubleshooting Resources

Reference Material

Feature Guides

Common Errors

This page covers the most frequent errors users encounter when using voyager-verifier, with practical solutions and examples.

Quick Navigation:

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 build works locally
  • Remote verification fails with compilation errors

Common Causes:

  1. 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
    
  2. 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" }
    
  3. Cairo version mismatch:

    • Remote compiler may use different Cairo version
    • Use --lock-file to 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:

  1. ✅ Does scarb build work locally?
  2. ✅ Does scarb --release build work locally?
  3. ✅ Are all files committed (not using uncommitted changes)?
  4. ✅ 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:

  1. Verify you have correct source:

    # Check current commit
    git log -1
    
    # If using tags
    git checkout v1.0.0  # Or whatever tag was deployed
    
  2. 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
    
  3. 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:

  • Check Voyager or Starkscan
  • Search for your class hash
  • Confirm it’s declared on the correct network

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:

  1. Test internet connection:

    ping api.voyager.online
    
  2. Check DNS:

    nslookup api.voyager.online
    
  3. Test API endpoint:

    curl -I https://api.voyager.online/beta
    
  4. 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 just scarb 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:

  1. Wrong source version (not matching deployment)
  2. Different dependency versions
  3. 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?

  1. Use verbose mode:

    voyager status --network mainnet --job <JOB_ID> --verbose
    
  2. Check full error code reference:

  3. Review debugging guide:

  4. Contact support:

When asking for help, include:

  • Error code and message
  • Full command you ran
  • Output with --verbose flag
  • Your Scarb.toml (remove sensitive info)
  • Output of scarb --release build

See Also

Debugging

This guide provides a systematic approach to debugging verification issues with voyager-verifier.

Quick Navigation:


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:

  1. Wrong source version

    git log --oneline
    git checkout <deployment-commit>
    
  2. 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
    
  3. 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

ScenarioCommandPurpose
Preview submission--dry-runSee what files will be sent
Get full error--verboseSee complete compiler output
Test local buildscarb --release buildVerify builds locally
Check historyvoyager history listReview past attempts
Recheck failedvoyager history recheck --failedUpdate status of old jobs
Compare buildsvoyager history list --format jsonAnalyze patterns
Test incrementallyAdd flags one at a timeIsolate problematic flag
Check metadatascarb metadataValidate 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:

  1. Document your debugging steps:

    • What you tried
    • What results you got
    • Full error messages with --verbose
  2. Gather information:

    # System info
    voyager --version
    scarb --version
    
    # Project info
    cat Scarb.toml
    
    # Error output
    voyager status --network mainnet --job <JOB_ID> --verbose
    
  3. Check resources:

  4. Ask for help:

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

Verbose Mode

The --verbose flag provides detailed error messages and compiler output to help diagnose verification issues.

Quick Navigation:


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 tests is declared in lib.cairo but file is missing
  • Location: src/lib.cairo line 2, column 5
  • File expected: src/tests.cairo
  • Solution: Add --test-files flag 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.cairo line 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 utils doesn’t exist or isn’t declared
  • Location: src/contract.cairo line 1
  • Solution: Check lib.cairo has mod 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.0 is 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

MethodCommand
CLI flag--verbose or -v
Config fileverbose = true in .voyager.toml

Common Commands

TaskCommand
Verbose statusvoyager status --network mainnet --job <ID> --verbose
Verbose verifyvoyager verify --network mainnet ... --verbose
Save to filevoyager status ... --verbose > output.log
Search outputvoyager status ... --verbose | grep "error"

What to Look For

  1. Status line - What stage failed?
  2. Error code - What type of error? (E0005, E0308, etc.)
  3. File location - Which file and line?
  4. Error message - What specifically went wrong?
  5. Suggestions - What does the output recommend?

See Also

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:

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:

  1. Search First: Check if your question has been asked before
  2. Be Specific: Include error messages and what you tried
  3. Share Context: Network, contract details (redact sensitive info)
  4. 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:

  1. Search Existing Issues: Your bug might already be reported

    • Check open issues: is:issue is:open
    • Check closed issues: is:issue is:closed
  2. Verify It’s a Bug: Test with minimal reproduction

    # Try with verbose mode
    voyager verify --verbose ...
    
    # Try with dry-run
    voyager verify --dry-run ...
    
  3. 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 ✅

  1. Be Specific

    ❌ "Verification doesn't work"
    ✅ "Verification fails with E030 (class hash mismatch) on mainnet"
    
  2. 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."
    
  3. 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?"
    
  4. Use Code Blocks

    ✅ Format commands and output in code blocks for readability
    
  5. Follow Up

    • If solution works, confirm and thank
    • If still stuck, provide additional details requested
    • Close GitHub issues when resolved

Don’ts ❌

  1. Don’t Spam Multiple Channels

    • Choose one channel (Telegram OR GitHub)
    • Don’t cross-post the same question immediately
  2. Don’t Expect Instant Responses

    • Community members help voluntarily
    • GitHub issues may take time to triage
  3. Don’t Post Huge Logs Without Context

    • Provide relevant excerpts
    • Use GitHub Gists for very long logs
  4. Don’t Hijack Other Threads

    • Create a new issue if your problem is different
    • Don’t add unrelated questions to existing issues
  5. Don’t Give Up Too Quickly

    • Work through the debugging checklist
    • Try the suggestions provided

Response Times

Typical response times:

ChannelTypeExpected Response
TelegramQuick QuestionMinutes to hours
TelegramComplex IssueHours to days
GitHubBug ReportDays to weeks
GitHubFeature RequestWeeks 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:

  1. Report Issues: Detailed bug reports help improve the tool
  2. Documentation: Suggest improvements or fix typos
  3. Code: Submit pull requests for bug fixes or features
  4. Community: Help others on Telegram

See the repository for contribution guidelines: https://github.com/NethermindEth/voyager-verifier


Emergency Support

For critical production issues:

  1. Check Status Page: Verify API status

    curl https://api.voyager.online/api-docs
    
  2. Try Alternative Network: If mainnet fails, test on sepolia

    voyager verify --network sepolia ...
    
  3. Use Dry-Run: Ensure your submission is correct

    voyager verify --dry-run ...
    
  4. Report on GitHub: For critical bugs affecting many users


Additional Resources

  • Documentation: https://docs.voyager.nethermind.io
  • GitHub: https://github.com/NethermindEth/voyager-verifier
  • Telegram: https://t.me/StarknetVoyager
  • Voyager Explorer: https://voyager.online
  • Starknet Documentation: https://docs.starknet.io
  • Scarb Documentation: https://docs.swmansion.com/scarb
  • Cairo Documentation: https://book.cairo-lang.org

Support Quick Reference

NeedChannelWhen to Use
Quick questionTelegramGeneral usage, tips
Bug reportGitHub IssuesTool defects
Feature requestGitHub IssuesNew functionality
DocumentationDocs SiteSelf-help first
API issuesGitHub IssuesAPI problems

See Also

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:

  1. Simple Contract - Basic single-contract verification
  2. Workspace Project - Multi-package Scarb workspace
  3. Dojo Project - Dojo project verification
  4. Multi-Contract Batch - Batch verification for multiple contracts
  5. 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:

  1. Start with Simple Contract to understand the basics
  2. Progress to Workspace Project for multi-package setups
  3. Try Dojo Project if you’re using the Dojo framework
  4. Learn Multi-Contract Batch for efficient bulk verification
  5. Implement CI/CD Pipeline to automate your workflow

For Reference

If you’re looking for a specific use case:

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

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:

  1. Check the Troubleshooting section in each example
  2. Review the Troubleshooting Guide
  3. Use --verbose flag to see detailed error messages
  4. Try --dry-run to preview what will be submitted
  5. 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 license field 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 balance value
  • 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.

voyager verify --wizard

The wizard will guide you through:

  1. Network selection: Choose mainnet
  2. Class hash: Enter your class hash
  3. Contract name: Enter HelloStarknet
  4. License: Confirm MIT (auto-detected from Scarb.toml)
  5. Optional features: Choose any extras (watch mode, notifications, etc.)
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:

  1. Verify local build works: scarb --release build
  2. Check [profile.release] configuration in Scarb.toml
  3. Use --verbose to 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:

  1. Verify the contract class was actually declared on the network
  2. Check you’re using the correct network (mainnet vs sepolia)
  3. Confirm the class hash is correct (no typos)

Error: “License not specified”

Problem: No license provided

Solutions:

  1. Add license = "MIT" to [package] in Scarb.toml
  2. Or provide via CLI: --license MIT
  3. Use a valid SPDX identifier from spdx.org/licenses

Verification Pending for Too Long

Problem: Status stuck at “Pending” or “Compiling”

Solutions:

  1. Wait a few more minutes (complex contracts take longer)
  2. Check status with --verbose for details
  3. 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:

  1. Workspace Projects - Learn to verify multi-package projects
  2. Batch Verification - Verify multiple contracts at once
  3. CI/CD Integration - Automate verification in your pipeline
  4. Configuration Guide - Deep dive into all configuration options
  5. History Tracking - Manage verification history

Additional Resources

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.lock file
  • 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 structure
  • members lists 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:

  1. Check package name matches [package] name in packages/xyz/Scarb.toml
  2. Verify package is listed in workspace members in root Scarb.toml
  3. Ensure package directory structure is correct

Error: “Dependency resolution failed”

Problem: Package dependencies not found or misconfigured

Solutions:

  1. Verify [dependencies] in package Scarb.toml:
    common = { path = "../common" }  # Correct relative path
    
  2. Check all workspace members are listed in root Scarb.toml
  3. Run scarb build to 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:

  1. Dojo Projects - Learn Dojo-specific verification
  2. Batch Verification - Master batch verification for multiple contracts
  3. CI/CD Integration - Automate workspace verification
  4. Configuration Guide - Deep dive into workspace configuration

Additional Resources


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:

  1. dojo dependency in Scarb.toml
  2. Dojo-specific imports (use dojo::...)
  3. 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 requirement
  • sierra-replace-ids = true - Required for deterministic builds
  • dojo dependency - Version should match your Dojo installation
  • build-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 indexing
  • Introspect - 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 system
  • world.read_model() / write_model() - Access Dojo world state
  • ModelStorage - 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.

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:

  1. Add explicit Dojo dependency:

    [dependencies]
    dojo = "1.7.2"  # Explicit version
    
  2. Or use --project-type dojo flag:

    voyager verify \
        --network sepolia \
        --class-hash <HASH> \
        --contract-name actions \
        --project-type dojo
    
  3. 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:

  1. Check compatibility:

    • Dojo 1.7.x requires Cairo 2.12.x
    • Dojo 2.0.x requires Cairo 2.13.x+
  2. Update cairo-version in Scarb.toml:

    [package]
    cairo-version = "2.12.2"  # Match Dojo requirements
    
  3. Verify locally first:

    sozo build  # Should succeed without errors
    

Error: “sozo command not found”

Problem: Dojo not installed or not in PATH

Solutions:

  1. Install Dojo:

    curl -L https://install.dojoengine.org | bash
    dojoup
    
  2. Verify installation:

    sozo --version
    
  3. 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 --watch to monitor progress
  • Use --verbose to 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:

  1. Multi-Contract Batch - Efficient batch verification for complex worlds
  2. CI/CD Integration - Automate Dojo verification in your deployment pipeline
  3. Workspace Projects - Learn about multi-package Scarb workspaces
  4. Configuration Guide - Deep dive into all configuration options
  5. History Tracking - Track verification history for your Dojo world

Additional Resources

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

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 contract
  • contract-name - Required for each contract
  • package - 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:

  1. Fix the issue (e.g., correct class hash)
  2. Update .voyager.toml
  3. Run voyager verify again

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.toml exists with [[contracts]] array
  • network specified in config or via --network flag
  • No --class-hash or --contract-name flags (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:

  1. Compilation errors - Syntax errors, missing imports
  2. Invalid class hash - Typo or wrong network
  3. Class hash not found - Contract class not declared yet
  4. Network errors - API timeouts, connectivity issues
  5. 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-delay for 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:

  1. Fix issues in failed contracts
  2. Update .voyager.toml to include only failed contracts
  3. Re-run batch

Configuration Errors

Problem: “No contracts defined” or “Invalid configuration”

Solution:

  1. Check .voyager.toml syntax:
# Correct
[[contracts]]
class-hash = "0x123..."
contract-name = "Token"

# Wrong - single bracket
[contracts]  # ❌ Should be [[contracts]]
  1. Validate TOML:
cat .voyager.toml | toml-lint
  1. 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:

  1. Note which contracts failed from summary
  2. Edit .voyager.toml to include only failed contracts
  3. 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:

  1. .voyager.toml has [[contracts]] array
  2. Not using --class-hash or --contract-name flags
  3. 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:

  1. CI/CD Integration - Automate batch verification in your deployment pipeline
  2. Configuration Reference - Deep dive into all configuration options
  3. History Management - Track and analyze verification history
  4. Workspace Projects - Combine workspaces with batch verification
  5. Desktop Notifications - Setup notifications for batch completion

Additional Resources


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:

  1. Build contracts with Scarb
  2. Deploy to Starknet
  3. Capture class hash from deployment
  4. Verify with voyager-verifier
  5. Report results

Verification as Quality Gate - Fail the build if verification fails:

  • Use --watch to 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:

  1. Go to SettingsSecrets and variablesActions
  2. Add the following secrets:
    • STARKNET_ACCOUNT - Your Starknet account JSON
    • STARKNET_KEYSTORE - Your keystore file
    • SLACK_WEBHOOK_URL - (Optional) For notifications
  3. 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: SettingsCI/CDVariables

Protected Variables (only available on protected branches):

  • STARKNET_ACCOUNT_FILE - Account configuration
  • STARKNET_KEYSTORE_FILE - Keystore file
  • Type: File

Regular Variables:

  • SCARB_VERSION - Scarb version to use
  • VOYAGER_VERSION - voyager-verifier version

Pipeline Status Reporting

GitLab provides built-in status reporting:

# Add status badge to README.md
[![Pipeline Status](https://gitlab.com/your-username/your-project/badges/main/pipeline.svg)](https://gitlab.com/your-username/your-project/-/pipelines)

[![Verification Status](https://gitlab.com/your-username/your-project/-/jobs/artifacts/main/raw/badges/verification.json?job=report:verification)](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:

  1. Go to Manage JenkinsCredentials
  2. Add credentials:
    • starknet-account - File credential with account JSON
    • starknet-keystore - File credential with keystore
  3. 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:

  1. Repository Settings → Secrets and variables → Actions
  2. Add secrets:
    • STARKNET_ACCOUNT
    • STARKNET_KEYSTORE
    • SLACK_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

  1. Never commit secrets to version control
  2. Use file-type secrets for JSON configs
  3. Mark secrets as protected for production
  4. Rotate secrets regularly
  5. Use different secrets for different environments
  6. 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:

  1. Never commit secrets to repository
  2. Use repository secrets for sensitive data
  3. Rotate secrets regularly
  4. Limit secret access to necessary jobs
  5. 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:

[![Verification Status](https://github.com/username/repo/actions/workflows/verify.yml/badge.svg)](https://github.com/username/repo/actions/workflows/verify.yml)

GitLab CI:

[![Pipeline Status](https://gitlab.com/username/repo/badges/main/pipeline.svg)](https://gitlab.com/username/repo/-/pipelines)

CircleCI:

[![CircleCI](https://circleci.com/gh/username/repo.svg?style=svg)](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:

  1. Configuration Reference - Deep dive into configuration options
  2. History Management - Track verification history
  3. Batch Verification - Verify multiple contracts efficiently
  4. Troubleshooting Guide - Resolve common issues
  5. Advanced Features - Desktop notifications, custom workflows

Additional Resources

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-files to 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

NetworkBase URLUsage
Mainnethttps://api.voyager.onlineProduction contracts
Sepoliahttps://sepolia-api.voyager.onlineTestnet contracts
Devhttps://dev-api.voyager.onlineDevelopment testing
CustomUser-specifiedCustom deployments

Job Status Codes

CodeNameDescriptionTerminal
0SubmittedJob queuedNo
1CompiledCompilation successNo
2CompileFailedCompilation failedYes
3FailVerification failedYes
4SuccessVerified successfullyYes
5ProcessingBeing processedNo

File Types

TypeIncludedFlag RequiredMax Size
Cairo source (.cairo)✅ YesNone20MB
Scarb.toml✅ YesNone20MB
Scarb.lock❌ No--lock-file20MB
Test files❌ No--test-files20MB
Documentation (.md)✅ If foundNone20MB

Version Support

ComponentSupport ModelCurrent
CairoServer-determinedUp to 2.13.1 (Oct 2025)
ScarbClient + Server1.x - 2.x
DojoAuto-detectedUp to 1.8.0 (Oct 2025)
ClientSemantic Versioningv2.0.1

Error Code Quick Lookup

Most Common Errors

CodeErrorQuick Fix
E005Module not foundAdd --test-files if importing tests
E007Verification failedCheck Troubleshooting Guide
E015Invalid contract nameVerify contract name matches #[starknet::contract] mod
E030Class hash mismatchUse --lock-file for reproducibility
E999Unexpected errorCheck 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:

  1. Go to Error Codes
  2. Find E005 in the list
  3. Read cause, solutions, and examples
  4. Apply suggested fix

Scenario 2: Version Check

Problem: Unsure if Cairo 2.12.0 is supported

Steps:

  1. Go to Supported Versions
  2. Check Cairo version compatibility matrix
  3. See note about server-side support
  4. Test with --dry-run on Sepolia first

Scenario 3: File Not Included

Problem: File missing from submission

Steps:

  1. Go to File Collection
  2. Check if file type is allowed
  3. Verify file location (must be in src/ or manifest)
  4. Use --dry-run to preview collection
  5. Check if flag needed (--lock-file, --test-files)

Scenario 4: Understanding Job Status

Problem: Understanding what status codes mean

Steps:

  1. Go to API Reference
  2. Review job status codes documentation
  3. Check response formats
  4. Understand state transitions
  5. Learn about typical timing

Scenario 5: Hash Mismatch

Problem: Class hash mismatch error

Steps:

  1. Check Error Codes E030
  2. Review File Collection for lock files
  3. Use --lock-file flag
  4. Check Supported Versions for compatibility
  5. 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:

Versions & Compatibility:

Files & Collection:

API & Integration:

By Task

I want to…

…understand an error codeError Codes

…check version compatibilitySupported Versions

…know what files are submittedFile Collection

…understand job status codesAPI Reference

…fix a verification failureCommon Errors

…upgrade Cairo/ScarbVersion Upgrade Guide

…debug compilation errorsDebugging


See Also

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: 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:

  1. Check available packages:

    scarb metadata
    
  2. List workspace members in Scarb.toml:

    [workspace]
    members = ["package1", "package2"]
    
  3. Use correct package name:

    voyager verify --network mainnet \
      --class-hash 0x044dc2b3... \
      --contract-name MyContract \
      --package correct_package_name
    
  4. 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:

  1. Check available contracts in Scarb.toml:

    [tool.voyager.contracts]
    MyToken = "0x044dc2b3..."
    MyNFT = "0x055dc2b3..."
    
  2. Use correct contract name:

    voyager verify --network mainnet \
      --class-hash 0x044dc2b3... \
      --contract-name MyToken  # Must match manifest
    
  3. 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:

  1. Test local build first:

    scarb --release build
    

    The remote compiler uses the same command. If it fails locally, it will fail remotely.

  2. Check dependencies:

    [dependencies]
    starknet = ">=2.11.0"  # Ensure all deps are declared
    
  3. Verify imports and modules:

    // In lib.cairo
    mod contract;  // Ensure this file exists
    // mod tests;  // Remove if tests.cairo isn't included
    
  4. Include test files if needed:

    voyager verify --network mainnet \
      --class-hash 0x044dc2b3... \
      --contract-name MyContract \
      --test-files  # Include if contract depends on test utilities
    
  5. Check release profile settings:

    [profile.release.cairo]
    sierra-replace-ids = true  # Any compiler settings must be here
    
  6. 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:

  1. Verify class hash is correct:

    # Double-check the class hash from deployment
    voyager verify --network mainnet \
      --class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18 \
      --contract-name MyContract
    
  2. 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
  3. Use lock file for reproducible builds:

    voyager verify --network mainnet \
      --class-hash 0x044dc2b3... \
      --contract-name MyContract \
      --lock-file  # Ensure same dependency versions
    
  4. Match compiler settings:

    [profile.release.cairo]
    # Ensure these match deployment settings
    sierra-replace-ids = true
    inlining-strategy = "default"
    
  5. 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:

  1. 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 ...
    
  2. Use predefined network instead:

    voyager verify --network mainnet \
      --class-hash 0x044dc2b3... \
      --contract-name MyContract
    
  3. Check URL format:

    • Must start with http:// or https://
    • Must be a valid URL structure
    • Include proper path if required

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:

  1. Wait and check again:

    # Wait a few seconds/minutes
    sleep 30
    voyager status --network mainnet --job <JOB_ID>
    
  2. Use watch mode to wait automatically:

    voyager verify --network mainnet \
      --class-hash 0x044dc2b3... \
      --contract-name MyContract \
      --watch  # Automatically waits for completion
    
  3. 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:

  1. Check job ID is correct:

    # Copy the full job ID from verification output
    voyager status --network mainnet --job abc-123-def-456
    
  2. 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>
    
  3. Check history for recent jobs:

    voyager history list --limit 10
    
  4. 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:

  1. 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://
    
  2. Encode special characters:

    • Ensure proper URL encoding
    • Avoid spaces and special characters
  3. 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 0x prefix)

Solutions:

  1. Check hash format:

    # ✅ Valid
    --class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
    
    # ❌ Invalid: Missing 0x prefix
    --class-hash 044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18
    
    # ❌ Invalid: Contains non-hex characters
    --class-hash 0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da1z
    
  2. Ensure correct characters:

    • Only hexadecimal: 0-9, a-f, A-F
    • No spaces or special characters
  3. 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:

  1. Report the issue on GitHub
  2. Include the full command you ran
  3. 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:

  1. Check path exists:

    ls ../my-dependency  # Verify path
    
  2. Use correct relative path:

    [dependencies]
    my_lib = { path = "../my-dependency" }  # Relative from Scarb.toml location
    
  3. 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:

  1. Check Scarb.toml exists:

    ls ../my-dependency/Scarb.toml
    
  2. Validate Scarb.toml:

    cd ../my-dependency
    scarb metadata  # Test if metadata can be read
    
  3. Verify file permissions:

    chmod 644 ../my-dependency/Scarb.toml
    
  4. 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:

  1. Use ASCII characters only:

    • Avoid special characters in file names
    • Avoid spaces in directory names
    • Use standard English letters and numbers
  2. Check for hidden characters:

    • Look for control characters or special Unicode
  3. 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:

  1. Verify class hash:

    # Check on block explorer (Voyager, Starkscan, etc.)
    # Ensure hash is declared on the network
    
  2. Check correct network:

    # Ensure using the right network
    voyager verify --network mainnet ...  # Or sepolia
    
  3. Declare class before verification:

    • Use starkli or deployment tool to declare
    • Wait for transaction confirmation
    • Then verify

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:

  1. Specify contract name:

    voyager verify --network mainnet \
      --class-hash 0x044dc2b3... \
      --contract-name MyContract  # Required
    
  2. Define in manifest:

    [tool.voyager.contracts]
    MyContract = "0x044dc2b3..."
    
  3. 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:

  1. Specify which contract:

    voyager verify --network mainnet \
      --class-hash 0x044dc2b3... \
      --contract-name MyToken  # Choose one
    
  2. 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:

  1. Reduce file size:

    • Split large files into smaller modules
    • Remove unnecessary code or comments
    • Check for generated content
  2. Exclude large files:

    • Add to .gitignore
    • Don’t use --test-files if tests are large
  3. 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:

  1. Check file permissions:

    chmod 644 Scarb.toml
    chmod 755 src/
    
  2. Verify path exists:

    ls -la <path>
    
  3. 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:

  1. Remove binary/executable files:

    # Don't include in project directory
    rm src/binary_file
    
  2. Check for unexpected files:

    find src -type f ! -name "*.cairo"
    
  3. 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:

  1. Check you’re in project directory:

    ls Scarb.toml  # Should exist
    
  2. Use correct path:

    voyager verify --network mainnet \
      --class-hash 0x044dc2b3... \
      --contract-name MyContract \
      --path /correct/path/to/project
    
  3. 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:

  1. Validate Scarb.toml:

    scarb metadata --format-version 1
    
  2. Check TOML syntax:

    # Ensure valid TOML format
    [package]
    name = "my_project"
    version = "0.1.0"
    
    [dependencies]
    starknet = ">=2.11.0"
    
  3. Run scarb check:

    scarb check
    
  4. 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:

  1. Use auto-detection:

    # Don't specify project type, let it auto-detect
    voyager verify --network mainnet \
      --class-hash 0x044dc2b3... \
      --contract-name MyContract
    
  2. 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:

  1. Ensure dojo-core dependency:

    [dependencies]
    dojo = { git = "https://github.com/dojoengine/dojo" }
    
  2. Check Dojo project structure:

    project/
    ├── Scarb.toml
    ├── src/
    │   └── lib.cairo
    
  3. Test with sozo:

    sozo build
    
  4. 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:

  1. Use CLI arguments instead:

    voyager verify --network mainnet \
      --class-hash 0x044dc2b3... \
      --contract-name MyContract \
      --license MIT
    
  2. Specify project type:

    voyager verify --network mainnet \
      --class-hash 0x044dc2b3... \
      --contract-name MyContract \
      --project-type scarb  # Skip prompt
    
  3. 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:

  1. Check file permissions:

    chmod 644 .voyager.toml
    
  2. Verify file exists:

    ls -la .voyager.toml
    
  3. 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:

  1. Validate TOML syntax:

    # Ensure proper format
    [voyager]
    network = "mainnet"  # String values in quotes
    watch = true         # Boolean without quotes
    
  2. 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
    
  3. Use TOML validator:

    • Online TOML validator
    • Or use example file as template
  4. 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:

  1. Check directory exists:

    mkdir -p ~/.voyager
    
  2. Check permissions:

    chmod 755 ~/.voyager
    chmod 644 ~/.voyager/history.db  # If exists
    
  3. Check disk space:

    df -h ~
    
  4. 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:

  1. Check home directory permissions:

    chmod 755 ~
    
  2. Check disk space:

    df -h ~
    
  3. 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:

  1. Check HOME variable:

    echo $HOME  # Should show /home/username
    
  2. Set HOME if missing:

    export HOME=/home/username
    
  3. 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:

  1. Check internet connection:

    ping api.voyager.online
    
  2. Verify DNS resolution:

    nslookup api.voyager.online
    
  3. Check firewall/proxy:

    • Ensure HTTPS (port 443) is allowed
    • Configure proxy if needed
  4. Retry the request:

    # Sometimes transient network issues resolve on retry
    voyager verify --network mainnet \
      --class-hash 0x044dc2b3... \
      --contract-name MyContract
    
  5. 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:

  1. Use verbose mode to get detailed error information:

    voyager status --network mainnet --job <JOB_ID> --verbose
    
  2. Check the troubleshooting guide: Troubleshooting

  3. Search for similar issues on GitHub

  4. Contact support:

When reporting errors, include:

  • Error code and full error message
  • Full command you ran
  • Output with --verbose flag
  • Your environment (OS, voyager-verifier version, scarb version)
  • Relevant configuration files (Scarb.toml, .voyager.toml)

See Also

Supported Versions

This reference documents version compatibility for Voyager Verifier, including Cairo, Scarb, and Dojo version support.

Quick Reference

ComponentSupport ModelCurrent SupportNotes
Cairo/ScarbServer-determinedUp to 2.13.1 (Oct 2025)Version agnostic client
DojoAuto-detectedUp to 1.8.0 (Oct 2025)Extracted from dependencies
ClientIndependent versioningv2.0.1Update 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:

  1. Check if it’s already supported by testing with --dry-run
  2. If not available, open an issue on GitHub
  3. 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 VersionSupport StatusNotes
2.13.x✅ Fully SupportedLatest stable (as of Oct 2025)
2.12.x✅ Fully SupportedPrevious stable
2.11.x✅ Fully SupportedStable
2.10.x✅ Fully SupportedStable
2.9.x✅ Fully SupportedMaintained
2.8.x✅ Fully SupportedMaintained
2.7.x and older✅ MaintainedLegacy support
1.x⚠️ Limited SupportCairo 1.0 era
2.14.x+🔄 Check API / RequestOpen 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 VersionSupport StatusNotes
2.13.x✅ Fully SupportedLatest (as of Oct 2025)
2.12.x✅ Fully SupportedPrevious stable
2.11.x✅ Fully SupportedStable
2.10.x✅ Fully SupportedStable
2.9.x✅ Fully SupportedMaintained
2.8.x✅ Fully SupportedMaintained
2.7.x and older✅ MaintainedLegacy support
1.x⚠️ LimitedLegacy
0.x❌ Not SupportedToo 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:

  1. Package Scarb.toml (if in workspace)
  2. 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 VersionSupport StatusProject Type
1.8.x✅ Fully SupportedLatest (as of Oct 2025)
1.7.x✅ Fully Supportedsozo build
1.6.x and older✅ Supportedsozo build
0.7.x✅ Supportedsozo build
0.6.x and older⚠️ LimitedMay 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:

  1. Review Release Notes: https://github.com/starkware-libs/cairo/releases
  2. Test Locally: Ensure your project builds with the new version
  3. 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


Issue 1: Cairo Version Not Supported

Problem:

Error: Cairo version 2.99.0 is not supported by the API

Solutions:

  1. Request Support: The Voyager team works to keep up with Scarb releases

  2. Test with dry-run: Check if the version is already supported

    voyager verify --dry-run --network sepolia \
      --class-hash 0x044dc2b3... \
      --contract-name MyContract
    
  3. 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:

  1. Update Scarb:

    asdf install scarb latest
    asdf global scarb latest
    
  2. Verify Scarb Works:

    scarb metadata --format-version 1
    
  3. 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:

  1. Check Dependency Format:

    # ✅ Correct formats:
    [dependencies]
    dojo = "1.7.1"
    # OR
    dojo = { version = "1.7.1" }
    # OR
    dojo = { tag = "v0.7.0" }
    
  2. Specify Project Type Explicitly:

    voyager verify --project-type dojo ...
    
  3. 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:

  1. Day 0: Cairo version released by Starkware
  2. Days 1-7: Testing and integration
  3. Week 2: Voyager API updated with support
  4. 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

  1. Pin Cairo Versions in Production

    # Scarb.toml - Use specific versions
    [dependencies]
    starknet = "2.8.4"  # Not "^2.8" or ">=2.8"
    
  2. Commit Lock Files

    git add Scarb.lock
    
  3. Test Before Upgrading

    # Always test on Sepolia first
    voyager verify --network sepolia ...
    
  4. Keep Voyager Updated

    # Update regularly for bug fixes
    asdf install voyager latest
    asdf global voyager latest
    

    Note: Voyager version is independent of toolchain versions - you can safely update without compatibility concerns.

  5. Document Your Versions

    # Add to your README.md:
    # Cairo: 2.8.4
    # Scarb: 2.8.4
    # Dojo: 1.7.1 (if applicable)
    
  6. 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:

  1. Test with --dry-run first to confirm it’s unsupported
  2. Open a GitHub issue
  3. 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

File Collection

This reference documents which files are collected and included when submitting contract verification requests.

Quick Reference

File TypeIncluded by DefaultFlag RequiredMax SizeNotes
Cairo source files (.cairo)✅ YesNone20MB eachExcluding tests by default
Scarb.toml (package)✅ YesNone20MBAlways included
Scarb.toml (workspace)✅ Yes (if workspace)None20MBAuto-detected
Scarb.lock❌ No--lock-file20MBOptional for reproducibility
Test files (.cairo in tests/)❌ No--test-files20MB eachIn src/ directory only
Documentation (.md, .txt)✅ Yes (if found)None20MB eachLICENSE, README, etc.
Rust files (.rs)✅ Yes (proc-macro only)None20MB eachFor 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:

  1. Recursive Search: All Cairo files under src/ are found recursively
  2. Test Exclusion: Files in test/ or tests/ directories are excluded by default
  3. 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:

  1. Your contract imports test modules:

    // src/lib.cairo
    mod contract;
    #[cfg(test)]
    mod tests;  // Error E005 without --test-files
    
  2. Test code is referenced in production:

    // src/lib.cairo
    use my_contract::tests::TestHelper;  // Requires --test-files
    
  3. 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:

  1. Cargo.toml - Rust package manifest
  2. Cargo.lock - Rust dependency lock file (if exists)
  3. All .rs files in src/
  4. 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:

ExtensionTypeExample
.cairoCairo sourcesrc/contract.cairo
.tomlConfigurationScarb.toml, Cargo.toml
.lockLock filesScarb.lock, Cargo.lock
.mdDocumentationREADME.md, CHANGELOG.md
.txtText filesLICENSE.txt, NOTICE.txt
.jsonJSON datametadata.json
.rsRust sourcesrc/lib.rs (proc-macro only)

Files Without Extensions:

These common project files are allowed without extensions:

  • LICENSE
  • README
  • CHANGELOG
  • NOTICE
  • AUTHORS
  • CONTRIBUTORS

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:

  1. Keep contracts modular: Split large contracts into smaller files
  2. Avoid generated code: Don’t include large auto-generated files
  3. 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:

  1. Split large files into modules
  2. Remove unnecessary code or comments
  3. 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:

  1. Verify file path is correct
  2. Check file was created
  3. Ensure proper casing (case-sensitive)

Best Practices

✅ File Collection Best Practices

  1. Commit Lock Files

    git add Scarb.lock
    git commit -m "Add lock file for reproducibility"
    
  2. Use –test-files Only When Needed

    # Only if tests are actually imported
    voyager verify --test-files ...
    
  3. Keep Files Under 20MB

    // Split large contracts:
    mod contract_part1;
    mod contract_part2;
    
  4. Use Dry-Run to Preview

    # Always check before submitting
    voyager verify --dry-run ...
    
  5. Organize Source Files

    src/
    ├── lib.cairo     # Main entry
    ├── contract.cairo  # Contract code
    ├── utils.cairo    # Utilities
    └── tests/        # Tests (separate)
    
  6. 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 .cairo files in src/ (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

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

CodeNameDescriptionTerminal
0SubmittedJob submitted, waiting to be processedNo
1CompiledContract compiled successfullyNo
2CompileFailedCompilation failedYes
3FailVerification failedYes
4SuccessContract verified successfullyYes
5ProcessingJob is being processedNo
UnknownUnknownUnknown statusNo

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 ResultTypical Duration
Success (simple contract)5-15 seconds
Success (complex contract)15-60 seconds
CompileFailed10-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

Contributing

Thank you for your interest in contributing to Voyager Verifier! This guide will help you get started.

Table of Contents

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

  1. Open an issue first to discuss the changes
  2. Fork the repository and create a branch from main
  3. Make your changes following our coding standards
  4. Write or update tests to cover your changes
  5. Update documentation as needed
  6. Ensure tests pass with cargo test
  7. Run linting with cargo lint
  8. Format code with cargo fmt
  9. Commit your changes with clear, descriptive messages
  10. 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

  1. Clone your fork:

    git clone https://github.com/YOUR_USERNAME/voyager-verifier.git
    cd voyager-verifier
    
  2. Add upstream remote:

    git remote add upstream https://github.com/NethermindEth/voyager-verifier.git
    
  3. Install dependencies:

    cargo build
    
  4. Run tests:

    cargo test
    
  5. 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 fmt to format code
  • Address all cargo lint warnings
  • Write idiomatic Rust code

Code Quality

  • Write tests - Aim for high test coverage
  • Handle errors properly - Use Result and 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

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: ![Architecture diagram](../images/arch.png)
  • 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

  1. Create the Markdown file in the appropriate directory
  2. Add it to docs/src/SUMMARY.md in the correct section
  3. Link to it from related pages

Updating API Documentation

  1. Update the relevant Rust doc comments in source code
  2. Update the corresponding API reference page if it exists
  3. Update any examples that reference the changed API

Adding Code Examples

  1. Write the example code
  2. Test that it compiles and runs correctly
  3. Add explanatory comments
  4. Include it in the documentation with context
  1. Use mdbook build to check for broken links
  2. Update links to point to the correct location
  3. 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

  1. Submit your PR referencing the related issue
  2. Maintainers will review for:
    • Technical accuracy
    • Clarity and readability
    • Consistency with existing docs
    • Proper formatting and structure
  3. Address any feedback
  4. 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
```
[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!