Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.arcium.com/llms.txt

Use this file to discover all available pages before exploring further.

Getting started with deployment

Deploy after arcium build and arcium test pass locally. This guide covers program preparation, cluster offsets, RPC setup, migration, and closing accounts.
This guide walks you through deploying to devnet first. Once you’ve validated your MXE on devnet, see Deploying to Mainnet for mainnet-specific configuration.

What you’ll need

Before deploying, make sure you have:
  • Your MXE built successfully with arcium build
  • Tests passing locally with arcium test
  • A Solana keypair with around 2-5 SOL for deployment costs (program deployment and account initialization)
  • Access to a reliable RPC endpoint
RPC reliability is critical for deployment. Default Solana RPC endpoints can be unreliable and drop transactions, causing deployment failures. Get an API key from Helius, Triton, or QuickNode before attempting deployment.

Preparing your program

Before deploying, decide how your program stores computation definitions.

Handling large circuits with offchain storage

Arcis compiled circuits can be several MB. Uploading the full bytecode onchain can require many transactions and high rent. For larger circuits, upload the compiled .arcis file to public storage and initialize the computation definition with its URL and hash. Standard approach (works for small circuits):
pub fn init_add_together_comp_def(ctx: Context<InitAddTogetherCompDef>) -> Result<()> {
    // This initializes the computation definition account
    init_computation_def(ctx.accounts, None)?;
    Ok(())
}
Offchain approach (recommended for larger circuits):
// First, import the types you'll need
use arcium_client::idl::arcium::types::{CircuitSource, OffChainCircuitSource};
use arcium_macros::circuit_hash;

pub fn init_add_together_comp_def(ctx: Context<InitAddTogetherCompDef>) -> Result<()> {
    // Point to your uploaded circuit file
    init_computation_def(
        ctx.accounts,
        Some(CircuitSource::OffChain(OffChainCircuitSource {
            source: "https://your-storage.com/path/to/add_together.arcis".to_string(),
            hash: circuit_hash!("add_together"),
        })),
    )?;
    Ok(())
}
The circuit_hash! macro embeds the SHA-256 hash of your compiled circuit at compile time. The hash is read from build/{circuit_name}.hash, which is generated automatically during arcium build. Arx nodes verify this hash when fetching your circuit to ensure the circuit hasn’t been tampered with.Important: Always use circuit_hash! for offchain circuits. Don’t use a placeholder like [0u8; 32] - this will cause verification to fail on Arx nodes.
Offchain circuit flow:
  1. Build your project with arcium build to generate the circuit files and hashes
  2. Upload the .arcis files from build/ folder to your preferred storage service
  3. Update your init functions with the public URLs and circuit_hash! macro calls
Circuit files must be publicly readable without authentication.

Note on cluster configuration

When testing locally, you’ve been using arciumEnv.arciumClusterOffset with getClusterAccAddress() in your test code. For devnet deployment, you’ll use the same pattern with your chosen cluster offset - we’ll show you exactly how in the post-deployment section.

Basic deployment

The arcium deploy command handles both deploying your program and initializing the MXE account. Here’s the basic command structure:
arcium deploy --cluster-offset <cluster-offset> --recovery-set-size <size> --keypair-path <path-to-your-keypair> --rpc-url <your-rpc-url>
Let’s break down what each parameter does:

Understanding cluster offsets

The --cluster-offset tells your MXE which Arcium cluster it should connect to. Think of clusters as groups of nodes that will perform your confidential computations. Available offsets: Devnet cluster:
  • 456
Mainnet cluster:
  • 2026

Recovery set size

The --recovery-set-size parameter specifies how many nodes form the recovery set that holds confidential key shares of your MXE’s key. This enables key reconstruction when needed, whether due to node failure or cluster migration. This is required. The absolute minimum is 4; larger clusters may require a larger recovery set, and the CLI prints the required value if the one you pass is too small.

Choosing your RPC provider

Always pass --rpc-url <your-rpc-url>. Solana’s default RPC endpoints (-u d, -u m) can drop transactions during deployment. Recommended approach with a reliable RPC:
arcium deploy --cluster-offset 456 \
  --recovery-set-size 4 \
  --keypair-path ~/.config/solana/id.json \
  --rpc-url <your-devnet-rpc-url>
