Разработка кошелька с social recovery
Seed-фраза из 12 слов — худший UX в истории финансов. Пользователь обязан надёжно хранить последовательность слов, которую нельзя ни сфотографировать, ни потерять, ни показать кому-либо. В результате: один записал на бумаге в ящике стола, другой сохранил в заметках телефона, третий не сохранил вообще. По оценкам Chainalysis, 20–25% всех биткоинов безвозвратно потеряны именно так.
Social recovery — механизм, при котором потеря ключей не означает потерю активов. Идея Виталика Бутерина, реализованная в Argent, Loopring, а теперь нативно доступная через ERC-4337 Account Abstraction. Суть: кошелёк принадлежит смарт-контракту, который имеет два режима управления — owner key для повседневных транзакций и guardian set для recovery.
Архитектура: как работает social recovery на уровне контракта
Guardian set и threshold recovery
Guardians — это адреса (EOA или другие смарт-контракты), которые коллективно могут сменить owner key кошелька. Владелец заранее назначает N guardian-ов и задаёт threshold — минимальное число подтверждений для recovery. Классика: 3 из 5.
Guardians никогда не трогают активы напрямую. Их единственная функция — вызов initiateRecovery и finalizeRecovery. Это принципиальное ограничение: если guardian скомпрометирован, он не может украсть средства, только запустить процесс смены ключа.
contract SocialRecoveryWallet {
address public owner;
mapping(address => bool) public isGuardian;
uint256 public guardianCount;
uint256 public threshold;
uint256 public recoveryDelay; // timelock в секундах
struct RecoveryRequest {
address proposedOwner;
uint256 approvalCount;
uint256 initiatedAt;
mapping(address => bool) approvals;
}
RecoveryRequest public pendingRecovery;
function initiateRecovery(address _proposedOwner) external onlyGuardian {
require(pendingRecovery.initiatedAt == 0, "Recovery already pending");
pendingRecovery.proposedOwner = _proposedOwner;
pendingRecovery.initiatedAt = block.timestamp;
pendingRecovery.approvalCount = 1;
pendingRecovery.approvals[msg.sender] = true;
}
function approveRecovery() external onlyGuardian {
require(pendingRecovery.initiatedAt != 0, "No pending recovery");
require(!pendingRecovery.approvals[msg.sender], "Already approved");
pendingRecovery.approvals[msg.sender] = true;
pendingRecovery.approvalCount++;
}
function finalizeRecovery() external {
require(pendingRecovery.approvalCount >= threshold, "Insufficient approvals");
require(
block.timestamp >= pendingRecovery.initiatedAt + recoveryDelay,
"Timelock not expired"
);
owner = pendingRecovery.proposedOwner;
delete pendingRecovery;
}
}
Timelock — ключевой элемент безопасности
recoveryDelay — обязательный параметр. Если guardian-ы сговорились или были скомпрометированы, у владельца есть окно для отмены (cancelRecovery). Argent использует 24-48 часов. Для institutional кошельков имеет смысл 72 часа или больше.
Без timelock: guardian threshold скомпрометирован → мгновенная потеря контроля. С timelock: владелец видит pending recovery в интерфейсе, успевает отменить, если это не он инициировал.
Guardian management
Добавление и удаление guardian-ов должно идти через timelock тоже — иначе owner может заменить всех guardian-ов на контролируемые адреса сразу перед продажей. Паттерн: pendingGuardianAdd с задержкой, аналогично recovery.
mapping(address => uint256) public pendingGuardianAdditions;
uint256 public guardianAddDelay;
function scheduleAddGuardian(address _guardian) external onlyOwner {
pendingGuardianAdditions[_guardian] = block.timestamp + guardianAddDelay;
}
function confirmAddGuardian(address _guardian) external {
require(pendingGuardianAdditions[_guardian] != 0, "Not scheduled");
require(block.timestamp >= pendingGuardianAdditions[_guardian], "Timelock active");
isGuardian[_guardian] = true;
guardianCount++;
delete pendingGuardianAdditions[_guardian];
}
Кто может быть guardian-ом
Выбор guardian-ов — задача не техническая, а социальная и архитектурная. Варианты:
Доверенные лица. Три близких человека. Каждый хранит guardian private key в своём кошельке. Простейшая схема, достаточная для большинства пользователей.
Hardware wallet + телефон + guardian сервис. Резервный Ledger в сейфе + личный телефон + Guardian сервис типа Argent или кастомный. При потере двух из трёх — recovery.
Multisig как guardian. Safe{Wallet} — guardian кошелька. Для recovery нужно собрать quorum в Safe. Подходит для корпоративных кошельков, где HR-процедура заменяет ключи.
Smart contract guardian. Guardian — это timelock контракт организации. Recovery инициируется через governance голосование. Крайний случай, но позволяет полностью формализовать процедуру.
| Тип guardian | Удобство | Децентрализация | Подходит для |
|---|---|---|---|
| Trusted persons (3-of-5) | Высокое | Высокая | Розничные пользователи |
| Hardware + mobile + service | Среднее | Средняя | Power users |
| Corporate multisig | Низкое | Высокая | Корпоративные |
| DAO governance | Очень низкое | Максимальная | Protocol-owned |
ERC-4337 и social recovery
Account Abstraction (ERC-4337) делает social recovery первоклассным паттерном. Кошелёк — смарт-контракт изначально, никакой конверсии от EOA не нужно. UserOperation вместо транзакции позволяет:
- Gasless recovery: Paymaster оплачивает gas за guardian-ов и пользователя
- Batched approvals: несколько guardian одобрений в одном bundled batch
- Social login как guardian: guardian key хранится в passkey/WebAuthn на телефоне пользователя, не требует знания crypto
Реализация через Kernel (ZeroDev) или Biconomy Smart Account v2: оба имеют plugin/module систему, где social recovery — подключаемый модуль, а не core логика.
ERC-4337 recovery flow
// Guardian подписывает UserOperation для approveRecovery
const userOp = await guardianSmartAccount.buildUserOperation({
target: walletAddress,
data: wallet.interface.encodeFunctionData('approveRecovery', [])
});
// Paymaster спонсирует gas — guardian не нужны ETH
const sponsoredOp = await paymasterClient.sponsorUserOperation(userOp);
await bundlerClient.sendUserOperation(sponsoredOp);
Это принципиально меняет UX: guardian-у не нужно держать ETH для gas. Он просто подписывает approval на телефоне, Paymaster покрывает стоимость.
Защита от атак
Griefing через spam recovery
Любой guardian может инициировать recovery — и этим заблокировать нормальную работу кошелька (pending recovery мешает транзакциям в некоторых реализациях). Решение: инициировать recovery может только порог guardian-ов коллективно, или recovery не блокирует транзакции owner-а.
Social engineering на guardian-ов
Злоумышленник убеждает нескольких guardian-ов, что пользователь потерял ключ и нужно recovery. Защита: timelock даёт window реакции, мониторинг pending recovery через нотификации (email/push/telegram bot), обязательная верификация через out-of-band канал.
Front-running finalizeRecovery
Атакующий видит в мемпуле finalizeRecovery с proposedOwner = легитимный адрес и front-run-ит с другим адресом. Защита: commit-reveal схема или использование flashbots/private mempool для финальной транзакции.
Off-chain guardian coordination
Guardian-ам нужен способ координироваться без on-chain газа. Варианты:
Centralized guardian service. Argent хранит guardian signature off-chain, пользователь запрашивает через сервис. Удобно, но центральная точка отказа.
IPFS + signature aggregation. Guardian-ы публикуют подписи в IPFS, aggregator собирает threshold подписей и отправляет один batchApprove вызов. Требует UI.
E2E encrypted messaging. Guardian-ы обмениваются через Signal/Matrix, подписи передаются вручную. Low-tech, максимальная независимость.
Для production рекомендуем гибрид: кастомный notification сервер уведомляет guardian-ов, они одобряют через dApp, aggregator батчит подписи.
Стек и инструменты
Solidity 0.8.x + OpenZeppelin — базовая реализация контракта. Foundry — тестирование, особенно timelock и recovery edge cases. ERC-4337 SDK (ZeroDev / Biconomy) — если строим AA кошелёк. wagmi + viem — frontend. WalletConnect v2 — подключение guardian-ов с разных устройств.
Процесс разработки
Аналитика (3-5 дней). Целевая аудитория, кто будет guardian-ами, нужна ли AA, gasless или нет, multichain или single chain.
Проектирование контракта (3-5 дней). Guardian management схема, timelock параметры, recovery flow, интеграция с ERC-4337 Account если нужна.
Разработка (4-8 недель). Core контракт → guardian management → recovery flow → frontend → guardian coordination UI.
Аудит. Обязателен: контракт управляет средствами, recovery — критическая функция. Особое внимание: reentrancy в execute, корректность timelock, guardian griefing vectors.
Тестирование. Fork-тесты на mainnet, симуляция полного recovery flow, тест каждого attack vector.
Базовый кошелёк без AA — 3-5 недель. С ERC-4337, gasless recovery и guardian coordination UI — 8-12 недель.







