Question regarding the governor propose

Hi OpenZeppelin community, I just started to learn writing contracts, and trying to build a customized DAO. So the easiest option for me is use the contract wizard to create my own governor, which I did.

Now when I'm testing it, I run into a silly problem in my tests. I created a propose transaction, and I can even print out the proposal transaction in javascript, but it doesn't contain a propose id which I can then refer to check its state and votes.

My questions are:

  1. The API says propose function returns a uint256, which is the propose id, but why did I get an object contains everything but its id?

  2. I was reading about successfully calling propose will emit an event called ProposalCreated , what's the best practice to make use of the emitted event?

  3. Since there is no correlation with propose function and execute function, can I make them do two separate things in my DAO? (Not trying to fool people, but I might have a valid use case).

:1234: Code to reproduce

Definition of my governor

contract MyGovernor is Governor, GovernorSettings, GovernorCountingSimple, GovernorVotes, GovernorVotesQuorumFraction {
    constructor(ERC20Votes _token)
        Governor("MyGovernor")
        GovernorSettings(1 /* 1 block */, 45818 /* 1 week */, 0)
        GovernorVotes(_token)
        GovernorVotesQuorumFraction(2)
    {}

js test to create a proposal

const proposal_tx = await governor.propose(
        [targetAddr],
        [0],
        [calldata],
        "my initial proposal"
    );

proposal_tx.wait(2)

I tried to print the proposal_tx : console.log(proposal_tx):

{
  hash: '0x7caae437c8325b2e715f6d322457d1dcf57abf6cd17dc2637b4ede139d269906',
  type: 2,
  accessList: [],
  blockHash: '0x8420a0da1dcd282b68ec662091c72c71062f504208cc3dac6f454cbb6040e7df',
  blockNumber: 16,
  transactionIndex: 0,
  confirmations: 1,
  from: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
  gasPrice: BigNumber { value: "1139728473" },
  maxPriorityFeePerGas: BigNumber { value: "1000000000" },
  maxFeePerGas: BigNumber { value: "1279456946" },
  gasLimit: BigNumber { value: "29027800" },
  to: '0x8A791620dd6260079BF849Dc5567aDC3F2FdC318',
  value: BigNumber { value: "0" },
  nonce: 14,
  data: '0x7d5e81e2000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000165878a594ca255338adfa4d48449f69242eb8f000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000246e6413b800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000227365742064616f2073756767657374656420707269636520666f72206974656d2031000000000000000000000000000000000000000000000000000000000000',
  r: '0xf91296e0d52244b67c87bf54fa5946e12519bd8917a5cead0eecc30fa4dba0d2',
  s: '0x317bdc57b1c1323d63b7127ccacd04d4f5af9a126542dd754b74288828c760df',
  v: 1,
  creates: null,
  chainId: 1337,
  wait: [Function (anonymous)]
}

But when I try to print the proposal id with : console.log(proposal_tx.return_value)

undefined

:computer: Environment

I used hardhat

Great question!

Return values are not available for transactions, they are only available for view methods. So while the function has a return value, you can't get it from the transaction receipt.

The expected way to retrieve the transaction id is to get it from the events. You will find the decoded ProposalCreated event in the transaction receipt, i.e. the return value of await proposal_tx.wait(). You can extract the id from there.

Another way to get the id is to use governor.hashProposal.


If I understand the question correctly, I don't think this is possible. Can you expand on what you want and what is your use case?

Thank you so much sir for your reply. It is very helpful!

I tried something like this:

    const proposal_tx = await governor.propose(
        [targetAddr],
        [0],
        [calldata],
        "do something"
    );

    const receipt = await proposal_tx.wait(1)
    const proposalId = receipt.events[0].args.proposalId

    console.log(receipt.events[0].args.proposalId)

Which worked, and give me back the proposal Id.

However I have another problem here, to be more specific, my governor has a delay period set to 1:

contract MyGovernor is Governor, GovernorSettings, GovernorCountingSimple, GovernorVotes, GovernorVotesQuorumFraction {
    constructor(ERC20Votes _token)
        Governor("MyGovernor")
        GovernorSettings(1 /* 1 block */, 45818 /* 1 week */, 0)
        GovernorVotes(_token)
        GovernorVotesQuorumFraction(2)

When I try to fetch the state of current proposal using the proposal Id I got, it returns 0, which I think means the proposal is Pending.

console.log(await governor.state(proposalId))

Can you help me understand why is that? Do I need to pass a bigger number to the proposal_tx.wait() function to be larger than the delay period config of my governor (which I tried and failed)?

You want to have a few blocks mined, after your proposal is submitted, so that you enter the voting phase.

If you are on a public networks, you should just have to wait. On local testnets, you may want to execute other transactions, or ask the chain to mine an empty block.

Thanks man, so for a hardhat local network, when I working on my javascript test, after I create the proposal:

 const proposal_tx = await governor.propose(
        [targetAddr],
        [0],
        [calldata],
        "do something"
    );

Then I should do something like this in my test (hardhat based) for the blocks to be mined right?

await network.provider.send("evm_increaseTime", [3600])

evm_increaseTime doesn't mine a block. You need to use evm_mine for that.