Skip to content

Commit

Permalink
feat: add emergency treasury initialization and recover funds function
Browse files Browse the repository at this point in the history
  • Loading branch information
taayyohh committed Aug 24, 2024
1 parent 98b65e2 commit c81c3de
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 1 deletion.
10 changes: 10 additions & 0 deletions src/governance/treasury/ITreasury.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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 ///
/// ///
Expand Down Expand Up @@ -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;
}
15 changes: 14 additions & 1 deletion src/governance/treasury/Treasury.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
}
}
10 changes: 10 additions & 0 deletions src/manager/IManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
19 changes: 19 additions & 0 deletions src/manager/Manager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

0 comments on commit c81c3de

Please sign in to comment.