If you must use the default RPC:
arcium deploy --cluster-offset 456 \
  --recovery-set-size 4 \
  --keypair-path ~/.config/solana/id.json \
  -u d  # 'd' for devnet, 'm' for mainnet, 'l' for localnet
Just be prepared for potential transaction failures with the default RPC.

Advanced deployment options

Once you’re comfortable with basic deployment, you might want to customize things further.

Using a custom program address

If you need your program at a specific address (maybe for consistency across deployments), you can provide a program keypair:
arcium deploy --cluster-offset 456 \
  --recovery-set-size 4 \
  --keypair-path ~/.config/solana/id.json \
  --rpc-url <your-rpc-url> \
  --program-keypair ./program-keypair.json

Partial deployments

Sometimes you might need to run just part of the deployment process. For instance, if you’ve already deployed the program but need to reinitialize the MXE account:
# Skip program deployment, only initialize MXE account
arcium deploy --cluster-offset 456 \
  --recovery-set-size 4 \
  --keypair-path ~/.config/solana/id.json \
  --rpc-url <your-rpc-url> \
  --skip-deploy
Or if you only want to deploy the program without initialization:
# Deploy program only, skip MXE initialization
arcium deploy --cluster-offset 456 \
  --recovery-set-size 4 \
  --keypair-path ~/.config/solana/id.json \
  --rpc-url <your-rpc-url> \
  --skip-init

After deployment

Initialize your computation definitions

Your MXE is deployed, but you still need to initialize the computation definitions. This tells the Arcium Network what confidential operations your MXE can perform. Computation definitions only need to be initialized once - they persist onchain and don’t need to be re-initialized unless you’re deploying to a new program address. You can initialize them anytime after deployment completes successfully. Remember how we mentioned you’d need to update your cluster configuration? Now’s the time! You’ll need to update your test or client code to derive the cluster account (and the related PDAs) from the cluster offset you selected during deployment. Local testing pattern:
const arciumEnv = getArciumEnv();

// In your transaction...
.accountsPartial({
    computationAccount: getComputationAccAddress(
        arciumEnv.arciumClusterOffset,
        computationOffset
    ),
    clusterAccount: getClusterAccAddress(arciumEnv.arciumClusterOffset),
    mxeAccount: getMXEAccAddress(program.programId),
    mempoolAccount: getMempoolAccAddress(arciumEnv.arciumClusterOffset),
    executingPool: getExecutingPoolAccAddress(arciumEnv.arciumClusterOffset),
    // ... other accounts
})
For devnet deployment:
// Use the cluster offset from your deployment (e.g., 456)
const clusterOffset = 456;

// In your transaction...
.accountsPartial({
    computationAccount: getComputationAccAddress(clusterOffset, computationOffset),
    clusterAccount: getClusterAccAddress(clusterOffset),
    mxeAccount: getMXEAccAddress(program.programId),
    mempoolAccount: getMempoolAccAddress(clusterOffset),
    executingPool: getExecutingPoolAccAddress(clusterOffset),
    // ... other accounts
})
Make sure to use the same cluster_offset value that you used during deployment! This ensures your program talks to the right cluster. Once you’ve updated the cluster configuration, you can run the initialization:
// Now with the correct cluster configured
await initAddTogetherCompDef(program, owner);

Verify everything’s working

Let’s make sure your deployment succeeded:
solana program show <your-program-id> --url <your-rpc-url>
To run your tests against the deployed program, configure the cluster offset in your Arcium.toml:
[clusters.devnet]
offset = <your-cluster-offset>
Then run:
arcium test --cluster devnet
The CLI reads the cluster offset from Arcium.toml and configures the test environment automatically. For RPC configuration, set the cluster and wallet in your Anchor.toml:
[provider]
cluster = "devnet"
wallet = "~/.config/solana/id.json"

Deploying to mainnet

Once you’ve validated your MXE on devnet, you can deploy to Arcium mainnet-alpha. The deployment process is the same, with a few key differences:

Mainnet cluster offset

Use the mainnet cluster offset from the Understanding Cluster Offsets section:
arcium deploy --cluster-offset <mainnet-cluster-offset> \
  --recovery-set-size 4 \
  --keypair-path ~/.config/solana/id.json \
  --rpc-url <your-mainnet-rpc-url>

Mainnet configuration

