diff --git a/README.md b/README.md index 3966951..5edb293 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,11 @@ ## Deployments ```sh - Depoist: 0x46275d29113f065c2aac262f34C7a3d8a8B7377D - gRING: 0xdafa555e2785DC8834F4Ea9D1ED88B6049142999 - Hub: 0xa4fFAC7A5Da311D724eD47393848f694Baee7930 + Depoist: 0x46275d29113f065c2aac262f34C7a3d8a8B7377D + gRING: 0xdafa555e2785DC8834F4Ea9D1ED88B6049142999 + Hub: 0xa4fFAC7A5Da311D724eD47393848f694Baee7930 + RingDAO: 0x52cDD25f7C83c335236Ce209fA1ec8e197E96533 + Timelock: 0x4DCf0f14cC58fc2Bf313e70573dDB7309523bb23 ``` diff --git a/script/Tally.s.sol b/script/Tally.s.sol new file mode 100644 index 0000000..3eb8262 --- /dev/null +++ b/script/Tally.s.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Script} from "forge-std/Script.sol"; +import {safeconsole} from "forge-std/safeconsole.sol"; +import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol"; +import {Options} from "openzeppelin-foundry-upgrades/Options.sol"; + +import {RingDAOTimelockController} from "../src/governance/RingDAOTimelockController.sol"; +import {RingDAO, IVotes, TimelockControllerUpgradeable} from "../src/governance/RingDAO.sol"; + +contract TallyScript is Script { + address gRING = 0xdafa555e2785DC8834F4Ea9D1ED88B6049142999; + address timelock = 0x4DCf0f14cC58fc2Bf313e70573dDB7309523bb23; + + function run() public { + vm.startBroadcast(); + + // deploy RingDAO + address ringDAO_PROXY = Upgrades.deployTransparentProxy( + "RingDAO.sol:RingDAO", + timelock, + abi.encodeCall( + RingDAO.initialize, + ( + IVotes(gRING), + TimelockControllerUpgradeable(payable(timelock)), + 1 days, + 2 weeks, + 1_000_000 * 1e18, + "RingDAO" + ) + ) + ); + safeconsole.log("RingDAO: ", ringDAO_PROXY); + safeconsole.log("RingDAO_Logic: ", Upgrades.getImplementationAddress(ringDAO_PROXY)); + + // deploy RingDAOTimelock + address[] memory roles = new address[](1); + roles[0] = ringDAO_PROXY; + address timelock_PROXY = Upgrades.deployTransparentProxy( + "RingDAOTimelockController.sol:RingDAOTimelockController", + timelock, + abi.encodeCall(RingDAOTimelockController.initialize, (1 days, roles, roles, address(0))) + ); + safeconsole.log("Timelock: ", timelock_PROXY); + safeconsole.log("Timelock_Logic: ", Upgrades.getImplementationAddress(timelock_PROXY)); + + require(timelock == timelock_PROXY, "!timelock"); + + vm.stopBroadcast(); + } +} diff --git a/src/governance/RingDAO.sol b/src/governance/RingDAO.sol new file mode 100644 index 0000000..47858b7 --- /dev/null +++ b/src/governance/RingDAO.sol @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.20; + +import "@openzeppelin/contracts-upgradeable/governance/GovernorUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/governance/extensions/GovernorSettingsUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/governance/extensions/GovernorCountingSimpleUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/governance/extensions/GovernorVotesUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/governance/extensions/GovernorTimelockControlUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +contract RingDAO is + Initializable, + GovernorUpgradeable, + GovernorSettingsUpgradeable, + GovernorCountingSimpleUpgradeable, + GovernorVotesUpgradeable, + GovernorTimelockControlUpgradeable +{ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize( + IVotes token, + TimelockControllerUpgradeable timelock, + uint48 initialVotingDelay, + uint32 initialVotingPeriod, + uint256 initialProposalThreshold, + string memory name + ) public initializer { + __Governor_init(name); + __GovernorSettings_init(initialVotingDelay, initialVotingPeriod, initialProposalThreshold); + __GovernorCountingSimple_init(); + __GovernorVotes_init(token); + __GovernorTimelockControl_init(timelock); + } + + // The following functions are overrides required by Solidity. + + function quorum(uint256) public view virtual override returns (uint256) { + return 40_000_000 * 1e18; + } + + function votingDelay() public view override(GovernorUpgradeable, GovernorSettingsUpgradeable) returns (uint256) { + return super.votingDelay(); + } + + function votingPeriod() public view override(GovernorUpgradeable, GovernorSettingsUpgradeable) returns (uint256) { + return super.votingPeriod(); + } + + function state(uint256 proposalId) + public + view + override(GovernorUpgradeable, GovernorTimelockControlUpgradeable) + returns (ProposalState) + { + return super.state(proposalId); + } + + function proposalNeedsQueuing(uint256 proposalId) + public + view + override(GovernorUpgradeable, GovernorTimelockControlUpgradeable) + returns (bool) + { + return super.proposalNeedsQueuing(proposalId); + } + + function proposalThreshold() + public + view + override(GovernorUpgradeable, GovernorSettingsUpgradeable) + returns (uint256) + { + return super.proposalThreshold(); + } + + function _queueOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(GovernorUpgradeable, GovernorTimelockControlUpgradeable) returns (uint48) { + return super._queueOperations(proposalId, targets, values, calldatas, descriptionHash); + } + + function _executeOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(GovernorUpgradeable, GovernorTimelockControlUpgradeable) { + super._executeOperations(proposalId, targets, values, calldatas, descriptionHash); + } + + function _cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(GovernorUpgradeable, GovernorTimelockControlUpgradeable) returns (uint256) { + return super._cancel(targets, values, calldatas, descriptionHash); + } + + function _executor() + internal + view + override(GovernorUpgradeable, GovernorTimelockControlUpgradeable) + returns (address) + { + return super._executor(); + } +} diff --git a/src/governance/RingDAOTimelockController.sol b/src/governance/RingDAOTimelockController.sol new file mode 100644 index 0000000..b4bf180 --- /dev/null +++ b/src/governance/RingDAOTimelockController.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.20; + +import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import "@openzeppelin/contracts-upgradeable/governance/TimelockControllerUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol"; + +contract RingDAOTimelockController is + Initializable, + TimelockControllerUpgradeable, + AccessControlEnumerableUpgradeable +{ + function initialize(uint256 minDelay, address[] memory proposers, address[] memory executors, address admin) + public + initializer + { + __TimelockController_init(minDelay, proposers, executors, admin); + __AccessControlEnumerable_init(); + } + + function _grantRole(bytes32 role, address account) + internal + override(AccessControlUpgradeable, AccessControlEnumerableUpgradeable) + returns (bool) + { + return super._grantRole(role, account); + } + + function _revokeRole(bytes32 role, address account) + internal + override(AccessControlUpgradeable, AccessControlEnumerableUpgradeable) + returns (bool) + { + return super._revokeRole(role, account); + } + + function supportsInterface(bytes4 interfaceId) + public + view + virtual + override(TimelockControllerUpgradeable, AccessControlEnumerableUpgradeable) + returns (bool) + { + return super.supportsInterface(interfaceId); + } +}