Skip to content

Commit

Permalink
fix: allow governance execution without dao spoke contract
Browse files Browse the repository at this point in the history
  • Loading branch information
leric7 committed Feb 24, 2025
1 parent 0937065 commit 0ab8779
Show file tree
Hide file tree
Showing 8 changed files with 179 additions and 40 deletions.
7 changes: 7 additions & 0 deletions packages/core/contracts/governance/MetaHumanGovernor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import '@openzeppelin/contracts/governance/extensions/GovernorVotes.sol';
import '@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol';
import '@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol';
import '@openzeppelin/contracts/utils/Address.sol';
import 'hardhat/console.sol';
import './CrossChainGovernorCountingSimple.sol';
import './DAOSpokeContract.sol';
import './wormhole/IWormholeRelayer.sol';
Expand Down Expand Up @@ -299,6 +300,12 @@ contract MetaHumanGovernor is

uint256 spokeContractsLength = spokeContractsSnapshots[proposalId]
.length;

// If there are no spoke contracts, finish the collection phase
if (spokeContractsLength == 0) {
_finishCollectionPhase(proposalId);
}

// Get a price of sending the message back to hub
uint256 sendMessageToHubCost = quoteCrossChainMessage(chainId, 0);

Expand Down
9 changes: 9 additions & 0 deletions packages/core/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,15 @@ const config: HardhatUserConfig = {
spacing: 2,
format: 'json',
},
{
path: './abis/governance',
runOnCompile: true,
clear: true,
flat: true,
only: ['contracts/governance/[a-zA-Z]*.sol'],
spacing: 2,
format: 'json',
},
],
etherscan: {
apiKey: {
Expand Down
35 changes: 9 additions & 26 deletions packages/core/scripts/create-proposal.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import { ethers, network } from 'hardhat';
import { ethers } from 'hardhat';
import dotenv from 'dotenv';
import { getProposal } from './proposal';

dotenv.config();

async function main() {
const deployerPrivateKey = process.env.PRIVATE_KEY;
const governorAddress = process.env.GOVERNOR_ADDRESS || '';
const hmtTokenAddress = process.env.HMT_TOKEN_ADDRESS || '';
const description = process.env.DESCRIPTION || '';

if (
!deployerPrivateKey ||
!governorAddress ||
!hmtTokenAddress ||
!description
) {
if (!deployerPrivateKey || !governorAddress) {
throw new Error('One or more required environment variables are missing.');
}

Expand All @@ -25,25 +19,14 @@ async function main() {
deployerSigner
);

const hmToken = await ethers.getContractAt('IERC20', hmtTokenAddress);

const encodedCall = hmToken.interface.encodeFunctionData('transfer', [
await deployerSigner.getAddress(),
ethers.parseEther('1'),
]);

// Proposal data
const targets = [hmtTokenAddress];
const values = [0];
const calldatas = [encodedCall];

const proposal = await getProposal();
// Create proposal
const transactionResponse = await governanceContract.crossChainPropose(
targets,
values,
calldatas,
description,
{ value: ethers.parseEther('0.1') }
proposal.targets,
proposal.values,
proposal.calldatas,
proposal.description,
{ value: ethers.parseEther('0.01') }
);

await transactionResponse.wait();
Expand Down
30 changes: 17 additions & 13 deletions packages/core/scripts/deploy-hub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,27 @@ async function main() {
const [deployer] = await ethers.getSigners();

// HMTDeployment
const HMToken = await ethers.getContractFactory(
'contracts/HMToken.sol:HMToken'
);
const HMTokenContract = await HMToken.deploy(
1000000000,
'HUMAN Token',
18,
'HMT'
);
await HMTokenContract.waitForDeployment();
console.log('HMToken Address: ', await HMTokenContract.getAddress());
// const HMToken = await ethers.getContractFactory(
// 'contracts/HMToken.sol:HMToken'
// );
// const HMTokenContract = await HMToken.deploy(
// 1000000000,
// 'HUMAN Token',
// 18,
// 'HMT'
// );
// await HMTokenContract.waitForDeployment();
// console.log('HMToken Address: ', await HMTokenContract.getAddress());
const hmtTokenAddress = process.env.HMT_TOKEN_ADDRESS || '';
if (!hmtTokenAddress) {
throw new Error('HMT Token Address is missing');
}

//vHMT Deployment
// vHMT Deployment
const VHMToken = await ethers.getContractFactory(
'contracts/governance/vhm-token/VHMToken.sol:VHMToken'
);
const VHMTokenContract = await VHMToken.deploy(HMTokenContract.getAddress());
const VHMTokenContract = await VHMToken.deploy(hmtTokenAddress);
await VHMTokenContract.waitForDeployment();
console.log('VHMToken deployed to:', await VHMTokenContract.getAddress());

Expand Down
37 changes: 37 additions & 0 deletions packages/core/scripts/deploy-vhmt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* eslint-disable no-console */
import { ethers } from 'hardhat';
import dotenv from 'dotenv';
dotenv.config();

async function main() {
// HMTDeployment
// const HMToken = await ethers.getContractFactory(
// 'contracts/HMToken.sol:HMToken'
// );
// const HMTokenContract = await HMToken.deploy(
// 1000000000,
// 'HUMAN Token',
// 18,
// 'HMT'
// );
// await HMTokenContract.waitForDeployment();
// console.log('HMToken Address: ', await HMTokenContract.getAddress());

const hmtTokenAddress = process.env.HMT_TOKEN_ADDRESS || '';
if (!hmtTokenAddress) {
throw new Error('HMT Token Address is missing');
}

//vHMT Deployment
const VHMToken = await ethers.getContractFactory(
'contracts/governance/vhm-token/VHMToken.sol:VHMToken'
);
const VHMTokenContract = await VHMToken.deploy(hmtTokenAddress);
await VHMTokenContract.waitForDeployment();
console.log('VHMToken deployed to:', await VHMTokenContract.getAddress());
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
57 changes: 57 additions & 0 deletions packages/core/scripts/proposal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { ethers } from 'hardhat';
import dotenv from 'dotenv';

dotenv.config();

const abiCoder = ethers.AbiCoder.defaultAbiCoder();

export const getProposal = async () => {
const deployerPrivateKey = process.env.PRIVATE_KEY;
const governorAddress = process.env.GOVERNOR_ADDRESS || '';
const description = process.env.DESCRIPTION || '';

if (!deployerPrivateKey || !governorAddress || !description) {
throw new Error('One or more required environment variables are missing.');
}

const deployerSigner = new ethers.Wallet(deployerPrivateKey, ethers.provider);
const governanceContract = await ethers.getContractAt(
'MetaHumanGovernor',
governorAddress,
deployerSigner
);

const encodedCall = governanceContract.interface.encodeFunctionData(
'setVotingPeriod',
[86400]
);

// Proposal data
const targets = [governorAddress];
const values = [0];
const calldatas = [encodedCall];

// Example inputs (replace with actual values)
const descriptionHash = ethers.id(description);

// Encode the data similar to Solidity's `abi.encode`
const encodedData = abiCoder.encode(
['address[]', 'uint256[]', 'bytes[]', 'bytes32'],
[targets, values, calldatas, descriptionHash]
);

// Compute the keccak256 hash
const hash = ethers.keccak256(encodedData);

// Convert to uint256 (BigNumber)
const proposalId = ethers.toBigInt(hash);

return {
proposalId,
targets,
values,
calldatas,
description,
descriptionHash,
};
};
42 changes: 42 additions & 0 deletions packages/core/scripts/queue-proposal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { ethers } from 'hardhat';
import dotenv from 'dotenv';
import { getProposal } from './proposal';

dotenv.config();

async function main() {
const deployerPrivateKey = process.env.PRIVATE_KEY;
const governorAddress = process.env.GOVERNOR_ADDRESS || '';

if (!deployerPrivateKey || !governorAddress) {
throw new Error('One or more required environment variables are missing.');
}

const deployerSigner = new ethers.Wallet(deployerPrivateKey, ethers.provider);
const governanceContract = await ethers.getContractAt(
'MetaHumanGovernor',
governorAddress,
deployerSigner
);

const proposal = await getProposal();

const transactionResponse = await governanceContract.cancel(
proposal.targets,
proposal.values,
proposal.calldatas,
proposal.descriptionHash
);

console.log(transactionResponse);

await transactionResponse.wait();
console.log('Proposal queued:');
}

main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
2 changes: 1 addition & 1 deletion packages/core/scripts/update-spokes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ async function main() {
);

const spokeContracts = spokeAddresses.map((address, index) => ({
contractAddress: ethers.zeroPadBytes(governorAddress, 32),
contractAddress: ethers.zeroPadBytes(address, 32),
chainId: spokeChainIds[index],
}));

Expand Down

0 comments on commit 0ab8779

Please sign in to comment.