Skip to content

Vault Smart Contracts Documentation

Overview

The vault smart contracts provide secure, access-controlled management of treasury funds for DAOs and market collateral. They implement comprehensive security features including:

  • Access Control: Role-based permissions with authorized spenders
  • Spending Limits: Per-transaction and rate-limited spending controls
  • Emergency Controls: Pause/unpause functionality with guardian oversight
  • Multi-Token Support: Handle both ETH and ERC20 tokens
  • Transparent Accounting: Complete event logging for all operations

Contracts

TreasuryVault

The TreasuryVault contract manages DAO treasury funds with sophisticated access control and spending limits.

Key Features

  1. Deposit Management
  2. Accepts ETH via depositETH() or receive() fallback
  3. Accepts ERC20 tokens via depositERC20()
  4. Emits Deposit events for all deposits

  5. Withdrawal Control

  6. Only authorized spenders or owner can withdraw
  7. Enforces transaction limits (per-transaction caps)
  8. Enforces rate limits (spending limits per time period)
  9. Emits Withdrawal events with authorizer information

  10. Authorization Management

  11. Owner can authorize/revoke spenders
  12. Owner is automatically authorized
  13. Emits SpenderAuthorized and SpenderRevoked events

  14. Spending Limits

  15. Transaction limits: Maximum amount per single withdrawal
  16. Rate limits: Maximum amount per time period (e.g., 100 ETH per day)
  17. Independent limits for each token (ETH = address(0))
  18. Automatic period reset after timeframe expires

  19. Emergency Controls

  20. Owner or Guardian can pause withdrawals
  21. Only owner can unpause
  22. Deposits remain enabled during pause
  23. Guardian can be updated by owner

  24. Nullification Restrictions (NEW)

  25. Integrates with NullifierRegistry for address blocking
  26. Can block withdrawals to nullified addresses
  27. Optional enforcement (can be enabled/disabled)
  28. Emits WithdrawalBlockedByNullification when blocking
  29. See NULLIFIER_SYSTEM.md for full details

Usage Example

// Deploy and initialize
TreasuryVault vault = new TreasuryVault();
vault.initialize(daoAddress);

// Deposit funds
vault.depositETH{value: 10 ether}();

// Authorize a spender
vault.authorizeSpender(governorAddress);

// Set spending limits
vault.setTransactionLimit(address(0), 5 ether); // Max 5 ETH per tx
vault.setRateLimit(address(0), 1 days, 20 ether); // Max 20 ETH per day

// Authorized spender withdraws
vault.withdrawETH(recipient, 3 ether);

// Emergency pause if needed
vault.pause();

// Configure nullification (optional)
vault.setNullifierRegistry(nullifierRegistryAddress);
vault.setNullificationEnforcement(true);

// Check if address is nullified before withdrawal
bool blocked = vault.isRecipientNullified(recipient);

Security Considerations

  • ReentrancyGuard: Protects against reentrancy attacks on withdrawals
  • Ownable: Clear ownership model with transfer capabilities
  • Spending Limits: Prevent single large withdrawals or rapid fund drainage
  • Guardian Role: Allows emergency pause without full admin control
  • Event Logging: Complete audit trail of all operations
  • Nullification: Optional blocking of withdrawals to known-bad addresses

MarketVault

The MarketVault contract manages collateral for prediction markets with per-market accounting and access control.

Key Features

  1. Market Management
  2. Factory creates markets with unique IDs
  3. Each market has a designated manager
  4. Markets can be closed by their manager
  5. Emits MarketCreated and MarketClosed events

  6. Collateral Deposits

  7. Accepts ETH collateral per market via depositETHCollateral()
  8. Accepts ERC20 collateral per market via depositERC20Collateral()
  9. Tracks collateral separately for each market and token
  10. Only active markets can receive deposits

  11. Collateral Withdrawals

  12. Only market manager can withdraw from their market
  13. Cannot withdraw more than deposited collateral
  14. Supports both ETH and ERC20 tokens
  15. Emits CollateralWithdrawn events

  16. Access Control

  17. Factory can create new markets
  18. Market managers control their market's funds
  19. Owner can update managers and factory
  20. Owner can pause all operations

  21. Emergency Controls

  22. Owner can pause deposits and withdrawals
  23. Affects all markets simultaneously
  24. Resumable by owner only

Usage Example

// Deploy and initialize
MarketVault vault = new MarketVault();
vault.initialize(daoAddress, factoryAddress);