Configure the mainnet cluster offset in your Arcium.toml (see Understanding Cluster Offsets for the current value):
[clusters.mainnet]
offset = <your-cluster-offset>
To test against your mainnet deployment:
arcium test --cluster mainnet
Mainnet deployments require real SOL — there are no airdrops. Ensure your wallet is funded before deploying.

Common issues and solutions

The examples below use devnet. For mainnet, replace -u d with -u m and use a mainnet RPC URL.

Dealing with dropped transactions

If your deployment fails with transaction errors, it’s almost always the RPC. Switch to a dedicated provider:
# Instead of this (unreliable):
arcium deploy --cluster-offset 456 \
  --recovery-set-size <recovery-set-size> \
  --keypair-path ~/.config/solana/id.json \
  -u d

# Use this (reliable):
arcium deploy --cluster-offset 456 \
  --recovery-set-size <recovery-set-size> \
  --keypair-path ~/.config/solana/id.json \
  --rpc-url <your-devnet-rpc-url>

Running out of SOL

Check your balance before deploying:
solana balance <your-keypair-pubkey> -u devnet
If you need more SOL on devnet, request it via airdrop:
solana airdrop 2 <your-keypair-pubkey> -u devnet

Deployment partially failed?

If your deployment was interrupted (e.g., due to a dropped transaction or network issue), use the --resume flag to pick up where it left off:
arcium deploy --cluster-offset 456 \
  --recovery-set-size 4 \
  --keypair-path ~/.config/solana/id.json \
  --rpc-url <your-rpc-url> \
  --resume
This skips already-completed steps and retries from the point of failure. The --resume flag is also available on init-mxe and migrate-cluster for the same purpose. For finer control, you can also skip specific phases: --skip-deploy (skip program deployment, only initialize MXE) or --skip-init (deploy program only, skip MXE initialization).

Managing your MXE

Cluster migration

If you need to move your MXE from one cluster to another, use the migrate-cluster command:
arcium migrate-cluster <mxe-program-id> \
  --keypair-path <path-to-your-keypair> \
  --cluster-offset <new-cluster-offset> \
  --rpc-url <your-rpc-url>
This reconstructs your MXE’s keys on the new cluster using the recovery set configured during deployment. Your MXE will be temporarily unavailable during migration.
MXEs deployed with v0.9.x already have the recovery material needed for migrate-cluster; no separate remediation command is required before migrating them with v0.10.x.
If a migration is interrupted, resume it with --resume:
arcium migrate-cluster <mxe-program-id> \
  --keypair-path <path-to-your-keypair> \
  --rpc-url <your-rpc-url> \
  --resume
To abort an in-progress migration:
arcium migrate-cluster <mxe-program-id> \
  --keypair-path <path-to-your-keypair> \
  --rpc-url <your-rpc-url> \
  --abort
With --resume/--abort the CLI infers the cluster offset from onchain state; --cluster-offset is required only on the initial call.
Do not abort and then re-initialize a migration back to the same target cluster — that opens a denial-of-service surface. If you need to retry, resume instead.

Closing an MXE or computation definition

When you no longer need an MXE or one of its computation definitions, close the accounts to reclaim rent. Comp defs close in two steps: deactivate, wait 180 slots, then close. MXEs can close only after all user-defined comp defs are closed.
# Comp def: deactivate, wait for TTL, then close
arcium deactivate-computation-definition \
  -o <comp-offset> \
  -p <mxe-program-id> \
  -k <keypair> \
  --rpc-url <url>

arcium close-computation-definition \
  -o <comp-offset> \
  -p <mxe-program-id> \
  -c <cluster-offset> \
  -k <keypair> \
  --rpc-url <url>

# OnChain circuits also need their raw buffers closed (one call per index)
arcium close-computation-definition-buffers \
  -o <comp-offset> \
  -p <mxe-program-id> \
  -i <raw-circuit-index> \
  -k <keypair> \
  --rpc-url <url>

# MXE
arcium close-mxe \
  -p <mxe-program-id> \
  -k <keypair> \
  --rpc-url <url>
Pass an explicit --rpc-url — the CLI defaults to mainnet without it. For the full state machine, authority rules, error codes, and common mistakes, see Account lifecycle and closing.

What’s next?

After deployment, update your client code to use the correct cluster offset, initialize your computation definitions onchain, and run end-to-end tests on devnet.

Arcis best practices

Learn patterns and optimizations for efficient confidential instructions.

Examples repository

Explore complete example projects and reference implementations.
For questions or issues, reach out on Discord.