Розробка omnichain-токену (OFT)

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Розробка omnichain-токену (OFT)
Середній
~3-5 днів
Часті запитання

Напрямки блокчейн-розробки

Етапи блокчейн-розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1288
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1198
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    902
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1122
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    589
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    859

Розробка omnichain-токена (OFT)

Стандартний підхід до multi-chain токена: wrap/bridge модель. Оригінальний токен на Ethereum, на кожній іншій цепи — wrapped версія через bridge. Проблема: ліквідність фрагментована, canonical supply неочевидна, користувач держит «USDC-Polygon» окремо від «USDC-Arbitrum», bridge ризики мультиплікуються з кількістю цепей.

OFT (Omnichain Fungible Token) від LayerZero вирішує це інакше: один контракт на кожній цепи, єдиний supply, перевід між цепями працює через burn-and-mint без wrapping. Токен на Arbitrum — це той же токен, не wrapped копія.

Як працює LayerZero OFT

Burn-and-mint механізм

Transfer: Arbitrum → Optimism
1. Користувач викликає oft.send() на Arbitrum
2. OFT контракт спалює X токенів на Arbitrum (зменшує supply)
3. LayerZero relayer передає mensaje на Optimism
4. OFT контракт на Optimism мінтить X токенів (збільшує supply)
5. Загальний supply поперед цепями не змінився

vs Bridge (wrap) модель:
1. Lock X токенів на source у bridge контракті
2. Mint X wrapped токенів на destination
Проблема: bridge контракт — single point of failure для всього locked supply

В OFT немає центрального bridge контракту з locked активами. Немає «TVL у bridge» який можна взломати. Можна взломати тільки LayerZero messaging layer — це окремий ризик, не «всё відразу».

OFT v2 реалізація

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import { OFT } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/OFT.sol";

contract MyOFT is OFT {
    constructor(
        string memory _name,
        string memory _symbol,
        address _lzEndpoint,   // LayerZero endpoint для цієї цепи
        address _delegate      // owner/admin
    ) OFT(_name, _symbol, _lzEndpoint, _delegate) {}
    
    // Mint тільки на home chain (звичайно)
    function mint(address to, uint256 amount) external onlyOwner {
        _mint(to, amount);
    }
}

Розгортаємо той же контракт на кожній target цепи. Різниця тільки в _lzEndpoint — адреса LayerZero endpoint специфічна для кожної цепи.

// Deployment скрипт (Hardhat/Foundry)
const LZ_ENDPOINTS = {
  ethereum:  "0x1a44076050125825900e736c501f859c50fE728c",
  arbitrum:  "0x1a44076050125825900e736c501f859c50fE728c", // V2 один
  optimism:  "0x1a44076050125825900e736c501f859c50fE728c",
  polygon:   "0x1a44076050125825900e736c501f859c50fE728c",
  base:      "0x1a44076050125825900e736c501f859c50fE728c",
}

// LayerZero V2: endpoint один на всіх EVM-сітях
// Але EID (Endpoint ID) унікальний для кожної цепи
const LZ_EIDS = {
  ethereum:  30101,
  arbitrum:  30110,
  optimism:  30111,
  polygon:   30109,
  base:      30184,
}

Конфігурація peers (wire-up)

Після розгортання на всі цепи — зв'язуємо контракти між собою. Кожен OFT повинен знати адреси своїх peer'ів.

import { ethers } from "ethers"
import { Options } from "@layerzerolabs/lz-v2-utilities"

// На Arbitrum: установити peer для Optimism
const oftArbitrum = new ethers.Contract(OFT_ARBITRUM, OFT_ABI, signerArbitrum)

// Адреса peer повинна бути bytes32-encoded (лівий padding нулями)
const optimismPeerBytes32 = ethers.zeroPadValue(OFT_OPTIMISM, 32)

await oftArbitrum.setPeer(
  LZ_EIDS.optimism,       // destination EID
  optimismPeerBytes32      // адреса peer на destination
)

// Аналогічно на Optimism: установити peer для Arbitrum
const oftOptimism = new ethers.Contract(OFT_OPTIMISM, OFT_ABI, signerOptimism)
await oftOptimism.setPeer(LZ_EIDS.arbitrum, ethers.zeroPadValue(OFT_ARBITRUM, 32))

Не автоматично — потрібно викликати setPeer для кожної пари цепей. При N цепях: N*(N-1) викликів (кожна цеп знає всіх інших).

Відправлення токенів між цепями

// Користувач: відправити 100 MTK з Arbitrum на Optimism
const oft = new ethers.Contract(OFT_ARBITRUM, OFT_ABI, signer)

// 1. Отримати quote (скільки нативного gas потрібно заплатити)
const sendParam = {
  dstEid: LZ_EIDS.optimism,
  to: ethers.zeroPadValue(recipientAddress, 32),
  amountLD: ethers.parseEther("100"),    // сума у локальних decimals
  minAmountLD: ethers.parseEther("99"),  // 1% slippage tolerance
  extraOptions: "0x",
  composeMsg: "0x",
  oftCmd: "0x",
}

