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 e42fa3f
Show file tree
Hide file tree
Showing 4 changed files with 72 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);
}
}
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 deployAndInitializeTreasuryUsingCreate2(
bytes memory bytecode,
bytes32 salt,
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 deployAndInitializeTreasuryUsingCreate2(
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);
}
}

0 comments on commit e42fa3f

Please sign in to comment.