Розробка протоколу кросс-чейн ліквідності
Проблема фрагментації ліквідності: $50B у DeFi розподілені по десяткам чейнів. USDC на Arbitrum — це не той же USDC, що на Optimism. Міст між ними — це не просто «перекидування токенів», це вирішення проблеми довіри: як мережа A знає, що токени на мережі B дійсно заблоковані?
Існує кілька відповідей, кожна — це власна архітектура з різним балансуванням між безпекою, швидкістю та децентралізацією. Оптимістичні мості, ZK-light client мості, intent-based мості, AMM-liquidity мості — різні компромиси для різних завдань.
Архітектурні моделі кросс-чейн протоколів
Lock-and-Mint vs Liquidity Pool
Lock-and-mint (wrapped активи): токени блокуються на вихідному чейні, завернені копії випускаються на цільовому. Класика: wBTC (Bitcoin → Ethereum). Проблема: wrapped актив — новий токен з ризиком контрпартнера на мост. Якщо міст взломаний — wrapped токени безцінні. Це спричинило втрату $320M у хаку Wormhole (2022) та $190M у хаку Nomad.
Liquidity Pool (нативні активи): кожен чейн містить пул нативних токенів (USDC на Arbitrum, USDC на Optimism). Користувач вносить у пул на вихідному чейні, забирає нативний токен з пула на цільовому. Це модель Stargate (LayerZero), Across Protocol, Hop Protocol.
Перевага: користувач отримує справжній USDC, не wrapped. Недолік: потрібна ліквідність на кожному чейні — проблема холодного старту.
Intent-based (solver модель): користувач виражає намір («хочу 1000 USDC на Optimism з моїх 1001 USDC на Arbitrum»), solver негайно надає з власного балансу на цільовому, пізніше гасить власний баланс через механізм settlement. Модель: Across Protocol (оптимізована) та UniswapX cross-chain.
Це забезпечує миттєвий user experience: користувач бачить гроші на цільовому чейні за секунди, гасіння solver-а відбувається пізніше (через bundling та офіційний міст).
Messaging layer: як чейн A дізнається про події на чейні B
Це фундаментальна проблема. Варіанти:
Optimistic verification: повідомлення приймається як дійсне, існує challenge window (30 хв – 7 днів). Якщо ніхто не оспорив — вважається фіналізованим. Модель: Nomad, Connext Amarok. Плюс: відносно простий. Мінус: затримка.
Validator/Oracle set: набір валідаторів спостерігає за вихідним чейном і підписує attestation про події. M-of-N multisig розблокує на цільовому. Модель: Wormhole (19 гвардіанів), Multichain (MPC ноди), cBridge (SGN валідатори). Ризик: централізований набір валідаторів — головна поверхня атаки.
ZK Light Client: цільовий чейн верифікує ZK proof про заголовок вихідного чейна. Trustless, але технічно складно і дорого по газу. Моделі: zkBridge (Polyhedra), Succinct Labs, Herodotus. Технологія дозріває в 2024–2025.
Native messaging (canonical): Arbitrum міст, Optimism міст — використовують офіційний механізм L1↔L2. Найбільш безпечно, але 7-денна затримка зняття (fraud proof window для Optimistic rollups).
LayerZero V2: Ultra Light Node (ULN). Дві незалежні ролі: DVN (Decentralized Verifier Network) верифікує заголовок, Executor доставляє повідомлення. Можна налаштувати набір DVN під вимоги безпеки. Stargate V2 побудований на LayerZero V2.
Глибокий розбір: Stargate / LayerZero архітектура
LayerZero — протокол обміну повідомленнями, Stargate — протокол ліквідності на його основі. Аналізуємо їхню архітектуру як еталонну реалізацію.
LayerZero V2: потік повідомлень
Source Chain Destination Chain
┌──────────────────────────────┐ ┌──────────────────────────────┐
│ OApp (User Contract) │ │ OApp (User Contract) │
│ ↓ _lzSend() │ │ ↑ _lzReceive() │
│ Endpoint │ │ Endpoint │
│ ↓ emit PacketSent event │ │ ↑ lzReceive() │
│ │ │ │
│ DVN monitors event │ DVN signs │ DVN submits verification │
│ Executor monitors event ─────┼─────────────→ Executor calls lzReceive() │
└──────────────────────────────┘ └──────────────────────────────┘
Ключовий інсайт LayerZero V2: OApp (Omnichain Application) — ваш контракт на кожному чейні. _lzSend відправляє повідомлення через Endpoint. _lzReceive — callback на цільовому. Все між ними — завдання DVN та Executor.
// OApp базовий контракт (LayerZero V2)
import { OApp, Origin, MessagingFee } from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol";
contract CrossChainLiquidityPool is OApp {
mapping(address => uint256) public deposits;
constructor(address _endpoint, address _owner) OApp(_endpoint, _owner) {}
// Ініціювання кросс-чейн депозиту
function depositAndBridge(
uint32 dstEid, // destination endpoint ID (чейн)
address recipient,
uint256 amount,
bytes calldata extraOptions
) external payable {
// Приймаємо токени
IERC20(depositToken).safeTransferFrom(msg.sender, address(this), amount);
// Кодуємо повідомлення
bytes memory message = abi.encode(recipient, amount);
// Розраховуємо fee
MessagingFee memory fee = _quote(dstEid, message, extraOptions, false);
require(msg.value >= fee.nativeFee, "Insufficient fee");
// Відправляємо кросс-чейн повідомлення
_lzSend(
dstEid,
message,
extraOptions,
fee,
payable(msg.sender)
);
emit DepositBridged(msg.sender, dstEid, recipient, amount);
}
// Callback на цільовому чейні
function _lzReceive(
Origin calldata origin,
bytes32 /*guid*/,
bytes calldata payload,
address /*executor*/,
bytes calldata /*extraData*/
) internal override {
// Верифікуємо джерело
require(
peers[origin.srcEid] == origin.sender,
"Unknown source"
);
(address recipient, uint256 amount) = abi.decode(payload, (address, uint256));
// Виплачуємо з пула на цільовому
require(poolBalance[depositToken] >= amount, "Insufficient pool");
poolBalance[depositToken] -= amount;
IERC20(depositToken).safeTransfer(recipient, amount);
emit BridgeReceived(origin.srcEid, recipient, amount);
}
}
Stargate V2: Hydra Pool та об'єднана ліквідність
Проблема Stargate V1: пул USDC на Arbitrum та пул USDC на Optimism — окремі. Дисбаланс: багато виводів з Arbitrum, мало вхідних → пул вичерпується.
Рішення Stargate V2 — Hydra Pool: єдиний глобальний пул з кредитними механізмами. Кожний чейн має кредит від глобального пула. Трансфери балансуються глобально, не лише між парами чейнів.
// Спрощена модель credit-based пула
contract StargatePool {
// Credits: скільки ми "винні" іншим пулам чейнів
mapping(uint32 => uint256) public credits; // dstEid => кредит
uint256 public localBalance;
function sendTokens(
uint32 dstEid,
address to,
uint256 amountLD // Local Decimals
) external {
// Конвертуємо у Shared Decimals (уніфіковану точність)
uint256 amountSD = _toSD(amountLD);
require(localBalance >= amountSD, "Insufficient balance");
localBalance -= amountSD;
// Збільшуємо кредит для цільового (вони нам винні)
credits[dstEid] += amountSD;
// Відправляємо повідомлення через LayerZero
_sendCrossChain(dstEid, abi.encode(to, amountSD, credits[dstEid]));
}
// Отримання: цільовий виплачує та оновлює кредити
function _receiveTokens(uint32 srcEid, address to, uint256 amountSD) internal {
// Зменшуємо борг перед джерелом
require(credits[srcEid] >= amountSD, "Insufficient credits");
credits[srcEid] -= amountSD;
localBalance += amountSD; // буде виплачено користувачу
IERC20(token).safeTransfer(to, _toLD(amountSD));
}
}
Shared Decimals — важлива деталь: різні чейни можуть мати різну точність ERC-20. 6 decimals USDC на Ethereum, 6 на Arbitrum, але потенційно різні. Stargate нормалізує до SD (Shared Decimals = 6) для міжчейн-обліку.
Механізм ребалансування
Проблема будь-якого liquidity мосту: дисбаланс потоків. Якщо всі виводять з чейна A та вносять до чейна B — пул на A вичерпується, на B переповнюється.
Автоматичне ребалансування
contract RebalancingModule {
// Пороги дисбалансу
uint256 public constant REBALANCE_THRESHOLD = 20; // 20% відхилення
uint256 public constant TARGET_UTILIZATION = 80; // цільовий utilization
function checkAndRebalance(uint32 srcEid, uint32 dstEid) external {
uint256 srcUtilization = getUtilization(srcEid); // % пула використано
uint256 dstUtilization = getUtilization(dstEid);
if (srcUtilization > TARGET_UTILIZATION + REBALANCE_THRESHOLD &&
dstUtilization < TARGET_UTILIZATION - REBALANCE_THRESHOLD) {
uint256 rebalanceAmount = calculateRebalanceAmount(srcEid, dstEid);
_initiateRebalance(srcEid, dstEid, rebalanceAmount);
}
}
// LP отримують ребалансуючу премію за додавання ліквідності до дефіцитних пулів
function rebalancingFeeMultiplier(uint32 chainId) public view returns (uint256) {
uint256 utilization = getUtilization(chainId);
if (utilization > 90) return 200; // 2x комісія для LP на дефіцитному чейні
if (utilization > 75) return 150;
return 100;
}
}
Fee механізм для балансування
Динамічна комісія: при високому utilization пула (>80%) — комісія за bridge до цього чейна зростає. Це економічно стимулює трансфери в протилежному напрямку та надання ліквідності.
Безпека: головні вектори атак
Reentrancy через кросс-чейн callback
Класична reentrancy посилена кросс-чейном: атакуючий може ініціювати повторний виклик через інший чейн до завершення першого.
// Захист: стан-машина + nonReentrant
enum BridgeStatus { IDLE, PENDING, COMPLETED }
mapping(bytes32 => BridgeStatus) public transferStatus;
modifier onlyIdle(bytes32 transferId) {
require(transferStatus[transferId] == BridgeStatus.IDLE, "Not idle");
transferStatus[transferId] = BridgeStatus.PENDING;
_;
transferStatus[transferId] = BridgeStatus.COMPLETED;
}
Маніпуляція Oracle/validator
Якщо набір валідаторів малий або централізований — атака на M-of-N threshold компрометує весь міст. Хак Wormhole: експлойт у верифікації підпису дозволив випустити 120,000 wETH без забезпечення.
Захисти:
- Використовувати перевірені messaging протоколи (LayerZero V2, Wormhole, Axelar) замість власного набору валідаторів
- Впровадити rate limiting: максимальна сума bridge за 1 годину/24 години
- Emergency pause: multisig + timelock на критичних операціях
- Insurance fund: % комісій йде до страхового фонду
Replay атака
Одне повідомлення не повинно бути доставлено двічі. LayerZero захищає через nonce: кожний OApp має впорядкований nonce для кожної пари src/dst. Повідомлення з неочікуваним nonce відхиляється.
Стимули для LP
Чому хтось буде тримати ліквідність у вашому bridge пулі? Потрібна економічна модель.
| Механізм | Опис |
|---|---|
| Bridge комісії (LP share) | 0.01–0.06% обсягу, розподіляється LP пропорційно |
| Награди протокол-токена | Емісії у governance токен для LP |
| Ребалансуючі бонуси | Вищої комісії для ліквідності у дефіцитних пулах |
| veToken голосування | LP голосують за збільшення емісії для своєї pool |
Для холодного старту: посилені награди в перші 3–6 місяців від казни протоколу.
Development Stack
Смарт-контракти: Solidity 0.8.x + Foundry. Messaging: LayerZero V2 OApp, або Axelar GMP, або Wormhole. Математика: FixedPoint (Uniswap V3 математика) для точності. Oracle: Chainlink CCIP Data Feeds для FX курсів.
Backend: Node.js + TypeScript. Моніторинг: стеження за станом пулів на всіх чейнах, автоматизоване ребалансування. Event indexing: The Graph (мультичейн subgraph) або кастомний indexer (Ponder).
Frontend: wagmi + viem, мультичейн wallet поддержка.
Фази розробки
| Фаза | Вміст | Таймлайн |
|---|---|---|
| Архітектура | Вибір messaging протоколу, моделі пула, механізму комісій | 2–3 тижні |
| Core контракти | Pool, bridge логіка, розподіл комісій | 4–6 тижнів |
| Messaging інтеграція | LayerZero/Axelar інтеграція, тестування кросс-чейн | 3–4 тижні |
| Ребалансування | Автоматизоване ребалансування, модель стимулів | 2–3 тижні |
| LP механіка | LP токени, накопичення комісій, staking | 2–3 тижні |
| Безпека | Rate limiting, pause, механізми надзвичайних ситуацій | 1–2 тижні |
| Аудит | Зовнішній аудит (критичний для мосту) | 4–8 тижнів |
| Testnet | Публічний testnet, bug bounty | 3–4 тижні |
Bridge контракти — одна з найбільш атакованих категорій DeFi. Аудит обов'язковий, в ідеалі — два незалежних аудитори. Бюджет аудиту: $50k–$200k залежно від складності та аудитора.







