Разработка системы unified accounts (единый аккаунт на всех сетях)

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка системы unified accounts (единый аккаунт на всех сетях)
Сложная
от 2 недель до 3 месяцев
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1221
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1163
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    855
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1056
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    828

Разработка системы unified accounts

Unified accounts — пользователь имеет один идентификатор (адрес, имя, NFT) и один «логический» баланс, который автоматически используется на любой цепи. Это эволюция от «мультичейн» (много кошельков) к chain-abstracted (один кошелёк, прозрачная мультичейн). Задача нетривиальная: реализовать её правильно значит решить несколько независимых технических проблем одновременно.

Что такое unified account на техническом уровне

Наивная реализация: смарт-контракт на каждой поддерживаемой цепи с одинаковым адресом (через CREATE2), синхронизация состояния через bridge. Это работает, но создаёт сложность: состояние разрознено, синхронизация имеет задержку и стоимость.

Продвинутая реализация разделяет:

  • Identity layer — кто вы (один идентификатор на всех цепях)
  • Intent layer — что вы хотите сделать (абстрагировано от конкретной цепи)
  • Execution layer — как это выполняется (routing, bridging, execution)
  • Settlement layer — окончательный расчёт

Детерминированные адреса через CREATE2

Первый шаг — один и тот же адрес на всех EVM цепях:

// Factory контракт с одинаковым адресом на всех цепях
contract AccountFactory {
    function deployAccount(
        bytes32 salt,
        bytes calldata initCode
    ) external returns (address account) {
        // CREATE2: адрес зависит только от factory address + salt + initCode
        // Если factory задеплоен через keyless deployment (один адрес на всех EVM),
        // то и Account будет иметь одинаковый адрес
        assembly {
            account := create2(0, add(initCode, 32), mload(initCode), salt)
        }
        
        if (account == address(0)) revert DeploymentFailed();
    }
    
    function predictAddress(
        bytes32 salt,
        bytes32 initCodeHash
    ) external view returns (address) {
        return address(uint160(uint256(keccak256(abi.encodePacked(
            bytes1(0xff),
            address(this),
            salt,
            initCodeHash
        )))));
    }
}

