A secure and flexible smart contract recovery system that allows for ownership transfer through configurable recovery conditions.
Recovery Pulse provides a flexible recovery mechanism for smart contracts. It enables secure ownership transfer when specific pre-set conditions are met. The system consists of a main Recoverable contract that can be inherited by other contracts, along with modular recovery condition contracts that define when recovery is allowed.
The main recovery contract that provides:
- Recovery Status Management: Tracks recovery states (Inactive, Active, Successful, Cancelled)
- Cooldown Protection: Prevents rapid recovery condition changes (mitigating usual attack vectors)
- Ownership Transfer: Secure transfer of contract ownership
- Event Emission: Comprehensive event logging for transparency
Interface for recovery condition contracts:
interface IRecoveryCondition {
function isRecoverable() external view returns (bool);
function canTriggerRecovery() external view returns (bool);
function triggerRecovery(address newOwner) external;
function resetRecovery() external;
}A basic recovery condition implementation:
- Guardian-based: Only a trusted guardian can trigger recovery
- Simple State: Boolean flag determines if recovery is allowed
- Event Logging: Emits events when recovery is triggered
A time-based recovery condition with counter mechanism:
- Maintainer Updates: Designated maintainer can update counter and reset timeout
- Time-based Recovery: Guardian can trigger recovery if timeout exceeded since last update
- Configurable Timeout: Adjustable recovery timeout period
- Role Management: Maintainer can update guardian and maintainer addresses
- Comprehensive Events: Detailed event logging for all operations
Testing utility for development:
- Configurable: Can be set to always return true or false
- Test-friendly: Easy to control in test scenarios
- Cooldown Periods: Prevents rapid configuration changes
- Owner-only Operations: Critical functions restricted to contract owner
- Condition Verification: Recovery only proceeds when conditions are met
- Status Tracking: Clear recovery state management
- Modular Conditions: Pluggable recovery condition contracts
- Configurable Cooldowns: Adjustable time delays
- Extensible Interface: Easy to implement custom recovery conditions
- Event Logging: All important actions emit events
- Status Visibility: Public state variables for monitoring
- Clear Error Messages: Descriptive revert reasons
- Setup: Deploy recovery condition contract with Recoverable address, then Recoverable with condition address and cooldown period
- Trigger & Start: Guardian calls
triggerRecovery(newOwner)on condition contract- Condition contract calls
startRecovery(newOwner)on the stored Recoverable address - Status changes from Inactive to Active, pendingOwner is set
- Condition contract calls
- Cancel (optional): Owner can cancel active recovery if still accessible
- Finalize: Pending owner calls
finaliseRecovery()to complete transfer- System verifies
isRecoverable()returns true - Ownership transfers, condition contract resets via
resetRecovery()
- System verifies
- Complete: Status returns to Inactive, ready for future recovery if needed
# Set environment variables (optional)
export COOLDOWN_PERIOD=86400 # 1 day in seconds
export GUARDIAN_ADDRESS=0x...
# Deploy contracts
npx hardhat run scripts/deploy.js --network <network># Set environment variables (optional)
export COOLDOWN_PERIOD=86400 # 1 day in seconds
export GUARDIAN_ADDRESS=0x...
export MAINTAINER_ADDRESS=0x...
export RECOVERY_TIMEOUT=604800 # 7 days in seconds
# Deploy contracts
npx hardhat run scripts/deploy-recovery-pulse.js --network <network>To make your contract recoverable, inherit from Recoverable:
contract MyContract is Recoverable {
constructor(
address _recoveryCondition,
uint256 _cooldownPeriod
) Recoverable(_recoveryCondition, _cooldownPeriod) {
// Your contract initialization
}
// Your contract logic
}-
Guardian triggers recovery (this also starts recovery on Recoverable):
simpleCondition.triggerRecovery(newOwnerAddress); -
Pending owner finalizes:
recoverable.finaliseRecovery();
-
Maintainer sends heartbeat (prevents recovery):
recoveryPulseCondition.updatePulse(newPulseValue); -
Guardian triggers recovery (if timeout exceeded, this also starts recovery):
recoveryPulseCondition.triggerRecovery(newOwnerAddress); -
Pending owner finalizes:
recoverable.finaliseRecovery();
- Node.js 16+
- Hardhat
- OpenZeppelin Contracts
npm install# Run all tests
npx hardhat test
# Run specific test files
npx hardhat test test/Recoverable.js
npx hardhat test test/RecoveryPulseCondition.jsnpx hardhat compilenpx hardhat run scripts/deploy.js --network <network>After deployment, you'll get:
- SimpleCondition: Recovery condition contract (or RecoveryPulseCondition for pulse-based)
- Recoverable: Main recovery contract
- Guardian Selection: Choose a trusted guardian address
- Cooldown Periods: Set appropriate delays for your use case
- Condition Logic: Implement secure recovery conditions
- Testing: Thoroughly test recovery scenarios
- Monitoring: Monitor recovery events and status changes
MIT License - see LICENSE file for details.
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Submit a pull request
- Integration Guide: Comprehensive guide for integrating Recovery Pulse into your contracts
- Example Contract: Time-locked vault demonstrating recovery integration
contracts/
├── Recoverable.sol # Main contract to inherit
├── interfaces/
│ ├── IRecoverable.sol # Recoverable interface
│ └── IRecoveryCondition.sol # Condition interface
├── modules/
│ ├── SimpleCondition.sol # Guardian-triggered recovery
│ └── RecoveryPulseCondition.sol # Heartbeat-based recovery
├── examples/
│ └── RecoverableLock.sol # Example integration
└── test/
└── MockRecoveryCondition.sol # Testing utility
scripts/
├── deploy.js # Default deployment
├── deploy-simple.js # SimpleCondition + Recoverable
├── deploy-recovery-pulse.js # RecoveryPulseCondition + Recoverable
├── deploy-lock-simple.js # RecoverableLock + SimpleCondition
└── deploy-lock-pulse.js # RecoverableLock + RecoveryPulseCondition
test/
├── Recoverable.js # Core contract tests
├── RecoveryPulseCondition.js # Pulse condition tests
└── RecoverableLock.js # Example contract tests
For questions or support, please open an issue in the repository.