| name | cannon |
| description | Cannon package manager for Ethereum deployments. Use when building, testing, deploying, or inspecting Cannon packages. Covers cannonfile syntax, CLI commands (build, run, test, publish, inspect), actions (deploy, invoke, clone, pull, router, diamond), and package workflows. NOT for general Solidity development questions. |
Cannon
⚠️ CRITICAL: Read This First
Some Cannon commands are IRREVERSIBLE and handle real value. Be careful with:
cannon build (without --dry-run) — deploys contracts on real networks
cannon publish — publishes to on-chain registry (permanent)
cannon register — registers package names on-chain
cannon publishers — manages package publisher permissions
Safe commands: cannon build --dry-run, cannon inspect, cannon run, cannon test, cannon decode, cannon trace, cannon clean
Rules:
- Always use
--dry-run first — Simulate before executing on real networks
- Make every operation clear to the user — Explain what will happen before running
- Confirm before deploying — Never use a real private key without explicit approval
- Test locally first — Use chain 13370 (Cannon Network) before target chains
- Protect private keys — Use
CANNON_PRIVATE_KEY env var or --impersonate (recommended)
Model Recommendation
Use state-of-the-art models for Cannon tasks. Deployment scripts handle real value — don't skimp on model quality. Prefer Claude, GPT-4, or equivalent high-capability models over cheaper alternatives.
Schema Reference
For complete cannonfile syntax validation and autocomplete, refer to the official JSON schemas:
For editor validation, add the schema reference at the top of your cannonfile.toml:
name = "my-package"
version = "1.0.0"
...
This enables autocomplete and validation in editors with TOML LSP support (like taplo).
Cannon is a package manager and deployment system for Ethereum smart contracts. It uses declarative cannonfiles to define deployment workflows and supports both local development and on-chain deployments.
Prerequisites
Before using this skill, ensure these tools are installed:
- Node.js 18+ and pnpm -
npm install -g pnpm
- Foundry (forge, anvil, cast) -
curl -L https://foundry.paradigm.xyz | bash && foundryup
- Cannon CLI -
pnpm add -g @usecannon/cli
Verify installation:
node --version && pnpm --version
forge --version && anvil --version
cannon --version
Environment Variables
Cannon CLI recognizes the following environment variables. All Cannon-specific environment variables use the CANNON_ prefix.
| Variable | Description |
|---|
CANNON_PRIVATE_KEY | Private key for signing on-chain transactions (deploy, publish, register). Required for non-dry-run operations on real networks. |
CANNON_RPC_URL | Ethereum RPC endpoint URL for target chain. Required for non-local deployments and publish operations. |
CANNON_ETHERSCAN_API_KEY | Etherscan API key for contract verification (cannon verify). Required for verifying deployed contracts on Etherscan-supported chains. |
CANNON_DIRECTORY | Custom directory for Cannon package storage and build artifacts. Defaults to ~/.local/share/cannon/ if not set. |
Quick Reference
For complete CLI options, see references/cli.md.
CLI Commands
cannon build
cannon run <pkg:ver>
cannon test
cannon inspect <pkg:ver>
cannon publish
cannon clean
cannon verify
Package Reference Format
<package-name>:<version>@<preset>
Examples:
greeter-foundry:2.24.0
safe:1.4.1
synthetix-omnibus:3.1.4@main
Cannonfile Syntax
Package Metadata & Includes
name = "my-package"
version = "1.0.0"
description = "My package description"
tags = ["defi", "token"]
preset = "main"
include = ["./deposits.toml", "./withdrawals.toml"]
Use include to split large cannonfiles into multiple files. Included files use the fragment schema and can contain any actions (deploy, invoke, clone, etc.).
Modern syntax uses [var.label] for settings (deprecated: [setting.name]).
Variables
[var.chainId]
defaultValue = 1
[var.owner]
defaultValue = "0x..."
Deploy Contract
[deploy.MyContract]
artifact = "MyContract"
args = ["<%= settings.owner %>"]
Invoke Function
[invoke.initialize]
target = ["<%= contracts.MyContract.address %>"]
func = "initialize"
args = ["<%= settings.owner %>"]
Import/Clone Package
[clone.safe]
source = "safe:1.4.1"
target = "safe"
When to use clone vs import:
clone — Use another package as a "blueprint" to deploy it anew. Always set target appropriately (same as source if you own it, or a new name if not).
import — Pull in data from an already-deployed package without re-deploying.
Pull Data from Package
[pull.usdc]
source = "usdc:1.0.0@main"
Access: <%= imports.usdc.contracts.USDC.address %>
Template Strings
Use ERB-style templates to reference values:
<%= settings.varName %> — settings
<%= contracts.ContractName.address %> — deployed contract address
<%= contracts.ContractName.abi %> — contract ABI
<%= imports.pkg.contracts.Contract.address %> — imported contract
Actions
| Action | Description |
|---|
deploy | Deploy a contract |
invoke | Call a contract function |
clone | Deploy another package as a blueprint |
import | Pull data from an already-deployed package |
pull | (deprecated) Alias for import |
var | Define computed variables |
router | Create a router contract to bypass size limits (pairs well with UUPS proxy) |
diamond | Create an EIP-2535 Diamond with facets |
Local Development
⚠️ Always use chain 13370 (Cannon Network) for local testing before deploying to target chains.
Default chain ID: 13370 (Cannon Network)
cannon build
cannon build --chain-id 1 --rpc-url $RPC_URL
cannon build --dry-run --impersonate-all
cannon run greeter-foundry:2.24.0
On-Chain Deployment
⚠️ Always use --dry-run first to verify deployments before executing on real networks.
cannon build --chain-id 1 --rpc-url $RPC_URL --private-key $KEY
cannon publish --chain-id 1 --rpc-url $RPC_URL --private-key $KEY
cannon build --chain-id 1 --rpc-url $RPC_URL --dry-run
Testing
cannon test
cannon test --match-path "test/MyContract.t.sol"
Use cannon-std in Forge tests:
import {Cannon} from "cannon-std/Test.sol";
contract MyTest is Cannon {
function setUp() public {
// Load deployed contracts
address myContract = getAddress("MyContract");
}
}
Storage Locations
| Directory | Contents |
|---|
~/.local/share/cannon/tags/ | Package reference files |
~/.local/share/cannon/ipfs_cache/ | Cached IPFS artifacts |
~/.local/share/cannon/build_results/ | Build outputs |
~/.local/share/cannon/blobs/ | Large binary blobs |
Common Patterns
Router Pattern (Bypass Contract Size Limits)
Create a router contract that efficiently passes calls to downstream contracts. Powerful when combined with a UUPS proxy.
[deploy.CoreImplementation]
artifact = "Core"
[deploy.AnotherImplementation]
artifact = "Another"
[router.CoreRouter]
dependencies = ["CoreImplementation", "AnotherImplementation"]
Diamond Pattern (EIP-2535)
[deploy.Diamond]
artifact = "Diamond"
[deploy.FacetA]
artifact = "FacetA"
[deploy.FacetB]
artifact = "FacetB"
[diamond.Diamond]
facets = ["FacetA", "FacetB"]
Linked Libraries
[deploy.Library]
artifact = "Library"
[deploy.Contract]
artifact = "Contract"
libraries = { Library = "<%= contracts.Library.address %>" }
Debugging Tools
Cannon provides commands to decode bytecode, trace transactions, and interact with deployed contracts.
Decode
Decode hex data (function calls, events, errors) using package ABIs:
cannon decode synthetix-omnibus --chain-id 8453 --preset main 0x...
Trace
Get human-readable stack traces for transactions:
cannon trace <tx-hash> --chain-id 1 --rpc-url $RPC_URL
Interact
Send transactions to deployed contracts through the CLI:
cannon interact synthetix-omnibus --chain-id 8453 --contract CoreProxy
Package State Manipulation (alter)
The alter command modifies existing Cannon packages outside the regular build process. Use for troubleshooting, migrations, or fixing broken package state.
⚠️ Only use alter when no other option exists.
Subcommands
| Command | Description |
|---|
import | Import existing artifacts into a deployment step (for migrations) |
set-contract-address | Change a contract's address in the deployment |
mark-complete | Mark a deployment step as complete |
mark-incomplete | Mark a deployment step as incomplete |
set-url | Update the deployment URL reference |
set-misc | Update miscellaneous data URL |
clean-unused | Remove unused deployment states |
migrate-212 | Migrate packages from version 2.12 format |
Example: Import existing deployment
cannon alter my-package:1.0.0 --chain-id 1 import deploy MyContract 0x...txhash
cannon alter my-package:1.0.0 --chain-id 1 import invoke initialize 0x...txhash
GitOps Workflows
Cannon supports GitOps-style deployments through the website interface.
Queue with GitOps
Deploy packages directly from GitHub repositories or IPFS hashes via the Cannon website:
- Preview transactions before execution
- View Git Diff of changes
- Execute through Safe multisig wallets
- Publish to registry after deployment
See: https://usecannon.com/deploy
Deployments Repository
Create a dedicated Git repository for deployment configurations (separate from source code):
- Keep smart contract source private while maintaining transparent deployments
- Enable team collaboration on deployments
- Maintain clear audit trail
Migration from Other Tools
Migrating from hardhat-deploy, Foundry scripts, or other deployment frameworks:
- Recreate deployment as cannonfile.toml (manual but usually quick)
- Build locally to create template:
cannon build (save the IPFS hash)
- For each network, import existing deployments:
cannon alter my-package --chain-id 1 set-url <ipfs-hash>
cannon alter my-package --chain-id 1 import deploy MyContract 0x...txhash
- Verify by running build (no steps should execute):
cannon build --chain-id 1
Advanced Topics
For detailed information on:
Troubleshooting
| Issue | Solution |
|---|
| "deployment not found" | Package not published for this chain ID. Check --chain-id |
| Build fails with "artifact not found" | Run forge build first, or check artifact path |
| IPFS timeout | Check network connection, may need IPFS gateway |
| Registry publish fails | Verify you have write permissions for the package name |
| Wrong chain deployed | Always double-check --chain-id — deployments cannot be undone |
| Published incorrect package | Registry publishes are permanent — verify version and artifacts first |
Development Workflow
- Develop contracts with Foundry
- Write cannonfile.toml to define deployment
- Build locally with
cannon build (chain 13370)
- Test with
cannon test
- Simulate with
--dry-run for target chain ⚠️ ALWAYS DO THIS FIRST
- Deploy with
cannon build --chain-id <id> ⚠️ IRREVERSIBLE on non-local networks (safe on chain 13370)
- Verify contracts on Etherscan with
cannon verify
- Publish with
cannon publish ⚠️ PERMANENT ON-CHAIN
Key Files
| File | Purpose |
|---|
cannonfile.toml | Package definition |
cannonfile.lock | Locked dependencies |
.cannon/ | Build cache (gitignored) |
deployments/ | Deployment artifacts |