Keyless deployment (через ERC-2470 Singleton Factory или Nick's method) обеспечивает одинаковый адрес factory на всех EVM цепях. Следовательно — один и тот же salt + initCode = один адрес account на всех цепях.

Cross-chain state synchronization

Второй шаг — синхронизация данных аккаунта между цепями. Например: пользователь обновляет список owners на Ethereum, это должно отразиться на Polygon.

Паттерн: Primary chain + синхронизация через bridge:

contract UnifiedAccountPrimary {
    // Primary state хранится на "home" цепи
    mapping(address => bool) public owners;
    uint256 public nonce;
    
    // Синхронизация изменений на другие цепи
    function addOwnerAndSync(
        address newOwner,
        uint64[] calldata targetChains,
        address[] calldata targetAccounts
    ) external onlyOwner {
        owners[newOwner] = true;
        
        // Отправляем update через bridge (CCIP, Axelar, LayerZero)
        for (uint i = 0; i < targetChains.length; i++) {
            bytes memory payload = abi.encode(
                "ADD_OWNER",
                newOwner,
                ++nonce
            );
            
            bridge.sendMessage(targetChains[i], targetAccounts[i], payload);
        }
        
        emit OwnerAdded(newOwner);
    }
}

contract UnifiedAccountReplica {
    // Реплика получает обновления от Primary
    uint256 public lastSyncedNonce;
    
    function receiveSync(
        bytes calldata payload,
        bytes32 originMessageId
    ) external onlyBridge {
        (string memory action, address target, uint256 nonce) = 
            abi.decode(payload, (string, address, uint256));
        
        // Защита от replay: nonce должен быть следующим
        require(nonce == lastSyncedNonce + 1, "Invalid nonce");
        lastSyncedNonce = nonce;
        
        if (keccak256(bytes(action)) == keccak256(bytes("ADD_OWNER"))) {
            _addOwner(target);
        }
    }
}

Intent-based execution

Unified account принимает намерения пользователя, не конкретные транзакции. Пользователь говорит «хочу stake 100 USDC в протоколе X» — система сама решает откуда взять USDC и на какой цепи исполнить:

interface UserIntent {
  action: "stake" | "swap" | "transfer" | "borrow";
  targetProtocol: string;
  targetChain?: number;  // опционально — если не указана, система выбирает
  inputToken: string;
  inputAmount: string;
  outputToken?: string;
  minOutputAmount?: string;
  deadline?: number;
}

class IntentRouter {
  async resolveIntent(intent: UserIntent, userProfile: UserProfile): Promise<ExecutionPlan> {
    // 1. Находим лучшую цепь для исполнения
    const targetChain = intent.targetChain || 
      await this.findOptimalChain(intent, userProfile);
    
    // 2. Определяем откуда взять средства
    const fundingSource = await this.findBestFundingSource(
      intent.inputToken,
      intent.inputAmount,
      userProfile.balances,
      targetChain
    );
    
    // 3. Строим execution plan
    const steps: ExecutionStep[] = [];
    
    if (fundingSource.chainId !== targetChain) {
      // Нужен bridge
      steps.push({
        type: "bridge",
        fromChain: fundingSource.chainId,
        toChain: targetChain,
        token: intent.inputToken,
        amount: intent.inputAmount,
        bridgeProtocol: await this.selectBridge(fundingSource.chainId, targetChain),
      });
    }
    
    // Основное действие
    steps.push({
      type: intent.action,
      chainId: targetChain,
      protocol: intent.targetProtocol,
      ...
    });
    
    return {
      steps,
      estimatedGas: await this.estimateTotalGas(steps),
      estimatedTime: this.estimateTime(steps),
    };
  }
}

Gasless cross-chain операции

Для полного UX unified account — пользователь не должен думать о газе. Система абстрагирует это:

// Пользователь платит в USDC, система конвертирует в нативные токены
async function executeGasless(
  intent: UserIntent,
  feeToken: "USDC" | "USDT" | string
): Promise<string> {
  const plan = await intentRouter.resolveIntent(intent, userProfile);
  
  // Рассчитываем общую стоимость в feeToken
  const totalCostInFeeToken = await priceOracle.convertGasCost(
    plan.estimatedGas,
    plan.steps.map(s => s.chainId),
    feeToken
  );
  
  // Получаем UserOperation со sponsored газом
  const userOp = await buildSponsordUserOp(plan, feeToken, totalCostInFeeToken);
  
  // Подписываем один раз на исходной цепи
  const signedOp = await userAccount.signUserOperation(userOp);
  
  // Executor relay выполняет все steps
  return relayer.submitIntent(signedOp);
}

Account abstraction как фундамент

Unified accounts нативно строятся на ERC-4337:

  • Smart account вместо EOA на каждой цепи
  • UserOperations как единица intent
  • Bundler как executor
  • Paymaster как gas abstraction layer

ZeroDev Kernel, Safe с модулями или кастомная ERC-4337 реализация — выбор зависит от требуемой гибкости.

Проблема атомарности

Критический вопрос: что происходит если шаг 1 (bridge) прошёл успешно, а шаг 2 (stake на целевой цепи) завершился ошибкой?

Варианты:

  • Optimistic execution: продолжаем, записываем pending state, retry при неудаче
  • Atomic through escrow: средства находятся в escrow контракте до подтверждения финального шага
  • Two-phase commit: prepare → commit/rollback

На практике большинство систем используют optimistic с retry механизмом и ручным fallback (средства остаются на целевой цепи если действие не выполнено).

Стек

Компонент Решение
Smart accounts ERC-4337 (ZeroDev Kernel или Safe)
Cross-chain messaging LayerZero / Axelar / CCIP
Gas abstraction ERC-4337 Paymaster
Intent routing Кастомный сервис + 1inch/LiFi для swaps
State sync Merkle proofs + bridge
Frontend wagmi v2 + viem + React

Сроки

  • Базовая unified identity (CREATE2 одинаковые адреса, базовый sync): 4-6 недель
  • Intent routing + cross-chain execution: 6-8 недель
  • Gas abstraction + feeToken: 3-4 недели
  • Production hardening + security audit: 6-8 недель
  • Итого: 4-6 месяцев