commit f74cba2e65e136b9437d8ac7c54eef2805ecbd0e
parent 3e33a2fb2692939a773feca03e556c72f74335b1
Author: lash <dev@holbrook.no>
Date: Mon, 8 May 2023 09:10:45 +0100
Use messy markdown readme
Diffstat:
A | README.md | | | 410 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
D | README.txt | | | 401 | ------------------------------------------------------------------------------- |
2 files changed, 410 insertions(+), 401 deletions(-)
diff --git a/README.md b/README.md
@@ -0,0 +1,410 @@
+::: {#Top .top-level-extent}
+::: nav-panel
+Next: [Overview](#overview){accesskey="n" rel="next"}
+\[[Contents](#SEC_Contents "Table of contents"){rel="contents"}\]
+:::
+
+# Introduction {#Introduction .top}
+
+::: {#SEC_Contents .element-contents}
+## Table of Contents {#table-of-contents .contents-heading}
+
+::: contents
+- [1 Overview](#overview){#toc-Overview}
+ - [1.1 Tooling](#Tooling){#toc-Tooling}
+ - [1.2 Interoperability](#Interoperability){#toc-Interoperability}
+ - [1.3 Publishing the
+ contract](#Publishing-the-contract){#toc-Publishing-the-contract}
+- [2 Proposal](#proposal){#toc-Proposal}
+ - [2.1 Parameters](#Parameters){#toc-Parameters}
+ - [2.1.1 Deadline](#Deadline){#toc-Deadline}
+ - [2.2 Target vote](#Target-vote){#toc-Target-vote}
+ - [2.3 Options](#Options){#toc-Options}
+ - [2.4 Creating a
+ proposal](#Creating-a-proposal){#toc-Creating-a-proposal}
+- [3 Voting](#voting){#toc-Voting}
+ - [3.1 Proposal context](#Proposal-context){#toc-Proposal-context}
+ - [3.2 Options](#Options-1){#toc-Options-1}
+ - [3.3 Cancellation
+ votes](#Cancellation-votes){#toc-Cancellation-votes}
+ - [3.4 How to vote](#How-to-vote){#toc-How-to-vote}
+- [4 Results](#results){#toc-Results}
+ - [4.1 Finalizing the
+ proposal](#Finalizing-the-proposal){#toc-Finalizing-the-proposal}
+ - [4.1.1 Enhanced
+ results](#Enhanced-results){#toc-Enhanced-results}
+ - [4.2 Recovering
+ tokens](#Recovering-tokens){#toc-Recovering-tokens}
+- [Appendix A Proposal states](#Proposal-states){#toc-Proposal-states}
+:::
+:::
+
+------------------------------------------------------------------------
+
+::: {#overview .chapter-level-extent}
+::: nav-panel
+Next: [Proposal](#proposal){accesskey="n" rel="next"}, Previous:
+[Introduction](#Top){accesskey="p" rel="prev"}, Up:
+[Introduction](#Top){accesskey="u" rel="up"}
+\[[Contents](#SEC_Contents "Table of contents"){rel="contents"}\]
+:::
+
+## 1 Overview {#Overview .chapter}
+
+This smart contract enables voting on proposals using ERC20 tokens.
+
+- [Tooling](#Tooling){accesskey="1"}
+- [Interoperability](#Interoperability){accesskey="2"}
+- [Publishing the contract](#Publishing-the-contract){accesskey="3"}
+
+::: {#Tooling .section-level-extent}
+### 1.1 Tooling {#tooling .section}
+
+Tests and tools are implemented using the
+[chainlib-eth](https://pypi.org/project/chainlib-eth){.url} python
+package.
+
+To learn more about the individual CLI tools mentioned in this document,
+please refer to their individual man pages. The man pages should be
+installed as part of the python packages.
+:::
+
+::: {#Interoperability .section-level-extent}
+### 1.2 Interoperability {#interoperability .section}
+
+The `evm-tokenvote`{.code} contract implements the
+`cic-contracts:TokenVote`{.code} interface.
+:::
+
+::: {#Publishing-the-contract .section-level-extent}
+### 1.3 Publishing the contract {#publishing-the-contract .section}
+
+In python, the smart contract can be published using the
+`constructor`{.code} method of the `evm_tokenvote.Voter`{.code} class.
+
+Also, constructor bytecode can be generated on the command-line using
+`chainlib-gen`{.code}. Thereafter, `eth-gen`{.code} can be used to
+publish the contract through an rpc endpoint:
+
+::: example
+``` example-preformatted
+# Make sure evm_tokenvote is in your PYTHONPATH
+$ chainlib-gen evm_tokenvote create --token_address <token_address> > data.bin
+$ eth-gas -p <rpc_url> -y <json_keyfile> [ --passphrase-file <file_with_keyfile_passphrase> ] --data data.bin -i <evm:chain:chain_id:common_name> -s -w 0
+```
+:::
+
+The `token_address`{.code} argument **MUST** be an existing and valid
+`ERC20`{.code} contract.
+
+------------------------------------------------------------------------
+:::
+:::
+
+::: {#proposal .chapter-level-extent}
+::: nav-panel
+Next: [Voting](#voting){accesskey="n" rel="next"}, Previous:
+[Overview](#overview){accesskey="p" rel="prev"}, Up:
+[Introduction](#Top){accesskey="u" rel="up"}
+\[[Contents](#SEC_Contents "Table of contents"){rel="contents"}\]
+:::
+
+## 2 Proposal {#Proposal .chapter}
+
+Proposals are created with a 32-byte description.
+
+How the description should be interpreted is up to the client
+application.
+
+A proposal may be a binary (yes or no) vote, or define a number of
+different options to choose from.
+
+- [Parameters](#Parameters){accesskey="1"}
+- [Target vote](#Target-vote){accesskey="2"}
+- [Options](#Options){accesskey="3"}
+- [Creating a proposal](#Creating-a-proposal){accesskey="4"}
+
+::: {#Parameters .section-level-extent}
+### 2.1 Parameters {#parameters .section}
+
+The arguments required to create a proposal depends on the type of
+proposal to create.
+
+- [Deadline](#Deadline){accesskey="1"}
+
+::: {#Deadline .subsection-level-extent}
+#### 2.1.1 Deadline {#deadline .subsection}
+
+The deadline must be defined for all proposals.
+
+It is defined as a period of number of blocks during which votes may be
+made.
+
+If a vote has been completed before the deadline is over, the result
+will be available immediately.
+
+The contract does not check the sanity of the deadline value. For
+example, setting the deadline to `1`{.code} block wait will be useless
+as voting will expire immediately.
+:::
+:::
+
+::: {#Target-vote .section-level-extent}
+### 2.2 Target vote {#target-vote .section}
+
+The target vote must be defined for all proposals.
+
+This defines the minimum participation in the vote. It is defined as
+parts-per-million of the total supply of tokens.
+
+For example. a value of `500000`{.code} will require 50% of all tokens
+in the vote. A value of `1000000`{.code} will require the full supply.
+:::
+
+::: {#Options .section-level-extent}
+### 2.3 Options {#options .section}
+
+A proposal may define one or more options for voters to choose between.
+
+Options are defined as 32-byte hexadecimal values. As with the
+description, it is up to the client application to decide how to
+interpret the values.
+:::
+
+::: {#Creating-a-proposal .section-level-extent}
+### 2.4 Creating a proposal {#creating-a-proposal .section}
+
+To create a proposal without options:
+
+``` verbatim
+# solidity:
+function propose(bytes32 _description, uint256 _blockWait, uint24 _targetVotePpm) public returns (uint256);
+
+# chainlib-python:
+def propose(self, contract_address, sender_address, description, block_deadline, tx_format=TxFormat.JSONRPC, id_generator=None)
+
+# eth-encode CLI:
+$ eth-encode --mode tx --signature propose -e <voter_contract_address> -y <keyfile_json> a:<token_address> u:<blocks_until_deadline> u:<target_vote_ppm>
+```
+
+To create a proposal with options:
+
+``` verbatim
+solidity:
+function proposeMulti(bytes32 _description, uint256 _blockWait, uint24 _targetVotePpm) public returns (uint256);
+
+chainlib-python:
+def propose(self, contract_address, sender_address, description, block_deadline, options=[<options_hex>, ...])
+```
+
+(Unfortunately, `eth-encode`{.code} does not currently support dynamic
+array arguments.)
+
+------------------------------------------------------------------------
+:::
+:::
+
+::: {#voting .chapter-level-extent}
+::: nav-panel
+Next: [Results](#results){accesskey="n" rel="next"}, Previous:
+[Proposal](#proposal){accesskey="p" rel="prev"}, Up:
+[Introduction](#Top){accesskey="u" rel="up"}
+\[[Contents](#SEC_Contents "Table of contents"){rel="contents"}\]
+:::
+
+## 3 Voting {#Voting .chapter}
+
+Votes are defined in magnitudes of ERC20 tokens.
+
+A vote will transfer ERC20 tokens to the custody of the smart contract
+for the duration of the voting.
+
+The smart contract uses the `transferFrom`{.code} method to transfer
+tokens. It is the caller's responsibility to make the necessary token
+allowance (using `approve`{.code}). Votes with insufficient allowance
+will fail.
+
+- [Proposal context](#Proposal-context){accesskey="1"}
+- [Options](#Options-1){accesskey="2"}
+- [Cancellation votes](#Cancellation-votes){accesskey="3"}
+- [How to vote](#How-to-vote){accesskey="4"}
+
+::: {#Proposal-context .section-level-extent}
+### 3.1 Proposal context {#proposal-context .section}
+
+Votes are always cast on the oldest proposal the has not been completed.
+:::
+
+::: {#Options-1 .section-level-extent}
+### 3.2 Options {#options-1 .section}
+
+If multiple options exist, the token holder may freely distribute votes
+between the options.
+:::
+
+::: {#Cancellation-votes .section-level-extent}
+### 3.3 Cancellation votes {#cancellation-votes .section}
+
+In both proposals with and without options, votes can be cast to cancel
+the proposal.
+
+For proposals with no or one option, the *cancel* amounts to a vote
+against the proposal.
+
+For proposals with two or more options, the *cancel* amounts to a vote
+against proposal and its all options.
+:::
+
+::: {#How-to-vote .section-level-extent}
+### 3.4 How to vote {#how-to-vote .section}
+
+In each case, make sure the necessary *allowance* has been successfully
+executed.
+
+For proposals without options, a simplified method can be called:
+
+``` verbatim
+# solidity:
+function vote(uint256 _value) public returns (bool);
+
+
+# chainlib-python:
+def vote(self, contract_address, sender_address, value)
+
+
+# eth-encode CLI:
+$ eth-encode --mode tx --signature vote -e <voter_contract_address> -y <keyfile_json> u:<value>
+```
+
+For proposal with options, the call is slightly more verbose:
+
+``` verbatim
+# solidity:
+function voteOption(uint256 _optionIndex, uint256 _value) public returns (bool);
+
+
+# chainlib-python:
+def vote(self, contract_address, sender_address, option=<option_index>, value)
+
+
+# eth-encode CLI:
+$ eth-encode --mode tx --signature voteOption -e <voter_contract_address> -y <keyfile_json> u:<option_index> u:<value>
+```
+
+To cast votes for cancellation, the call will be:
+
+``` verbatim
+# solidity:
+function voteCancel(uint256 _value) public returns (bool);
+
+
+# chainlib-python:
+def vote_cancel(self, contract_address, sender_address, value)
+
+
+# eth-encode CLI:
+$ eth-encode --mode tx --signature voteCancel -e <voter_contract_address> -y <keyfile_json> u:<value>
+```
+
+------------------------------------------------------------------------
+:::
+:::
+
+::: {#results .chapter-level-extent}
+::: nav-panel
+Previous: [Voting](#voting){accesskey="p" rel="prev"}, Up:
+[Introduction](#Top){accesskey="u" rel="up"}
+\[[Contents](#SEC_Contents "Table of contents"){rel="contents"}\]
+:::
+
+## 4 Results {#Results .chapter}
+
+A proposal vote is completed if either of the following are true:
+
+- The deadline has been reached
+- Proposal contains zero or one options, and target participation has
+ been reached.
+- Cancellation votes have the majority.
+
+```{=html}
+<!-- -->
+```
+- [Finalizing the proposal](#Finalizing-the-proposal){accesskey="1"}
+- [Recovering tokens](#Recovering-tokens){accesskey="2"}
+
+::: {#Finalizing-the-proposal .section-level-extent}
+### 4.1 Finalizing the proposal {#finalizing-the-proposal .section}
+
+Once a proposal vote has been completed, the proposal must be explicitly
+finalized.
+
+Finalization analyzes the results of the vote, and marks the proposal
+state accordingly.
+
+It also moves the proposal cursor to activate the next proposal in the
+queue.
+
+Finally, it releases the ERC20 tokens used for the vote.
+
+Finalization is performed using the `finalize()`{.code} contract method.
+It will fail if used before the proposal vote has been *completed*.
+
+- [Enhanced results](#Enhanced-results){accesskey="1"}
+
+::: {#Enhanced-results .subsection-level-extent}
+#### 4.1.1 Enhanced results {#enhanced-results .subsection}
+
+The optional method `scan(uint256 _proposalIndex, uint256 _count`{.code}
+can be called on a completed proposal to further analyze the results of
+the vote.
+
+In the current state of the contract, it will iterate the options of the
+proposal, and mark the state as `TIED`{.code} if two or more options
+have the same amount of votes.
+
+This method may be called any time after proposal has been completed
+(even before `finalize()`{.code}. The proposal is identified by the
+`_proposalIndex`{.code} parameter, where the index is the order of
+addition of the proposal.
+
+The `_count`{.code} parameter limits the amount of options that will be
+scanned. A consecutive call will start at the option where the previous
+left off.
+:::
+:::
+
+::: {#Recovering-tokens .section-level-extent}
+### 4.2 Recovering tokens {#recovering-tokens .section}
+
+Before a new vote can take place, the ERC20 tokens used in previous
+voting must be withdrawn.
+
+Withdrawal is performed using the `withdraw()`{.code} contract method.
+It will fail if used before the proposal vote has been *finalized*.
+:::
+:::
+
+::: {#Proposal-states .appendix-level-extent}
+## Appendix A Proposal states {#appendix-a-proposal-states .appendix}
+
+ label bit value description
+ ----------------------- ----------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ INIT 1 Proposal has been initiated. It is used to disambiguate a proposal struct that has not yet been added, due to the ambiguity of the default struct value in solidity.
+ `FINAL`{.code} 2 `finalize()`{.code} has been successfully called.
+ `SCANNED`{.code} 4 `scan(...)`{.code} has been successfully called for all available options.
+ `INSUFFICIENT`{.code} 8 Voting participation did not been the required target vote before the deadline.
+ `TIED`{.code} 16 Proposal contains two or more options, and two or more options have received the same amount of votes before the deadline.
+ `SUPPLYCHANGE`{.code} 32 The token supply changed between when the proposal was added and voting ended. If supply is protected, this has also `CANCELLED`{.code} the vote.
+ `IMMEDIATE`{.code} 64 Voting was completed before the deadline.
+ `CANCELLED`{.code} 128 Interpretation depends on context. See below.
+
+Interpreting `CANCELLED`{.code}:
+
+- With `SUPPLYCHANGE`{.code}, this means that vote has been
+ invalidated and should be discarded.
+- If proposal has options, it should be interpreted as that the
+ existence of the proposal itself has been *rejected*.
+- With no or one option, it should be interpreted as the proposal has
+ been *defeated*.
+:::
+:::
diff --git a/README.txt b/README.txt
@@ -1,401 +0,0 @@
-Introduction
-1 Overview
- 1.1 Tooling
- 1.2 Interoperability
- 1.3 Publishing the contract
-2 Proposal
- 2.1 Parameters
- 2.1.1 Deadline
- 2.2 Target vote
- 2.3 Options
- 2.4 Creating a proposal
-3 Voting
- 3.1 Proposal context
- 3.2 Options
- 3.3 Cancellation votes
- 3.4 How to vote
-4 Results
- 4.1 Finalizing the proposal
- 4.1.1 Enhanced results
- 4.2 Recovering tokens
-Appendix A Proposal states
-Introduction
-************
-
-1 Overview
-**********
-
-This smart contract enables voting on proposals using ERC20 tokens.
-
-1.1 Tooling
-===========
-
-Tests and tools are implemented using the chainlib-eth
-(https://pypi.org/project/chainlib-eth) python package.
-
- To learn more about the individual CLI tools mentioned in this
-document, please refer to their individual man pages. The man pages
-should be installed as part of the python packages.
-
-1.2 Interoperability
-====================
-
-The ‘evm-tokenvote’ contract implements the ‘cic-contracts:TokenVote’
-interface.
-
-1.3 Publishing the contract
-===========================
-
-In python, the smart contract can be published using the ‘constructor’
-method of the ‘evm_tokenvote.Voter’ class.
-
- Also, constructor bytecode can be generated on the command-line using
-‘chainlib-gen’. Thereafter, ‘eth-gen’ can be used to publish the
-contract through an rpc endpoint:
-
- # Make sure evm_tokenvote is in your PYTHONPATH
- $ chainlib-gen evm_tokenvote create --token_address <token_address> > data.bin
- $ eth-gas -p <rpc_url> -y <json_keyfile> [ --passphrase-file <file_with_keyfile_passphrase> ] --data data.bin -i <evm:chain:chain_id:common_name> -s -w 0
-
- The ‘token_address’ argument *MUST* be an existing and valid ‘ERC20’
-contract.
-
-2 Proposal
-**********
-
-Proposals are created with a 32-byte description.
-
- How the description should be interpreted is up to the client
-application.
-
- A proposal may be a binary (yes or no) vote, or define a number of
-different options to choose from.
-
-2.1 Parameters
-==============
-
-The arguments required to create a proposal depends on the type of
-proposal to create.
-
-2.1.1 Deadline
---------------
-
-The deadline must be defined for all proposals.
-
- It is defined as a period of number of blocks during which votes may
-be made.
-
- If a vote has been completed before the deadline is over, the result
-will be available immediately.
-
- The contract does not check the sanity of the deadline value. For
-example, setting the deadline to ‘1’ block wait will be useless as
-voting will expire immediately.
-
-2.2 Target vote
-===============
-
-The target vote must be defined for all proposals.
-
- This defines the minimum participation in the vote. It is defined as
-parts-per-million of the total supply of tokens.
-
- For example. a value of ‘500000’ will require 50% of all tokens in
-the vote. A value of ‘1000000’ will require the full supply.
-
-2.3 Options
-===========
-
-A proposal may define one or more options for voters to choose between.
-
- Options are defined as 32-byte hexadecimal values. As with the
-description, it is up to the client application to decide how to
-interpret the values.
-
-2.4 Creating a proposal
-=======================
-
-To create a proposal without options:
-
-# solidity:
-function propose(bytes32 _description, uint256 _blockWait, uint24 _targetVotePpm) public returns (uint256);
-
-# chainlib-python:
-def propose(self, contract_address, sender_address, description, block_deadline, tx_format=TxFormat.JSONRPC, id_generator=None)
-
-# eth-encode CLI:
-$ eth-encode --mode tx --signature propose -e <voter_contract_address> -y <keyfile_json> a:<token_address> u:<blocks_until_deadline> u:<target_vote_ppm>
-
- To create a proposal with options:
-
-solidity:
-function proposeMulti(bytes32 _description, uint256 _blockWait, uint24 _targetVotePpm) public returns (uint256);
-
-chainlib-python:
-def propose(self, contract_address, sender_address, description, block_deadline, options=[<options_hex>, ...])
-
- (Unfortunately, ‘eth-encode’ does not currently support dynamic array
-arguments.)
-
-3 Voting
-********
-
-Votes are defined in magnitudes of ERC20 tokens.
-
- A vote will transfer ERC20 tokens to the custody of the smart
-contract for the duration of the voting.
-
- The smart contract uses the ‘transferFrom’ method to transfer tokens.
-It is the caller’s responsibility to make the necessary token allowance
-(using ‘approve’). Votes with insufficient allowance will fail.
-
-3.1 Proposal context
-====================
-
-Votes are always cast on the oldest proposal the has not been completed.
-
-3.2 Options
-===========
-
-If multiple options exist, the token holder may freely distribute votes
-between the options.
-
-3.3 Cancellation votes
-======================
-
-In both proposals with and without options, votes can be cast to cancel
-the proposal.
-
- For proposals with no or one option, the _cancel_ amounts to a vote
-against the proposal.
-
- For proposals with two or more options, the _cancel_ amounts to a
-vote against proposal and its all options.
-
-3.4 How to vote
-===============
-
-In each case, make sure the necessary _allowance_ has been successfully
-executed.
-
- For proposals without options, a simplified method can be called:
-
-# solidity:
-function vote(uint256 _value) public returns (bool);
-
-
-# chainlib-python:
-def vote(self, contract_address, sender_address, value)
-
-
-# eth-encode CLI:
-$ eth-encode --mode tx --signature vote -e <voter_contract_address> -y <keyfile_json> u:<value>
-
- For proposal with options, the call is slightly more verbose:
-
-# solidity:
-function voteOption(uint256 _optionIndex, uint256 _value) public returns (bool);
-
-
-# chainlib-python:
-def vote(self, contract_address, sender_address, option=<option_index>, value)
-
-
-# eth-encode CLI:
-$ eth-encode --mode tx --signature voteOption -e <voter_contract_address> -y <keyfile_json> u:<option_index> u:<value>
-
- To cast votes for cancellation, the call will be:
-
-# solidity:
-function voteCancel(uint256 _value) public returns (bool);
-
-
-# chainlib-python:
-def vote_cancel(self, contract_address, sender_address, value)
-
-
-# eth-encode CLI:
-$ eth-encode --mode tx --signature voteCancel -e <voter_contract_address> -y <keyfile_json> u:<value>
-
-4 Results
-*********
-
-A proposal vote is completed if either of the following are true:
-
- • The deadline has been reached
- • Proposal contains zero or one options, and target participation has
- been reached.
- • Cancellation votes have the majority.
-
-4.1 Finalizing the proposal
-===========================
-
-Once a proposal vote has been completed, the proposal must be explicitly
-finalized.
-
- Finalization analyzes the results of the vote, and marks the proposal
-state accordingly.
-
- It also moves the proposal cursor to activate the next proposal in
-the queue.
-
- Finally, it releases the ERC20 tokens used for the vote.
-
- Finalization is performed using the ‘finalize()’ contract method. It
-will fail if used before the proposal vote has been _completed_.
-
-4.1.1 Enhanced results
-----------------------
-
-The optional method ‘scan(uint256 _proposalIndex, uint256 _count’ can be
-called on a completed proposal to further analyze the results of the
-vote.
-
- In the current state of the contract, it will iterate the options of
-the proposal, and mark the state as ‘TIED’ if two or more options have
-the same amount of votes.
-
- This method may be called any time after proposal has been completed
-(even before ‘finalize()’. The proposal is identified by the
-‘_proposalIndex’ parameter, where the index is the order of addition of
-the proposal.
-
- The ‘_count’ parameter limits the amount of options that will be
-scanned. A consecutive call will start at the option where the previous
-left off.
-
-4.2 Recovering tokens
-=====================
-
-Before a new vote can take place, the ERC20 tokens used in previous
-voting must be withdrawn.
-
- Withdrawal is performed using the ‘withdraw()’ contract method. It
-will fail if used before the proposal vote has been _finalized_.
-
-Appendix A Proposal states
-**************************
-
-label bit description
- value
-------------------
-INIT 1 Proposal
- has
- been
- initiated.
- It
- is
- used
- to
- disambiguate
- a
- proposal
- struct
- that
- has
- not
- yet
- been
- added,
- due
- to
- the
- ambiguity
- of
- the
- default
- struct
- value
- in
- solidity.
-‘FINAL’2 ‘finalize()’
- has
- been
- successfully
- called.
-‘SCANNED’4 ‘scan(...)’
- has
- been
- successfully
- called
- for
- all
- available
- options.
-‘INSUFFICIENT’8Voting
- participation
- did
- not
- been
- the
- required
- target
- vote
- before
- the
- deadline.
-‘TIED’16 Proposal
- contains
- two
- or
- more
- options,
- and
- two
- or
- more
- options
- have
- received
- the
- same
- amount
- of
- votes
- before
- the
- deadline.
-‘SUPPLYCHANGE’32The
- token
- supply
- changed
- between
- when
- the
- proposal
- was
- added
- and
- voting
- ended.
- If
- supply
- is
- protected,
- this
- has
- also
- ‘CANCELLED’
- the
- vote.
-‘IMMEDIATE’64Voting
- was
- completed
- before
- the
- deadline.
-‘CANCELLED’128Interpretation
- depends
- on
- context.
- See
- below.
-
- Interpreting ‘CANCELLED’:
-
- • With ‘SUPPLYCHANGE’, this means that vote has been invalidated and
- should be discarded.
- • If proposal has options, it should be interpreted as that the
- existence of the proposal itself has been _rejected_.
- • With no or one option, it should be interpreted as the proposal has
- been _defeated_.