Proposal
A Proposal is a request to execute code as a one-time component according to the governance rules of the organization. The Proposal can be anything you like: attach/remove a microservice; attach/remove components; manage TreasuryManager funds; etc.
A Proposal follows this path:
Any address allowed for by the set governance rules can propose a Proposal.
The Proposal is created, and its references are saved in the Proposal Manager.
The Proposal can be voted on by holders of the token(s) supported by the Proposal Manager.
Voting methods and criteria for passing a Proposal are defined by the governance rules.
The Proposal ultimately terminates. If it passes, its code will be executed as a temporary component, and immediately jettisoned afterwards.
Create a Proposal
A Proposal is represented by a ProposalCodes
struct composed as follow:
ProposalCode
is a struct composed as follows:
address
location
-> if the Proposal smart contract is already deployed, this represents its address.bytes
bytecode
-> if the smart contract is not deployed, you can pass here the bytecode that will be deployed as the smart contract.
alsoTerminate
is a parameter indicating whether the Proposal should be created and terminated in the same transaction (true) or not (false).
alsoTerminate
as true can be used only if the Proposal Manager has set canTerminateAddresses
and validatorsAddresses
host only or if canTerminateAddresses
is not present (and therefore the proposal can always terminate) and validatorsAddresses
is not present (the proposal is always valid).
In all other cases alsoTerminate has
to be passed as false.
So, a ProposalCodes
--i.e, a Proposal--may consist of one or more ProposalCode
structs. It is not mandatory to have more than one, but there must be at least one.
The batchCreate
function--i.e, the function used to create more than one Proposal-- takes, as input, an array of ProposalCodes
parameters; multiple Proposals can be created at once in a single transaction.
The code of a ProposalCodes
, composed of one or more proposalCode
structs, will be executed if the Proposal passes.
In particular, all the smart contracts (represented by their location addresses) or bytecodes to deploy as smart contracts are executed following the order they were passed in the array as one-time components.
For example, a ProposalCodes
containing the three contracts [proposalCode2, proposalCode1 and proposalCode3] is a single Proposal, and will be executed in that arrayed order (2 -> 1 -> 3).
A proposalCode
can be managed in two different ways:
If, in the
proposalCode
, the address location is populated, the Proposal will execute the code of that passed smart contract. In this case, that contract must be deployed before creating the Proposal, so two transactions are required: the first to deploy the contract, the second to create the Proposal via the create function.If, in the
proposalCode
, thebytes bytecode
is populated, the Proposal Manager itself will deploy the contract (using thebytecode
) and then execute it. In this case, the contract that contains the code to execute has not yet been deployed, but only one transaction is needed, because the code of the contract and the Proposal creation are made in a single transaction.
If both the location and bytecode are populated, the Proposal will both take the deployed contract address (location) and also deploy the contract (bytecode).
When executing a Proposal, if the Proposal passed, the Proposal Manager will call each contract in the ProposalCodes
array.
Why Run Multiple Contracts In Sequence In a Proposal, and Not Just One?
It can be useful in certain situations.
For example, imagine root layer Org X. Org X clones Component A from a Factory to link it to itself. However, the code of Component A is customized for use by Org Y and in its current state doesn't comport with Org X. So Org X needs to clean up its State Manager before it can link Component A.
Obviously the contract that will carry out this cleanup must be executed before the link. Therefore, in the ProposalCodes
, that contract will be the first address, and the second will be Component A's contract address.
If Org X needs to also execute a third contract to efficiently use Component A, that will be the third address passed in the ProposalCodes
.
Keep in mind that you are not obliged by the ProposalManager syntax to insert multiple contracts.
For every created Proposal (and thus for each ProposalCodes
), a proposal id is generated. This is a bytes32
key that identifies that Proposal, and is known only to the Proposal Manager.
Every ProposalCodes
passed in a single batchCreate
function becomes a Proposal represented by a Proposal
struct.
Proposal struct
Once a Proposal--represented by a ProposalCodes
--is created through the batchCreate
function, it is represented by a Proposal
struct.
The Proposal Manager uses the struct to manage the Proposal in all of its main operations, such as voting on it, terminating it, executing it; and so on.
The Proposal
struct is composed of the following parameters:
address proposer
-> this is the address of the user/project/wallet that created the Proposal.address[] codeSequence
-> this represents the addresses of the contract(s) that will be executed if the Proposal passes. There can be one or more contracts, and they will be executed in the same sequence they are positioned in the array.uint256 creationBlock
-> this is the Proposal creation block.uint256 accept
-> this is the accept vote tally, weighted according to the defined_weights
rules.uint256 refuse
-> this is the refuse vote tally, weighted according to the defined_weights
rules.triggeringRules
-> this is the address of the contract representing the definedtriggeringRules
rules.address[] canTerminateAddress
-> these are the addresses of the contract(s) representing the definedcanTerminate
rules.address[] validatorsAddresses
-> these are the addresses of the contract(s) representing the definedvalidators
rules.bool validationPassed
-> this represents whether the Proposal passed (true) or not (false) according to the governance rules.uint256 terminationBlock
-> this is the Proposal termination block; i.e. the block when the terminate function is correctly executed.bytes
votingTokens
-> this represents, encoded as bytes parameter, thecollections
,objectIds
andweights
set to vote the Proposal. In the Root Proposal Manager,collections
,objectIds
andweights
are those of the local configuration set at the time of Proposal Manager initialization or changed at a later time viasetConfiguration
function.
Regarding those final two parameters, validationPassed
and terminationBlock
, there can be three possible outcomes after the terminate
function is called:
validationPassed
false andterminationBlock
populated -> the Proposal is refused (number of refuse votes > number of accept votes for example);terminationBlock
represents the number of the block when the terminate function is called.validationPassed
true andterminationBlock
populated -> the Proposal is accepted (number of accept votes > number of refuse votes, for example); theterminationBlock
represents the number of the block when the terminate function is called.validationPassed
true andterminationBlock
not populated -> the Proposal is accepted (number of accept votes > number of refuse votes, for example) but theterminationBlock
is empty, because the Proposal code cannot be executed. This can happen if for example, the Proposal code does not compile or if it runs out of gas. Remember that in the proposal there can be written anything at code level(!).
Last updated