Розгортування смарт-контрактів у StarkNet
StarkNet — це ZK Rollup від StarkWare, побудований на основі Ethereum. На відміну від zkSync Era з його EVM-сумісністю, StarkNet використовує власну мову Cairo та віртуальну машину CASM. Вам не вдасться прямо перенести контракт Solidity на StarkNet — потрібно переписати його з нуля або використовувати транспайлер Warp (який працює лише з обмеженою підмножиною Solidity). Це обов'язково потрібно враховувати при оцінці трудовитрат.
Cairo: мова контрактів StarkNet
Cairo 1.x vs Cairo 0.x
Історично Cairo писався в процедурному стилі з явним управлінням hints, що було нетривіально. Починаючи з Cairo 1.0 (2023) синтаксис було перероблено у Rust-подібний стиль, контракти тепер пишуться як модулі #[starknet::contract]:
#[starknet::contract]
mod Counter {
use starknet::ContractAddress;
#[storage]
struct Storage {
count: u128,
owner: ContractAddress,
}
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
Incremented: Incremented,
}
#[derive(Drop, starknet::Event)]
struct Incremented {
new_count: u128,
}
#[constructor]
fn constructor(ref self: ContractState, owner: ContractAddress) {
self.owner.write(owner);
self.count.write(0);
}
#[abi(embed_v0)]
fn increment(ref self: ContractState) {
let current = self.count.read();
self.count.write(current + 1);
self.emit(Incremented { new_count: current + 1 });
}
}
Компілятор — scarb (менеджер пакетів і build tool для Cairo, аналог Cargo). Контракти компілюються в Sierra (Safe Intermediate Representation), потім у CASM для виконання.
Ключові відмінності від Solidity
-
Storage — у Cairo сховище працює інакше. Немає динамічних массивів у storage напрямку: використовуйте
Vec<T>черезStorageVecабо маппінги черезMap<K, V>. Структури розкладаються в окремі слоти storage автоматично. -
Felt252 — базовий тип даних, 252-бітне поле. Звичні
uint256реалізовані як структура з двохfelt252. Арифметика u256 дорожче в газі, ніж робота зfelt252. -
Account Abstraction є нативною — у StarkNet немає EOA у сенсі Ethereum. Кожен аккаунт — це контракт, що реалізує інтерфейс
IAccount. Це означає, що multicall, session keys, social recovery — все це "з коробки" на рівні аккаунту.
Інфраструктура розгортування
Scarb та ініціалізація проекту
# Встановлення Scarb
curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | sh
# Новий проект
scarb new my_contract
cd my_contract
# Scarb.toml
[package]
name = "my_contract"
version = "0.1.0"
[dependencies]
starknet = ">=2.6.0"
[[target.starknet-contract]]
sierra = true
casm = true
# Компіляція
scarb build
# Результат: target/dev/my_contract_Counter.contract_class.json (Sierra)
# target/dev/my_contract_Counter.compiled_contract_class.json (CASM)
Розгортування через starkli
starkli — основний CLI інструмент для взаємодії зі StarkNet:
# Встановлення
curl https://get.starkli.sh | sh
# Налаштування keystore
starkli signer keystore new ~/.starkli-wallets/deployer/keystore.json
# Оголосити клас контракту (declare) — це унікально для StarkNet
# Спочатку клас реєструється у мережі, потім розгортується інстанс
starkli declare \
target/dev/my_contract_Counter.contract_class.json \
--account ~/.starkli-wallets/deployer/account.json \
--keystore ~/.starkli-wallets/deployer/keystore.json \
--rpc https://starknet-mainnet.public.blastapi.io
# Розгортування інстанса з аргументами constructor
starkli deploy \
CLASS_HASH \
OWNER_ADDRESS \
--account ~/.starkli-wallets/deployer/account.json \
--keystore ~/.starkli-wallets/deployer/keystore.json \
--rpc https://starknet-mainnet.public.blastapi.io
Двошагова модель declare/deploy — архітектурна особливість StarkNet. Один і той же class_hash може мати тисячі інстансів — це економить місце у мережі.
Розгортування через starknet-rs / starknet.js
Для програмного розгортування через TypeScript:
import { RpcProvider, Account, Contract, json, stark } from 'starknet'
import fs from 'fs'
const provider = new RpcProvider({
nodeUrl: 'https://starknet-mainnet.public.blastapi.io',
})
const account = new Account(
provider,
ACCOUNT_ADDRESS,
PRIVATE_KEY,
'1' // Cairo version
)
// Declare
const compiledSierra = json.parse(
fs.readFileSync('./target/dev/my_contract_Counter.contract_class.json').toString('ascii')
)
const compiledCasm = json.parse(
fs.readFileSync('./target/dev/my_contract_Counter.compiled_contract_class.json').toString('ascii')
)
const declareResponse = await account.declare({
contract: compiledSierra,
casm: compiledCasm,
})
await provider.waitForTransaction(declareResponse.transaction_hash)
// Deploy
const deployResponse = await account.deployContract({
classHash: declareResponse.class_hash,
constructorCalldata: [OWNER_ADDRESS],
})
await provider.waitForTransaction(deployResponse.transaction_hash)
Верифікація та Voyager
StarkNet explorer — Voyager (voyager.online) та Starkscan. Верифікація через Voyager приймає джерела Cairo та Scarb.toml. API для програмної верифікації:
curl -X POST https://api.voyager.online/beta/contract/verify \
-H "Content-Type: application/json" \
-d '{
"contractAddress": "0x...",
"files": { "src/lib.cairo": "..." },
"scarbVersion": "2.6.0"
}'
Оцінка трудовитрат
| Сценарій | Строк |
|---|---|
| Простий контракт (лічильник, сховище) з нуля | 4–8 год |
| Міграція ERC-20 / ERC-721 з Solidity | 1 день (OpenZeppelin Cairo вже реалізує стандарти) |
| Кастомна DeFi логіка (переписати з Solidity) | 1–2 дні + тести |
Якщо контракт вже написаний на Solidity і немає принципіальної необхідності у StarkNet-специфічних можливостях (native AA, ZK-доказах для кастомної логіки) — рекомендую спочатку розглянути zkSync Era з його EVM-сумісністю. Перехід на Cairo виправданий, коли вам потрібні можливості, які Cairo надає нативно.







