Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add emergency treasury initialization and recover funds function #134

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
}
13 changes: 13 additions & 0 deletions src/manager/IManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,17 @@ 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 Deploys and initializes a Treasury contract using CREATE2 with the specified bytecode, salt, and initialization parameters.
/// @param bytecode The bytecode of the Treasury contract to deploy.
/// @param salt The salt used to create the deterministic contract address.
/// @param governor The address to set as the governor of the Treasury.
/// @param timelockDelay The timelock delay to be set in the Treasury.
/// @return treasury The address of the deployed Treasury contract.
function deployAndInitializeTreasury(
bytes32 salt,
bytes memory bytecode,
address governor,
uint256 timelockDelay
) external returns (address treasury);
}
35 changes: 35 additions & 0 deletions src/manager/Manager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -293,4 +293,39 @@ 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 Deploy a Treasury contract using CREATE2 at a predetermined address and initialize it
/// @param salt The salt used for CREATE2 deployment
/// @param bytecode The bytecode of the Treasury contract
/// @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 deployAndInitializeTreasury(
bytes32 salt,
bytes memory bytecode,
address governor,
uint256 timelockDelay
) external onlyOwner returns (address treasury) {
// Compute the address where the contract will be deployed
address predictedAddress = address(uint160(uint256(keccak256(abi.encodePacked(
bytes1(0xff),
address(this),
salt,
keccak256(bytecode)
)))));

// Deploy the Treasury contract using CREATE2
assembly {
treasury := create2(0, add(bytecode, 0x20), mload(bytecode), salt)
if iszero(extcodesize(treasury)) {
revert(0, 0)
}
}

require(treasury == predictedAddress, "Unexpected deployed address");

// Initialize the Treasury
ITreasury(treasury).initialize(governor, timelockDelay);
}
}
Loading