Governor hardhat testing

Hello,
I'd like to test the core functionalities of the Governor smart contract using hardhat automatic testing framework. I'm trying to emulate a full workflow but it constantly fails at vote counting, apparently no votes get registered.
I guess it has to do with the governance token distribution, for that I just used a mint.

// Distribute governance tokens
const votes = ethers.utils.parseUnits("100.0", 18);
await governanceToken.connect(userA).mint(userA.address, votes);
await governanceToken.connect(userB).mint(userB.address, votes);
await governanceToken.connect(userC).mint(userC.address, votes);

// Create new proposal
const grant = ethers.utils.parseUnits("500.0", 18);
const newProposal = {
            grantAmount: grant,
            transferCalldata: governanceToken.interface.encodeFunctionData('mint', [admin.address, grant]),
            descriptionHash: ethers.utils.id("Proposal #2: Give admin some tokens")
};

const proposeTx = await governor.connect(userA).propose(
            [governanceToken.address],
            [0],
            [newProposal.transferCalldata],
            newProposal.descriptionHash,
);

const tx = await proposeTx.wait();
await network.provider.send('evm_mine'); // wait 1 block before opening voting
const proposalId = tx.events.find((e) => e.event == 'ProposalCreated').args.proposalId;

// Let's vote
await governor.connect(userA).castVote(proposalId, VoteType.For);
await governor.connect(userB).castVote(proposalId, VoteType.For);
await governor.connect(userC).castVote(proposalId, VoteType.Against);
await governor.connect(admin).castVote(proposalId, VoteType.Abstain);

const votes = await governor.proposalVotes(proposalId);
assert(votes.forVotes.eq(2), "Vote count mismatch"); // < FAILS votes is an array and all its members, "forVotes", "againstVotes", etc are all 0

// Exec
await governor.execute(
            [governanceToken.address],
            [0],
            [newProposal.transferCalldata],
            newProposal.descriptionHash,
);

VoteType is defined in a separate file

export const VoteType: Enum('Against', 'For', 'Abstain'),

function Enum(...options) {
    return Object.fromEntries(options.map((key, i) => [key, i]))
}

Hi, welcome! :wave:

If you call getVotes(), what is the returning value? That is do you delegate the voting rights of the governance token to users?

1 Like

I tried running getVotes() on all users and it always returns 0 despite having minted and sent governance tokens to their accounts.
I don't get how delegation works. Looking at this line from the governance tests https://github.com/OpenZeppelin/openzeppelin-contracts/blob/8a775cd8d428595804bb1cc77a5e77f9c39f8c6d/test/token/ERC20/extensions/ERC20Votes.test.js#L121 it seems there is no "numeric" parameter for delegation, it's the user assigning all their voting power to another user. In my test case scenarios I want users to vote for themselves without specifying a delegator.

Can you please give me any insight on how to solve the error? Ty!

Hi, I think users should call delegate() at fist, and then users can vote.
For more details, you can have a look at this documentation ERC20Vote:

By default, token balance does not account for voting power. This makes transfers 
cheaper. The downside is that it requires users to delegate to themselves in order 
to activate checkpoints and have their voting power tracked. 

Okay, now it seems to work. Thanks!
Another issue, where does the proposalId go in execute? It is failing with 'Governor: unknown proposal id'

Hey Anelito,

I had the same problem you had. Turns out the propose description should be the whole text. It's only the execute description that needs to be hashed.

Hope this helps

1 Like