This repository contains smart contracts for Safe wallet transaction management and security guards, including a modular SafeTxPool implementation and delegate call restrictions.
The SafeGuard contract is a guard implementation for the Safe (formerly Gnosis Safe) smart contract wallet. It restricts delegate calls to only allowed target addresses, providing an additional layer of security.
The SafeTxPool has been refactored into a modular architecture to solve contract size limitations and improve maintainability:
- SafeTxPoolRegistry: Main interface contract (13,240 bytes)
- SafeTxPoolCore: Core transaction pool functionality (10,595 bytes)
- AddressBookManager: Address book management (3,409 bytes)
- DelegateCallManager: Delegate call permissions (4,913 bytes)
- TrustedContractManager: Trusted contract management (1,650 bytes)
- TransactionValidator: Transaction validation logic (5,580 bytes)
Key Benefits:
- ✅ All contracts well within 24KB size limit
- ✅ 100% backward compatibility with original SafeTxPool
- ✅ Enhanced security with proper access control
- ✅ Modular design for easier maintenance and upgrades
This project uses Foundry for development and testing.
forge installforge testforge coverage- Install Foundry: Follow the Foundry installation guide
- Clone and setup:
git clone https://github.com/hadv/vito-contracts cd vito-contracts forge install
Create a .env file from the example:
cp .env.example .envEdit .env with your values:
PRIVATE_KEY=your_private_key_without_0x_prefix
RPC_URL=your_rpc_endpoint_url
ETHERSCAN_API_KEY=your_etherscan_api_key_for_verificationPre-commit checks run automatically via Git hooks before each commit:
- ✅ All contracts build successfully
- ✅ All tests pass (105/105)
- ✅ Contract sizes are within limits
The Git pre-commit hook ensures code quality automatically. If checks fail, the commit will be blocked until issues are resolved.
Deploy the SafeTxPool with modular architecture:
source .env && forge script script/DeploySafeTxPool.s.sol:DeploySafeTxPool --rpc-url $RPC_URL --broadcast --verify -vvvvWhat gets deployed:
- SafeTxPoolCore (transaction management)
- AddressBookManager (address book functionality)
- DelegateCallManager (delegate call permissions)
- TrustedContractManager (trusted contract management)
- TransactionValidator (validation logic)
- SafeTxPoolRegistry (main interface - use this address)
Deploy just the SafeGuard for delegate call restrictions:
source .env && forge script script/DeploySafeGuard.s.sol:DeploySafeGuard --rpc-url $RPC_URL --broadcast --verify -vvvv--verify: Verify contracts on Etherscan (recommended)--chain-id <id>: Specify network chain ID--gas-price <price>: Set specific gas price--legacy: For networks not supporting EIP-1559-vvvv: Verbose output for debugging
source .env && forge script script/DeploySafeTxPool.s.sol:DeploySafeTxPool \
--rpc-url $RPC_URL \
--broadcast \
--verify \
--chain-id 1 \
-vvvvsource .env && forge script script/DeploySafeTxPool.s.sol:DeploySafeTxPool \
--rpc-url $RPC_URL \
--broadcast \
--verify \
--chain-id 11155111 \
-vvvvsource .env && forge script script/DeploySafeTxPool.s.sol:DeploySafeTxPool \
--rpc-url $RPC_URL \
--broadcast \
--verify \
--chain-id 137 \
-vvvvAfter deployment, verify the contracts are working correctly:
# Check contract sizes
forge build --sizes
# Run all tests
forge test
# Check specific contract deployment
cast code <DEPLOYED_CONTRACT_ADDRESS> --rpc-url $RPC_URLThe SafeTxPool provides comprehensive transaction management with a modular architecture:
// Use the SafeTxPoolRegistry address from deployment
SafeTxPoolRegistry pool = SafeTxPoolRegistry(DEPLOYED_REGISTRY_ADDRESS);// Propose a transaction
pool.proposeTx(txHash, safe, to, value, data, operation, nonce);
// Sign a transaction
pool.signTx(txHash, signature);
// Get transaction details
(safe, to, value, data, operation, proposer, nonce, txId) = pool.getTxDetails(txHash);
// Get pending transactions
bytes32[] memory pending = pool.getPendingTxHashes(safe, offset, limit);// Add address to Safe's address book (only Safe can call)
pool.addAddressBookEntry(safe, walletAddress, "Recipient Name");
// Remove address from address book
pool.removeAddressBookEntry(safe, walletAddress);
// Get all address book entries
IAddressBookManager.AddressBookEntry[] memory entries = pool.getAddressBookEntries(safe);// Enable delegate calls for a Safe
pool.setDelegateCallEnabled(safe, true);
// Add allowed delegate call target
pool.addDelegateCallTarget(safe, targetAddress);
// Check if delegate calls are enabled
bool enabled = pool.isDelegateCallEnabled(safe);// Add trusted contract (bypasses some validations)
pool.addTrustedContract(safe, tokenAddress, "Token Name");
// Check if contract is trusted
bool trusted = pool.isTrustedContract(safe, contractAddress);
// Get all trusted contracts
ITrustedContractManager.TrustedContractEntry[] memory contracts = pool.getTrustedContracts(safe);Set the SafeTxPoolRegistry as a Guard on your Safe:
// In your Safe wallet, call:
safe.setGuard(DEPLOYED_REGISTRY_ADDRESS);Benefits of using as Guard:
- ✅ Automatic transaction validation
- ✅ Address book enforcement
- ✅ Delegate call restrictions
- ✅ Automatic execution tracking
- ✅ Enhanced security for Safe transactions
For delegate call restrictions only:
SafeGuard guard = SafeGuard(DEPLOYED_GUARD_ADDRESS);
// Add allowed target for delegate calls
guard.addAllowedTarget(targetAddress);
// Set as guard on Safe
safe.setGuard(address(guard));If you were using an earlier version of SafeTxPool, the current modular architecture is 100% backward compatible:
// Same interface as before
SafeTxPoolRegistry pool = SafeTxPoolRegistry(DEPLOYED_REGISTRY_ADDRESS);
pool.proposeTx(...); // Same function signature
pool.addAddressBookEntry(...); // Same function signature
// All existing functions work identicallyUpgrade benefits:
- ✅ All contracts within 24KB size limit
- ✅ Enhanced security with proper access control
- ✅ Modular architecture for easier maintenance
- ✅ Same interface - no code changes required
Error: some contracts exceed the runtime size limit (EIP-170: 24576 bytes)
Solution: Use the refactored SafeTxPool deployment instead of the original.
# Clean and rebuild
forge clean
forge build
# Format code
forge fmt# Run specific test
forge test --match-contract SafeTxPool -vvv
# Run with gas reporting
forge test --gas-report- Ensure sufficient ETH balance for gas
- Check RPC URL is correct
- Verify private key format (no 0x prefix)
- For verification, ensure ETHERSCAN_API_KEY is set
- Documentation: See REFACTORING_GUIDE.md for detailed architecture information
- Issues: Report bugs on GitHub Issues
- Testing: Pre-commit hooks automatically run comprehensive checks before each commit
For detailed information about the refactored architecture, contract interactions, and migration guide, see:
- 📖 REFACTORING_GUIDE.md - Comprehensive refactoring documentation
- 🧪 test/ - Test files with usage examples
- 📜 script/ - Deployment scripts
This project is licensed under the MIT License - see the LICENSE file for details.