An Ethereum smart contract that protects funds in a "primary" wallet by requiring a separate "verification" wallet for large transfers and offering a failover "secondary" wallet.
# Start local blockchain
npm run anvil
# Deploy contract
npm run deploy
# Run tests
npm run test
# Start with funded contract
npm run startThe VerificationVault implements a three-wallet security model:
- Primary Wallet: Initiates regular withdrawals up to daily limits
- Verification Wallet: Controls limits, emergency functions, and security parameters (
β οΈ NEVER stores funds) - Secondary Wallet: Emergency backup that receives extracted funds with time-limited forwarding capabilities
The verification wallet is designed to NEVER receive funds from the contract. This is enforced through:
- Constructor validation preventing verifier from being primary or secondary
- Runtime checks in all transfer functions (
require(to != verifier)) - Emergency extraction only sends to secondary wallet
- Primary wallet can withdraw up to a configurable daily limit
- Rolling 24-hour window based on
block.timestamp / 1 days - Verifier can temporarily bypass limits with
allowAnyAmountNextTransaction
- Verifier blocks primary wallet
- Verifier triggers
extractAllToSecondary()- sends all funds to secondary - Secondary has 1-2 hours (configurable) to forward funds
- After deadline, secondary is automatically blocked
- Primary:
primaryWithdraw(to, amount) - Verifier:
setDailyLimit(),blockPrimary(),extractAllToSecondary(), etc. - Secondary:
secondaryForward(to, amount)(time-limited)
- Solidity Version: ^0.8.20
- Dependencies: OpenZeppelin ReentrancyGuard
- Gas Optimized: Uses immutable addresses, efficient storage patterns
- Reentrancy Protected: All external calls protected
# Clone and install dependencies
git clone <repository-url>
cd verification-wallet
npm install
# Install Foundry (if not already installed)
curl -L https://foundry.paradigm.xyz | bash
foundryupnpm run compile
# or
forge buildnpm run test
# or
forge test -vvvnpm run test-gas
# or
forge test --gas-reportThe test suite includes comprehensive coverage:
- β Constructor validation and access controls
- β Daily limit enforcement and bypass mechanisms
- β Emergency extraction and secondary forwarding
- β Critical security: No funds to verifier validation
- β Reentrancy attack protection
- β Edge cases and failure scenarios
// Daily limit enforcement
testPrimaryCanWithdrawBelowDailyLimit()
testPrimaryCannotExceedDailyLimit()
// Emergency procedures
testExtractAllToSecondary()
testSecondaryCannotForwardToVerifier()
// Security validations
testCannotSendToVerifierInAnyContext()
testReentrancyProtection()VerificationVault vault = new VerificationVault(
primaryAddress, // EOA or multisig for regular use
verifierAddress, // Multisig for governance (NEVER receives funds)
secondaryAddress, // EOA or multisig for emergency backup
dailyLimitWei // Initial daily limit in wei
);// Deposit funds (anyone can deposit)
vault.deposit{value: amount}();
// Primary wallet withdraws (up to daily limit)
vault.primaryWithdraw(recipient, amount);
// Verifier adjusts security parameters
vault.setDailyLimit(newLimit);
vault.setAllowAnyAmountNextTransaction(true); // One-time bypass// 1. Verifier blocks compromised primary
vault.blockPrimary(true);
// 2. Extract all funds to secondary
vault.extractAllToSecondary();
// 3. Secondary forwards funds within deadline
vault.secondaryForward(safeAddress, amount);- Smart contracts cannot generate private keys
- Use externally generated addresses (EOAs, hardware wallets, multisigs)
- Recommended: Gnosis Safe multisig for verifier wallet
- Uses
block.timestampfor daily limits and deadlines - Minor miner manipulation possible (~15 seconds)
- Choose extraction windows conservatively (1-2 hours)
- Primary: Hardware wallet or EOA for regular access
- Verifier: Multisig (2-of-3 or 3-of-5) for governance only
- Secondary: Hardware wallet or multisig for emergency recovery
- Never send funds to the verifier address
- Verifier is governance-only, not a funds-holding wallet
- Use multisig for verifier to prevent single points of failure
- Test on testnets before mainnet deployment
| Function | Caller | Description |
|---|---|---|
primaryWithdraw(to, amount) |
Primary | Withdraw up to daily limit |
setDailyLimit(newLimit) |
Verifier | Update withdrawal limit |
blockPrimary(blocked) |
Verifier | Emergency block/unblock |
extractAllToSecondary() |
Verifier | Emergency fund extraction |
secondaryForward(to, amount) |
Secondary | Time-limited forwarding |
| Function | Returns | Description |
|---|---|---|
getDailySpent() |
uint256 | Amount spent today |
remainingDailyLimitToday() |
uint256 | Remaining daily allowance |
getSecondaryStatus() |
(bool,bool,uint256) | Active, blocked, deadline |
getBalance() |
uint256 | Contract ETH balance |
event Deposit(address indexed sender, uint256 amount);
event PrimaryWithdrawal(address indexed to, uint256 amount);
event DailyLimitChanged(uint256 oldLimit, uint256 newLimit);
event AllowAnyToggled(bool enabled);
event PrimaryBlocked(bool blocked);
event ExtractedToSecondary(uint256 amount);
event SecondaryForwarded(address indexed to, uint256 amount);
event SecondaryFinalized(bool blocked);verification-wallet/
βββ src/
β βββ Contract.sol # VerificationVault implementation
βββ test/
β βββ Contract.t.sol # Comprehensive test suite
βββ lib/
β βββ forge-std/ # Foundry testing framework
β βββ openzeppelin-contracts/
βββ foundry.toml # Foundry configuration
βββ package.json # npm scripts and dependencies
βββ README.md # This file
- Fork the repository
- Create a feature branch
- Write tests for new functionality
- Ensure all tests pass:
npm run test - Submit a pull request
MIT License - see LICENSE file for details.
This smart contract is for educational and experimental purposes. Audit thoroughly before deploying real funds. The authors assume no responsibility for lost funds or security vulnerabilities. Always test on testnets first and consider professional security audits for production use.