Proposal Termination and Execution

The terminate function is used to terminate the Proposal and check the result of the vote; i.e, whether or not it passed, and therefore whether or not it will be executed:

function terminate(bytes32[] calldata proposalIds) external;

As input, the terminate function can take and attempt the termination of multiple Proposal ids.

The terminate function can be called on a Proposal that has the terminationBlock parameter (explained on the Proposal page) in its Proposal struct as unpopulated.

The terminate function has two steps:

  1. Proposal termination -> depending on the governance rules codified in the canTerminate contract(s), termination of the Proposal is attempted.

  2. Code execution -> if the first step is successful, i.e. the Proposal is terminated, a check is made to determine whether or not the Proposal has passed according to the governance rules codified in the validators contract(s).

If both steps are successful, execution of the Proposal code is attempted.

If the Proposal is not passed, the validationPassed and terminationBlock parameters of its struct are populated as false, and the block parameter is populated with the block when the terminate function was called.

If the Proposal is passed, the terminate function will call the tryExecute method to execute the Proposal code as a one-time Component. At this point, if the Proposal code is fully functional, the validationPassed and terminationBlock parameters are populated as true, and the block parameter is populated with the block at which the Proposal code is executed.

If the Proposal code faces any issues (i.e the contract does not compile, or the transaction runs out-of-gas, for example) the validationPassed parameter is populated as true, and the terminationBlock is not populated.

This design allows you to retry the running the Proposal again; if something fails during an attempt, the terminate call itself doesn't fail, but rather just saves a failed termination attempt. This means that if failure was merely circumstantial, success can be achieved by simply attempting execution once more, and the code can be validated.

Once this is achieved, the terminationBlock is populated correctly.

Every time the terminate function is called, regardless of whether the Proposal passes or not, an event is emitted. This can be useful on the frontend side to keep track of the Proposal result.

For example, if the terminate function is called 3 times, and therefore the tryExecute method is called 3 times, and each time the termination attempt fails, you have 3 events logged that state the Proposal code was not correctly deployed, and you can display this on the frontend.

Keep in mind that once the terminationBlock is populated, you can't call terminate on that Proposal anymore.

If the Proposal is passed and therefore its code can be executed, the terminate function calls the Proposal's execute method. This must contain the actual code that you want to execute.

See the guidelines section for more information.

Last updated