const [nativeFee, lzTokenFee] = await oft.quoteSend(sendParam, false)
console.log(`Fee: ${ethers.formatEther(nativeFee)} ETH`)

// 2. Відправити (msg.value = nativeFee для оплати LayerZero)
const tx = await oft.send(
  sendParam,
  { nativeFee, lzTokenFee: 0n },
  signer.address, // refund адреса (якщо overpay)
  { value: nativeFee }
)

const receipt = await tx.wait()
// Токени на Arbitrum спалені
// Через ~15-60 секунд з'являються на Optimism

Decimals: потенційна пастка

Різні цепи можуть мати різні native decimals. Solana використовує 6 decimals (lamports), EVM — 18. OFT v2 вирішує це через shared decimals: всі цепи працюють з меншим числом (звичайно 6), конвертуючи при відправленні.

// OFT v2: sharedDecimals за замовченням 6
// При відправленні з EVM (18 decimals) → dust видалено

// Приклад: відправлення 1.000000000000000001 MTK (18 decimals)
// Реальна сума яка прибуде: 1.000000 MTK (6 shared decimals)
// 0.000000000000000001 MTK залишається у відправника як "dust"

// Завжди перевіряйте: quoteSend → amountReceivedLD
// amountReceivedLD = фактично отримана сума з урахуванням конвертації

Важливо для UI: показувати користувачу amountReceivedLD, не оригінальну суму.

OFTAdapter: для існуючих токенів

Якщо токен вже існує на Ethereum та його контракт не можна змінити (немає mint/burn функцій у потрібному контексті) — використовуємо OFTAdapter. На Ethereum: Lock&Release (токени locked у adapter). На інших цепях: OFT з burn&mint.

import { OFTAdapter } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/OFTAdapter.sol";

contract MyTokenAdapter is OFTAdapter {
    constructor(
        address _token,        // існуючий ERC-20 токен
        address _lzEndpoint,
        address _delegate
    ) OFTAdapter(_token, _lzEndpoint, _delegate) {}
}

На інших цепях розгортаємо звичайний OFT (з mint/burn). Тільки Ethereum використовує lock модель — інші цепи використовують burn/mint.

OFTAdapter компроміс: Ethereum-locked токени — це знову bridge ризик. Якщо adapter взломан — supply на інших цепях незабезпечений. Для критичних проектів: multisig або timelock на adapter, cap на locked суму.

DVN: конфігурація безпеки

LayerZero V2 дозволяє конфігурувати DVN (Decentralized Verifier Network) — хто верифікує cross-chain mensaje.

// Кастомна DVN конфігурація
// За замовченням: LayerZero DVN (один верифікатор)
// Посилена: потребуємо 2-of-3 верифікацію

const enforcedOptions = [
  {
    eid: LZ_EIDS.optimism,
    msgType: 1,
    options: Options.newOptions()
      .addExecutorLzReceiveOption(200_000, 0) // 200k gas на destination
      .toHex()
  }
]

// Установити через OApp config
await oft.setEnforcedOptions(enforcedOptions)

Для production OFT з великим TVL: конфігурувати мінімум два незалежних DVN (LayerZero + Google Cloud DVN або Polyhedra). Компроміс: більше DVN = дорожча комісія, але вища безпека.

Моніторинг та обробка failed mensaje

Mensaje може зависнути якщо destination цеп тимчасово недоступна або gas недостатньо. LayerZero V2 зберігає failed mensaje, можна retry.

// LayerZero Scan API для моніторингу
const response = await fetch(
  `https://scan.layerzero-api.com/v1/messages/tx/${txHash}`
)
const { data } = await response.json()

if (data.status === 'FAILED') {
  console.log(`Message failed: ${data.failReason}`)
  // Викликаємо lzEndpoint.retryMessage() або
  // lzEndpoint.forceResumeReceive() якщо потрібно пропустити
}

Для UX: показувати користувачу статус cross-chain транзакції через LayerZero Scan embeddable widget або кастомний polling.

Робочий процес

Підготовка (3-5 днів). Список target цепей, tokenomics (де мінтити initial supply, adapter потрібен для існуючого токена), вимоги безпеки (DVN конфігурація, multisig).

Розробка (1-2 тижні). OFT контракти → Foundry тести для кожного сценарію (send, receive, failed mensaje retry) → deployment скрипти для всіх цепей → wire-up (setPeer на кожній).

Тестування (1 тиждень). Testnet розгортання на всі target цепи → функціональне тестування cross-chain transfers → перевірка decimals конвертації → load тест з concurrent mensaje.

Mainnet розгортання та верифікація. Верифікація контрактів на Etherscan/explorer кожної цепи. Тестова small-amount транзакція перед анонсом.

OFT для 3-5 цепей з базовим функціоналом — 3-4 тижні. З OFTAdapter для існуючого токена, кастомними DVN та monitoring дашбордом — 5-7 тижнів.