// Factory creates a market
vault.createMarket(1, managerAddress);

// Users deposit collateral
vault.depositETHCollateral{value: 5 ether}(1);

// Manager withdraws to settle market
vault.withdrawETHCollateral(1, winnerAddress, 5 ether);

// Close market when done
vault.closeMarket(1);

Security Considerations

  • Per-Market Isolation: Collateral tracked separately prevents cross-market contamination
  • Manager-Only Withdrawals: Only designated manager can move funds
  • Factory Control: Only authorized factory can create markets
  • ReentrancyGuard: Protects withdrawal operations
  • Active Market Check: Prevents operations on closed markets

Integration with Existing Contracts

DAOFactory Integration

The DAOFactory should deploy TreasuryVault instances for each DAO:

// In DAOFactory._deployDAOComponents()
address treasuryVaultImpl = address(new TreasuryVault());

// Clone and initialize for each DAO
address treasuryVaultClone = Clones.clone(treasuryVaultImpl);
TreasuryVault(treasuryVaultClone).initialize(futarchyGovernor);

// Authorize the governor to spend
TreasuryVault(treasuryVaultClone).authorizeSpender(futarchyGovernor);

// Set appropriate limits
TreasuryVault(treasuryVaultClone).setTransactionLimit(address(0), 100 ether);
TreasuryVault(treasuryVaultClone).setRateLimit(address(0), 1 days, 500 ether);

FutarchyGovernor Integration

Update FutarchyGovernor to interact with TreasuryVault:

// In executeProposal()
TreasuryVault(treasuryVault).withdrawETH(recipient, fundingAmount);
// or
TreasuryVault(treasuryVault).withdrawERC20(token, recipient, fundingAmount);

ConditionalMarketFactory Integration

Markets should use MarketVault for collateral:

// Deploy shared MarketVault
MarketVault marketVault = new MarketVault();
marketVault.initialize(owner, address(this));

// When creating a market
marketVault.createMarket(marketId, address(this));

// Accept collateral deposits
marketVault.depositETHCollateral{value: amount}(marketId);

// Settle market
marketVault.withdrawETHCollateral(marketId, winner, amount);
marketVault.closeMarket(marketId);

Testing

Both contracts have comprehensive test suites with >95% coverage:

  • TreasuryVault: 67 test cases covering all functionality
  • MarketVault: 67 test cases covering all functionality

Run tests:

npx hardhat test test/TreasuryVault.test.js
npx hardhat test test/MarketVault.test.js

Best Practices

  1. Set Reasonable Limits: Configure transaction and rate limits based on DAO size and activity
  2. Use Multisig for Owner: Treasury vault owner should be a multisig wallet
  3. Separate Guardian: Guardian should be different from owner for emergency responses
  4. Monitor Events: Watch for Deposit/Withdrawal events to track treasury activity
  5. Regular Reviews: Periodically review authorized spenders and limits
  6. Test Before Production: Always test limit configurations on testnet first

Security Audit Checklist

Before production deployment:

  • Verify all spending limits are appropriate
  • Confirm owner and guardian addresses
  • Test emergency pause functionality
  • Verify all authorized spenders are correct
  • Review event emissions for monitoring
  • Confirm ReentrancyGuard protection
  • Test with various token types
  • Verify upgrade/clone patterns work correctly
  • Run static analysis tools (Slither, Mythril)
  • Consider external security audit
  • Configure NullifierRegistry address if using nullification
  • Decide on nullification enforcement policy
  • Verify nullification admin roles are correctly assigned

Gas Optimization Notes

  • Uses SafeERC20 for safe token transfers
  • Minimal storage reads in hot paths
  • Events use indexed parameters for efficient filtering
  • ReentrancyGuard only on external state-changing functions
  • Efficient limit checking with early returns

Future Enhancements

Potential improvements for future versions:

  1. Multi-Signature Withdrawals: Require multiple approvals for large withdrawals
  2. Time-Locked Withdrawals: Delay large withdrawals for review period
  3. Whitelisted Recipients: Restrict withdrawals to approved addresses
  4. Budget Categories: Track spending by category/purpose
  5. Scheduled Payments: Automatic recurring payments
  6. Integration with Gnosis Safe: Native Safe module support
  7. Flash Loan Protection: Additional guards against flash loan attacks
  8. Oracle Integration: Dynamic limits based on token prices