Деплой смарт-контрактов в zkSync
zkSync Era — ZK Rollup с EVM-совместимостью, но не EVM-эквивалентностью. Большинство Solidity контрактов компилируются и деплоятся без изменений, но есть специфика компилятора zksolc и ряд опкодов, которые ведут себя иначе. Знать это нужно до деплоя, иначе контракт задеплоится, но будет работать неправильно.
Специфика zkSync Era
Компилятор zksolc
zkSync использует собственный компилятор zksolc, который компилирует Solidity в EraVM bytecode (не EVM bytecode). Это важное отличие:
- Контракт, задеплоенный на zkSync, имеет другой bytecode чем тот же контракт на Ethereum
-
CREATEиCREATE2работают по-другому: перед деплоем байткод контракта должен быть объявлен в транзакции (feature "factory dependencies") -
SELFDESTRUCT— задеплоить можно, но опкод не удаляет контракт (изменено в EIP-6049, zkSync следует этой семантике) -
PUSH0— поддерживается начиная с определённых версий zksolc; для старых контрактов сpragma solidity ^0.8.19может быть проблема
Отличия в gas модели
zkSync Era имеет двумерную gas модель: gasLimit (computation) + gasPerPubdata (стоимость публикации данных в L1). При деплое контрактов с большим bytecode gasPerPubdata может доминировать над вычислительным gas.
Деплой через Hardhat
npm install -D @matterlabs/hardhat-zksync @matterlabs/zksync-contracts
// hardhat.config.ts
import { HardhatUserConfig } from 'hardhat/config'
import '@matterlabs/hardhat-zksync'
const config: HardhatUserConfig = {
zksolc: {
version: 'latest',
settings: {
optimizer: {
enabled: true,
mode: '3', // z (size), s (speed), 3 (balanced)
},
},
},
networks: {
zkSyncMainnet: {
url: 'https://mainnet.era.zksync.io',
ethNetwork: 'mainnet',
zksync: true,
verifyURL: 'https://zksync2-mainnet-explorer.zksync.io/contract_verification',
},
zkSyncTestnet: {
url: 'https://sepolia.era.zksync.dev',
ethNetwork: 'sepolia',
zksync: true,
verifyURL: 'https://explorer.sepolia.era.zksync.dev/contract_verification',
},
},
solidity: '0.8.24',
}
export default config
Скрипт деплоя:
import { Wallet, Provider } from 'zksync-ethers'
import { Deployer } from '@matterlabs/hardhat-zksync'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
export default async function (hre: HardhatRuntimeEnvironment) {
const provider = new Provider(hre.network.config.url)
const wallet = new Wallet(process.env.DEPLOYER_PRIVATE_KEY!, provider)
const deployer = new Deployer(hre, wallet)
// Загружаем артефакт (zksolc компилирует в zk-специфичный формат)
const artifact = await deployer.loadArtifact('MyContract')
// Оцениваем стоимость деплоя
const deploymentFee = await deployer.estimateDeployFee(artifact, [/* constructor args */])
console.log(`Estimated deploy fee: ${ethers.formatEther(deploymentFee)} ETH`)
const contract = await deployer.deploy(artifact, [/* constructor args */])
await contract.waitForDeployment()
console.log(`Deployed to: ${await contract.getAddress()}`)
}
npx hardhat deploy-zksync --script deploy.ts --network zkSyncMainnet
Деплой через Foundry (zkSync fork)
Foundry официально поддерживает zkSync через foundry-zksync — форк, который добавляет --zksync флаг:
# Установка foundry-zksync
curl -L https://raw.githubusercontent.com/matter-labs/foundry-zksync/main/install-foundry-zksync | bash
# Деплой
forge create src/MyContract.sol:MyContract \
--rpc-url https://mainnet.era.zksync.io \
--private-key $PRIVATE_KEY \
--zksync \
--constructor-args "arg1" 123
# Или через скрипт
forge script script/Deploy.s.sol \
--rpc-url https://mainnet.era.zksync.io \
--private-key $PRIVATE_KEY \
--zksync \
--broadcast
Верификация контракта
# Через Hardhat
npx hardhat verify --network zkSyncMainnet CONTRACT_ADDRESS "constructor_arg1"
# Через zkSync Explorer API напрямую
curl -X POST https://zksync2-mainnet-explorer.zksync.io/contract_verification \
-H "Content-Type: application/json" \
-d '{
"contractAddress": "0x...",
"sourceCode": "...",
"contractName": "MyContract",
"compilerZksolcVersion": "v1.4.1",
"compilerSolcVersion": "0.8.24",
"optimizationUsed": true
}'
Native Account Abstraction
Ключевое преимущество zkSync Era — нативная AA на уровне протокола (в отличие от ERC-4337, который работает через entrypoint контракт). Каждый аккаунт может быть смарт-контрактом. Для деплоя AA-аккаунта:
// Контракт должен реализовать IAccount интерфейс
import "@matterlabs/zksync-contracts/l2/system-contracts/interfaces/IAccount.sol";
contract MyAccount is IAccount {
function validateTransaction(
bytes32 _txHash,
bytes32 _suggestedSignedHash,
Transaction calldata _transaction
) external payable override returns (bytes4 magic) {
// Кастомная логика валидации (multisig, session keys, etc.)
}
function executeTransaction(
bytes32 _txHash,
bytes32 _suggestedSignedHash,
Transaction calldata _transaction
) external payable override {
// Исполнение
}
// ...
}
Мосты и депозит ETH
Для деплоя нужен ETH на zkSync. Бридж через официальный zkSync bridge (~15–30 минут финализация на L1). Programmatic бридж через L1 контракт:
import { Provider, Wallet, utils } from 'zksync-ethers'
import { ethers } from 'ethers'
const l1Provider = new ethers.JsonRpcProvider(L1_RPC_URL)
const l2Provider = new Provider('https://mainnet.era.zksync.io')
const wallet = new Wallet(PRIVATE_KEY, l2Provider, l1Provider)
// Депозит 0.1 ETH из L1 на L2
const depositHandle = await wallet.deposit({
token: utils.ETH_ADDRESS,
amount: ethers.parseEther('0.1'),
})
await depositHandle.waitFinalize()
Деплой простого контракта занимает несколько часов (подготовка окружения + верификация). Миграция существующего Ethereum проекта на zkSync с учётом специфики компилятора и тестированием — 1–2 дня.







