Разработка мультисиг-контрактов
Мультисиг — это не про параноидальную безопасность. Это про то, что ни один человек в команде не должен иметь возможность в одностороннем порядке вывести treasury, обновить контракт или поменять критический параметр протокола. При $3M в treasury достаточно одного скомпрометированного Ledger или утёкшего приватника — и recovery невозможен.
Gnosis Safe vs кастомный мультисиг
Большинство задач закрывает Safe (Gnosis Safe) — аудированный контракт с 4+ годами на mainnet, $100B+ под управлением, поддержкой всех EVM-сетей. Под капотом — пороговая схема M-of-N: M подписей из N авторизованных owners. Safe хранит транзакции на chain, каждый owner подписывает офчейн (EIP-712 structured data), при сборе M подписей — любой может исполнить.
Когда нужен кастомный мультисиг:
- нестандартная логика авторизации (timelock + multisig + DAO vote)
- оn-chain голосование с весами (weighted multisig)
- специфические условия исполнения (только после оракульного события)
- TON, Solana, Aptos — где Safe не существует
Что стоит за "M-of-N подписей"
Реализация мультисига на Solidity — хрестоматийный материал для аудиторов, потому что в нём регулярно находят один и тот же класс проблем.
Replay attack. Контракт принимает список подписей и проверяет их. Если nonce не включён в подписываемый хэш — та же транзакция может быть переиграна. Правильная структура: keccak256(abi.encode(to, value, data, nonce, chainId)). ChainId обязателен — иначе подпись, действующая на Ethereum mainnet, принимается на Polygon.
Signature malleability. ECDSA имеет две действительные подписи для одного сообщения (s и -s mod n). OpenZeppelin ECDSA.recover обрабатывает это корректно с версии 4.x, проверяя s <= secp256k1n / 2. Самописный ecrecover без этой проверки позволяет дублировать подписи одного owner-а.
Duplicate signer. Контракт собирает N подписей, проверяет каждую против списка owners, но не проверяет уникальность подписантов. Атака: один owner предоставляет M подписей одного и того же сообщения — транзакция исполняется с M/N = 1 фактическим участником. Защита: require(signer > lastSigner) — сортировка адресов в возрастающем порядке гарантирует уникальность.
Вот минимальный корректный чеклист верификации подписей:
function _verifySignatures(
bytes32 txHash,
bytes[] calldata signatures
) internal view {
require(signatures.length >= threshold, "Below threshold");
address lastSigner = address(0);
for (uint256 i = 0; i < signatures.length; i++) {
address signer = ECDSA.recover(txHash, signatures[i]);
require(isOwner[signer], "Not an owner");
require(signer > lastSigner, "Duplicate signer"); // ключевая проверка
lastSigner = signer;
}
}
Timelock как обязательный слой
Мультисиг 2-of-3 с тремя ключами в одном офисе — не мультисиг в смысле безопасности. Реальная защита — комбинация мультисига с TimelockController (OpenZeppelin). Транзакция, поддержанная M подписями, ставится в очередь с задержкой (обычно 24-72 часа). В этом окне community может заметить вредоносное действие.
Для протоколов с TVL > $1M TimelockController с задержкой 48 часов — baseline. Параметр minDelay задаётся при деплое и не может быть уменьшен самим timelock-ом (только через governance vote или multisig).
Weighted multisig и DAO-интеграция
Если подписанты имеют разный вес (VC фонд с 40% voting power vs отдельные контрибьюторы с 5% каждый) — нужна взвешенная схема. Реализуем через mapping weights[address] и проверку totalWeight >= requiredWeight вместо threshold по количеству.
Интеграция с Governor (OpenZeppelin) позволяет строить гибридные схемы: мелкие операции (до X ETH) — через мультисиг, крупные — через DAO vote с timelock.
Multisig на Solana и TON
На Solana используем Squads Protocol — аналог Safe для Solana. Squads v4 поддерживает программируемые spending limits, роли, интеграцию с Serum/Jupiter. Кастомный мультисиг на Anchor пишем когда Squads не покрывает логику.
На TON — кастомная реализация на Tact или FunC. TON multisig wallet (официальный контракт от TON Foundation) подходит для простых случаев хранения TON. Для jetton-ов и сложной логики — кастомный контракт с обработкой bounce сообщений.
Сроки
Интеграция Safe + конфигурация owners/threshold + деплой TimeelockController — 2-3 дня. Кастомный мультисиг на Solidity с полным тест-покрытием — 3-5 дней. Weighted multisig с DAO-интеграцией — 1-2 недели.







