$npx -y skills add keep-starknet-strange/starknet-agentic --skill cairo-deployDeployment guidance for Cairo contracts on Starknet covering sncast commands, account setup, declare/deploy workflow, network configuration, and contract verification.
| 1 | # Cairo Deploy |
| 2 | |
| 3 | Reference for deploying Cairo smart contracts to Starknet using sncast (Starknet Foundry). |
| 4 | |
| 5 | ## When to Use |
| 6 | |
| 7 | - Deploying contracts to Starknet devnet, Sepolia, or mainnet |
| 8 | - Declaring contract classes |
| 9 | - Setting up deployer accounts |
| 10 | - Configuring network endpoints |
| 11 | - Verifying deployed contracts |
| 12 | - Invoking/calling deployed contracts |
| 13 | |
| 14 | ## When NOT to Use |
| 15 | |
| 16 | - Writing or refactoring contract logic (`cairo-contract-authoring`). |
| 17 | - Unit, integration, or fuzz testing (`cairo-testing`). |
| 18 | - Gas or performance optimization (`cairo-optimization`). |
| 19 | - Security review of existing code (`cairo-auditor`). |
| 20 | |
| 21 | ## Quick Start |
| 22 | |
| 23 | 1. Build with `scarb build`, then declare and deploy with `sncast`. |
| 24 | 2. Use [skills catalog](../README.md) when the task moves back into authoring, testing, or auditing. |
| 25 | |
| 26 | ## Setup |
| 27 | |
| 28 | ### Install Starknet Foundry |
| 29 | |
| 30 | ```bash |
| 31 | # Install via asdf (recommended for version pinning) |
| 32 | asdf plugin add starknet-foundry |
| 33 | asdf install starknet-foundry 0.56.0 |
| 34 | asdf global starknet-foundry 0.56.0 |
| 35 | |
| 36 | # Or install directly |
| 37 | curl -L https://raw.githubusercontent.com/foundry-rs/starknet-foundry/master/scripts/install.sh | sh |
| 38 | snfoundryup |
| 39 | ``` |
| 40 | |
| 41 | ### .tool-versions |
| 42 | |
| 43 | Pin versions for reproducible builds: |
| 44 | |
| 45 | ``` |
| 46 | scarb 2.15.1 |
| 47 | starknet-foundry 0.56.0 |
| 48 | ``` |
| 49 | |
| 50 | > **Note:** snforge 0.56.0 requires Scarb >= 2.12.0. Check [github.com/foundry-rs/starknet-foundry/releases](https://github.com/foundry-rs/starknet-foundry/releases) for the latest. |
| 51 | |
| 52 | ## Build |
| 53 | |
| 54 | ```bash |
| 55 | # Build contracts (generates Sierra + CASM) |
| 56 | scarb build |
| 57 | ``` |
| 58 | |
| 59 | Output goes to `target/dev/`: |
| 60 | - `myproject_MyContract.contract_class.json` (Sierra) |
| 61 | - `myproject_MyContract.compiled_contract_class.json` (CASM) |
| 62 | |
| 63 | ## Account Setup |
| 64 | |
| 65 | ### Create a New Account |
| 66 | |
| 67 | ```bash |
| 68 | # Generate account on Sepolia |
| 69 | sncast account create \ |
| 70 | --url https://starknet-sepolia.g.alchemy.com/v2/YOUR_KEY \ |
| 71 | --name my-deployer |
| 72 | |
| 73 | # This outputs the account address — fund it with ETH/STRK before deploying |
| 74 | |
| 75 | # Deploy the account contract |
| 76 | sncast account deploy \ |
| 77 | --url https://starknet-sepolia.g.alchemy.com/v2/YOUR_KEY \ |
| 78 | --name my-deployer |
| 79 | ``` |
| 80 | |
| 81 | ### Import Existing Account |
| 82 | |
| 83 | ```bash |
| 84 | sncast account import \ |
| 85 | --url https://starknet-sepolia.g.alchemy.com/v2/YOUR_KEY \ |
| 86 | --name my-deployer \ |
| 87 | --address 0x123... \ |
| 88 | --private-key 0xabc... \ |
| 89 | --type oz |
| 90 | ``` |
| 91 | |
| 92 | Account types: `oz` (OpenZeppelin), `argent`, `braavos` |
| 93 | |
| 94 | ## sncast.toml |
| 95 | |
| 96 | Configure defaults to avoid repeating flags: |
| 97 | |
| 98 | ```toml |
| 99 | [default] |
| 100 | url = "https://starknet-sepolia.g.alchemy.com/v2/YOUR_KEY" |
| 101 | account = "my-deployer" |
| 102 | accounts-file = "~/.starknet_accounts/starknet_open_zeppelin_accounts.json" |
| 103 | wait = true |
| 104 | |
| 105 | [mainnet] |
| 106 | url = "https://starknet-mainnet.g.alchemy.com/v2/YOUR_KEY" |
| 107 | account = "mainnet-deployer" |
| 108 | ``` |
| 109 | |
| 110 | Use profiles: `sncast --profile mainnet declare ...` |
| 111 | |
| 112 | ## Declare (Register Class) |
| 113 | |
| 114 | Before deploying, declare the contract class on-chain: |
| 115 | |
| 116 | ```bash |
| 117 | # Declare contract |
| 118 | sncast declare \ |
| 119 | --contract-name MyContract |
| 120 | |
| 121 | # Output: |
| 122 | # class_hash: 0x1234... |
| 123 | # transaction_hash: 0xabcd... |
| 124 | ``` |
| 125 | |
| 126 | If the class is already declared, sncast will tell you — that's fine, use the existing class hash. |
| 127 | |
| 128 | ## Deploy (Create Instance) |
| 129 | |
| 130 | ```bash |
| 131 | # Deploy with constructor args |
| 132 | sncast deploy \ |
| 133 | --class-hash 0x1234... \ |
| 134 | --constructor-calldata 0xOWNER_ADDRESS |
| 135 | |
| 136 | # Multiple constructor args (space-separated) |
| 137 | sncast deploy \ |
| 138 | --class-hash 0x1234... \ |
| 139 | --constructor-calldata 0xOWNER 0xTOKEN_ADDRESS 1000 |
| 140 | ``` |
| 141 | |
| 142 | ### Constructor Calldata Encoding |
| 143 | |
| 144 | Arguments are passed as felt252 values: |
| 145 | - `ContractAddress` — pass as hex `0x123...` |
| 146 | - `u256` — pass as TWO felts: `low high` (e.g., `1000 0` for 1000) |
| 147 | - `felt252` — pass directly |
| 148 | - `bool` — `1` for true, `0` for false |
| 149 | - `ByteArray` (strings) — use sncast's string encoding or pass raw |
| 150 | |
| 151 | ## Invoke (Write) |
| 152 | |
| 153 | ```bash |
| 154 | # Call a write function |
| 155 | sncast invoke \ |
| 156 | --contract-address 0xCONTRACT \ |
| 157 | --function "transfer" \ |
| 158 | --calldata 0xRECIPIENT 1000 0 |
| 159 | ``` |
| 160 | |
| 161 | ## Call (Read) |
| 162 | |
| 163 | ```bash |
| 164 | # Call a view function (free, no tx) |
| 165 | sncast call \ |
| 166 | --contract-address 0xCONTRACT \ |
| 167 | --function "get_balance" \ |
| 168 | --calldata 0xACCOUNT |
| 169 | ``` |
| 170 | |
| 171 | ## Programmatic Deployment (starknet.js) |
| 172 | |
| 173 | ```ts |
| 174 | import { Account, CallData, Contract, RpcProvider } from "starknet"; |
| 175 | |
| 176 | const provider = new RpcProvider({ nodeUrl: process.env.STARKNET_RPC! }); |
| 177 | const account = new Account(provider, process.env.ACCOUNT_ADDRESS!, process.env.PRIVATE_KEY!); |
| 178 | |
| 179 | const declareTx = await account.declare({ contract: compiledSierra, casm: compiledCasm }); |
| 180 | await provider.waitForTransaction(declareTx.transaction_hash); |
| 181 | |
| 182 | const deployT |