Разработка мультичейн-токена
Мультичейн-токен — это не просто деплой одного и того же ERC-20 на несколько сетей. Это архитектурное решение с серьёзными последствиями для supply management, безопасности и UX. Неправильно спроектированный мультичейн-токен создаёт иллюзию единого актива при реально раздробленном supply, открывает поверхность для bridge-атак и усложняет governance. Разберём, как это делается правильно.
Модели мультичейн-токена
Прежде чем писать код, нужно выбрать архитектурную модель. Их три, и они фундаментально различаются.
Lock & Mint (каноническая модель)
Токен существует нативно на одном чейне (home chain, обычно Ethereum). На всех остальных чейнах существуют wrapped версии. Bridge блокирует токены на home chain и минтит wrapped на destination chain. При бриджинге обратно — burning wrapped, unlock оригинала.
Плюсы: единый canonical supply, простая ментальная модель для пользователей.
Минусы: если bridge взломан — злоумышленник может минтить wrapped токены без обеспечения. Так был взломан Wormhole ($320M в 2022) и Ronin Bridge ($625M).
Burn & Mint (omnichain модель)
При трансфере токен сжигается на source chain и минтится на destination chain. Total supply глобально постоянен. Этот подход используют LayerZero OFT (Omnichain Fungible Token) и Axelar ITS.
Плюсы: нет locked liquidity на одном чейне, равноценность токенов на всех сетях.
Минусы: транзакция не атомарна — токен уничтожен на source, но может не доминтиться на destination при сбое. Нужен механизм recovery.
Liquidity Pool модель
Независимые токены на каждом чейне соединены через AMM-пулы в bridge-протоколах (Stargate, Synapse). Bridge нативного свопа, не wrapped tokens.
Плюсы: мгновенность (атомарный своп из пула), нет wrapped токенов.
Минусы: требует bootstrap liquidity на каждом чейне, slippage при несбалансированных пулах.
Реализация через LayerZero OFT
LayerZero стал де-факто стандартом для новых мультичейн-токенов. OFT (Omnichain Fungible Token) — burn & mint модель с messaging через LayerZero Endpoint.
Базовая реализация OFT
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;
import { OFT } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/OFT.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
contract MyToken is OFT {
constructor(
string memory _name,
string memory _symbol,
address _lzEndpoint, // LayerZero Endpoint адрес для текущей сети
address _delegate
) OFT(_name, _symbol, _lzEndpoint, _delegate) Ownable(_delegate) {}
// Минтинг только при деплое или через governance
function mint(address _to, uint256 _amount) external onlyOwner {
_mint(_to, _amount);
}
}
На home chain деплоим этот контракт и минтим весь supply. На остальных чейнах деплоим тот же контракт, но без начального минтинга — токены туда приходят через bridge.
Конфигурация OFT после деплоя
После деплоя на всех чейнах нужно связать контракты через setPeer:
// На каждом чейне для каждой другой сети
function configurePeers() external onlyOwner {
// eid = endpoint ID в системе LayerZero
// Ethereum mainnet: 30101, Arbitrum: 30110, Base: 30184, BSC: 30102
// Если мы на Ethereum, регистрируем Arbitrum peer
oft.setPeer(30110, bytes32(uint256(uint160(ARBITRUM_OFT_ADDRESS))));
// Регистрируем Base peer
oft.setPeer(30184, bytes32(uint256(uint160(BASE_OFT_ADDRESS))));
}
Отправка токенов между чейнами
// Подготовка параметров для cross-chain transfer
function bridgeTokens(
uint32 _dstEid, // destination endpoint ID
address _recipient,
uint256 _amount
) external payable {
SendParam memory sendParam = SendParam({
dstEid: _dstEid,
to: bytes32(uint256(uint160(_recipient))),
amountLD: _amount,
minAmountLD: (_amount * 995) / 1000, // 0.5% slippage tolerance
extraOptions: OptionsBuilder.newOptions()
.addExecutorLzReceiveOption(200000, 0), // gas на destination
composeMsg: "",
oftCmd: ""
});
// Получаем quote на native fee для оплаты LayerZero messaging
MessagingFee memory fee = oft.quoteSend(sendParam, false);
oft.send{ value: fee.nativeFee }(sendParam, fee, payable(msg.sender));
}
Управление supply между чейнами
Это самый сложный аспект. Нужен мониторинг:
| Метрика | Как отслеживать |
|---|---|
| Supply per chain | Вызов totalSupply() на каждом деплое |
| Circulating supply | Сумма всех totalSupply() минус locked в bridge контрактах |
| Bridge flow | Ивенты OFTSent / OFTReceived |
| Pending messages | LayerZero Scan API |
Для Lock & Mint модели (если используете кастомный bridge) нужен invariant check: sum(wrapped supplies) <= locked_on_home_chain. Мониторинг через Tenderly или собственный скрипт с алертингом в PagerDuty.
Безопасность мультичейн-токена
DVN (Decentralized Verifier Network) конфигурация
LayerZero V2 позволяет настраивать, какие верификаторы должны подтвердить сообщение перед исполнением. Минимальная безопасная конфигурация — 2 из N верификаторов:
// Настройка ULN (Ultra Light Node) конфигурации
UlnConfig memory ulnConfig = UlnConfig({
confirmations: 15, // блоков для finality
requiredDVNCount: 2, // минимум 2 DVN должны подтвердить
optionalDVNCount: 0,
optionalDVNThreshold: 0,
requiredDVNs: [LAYERZERO_DVN, GOOGLE_CLOUD_DVN],
optionalDVNs: new address[](0)
});
Для production рекомендуется использовать LayerZero DVN + один независимый DVN (Google Cloud, Nethermind, p2p.org).
Rate limiting
Даже с надёжным bridge — добавьте rate limiting на уровне токен-контракта как последнюю линию защиты:
// Ограничение на максимальный transfer за период
mapping(uint256 => uint256) public dailyBridgeVolume; // day => volume
uint256 public constant MAX_DAILY_BRIDGE = 1_000_000e18; // 1M токенов/день
modifier withRateLimit(uint256 amount) {
uint256 today = block.timestamp / 1 days;
require(
dailyBridgeVolume[today] + amount <= MAX_DAILY_BRIDGE,
"Daily bridge limit exceeded"
);
dailyBridgeVolume[today] += amount;
_;
}
Если bridge взломан — rate limit даст время на реакцию, ограничив ущерб.
Pause механизм
Контракт должен иметь pause функцию, управляемую мультисигом с коротким timelock (или без него — для экстренных случаев). При обнаружении аномального bridge activity — мгновенная остановка передач.
Деплой и инфраструктура
Последовательность деплоя
- Деплой на home chain, минтинг supply
- Деплой на все destination chains
- Вызов
setPeerна каждом чейне для каждой пары - Верификация: тестовый bridge transfer небольшой суммы
- Мониторинг: настройка алертов на bridge events
Сети и LayerZero Endpoint IDs (актуальные)
| Сеть | Endpoint ID | Chain ID |
|---|---|---|
| Ethereum | 30101 | 1 |
| Arbitrum One | 30110 | 42161 |
| Base | 30184 | 8453 |
| Optimism | 30111 | 10 |
| BSC | 30102 | 56 |
| Polygon | 30109 | 137 |
| Avalanche | 30106 | 43114 |
Скрипт деплоя через Hardhat
// scripts/deploy-oft.ts
import { ethers } from "hardhat";
import { EndpointId } from "@layerzerolabs/lz-definitions";
async function main() {
const [deployer] = await ethers.getSigners();
const lzEndpoint = getEndpointForNetwork(network.name);
const OFT = await ethers.getContractFactory("MyToken");
const oft = await OFT.deploy(
"My Token",
"MYT",
lzEndpoint,
deployer.address
);
await oft.waitForDeployment();
console.log(`OFT deployed to: ${await oft.getAddress()}`);
// Минтинг только на home chain
if (network.name === "ethereum") {
await oft.mint(deployer.address, ethers.parseEther("100000000"));
}
}
Governance и мультичейн-токен
Если токен используется для governance — возникает проблема: как считать voting power при распределённом supply? Три подхода:
Hub-and-spoke: голосование только на home chain. Пользователи с других чейнов должны bridge токены обратно. Просто, но UX плохой.
Cross-chain voting: off-chain snapshot голосов на всех чейнах, агрегация через LayerZero или Axelar. Использует Snapshot + XCHAIN voting.
Dedicated governance token: отдельный non-transferable governance token на одном чейне, distribution token — мультичейн. Сложнее, но чище архитектурно.
Мультичейн-токен — это не feature, это commitment. Каждый новый чейн добавляет операционную нагрузку, аудит поверхность и риски. Добавляйте сети только там, где реально есть ликвидность и пользователи.







