Разработка модулей для Safe{Wallet}

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка модулей для Safe{Wallet}
Средняя
~3-5 рабочих дней
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1258
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1170
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    873
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1092
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    563
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    830

Разработка модулей для Safe{Wallet}

Safe (бывший Gnosis Safe) — стандарт мультисиг-кошелька в Web3. На нём хранится больше $100B в активах DAO, протоколов и корпоративных казначейств. Архитектура Safe намеренно минималистична в ядре, но расширяема через модули — это контракты, которым владелец Safe делегирует право выполнять транзакции без стандартного порога подписей.

Как устроены модули в Safe

Safe{Wallet} следует паттерну модульного прокси. Ядро (GnosisSafe.sol) содержит базовую логику мультисига и хранит список активных модулей в linked list storage. Модуль активируется через enableModule(address module) — это стандартная мультисиг-транзакция, требующая порог подписей.

После активации модуль может вызывать execTransactionFromModule() напрямую на Safe, минуя стандартный процесс подписей:

interface IGnosisSafe {
    function execTransactionFromModule(
        address to,
        uint256 value,
        bytes calldata data,
        Enum.Operation operation
    ) external returns (bool success);
}

operation — 0 для CALL, 1 для DELEGATECALL. DELEGATECALL выполняет код target-контракта в контексте хранилища Safe — это мощный инструмент и одновременно вектор атаки если модуль не проверен тщательно.

Типичные кейсы для кастомных модулей

Spending limits (лимиты трат). DAO разрешает операционной команде тратить до $10K в день без мультисига. Модуль хранит лимит, счётчик трат за период и разрешённых вызывающих. Стандартный Safe Allowance Module реализует это, но кастомные версии нужны когда лимит должен работать с несколькими токенами одновременно или сбрасываться по событию, а не по времени.

Автоматизированные выплаты. Интеграция с Chainlink Automation или Gelato: модуль получает право раз в месяц выполнять transfer из Safe на адреса команды. Без мультисига, но с жёсткими ограничениями: только предодобренные адреса, только определённые токены, только в рамках бюджета.

Recovery модуль. Safe конфигурации с 3/5 подписантов, но что если 3 ключа потеряны? Recovery модуль позволяет назначить guardian-адреса (другие Safe, холодные кошельки), которые через timelock могут заменить список подписантов. Guardian не может вывести средства — только изменить конфигурацию Safe после периода ожидания.

Governance-controlled execution. Модуль принимает решения от on-chain governance (Snapshot X с on-chain execution, OpenZeppelin Governor). Голосование проходит, результат исполняется через модуль без дополнительных подписей мультисига.

Архитектура безопасного модуля

Проверки авторизации

Главная ответственность модуля — корректная авторизация. Если execTransactionFromModule может вызвать кто угодно — это катастрофа. Шаблон:

contract SpendingLimitModule {
    mapping(address safe => mapping(address delegate => SpendingLimit)) public limits;

    modifier onlyDelegate(address safe) {
        require(limits[safe][msg.sender].amount > 0, "Not a delegate");
        _;
    }

    function executeTransfer(
        address safe,
        address token,
        address recipient,
        uint256 amount
    ) external onlyDelegate(safe) {
        SpendingLimit storage limit = limits[safe][msg.sender];
        require(amount <= limit.remaining, "Exceeds limit");

        // Сначала обновляем состояние
        limit.remaining -= amount;

        // Потом выполняем транзакцию
        bytes memory data = abi.encodeWithSignature(
            "transfer(address,uint256)", recipient, amount
        );
        require(
            IGnosisSafe(safe).execTransactionFromModule(token, 0, data, Enum.Operation.Call),
            "Module tx failed"
        );
    }
}

Порядок: проверки → изменение состояния → внешний вызов. Классический checks-effects-interactions.

Guard — дополнительный слой защиты

Safe 1.3+ поддерживает Guard — контракт, который вызывается до и после каждой транзакции Safe. Guard может блокировать транзакции по любым условиям: запрещать взаимодействие с определёнными адресами, требовать cooldown между крупными транзакциями, логировать всё on-chain.

Guard и Module — разные механизмы. Guard не выполняет транзакции, только фильтрует их. Module выполняет транзакции, обходя стандартный порог.

Timelock в модуле

Для critical actions модуль должен включать timelock. Операция ставится в очередь с timestamp, выполняется только после прохождения delay-периода. Это даёт наблюдателям (community, другим подписантам) время среагировать на нежелательное действие.

mapping(bytes32 => uint256) public queue;
uint256 public constant DELAY = 2 days;

function propose(address target, uint256 value, bytes calldata data)
    external onlyAuthorized returns (bytes32 txHash) {
    txHash = keccak256(abi.encode(target, value, data, block.timestamp));
    queue[txHash] = block.timestamp + DELAY;
    emit Proposed(txHash, target, value, data);
}

function execute(address target, uint256 value, bytes calldata data, uint256 timestamp)
    external onlyAuthorized {
    bytes32 txHash = keccak256(abi.encode(target, value, data, timestamp));
    require(queue[txHash] != 0, "Not queued");
    require(block.timestamp >= queue[txHash], "Timelock active");
    delete queue[txHash];
    // execute via Safe module
}

Тестирование и аудит

Тестируем на Foundry с реальным инстансом Safe. Forge позволяет деплоить Safe factory и создавать Safe инстансы в тестах — не нужны моки.

import {GnosisSafeProxyFactory} from "safe-contracts/proxies/GnosisSafeProxyFactory.sol";
import {GnosisSafe} from "safe-contracts/GnosisSafe.sol";

function setUp() public {
    factory = new GnosisSafeProxyFactory();
    singleton = new GnosisSafe();
    // деплой Safe с нашим модулем уже включённым через setup
}

Проверяем: модуль не может вызвать execTransactionFromModule от произвольного адреса, timelock нельзя обойти, reentrancy в коллбэках невозможна, модуль корректно работает после Safe upgrade.

Аудит модулей для Safe с крупными активами — обязателен. Вектор атаки через DELEGATECALL особенно опасен: злонамеренный модуль через delegatecall может перезаписать storage Safe, включая список подписантов.

Сроки

Spending Limit модуль с базовой логикой: 3-5 дней. Recovery модуль с timelock и guardian system: 5-8 дней. Комплексный governance модуль с интеграцией Snapshot X или OpenZeppelin Governor: 2-3 недели. Аудит — дополнительно 1-2 недели.

Стоимость рассчитывается после уточнения требований к управлению и количеству интегрируемых систем.