-
Notifications
You must be signed in to change notification settings - Fork 152
docs (governance): update interactions and overview #1145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2bdfe1b
ea3c9ee
a257ff9
f74892b
4f2ab22
dda38d8
a90f711
65ddd1e
749d2b7
bbcd78d
1b33881
24a6491
2f6f6a0
20581df
eb77ec4
21a2cbf
37ebcdb
17d787b
283e1b7
d63b7ff
4208eaf
c0ed157
c0e65eb
9893040
20d57a6
ac32312
cc97305
d64eff3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,7 +7,7 @@ title: Governance interaction | |
|
|
||
| ### Introduction | ||
|
|
||
| The interaction with the governance system smartcontract is done through correctly formatted transactions to submit actions and through the usage of the vm-query REST API calls for reading the proposal(s) status. | ||
| The interaction with the governance system smartcontract is done through correctly formatted transactions to submit actions and through the usage of the vm-query REST API calls for reading the proposal(s) status. | ||
|
|
||
| [comment]: # (mx-context-auto) | ||
|
|
||
|
|
@@ -19,7 +19,7 @@ The proposal creation transaction has the following parameters: | |
| GovernanceProposalTransaction { | ||
| Sender: <account address of the wallet that creates the proposal> | ||
| Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqrlllsrujgla | ||
| Value: 1000 EGLD | ||
| Value: 500 EGLD | ||
| GasLimit: 51000000 | ||
| Data: "proposal" + | ||
| "@<identifier>" + | ||
|
|
@@ -28,9 +28,13 @@ GovernanceProposalTransaction { | |
| } | ||
| ``` | ||
|
|
||
| The value parameter represents the mandatory proposal submission deposit of 500 EGLD. | ||
|
|
||
| The proposal identifier is a hex string containing exactly 40 characters. Usually, this can be a git commit hash on which the proposal is made but can be any other identifier string. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think something like this is a bit more accurate: |
||
|
|
||
| The starting & ending epochs should be an even-length hex string containing the starting epoch and the ending epoch. During this time frame the votes can be cast. | ||
| The starting & ending epochs should be an even-length hex string containing the starting epoch and the ending epoch. During this time frame, lasting 10 days, the votes can be cast. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. During this time frame,
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we rename days to Unbound Period duration, which is 10 Epochs on Mainnet |
||
|
|
||
| >**Note:** When providing the starting epoch, it should be taken into consideration that the governance contract enforcing a configured maximum gap of 30 epochs between the current epoch and the proposal’s starting epoch. | ||
|
|
||
| After issuing the proposal, there is a log event generated having the `proposal` identifier that will contain the following encoded topics: | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. replace identifier with commit hash bellow |
||
|
|
@@ -43,7 +47,7 @@ After issuing the proposal, there is a log event generated having the `proposal` | |
|
|
||
| ### Voting a proposal using the direct staked or delegation-system amount | ||
|
|
||
| Any wallet that has staked EGLD (either direct staked or through the delegation sub-system) can cast a vote for a proposal. | ||
| Any wallet that has staked EGLD (either direct staked or through the delegation sub-system) can cast a vote for a proposal. | ||
| ```rust | ||
| GovernanceVoteTransaction { | ||
| Sender: <account address of the wallet that will vote the proposal> | ||
|
|
@@ -56,6 +60,8 @@ GovernanceVoteTransaction { | |
| } | ||
| ``` | ||
|
|
||
| The value parameter for the voting transaction must be set to 0, since the function is non-payable. | ||
|
|
||
| The `nonce` is the hex encoded value of the proposal's unique nonce and the `vote_type` can be one of the following values: | ||
| - for **Yes**: `796573`; | ||
| - for **No**: `6e6f`; | ||
|
|
@@ -64,12 +70,21 @@ The `nonce` is the hex encoded value of the proposal's unique nonce and the `vot | |
|
|
||
| The vote value for the account that will vote a proposal is the sum of all staked values along with the sum of all delegated values in the delegation sub-system. | ||
|
|
||
| After issuing the vote, a log event is generated containing the `proposal` identifier and the following encoded topics: | ||
|
|
||
| - `nonce` as encoded integer which uniquely identifies the proposals | ||
| - `vote_type` as encoded string representing the vote | ||
| - `total_stake` total staked EGLD for the sender address | ||
| - `total_voting_power` total available voting power for the sender address | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we please add an example here how the encoding looks like? I took this example: https://devnet-explorer.multiversx.com/transactions/2cd33ee164881dd273a3568ed6cb272e3d7f05b7b46fd8f4a64d28dc30e1fe48/logs |
||
| [comment]: # (mx-context-auto) | ||
|
|
||
| ### Voting a proposal through smart contracts (delegation voting) | ||
|
|
||
| Whenever we deal with a smart contract that delegated through the delegation sub-system or owns staked nodes it is the out of scope of the metachain's governance contract to track each address that sent EGLD how much is really staked (if any EGLD is staked). | ||
|
|
||
| That is why we offered an endpoint to the governance smart contact that can be called **only by a shard smart contract** and the governance contract will record the address provided, the vote type and vote value. | ||
|
|
||
| This is very useful whenever implementing liquid-staking-like smart contracts. The liquid-staking contract knows the balance for each user, so it will delegate the call to the governance contract providing the value. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. providing the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. before the GovernanceVoteThroughDelegationTransaction we need a short explanation like this: The user that delegated through a liquid-staking-like contract in order to vote on a proposal, sends a transaction to the liquid-staking-like contract. The smart contract then creates the GovernanceVoteThroughDelegationTransaction based on the users transaction inputs to forward the vote and the computed voting power to the governance contract. There's a typo in |
||
|
|
||
| :::important | ||
|
|
@@ -90,39 +105,56 @@ GovernanceVoteThourghDelegationTransaction { | |
| } | ||
| ``` | ||
|
|
||
| The value parameter for the voting transaction must be set to 0, since the function is non-payable. | ||
|
|
||
| The `nonce` is the hex encoded value of the proposal's unique nonce and the `vote_type` can be one of the following values: | ||
| - for **Yes**: `796573`; | ||
| - for **No**: `6e6f`; | ||
| - for **Abstain**: `6162737461696e`; | ||
| - for **Veto**: `7665746f`. | ||
|
|
||
| The `account address handled by the smart contract` is the address handled by the smart contract that will delegate the vote towards the governance smart contract. This address will be recorded for casting the vote. | ||
|
|
||
| The `vote_balance` is the amount of stake the address has in the smart contract. The governance contract will "believe" that this is the right amount as it impossible to verify the information. The balance will diminish the total voting power the smart contract has. | ||
|
|
||
| After issuing the vote, a log event is generated containing the `proposal` identifier and the following encoded topics: | ||
|
|
||
| - `nonce` as encoded integer which uniquely identifies the proposals | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also here please have an example of the encoding. |
||
| - `vote_type` as encoded string representing the vote | ||
| - `voter` account address handled by the smart contract | ||
| - `total_stake` total staked EGLD for the sender address | ||
| - `total_voting_power` total available voting power for the sender address | ||
|
|
||
| [comment]: # (mx-context-auto) | ||
|
|
||
| ### Closing a proposal | ||
|
|
||
| A proposal can be closed only in an epoch that is strictly higher than the end epoch value provided when the proposal was open. | ||
| A proposal can be closed only in an epoch that is strictly higher than the end epoch value provided when the proposal was opened. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A proposal can be closed also before the voting period starts by the proposer/issuer but with an early closing fee equal to Closing after the voting period can be done by anyone. |
||
| Closing can only be performed by the account that created the proposal (the issuer). | ||
|
|
||
| ```rust | ||
| CloseProposalTransaction { | ||
| Sender: <account address of the wallet that created the proposal> | ||
| Sender: <account address of the wallet that created the proposal> | ||
| Receiver: erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqrlllsrujgla | ||
| Value: 0 EGLD | ||
| Value: 0 EGLD | ||
| GasLimit: 51000000 | ||
| Data: "closeProposal" + | ||
| "@<nonce>" | ||
| Data: "closeProposal" + | ||
| "@<nonce>" | ||
| } | ||
| ``` | ||
|
|
||
| Only the address that created the proposal can call the `closeProposal` function that will also trigger the funds unlocking. As stated in the overview page, if the proposal does not pass, the amount returned will be less with 10 EGLD. | ||
|
|
||
| #### Rules for closing | ||
| - Only the issuer can call `closeProposal`. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. before the voting period yes, only the issuer, but after the voting period, anyone can close a proposal. |
||
| - If the proposal **passes** → the full proposal fee is refunded. | ||
| - If the proposal **fails** or is **vetoed** → the refund is reduced by the `LostProposalFee`. | ||
| - Once a proposal is closed, it cannot be reopened. | ||
| - Closing also finalizes the vote tally (the proposal is marked as `Passed` or not, based on the results). | ||
|
|
||
|
|
||
| [comment]: # (mx-context-auto) | ||
|
|
||
| ### Querying the status of a proposal | ||
|
|
||
| The status of a certain proposal can be queried at any time by using the `vm-values/query` REST API endpoints provided by the gateway/API. | ||
| The status of any proposal can be queried at any time through `vm-values/query` REST API endpoints provided by the gateway/API. | ||
|
|
||
| ```bash | ||
| https://<gateway>.multiversx.com/vm-values/query | ||
|
|
@@ -132,52 +164,54 @@ https://<gateway>.multiversx.com/vm-values/query | |
| { | ||
| "scAddress": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqrlllsrujgla", | ||
| "funcName": "viewProposal", | ||
| "args": ["<nonce>"] | ||
| "args": ["<nonce-hex>"] | ||
| } | ||
| ``` | ||
|
|
||
| the `nonce` represents the proposal nonce in hex format. The response will contain the following json definition where all fields are base64-encoded: | ||
| - The argument `nonce` is the proposal nonce in hex format. | ||
| - The response will contain the following json definition where all fields are base64-encoded: | ||
|
|
||
| ```json | ||
| { | ||
| "returnData": [ | ||
| "<proposal_cost>", | ||
| "<commit_hash>", | ||
| "<nonce>", | ||
| "<account address of the wallet that created the proposal>", | ||
| "<starting epoch>", | ||
| "<ending epoch>", | ||
| "<quorum stake>", | ||
| "<yes_value>", | ||
| "<no_value>", | ||
| "<veto_value>", | ||
| "<abstain_value>", | ||
| "<proposal_cost>", (amount locked by proposer) | ||
| "<commit_hash>", (unique identifier of the proposal) | ||
| "<nonce>", (proposal number) | ||
| "<issuer_address>", (address of the proposer) | ||
| "<start_epoch>", (epoch when voting starts) | ||
| "<end_epoch>", (epoch when voting ends) | ||
| "<quorum_stake>", (current quorum stake: sum of stake that participated) | ||
| "<yes_votes>", (total stake voting YES) | ||
| "<no_votes>", (total stake voting NO) | ||
| "<veto_votes>", (total stake vetoing the proposal) | ||
| "<abstain_votes>", (total stake abstaining) | ||
| "<proposal_closed true|false>", | ||
| "<proposal_passed true|false>" | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| Example: | ||
| Example response: | ||
| ```json | ||
| { | ||
| "returnData": [ | ||
| "NjXJrcXeoAAA", (proposal locked amount: 1000 EGLD denominated = 1000 * 10^18) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should be 500 EGLD.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's change the example to use 500 EGLD |
||
| "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABg==", (commit hash: 0x0000...006) | ||
| "AQ==", (nonce: 1) | ||
| "aj88GtqHy9ibm5ePPQlG4aqLhpgqsQWygoTppckLa4M=", (address: erd1dglncxk6sl9a3xumj78n6z2xux4ghp5c92cstv5zsn56tjgtdwpsk46qrs) | ||
| "aj88GtqHy9ibm5ePPQlG4aqLhpgqsQWygoTppckLa4M=", (proposer address) | ||
| "bQ==", (starting epoch: 109) | ||
| "bg==", (ending epoch: 110) | ||
| "ntGU2xmyOMAAAA==", (quorum: 750000 EGLD = 7500000 * 10^18) | ||
| "", (yes value: 0) | ||
| "", (no value: 0) | ||
| "ntGU2xmyOMAAAA==", (veto value: 7500000 * 10^18) | ||
| "", (abstain value: 0) | ||
| "ntGU2xmyOMAAAA==", (quorum: 7,500,000 EGLD denominated) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this value seems to be 750K |
||
| "", (yes votes: 0) | ||
| "", (no votes: 0) | ||
| "ntGU2xmyOMAAAA==", (veto votes: 7,500,000 EGLD denominated) | ||
| "", (abstain votes: 0) | ||
| "dHJ1ZQ==", (proposal closed: true) | ||
| "ZmFsc2U=" (proposal passed: false) | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
|
|
||
|
|
||
| [comment]: # (mx-context-auto) | ||
|
|
||
|
|
@@ -192,51 +226,51 @@ https://<gateway>.multiversx.com/vm-values/query | |
| ```json | ||
| { | ||
| "scAddress": "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqrlllsrujgla", | ||
| "funcName": "viewUserVoteHistory", | ||
| "args": ["<address>"] | ||
| "funcName": "viewDelegatedVoteInfo", | ||
| "args": ["<proposal_nonce-hex>", "<address>"] | ||
| } | ||
| ``` | ||
|
|
||
| the `address` represents the address in hex format. The response will contain the following json definition where all fields are base64-encoded: | ||
| - `proposal_nonce` → the proposal identifier (nonce, hex-encoded). | ||
| - `address` → the bech32 address of the account to check. | ||
|
|
||
| > **Note:** The older function `viewUserVoteHistory` (which returned lists of proposal nonces) is now considered legacy. | ||
| > Use `viewDelegatedVoteInfo` for detailed voting power and stake information. | ||
|
|
||
| The response will contain the following json definition where all fields are base64-encoded: | ||
|
|
||
| ```json | ||
| { | ||
| "returnData": [ | ||
| "<the number of delegated nonces>", | ||
| "<delegated nonce 0>", | ||
| "<delegated nonce 1>", | ||
| ... | ||
| "<delegated nonce n>", | ||
| "<the number of direct nonces>", | ||
| "<direct nonce 0>", | ||
| "<direct nonce 1>", | ||
| ... | ||
| "<direct nonce m>" | ||
| "<used_power>", (voting power already used by this address on the proposal) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove |
||
| "<used_stake>", (stake associated with the used power) | ||
| "<total_power>", (total available voting power for the address) | ||
| "<total_stake>" (total stake considered in governance for the address) | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| Example for an address that cast votes on 5 proposals: | ||
| Example for an address that voted: | ||
| ```json | ||
| { | ||
| "returnData": [ | ||
| "Aw==", (number of delegated nonces: 3) | ||
| "AQ==", (nonce: 1) | ||
| "Ag==", (nonce: 2) | ||
| "Aw==", (nonce: 3) | ||
| "Ag==", (number of direct nonces: 2) | ||
| "BA==", (nonce: 4) | ||
| "BQ==", (nonce: 5) | ||
| "Cg==", (used power: 10) | ||
| "ZAA=", (used stake: 100) | ||
| "A+g=", (total power: 1000) | ||
| "Gg4M=", (total stake: 10000) | ||
| ] | ||
| } | ||
| ``` | ||
| In this example, the queried address voted on this proposal with **100 stake**, which translated into **10 voting power**. The proposal overall had **10000 total stake** and **1000 total voting power** recorded. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. right now we have a linear voting system. We moved from a quadratic voting system where each stake translated to sqrt(stake). EG: 100 stake -> 10 voting power. |
||
|
|
||
| Example for an address that did not cast votes on any proposals: | ||
| Example for an address that did not vote: | ||
| ```json | ||
| { | ||
| "returnData": [ | ||
| "AA==", (number of delegated nonces: 0) | ||
| "AA==", (number of direct nonces: 0) | ||
| "AA==", (used power: 0) | ||
| "AA==", (used stake: 0) | ||
| "A+g=", (total power: 1000) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also here please make last 2 values equal. |
||
| "Gg4M=", (total stake: 10000) | ||
| ] | ||
| } | ||
| ``` | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think a better name would be
commit_hash.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and also specify than length is mandatory to be exactly 40 chars