Розробка системи резолвінгу ENS-доменів

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

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

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

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

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

Розробка системи розв'язування ENS-доменів

Розв'язування ENS — це не просто виклик provider.resolveName(). Для production систем потрібно врахувати кешування, підтримку wildcard, CCIP-Read (off-chain resolvers) та коректну обробку multi-chain адрес. Особливо якщо розв'язування відбувається не у браузері, а в backend сервісах або смарт-контрактах.

Повна цепочка розв'язування

Стандартний ENS lookup виглядає так:

  1. Нормалізація імені за UTS-46 (нижний регістр + IDNA2008)
  2. Обчислення namehash
  3. Запит до ENS Registry: registry.resolver(namehash)
  4. Якщо resolver підтримує wildcard (supportsInterface(ENSIP-10)) — використовуємо extended resolution
  5. Запит до Resolver: resolver.addr(namehash, coinType)
  6. Якщо resolver повертає OffchainLookup (EIP-3668) — виконуємо CCIP-Read
  7. Остаточна адреса

Більшість бібліотек (ethers.js, viem) обробляють кроки 1-5. CCIP-Read підтримується в ethers v6 та viem нативно.

Кастомний сервіс розв'язування

Для високонавантажених додатків варто реалізувати власний сервіс розв'язування з кешем:

import { createPublicClient, http, normalize } from "viem";
import { mainnet } from "viem/chains";
import NodeCache from "node-cache";

class ENSResolutionService {
  private client = createPublicClient({ chain: mainnet, transport: http(RPC_URL) });
  private cache = new NodeCache({ stdTTL: 300 }); // 5 хвилин TTL
  
  async resolveName(name: string): Promise<string | null> {
    const normalized = normalize(name);
    const cacheKey = `addr:${normalized}`;
    
    const cached = this.cache.get<string>(cacheKey);
    if (cached !== undefined) return cached;
    
    try {
      const address = await this.client.getEnsAddress({ name: normalized });
      this.cache.set(cacheKey, address ?? null);
      return address;
    } catch (e) {
      return null;
    }
  }
  
  async lookupAddress(address: `0x${string}`): Promise<string | null> {
    const cacheKey = `name:${address.toLowerCase()}`;
    const cached = this.cache.get<string>(cacheKey);
    if (cached !== undefined) return cached;
    
    const name = await this.client.getEnsName({ address });
    this.cache.set(cacheKey, name ?? null);
    return name;
  }
  
  // Batch розв'язування для списку адрес
  async batchLookup(addresses: `0x${string}`[]): Promise<Map<string, string | null>> {
    const results = new Map<string, string | null>();
    const uncached: `0x${string}`[] = [];
    
    for (const addr of addresses) {
      const cached = this.cache.get<string>(`name:${addr.toLowerCase()}`);
      if (cached !== undefined) {
        results.set(addr, cached);
      } else {
        uncached.push(addr);
      }
    }
    
    // Паралельне розв'язування для некешованих
    await Promise.allSettled(
      uncached.map(async (addr) => {
        const name = await this.lookupAddress(addr);
        results.set(addr, name);
      })
    );
    
    return results;
  }
}

Multi-chain адреси (ENSIP-9)

ENS зберігає адреси для різних мереж через coinType (SLIP-44):

const COIN_TYPES = { ETH: 60, BTC: 0, SOL: 501, MATIC: 966, ARB: 9001 };

async function getMultiChainAddresses(name: string) {
  const resolver = await provider.getResolver(name);
  if (!resolver) return null;
  
  return {
    eth: await resolver.getAddress(COIN_TYPES.ETH),
    btc: await resolver.getAddress(COIN_TYPES.BTC),
    sol: await resolver.getAddress(COIN_TYPES.SOL),
  };
}

Строк розробки кастомного сервісу розв'язування з кешем та підтримкою multi-chain — 3-5 робочих днів. Інтеграція в існуючий бекенд — додаткові 1-2 дні.