Деплойментт смарт-контрактів в 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). Програмний бридж через 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 дні.







