From c81c3decb4c5259cee5ec15f220691f10e55f33b Mon Sep 17 00:00:00 2001 From: taayyohh Date: Sat, 24 Aug 2024 11:12:20 -0400 Subject: [PATCH] feat: add emergency treasury initialization and recover funds function --- src/governance/treasury/ITreasury.sol | 10 ++++++++++ src/governance/treasury/Treasury.sol | 15 ++++++++++++++- src/manager/IManager.sol | 10 ++++++++++ src/manager/Manager.sol | 19 +++++++++++++++++++ 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/governance/treasury/ITreasury.sol b/src/governance/treasury/ITreasury.sol index 84e84a9..4772de4 100644 --- a/src/governance/treasury/ITreasury.sol +++ b/src/governance/treasury/ITreasury.sol @@ -27,6 +27,11 @@ interface ITreasury is IUUPS, IOwnable { /// @notice Emitted when the grace period is updated event GracePeriodUpdated(uint256 prevGracePeriod, uint256 newGracePeriod); + /// @notice Event emitted when ETH is withdrawn from the Treasury + /// @param to The address that received the ETH + /// @param amount The amount of ETH withdrawn + event RecoverFunds(address indexed to, uint256 amount); + /// /// /// ERRORS /// /// /// @@ -114,4 +119,9 @@ interface ITreasury is IUUPS, IOwnable { /// @notice Updates the grace period /// @param newGracePeriod The grace period function updateGracePeriod(uint256 newGracePeriod) external; + + /// @notice Allows the owner to withdraw ETH from the Treasury + /// @param to The address to send the withdrawn ETH to + /// @param amount The amount of ETH to withdraw + function recoverFunds(address payable to, uint256 amount) external; } diff --git a/src/governance/treasury/Treasury.sol b/src/governance/treasury/Treasury.sol index efdba99..d47af77 100644 --- a/src/governance/treasury/Treasury.sol +++ b/src/governance/treasury/Treasury.sol @@ -15,7 +15,7 @@ import { VersionedContract } from "../../VersionedContract.sol"; /// @title Treasury /// @author Rohan Kulkarni /// @notice A DAO's treasury and transaction executor -/// @custom:repo github.com/ourzora/nouns-protocol +/// @custom:repo github.com/ourzora/nouns-protocol /// Modified from: /// - OpenZeppelin Contracts v4.7.3 (governance/TimelockController.sol) /// - NounsDAOExecutor.sol commit 2cbe6c7 - licensed under the BSD-3-Clause license. @@ -276,4 +276,17 @@ contract Treasury is ITreasury, VersionedContract, UUPS, Ownable, ProposalHasher // Ensure the new implementation is a registered upgrade if (!manager.isRegisteredUpgrade(_getImplementation(), _newImpl)) revert INVALID_UPGRADE(_newImpl); } + + /// @notice Allows the owner to withdraw ETH from the Treasury + /// @param to The address to send the withdrawn ETH to + /// @param amount The amount of ETH to withdraw + function recoverFunds(address payable to, uint256 amount) external onlyOwner { + require(to != address(0), "Cannot withdraw to the zero address"); + require(amount <= address(this).balance, "Insufficient balance"); + + (bool success, ) = to.call{ value: amount }(""); + require(success, "Transfer failed"); + + emit RecoverFunds(to, amount); + } } diff --git a/src/manager/IManager.sol b/src/manager/IManager.sol index 173bed2..eeca90b 100644 --- a/src/manager/IManager.sol +++ b/src/manager/IManager.sol @@ -170,4 +170,14 @@ interface IManager is IUUPS, IOwnable { /// @param baseImpl The base implementation address /// @param upgradeImpl The upgrade implementation address function removeUpgrade(address baseImpl, address upgradeImpl) external; + + /// @notice Allows the owner to initialize a Treasury with an arbitrary EOA as the governor + /// @param treasury The address of the Treasury contract to be initialized + /// @param governor The EOA to be set as the governor of the Treasury + /// @param timelockDelay The timelock delay to be set in the Treasury + function initializeTreasuryWithGovernor( + address treasury, + address governor, + uint256 timelockDelay + ) external; } diff --git a/src/manager/Manager.sol b/src/manager/Manager.sol index 5a1f243..2f5c0ec 100644 --- a/src/manager/Manager.sol +++ b/src/manager/Manager.sol @@ -293,4 +293,23 @@ contract Manager is IManager, VersionedContract, UUPS, Ownable, ManagerStorageV1 /// @dev This function is called in `upgradeTo` & `upgradeToAndCall` /// @param _newImpl The new implementation address function _authorizeUpgrade(address _newImpl) internal override onlyOwner {} + + + /// @notice Allows the owner to initialize a Treasury with an arbitrary EOA as the governor + /// for the purposes of recovering funds sent to the treasury on a chain where it doesn't exist + /// @param treasury The address of the Treasury contract to be initialized + /// @param governor The EOA to be set as the governor of the Treasury + /// @param timelockDelay The timelock delay to be set in the Treasury + function emergencyInitializeTreasuryWithGovernor( + address treasury, + address governor, + uint256 timelockDelay + ) external onlyOwner { + // Ensure the Treasury is not already initialized + require(treasury != address(0), "Treasury address cannot be zero"); + require(governor != address(0), "Governor address cannot be zero"); + + // Call the initialize function on the Treasury + ITreasury(treasury).initialize(governor, timelockDelay); + } }