-
Notifications
You must be signed in to change notification settings - Fork 1
feat: Governor basic #13
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
Changes from all commits
43fbcdf
e7bf9cd
a1655a6
a73105d
f2a1190
85206ba
ee645b7
4bbd22c
3b43ee6
50d74c6
b42b722
86b557b
7a71e55
cae8e4e
d822c0f
25d1ea6
73ba30e
10f5cf8
2a0e5a5
747bfa1
9ae78da
e876e09
9a53cfd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
{ | ||
"solidity.compileUsingRemoteVersion": "v0.8.24+commit.e11b9ed9" | ||
"solidity.compileUsingRemoteVersion": "v0.8.24+commit.e11b9ed9", | ||
"editor.defaultFormatter": "esbenp.prettier-vscode", | ||
"editor.formatOnSave": true | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; | ||
Check warning on line 3 in contracts/DaoTimelockUpgradable.sol
|
||
import "@openzeppelin/contracts-upgradeable/governance/TimelockControllerUpgradeable.sol"; | ||
Check warning on line 4 in contracts/DaoTimelockUpgradable.sol
|
||
|
||
contract DaoTimelockUpgradable is | ||
UUPSUpgradeable, | ||
TimelockControllerUpgradeable | ||
{ | ||
function initialize( | ||
uint256 minDelay, | ||
address[] memory proposers, | ||
address[] memory executors, | ||
address admin | ||
) public initializer { | ||
__UUPSUpgradeable_init(); | ||
__AccessControl_init(); | ||
__TimelockController_init(minDelay, proposers, executors, admin); | ||
} | ||
function _authorizeUpgrade( | ||
address newImplementation | ||
) internal override onlyRole(DEFAULT_ADMIN_ROLE) {} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
import "@openzeppelin/contracts-upgradeable/governance/GovernorUpgradeable.sol"; | ||
Check warning on line 4 in contracts/Governor.sol
|
||
import "@openzeppelin/contracts-upgradeable/governance/extensions/GovernorSettingsUpgradeable.sol"; | ||
Check warning on line 5 in contracts/Governor.sol
|
||
import "@openzeppelin/contracts-upgradeable/governance/extensions/GovernorCountingSimpleUpgradeable.sol"; | ||
Check warning on line 6 in contracts/Governor.sol
|
||
import "@openzeppelin/contracts-upgradeable/governance/extensions/GovernorStorageUpgradeable.sol"; | ||
Check warning on line 7 in contracts/Governor.sol
|
||
import "@openzeppelin/contracts-upgradeable/governance/extensions/GovernorVotesUpgradeable.sol"; | ||
Check warning on line 8 in contracts/Governor.sol
|
||
import "@openzeppelin/contracts-upgradeable/governance/extensions/GovernorVotesQuorumFractionUpgradeable.sol"; | ||
Check warning on line 9 in contracts/Governor.sol
|
||
import "@openzeppelin/contracts-upgradeable/governance/extensions/GovernorTimelockControlUpgradeable.sol"; | ||
Check warning on line 10 in contracts/Governor.sol
|
||
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; | ||
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; | ||
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; | ||
|
||
contract RootDao is | ||
Initializable, | ||
GovernorUpgradeable, | ||
GovernorSettingsUpgradeable, | ||
GovernorCountingSimpleUpgradeable, | ||
GovernorStorageUpgradeable, | ||
GovernorVotesUpgradeable, | ||
GovernorVotesQuorumFractionUpgradeable, | ||
GovernorTimelockControlUpgradeable, | ||
OwnableUpgradeable, | ||
UUPSUpgradeable | ||
{ | ||
/// @custom:oz-upgrades-unsafe-allow constructor | ||
constructor() { | ||
_disableInitializers(); | ||
} | ||
|
||
function initialize( | ||
IVotes voteToken, | ||
TimelockControllerUpgradeable timelockController, | ||
address initialOwner | ||
) public initializer { | ||
__Governor_init("RootDao"); | ||
__GovernorSettings_init(7200 /* 1 day */, 50400 /* 1 week */, 10 * 10 ** 18); | ||
__GovernorCountingSimple_init(); | ||
__GovernorStorage_init(); | ||
__GovernorVotes_init(voteToken); | ||
__GovernorVotesQuorumFraction_init(4); | ||
__GovernorTimelockControl_init(timelockController); | ||
__Ownable_init(initialOwner); | ||
__UUPSUpgradeable_init(); | ||
} | ||
|
||
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {} | ||
|
||
// The following functions are overrides required by Solidity. | ||
|
||
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 quorum( | ||
uint256 blockNumber | ||
) public view override(GovernorUpgradeable, GovernorVotesQuorumFractionUpgradeable) returns (uint256) { | ||
return super.quorum(blockNumber); | ||
} | ||
|
||
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 _propose( | ||
address[] memory targets, | ||
uint256[] memory values, | ||
bytes[] memory calldatas, | ||
string memory description, | ||
address proposer | ||
) internal override(GovernorUpgradeable, GovernorStorageUpgradeable) returns (uint256) { | ||
return super._propose(targets, values, calldatas, description, proposer); | ||
} | ||
|
||
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(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/** | ||
* @title RIF Token Faucet | ||
* @author IOV Labs | ||
* @notice Original source code is taken from the repository: | ||
* https://github.com/riflabs/rif-faucet/blob/master/contracts/TokenFaucet.sol | ||
*/ | ||
|
||
pragma solidity ^0.8.20; | ||
|
||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | ||
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; | ||
|
||
contract TokenFaucet is Ownable { | ||
IERC20 public immutable tokenContract; | ||
|
||
mapping(address => uint) cannotDispenseUntil; | ||
|
||
uint256 public dispenseValue = 10 * 10 ** 18; // 10 tRIFs | ||
uint256 public dispenceFrequency = 1 hours; | ||
|
||
event DispenceFrequencyChanged(address changer, uint256 oldValue, uint256 newValue); | ||
event DispenceValueChanged(address changer, uint256 oldValue, uint256 newValue); | ||
|
||
modifier canDispense(address to) { | ||
require(cannotDispenseUntil[to] < block.timestamp, "CANNOT DISPENSE MORE THAN 1 TIME PER HOUR"); | ||
_; | ||
} | ||
|
||
constructor(IERC20 rifToken) Ownable(msg.sender) { | ||
tokenContract = rifToken; | ||
} | ||
|
||
function recover() public returns (bool) { | ||
uint256 totalAmount = tokenContract.balanceOf(address(this)); | ||
return tokenContract.transfer(owner(), totalAmount); | ||
} | ||
|
||
function dispense(address to) public canDispense(to) returns (bool) { | ||
cannotDispenseUntil[to] = block.timestamp + dispenceFrequency; | ||
return tokenContract.transfer(to, dispenseValue); | ||
} | ||
|
||
function setDispenseValue(uint256 value) public onlyOwner { | ||
emit DispenceValueChanged(msg.sender, dispenseValue, value); | ||
dispenseValue = value; | ||
} | ||
|
||
function setDispenseFrequency(uint256 freqSeconds) public onlyOwner { | ||
emit DispenceFrequencyChanged(msg.sender, dispenceFrequency, freqSeconds); | ||
dispenceFrequency = freqSeconds; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import hre, { ethers, upgrades } from 'hardhat' | ||
import { GovernorTimelockControlUpgradeable, RootDao } from '../typechain-types' | ||
|
||
export const deployGovernor = async (tokenAddress: string, deployerAddress: string) => { | ||
const RootDAOFactory = await ethers.getContractFactory('RootDao') | ||
const TimelockFactory = await ethers.getContractFactory('DaoTimelockUpgradable') | ||
// TODO: figure out why it allows to put only a single argument | ||
const timelock = (await upgrades.deployProxy(TimelockFactory, [1, [], [], ethers.ZeroAddress], { | ||
initializer: 'initialize(uint256,address[],address[],address)', | ||
kind: 'uups', | ||
timeout: 0, | ||
})) as unknown as GovernorTimelockControlUpgradeable | ||
|
||
const rootDAOGovernor = (await upgrades.deployProxy( | ||
RootDAOFactory, | ||
[tokenAddress, await timelock.getAddress(), deployerAddress], | ||
{ | ||
initializer: 'initialize', | ||
kind: 'uups', | ||
timeout: 0, | ||
}, | ||
)) as unknown as RootDao | ||
|
||
const rootDAOContact = await rootDAOGovernor.waitForDeployment() | ||
|
||
console.log(`Deployed Governor on ${hre.network.name} with address ${await rootDAOContact.getAddress()}`) | ||
|
||
return rootDAOContact | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers' | ||
import hre, { ethers } from 'hardhat' | ||
|
||
export const deployRif = async (deployer: SignerWithAddress) => { | ||
const rifToken = await ethers.deployContract('RIFToken') | ||
await rifToken.waitForDeployment() | ||
|
||
const rifAddress = await rifToken.getAddress() | ||
|
||
console.log(`Deployed RIF Token on ${hre.network.name} with address ${rifAddress}`) | ||
|
||
// `setAuthorizedManagerContract` transfers all tokens to Deployer | ||
const tx1 = await rifToken.setAuthorizedManagerContract(deployer.address) | ||
await tx1.wait() | ||
console.log(`All RIF tokens transferred to ${deployer.address}`) | ||
|
||
// close distribution | ||
const block = await ethers.provider.getBlock('latest') | ||
const now = Math.round(Date.now() / 1000) | ||
const tx2 = await rifToken.closeTokenDistribution(block?.timestamp ?? now) | ||
await tx2.wait() | ||
console.log(`RIF distribution closed`) | ||
|
||
const tokenFaucet = await (await ethers.deployContract('TokenFaucet', [rifToken])).waitForDeployment() | ||
|
||
// transfer half of RIFs to the faucet | ||
const rifSupply = 10n ** 27n | ||
|
||
const tx3 = await rifToken.transfer(await tokenFaucet.getAddress(), rifSupply / 2n) | ||
await tx3.wait() | ||
console.log(`RIF tokens transferred to the Faucet`) | ||
|
||
console.log(`Deployed Token Faucet on ${hre.network.name} with address ${await tokenFaucet.getAddress()}`) | ||
|
||
return { rifToken, rifAddress, tokenFaucet } | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of doing this I would recommend using optimizer with 200 runs because otherwise you won't be able to deploy it on Rootstock!