-
Notifications
You must be signed in to change notification settings - Fork 359
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
Cw3 spec #90
Cw3 spec #90
Changes from all commits
9c3fd95
037431c
b7c7bef
bca0143
d70f1b6
e9d8dca
8915943
fd53655
77d5423
916f6bf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
[alias] | ||
wasm = "build --release --target wasm32-unknown-unknown" | ||
wasm-debug = "build --target wasm32-unknown-unknown" | ||
schema = "run --example schema" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
[package] | ||
name = "cw3" | ||
version = "0.2.1" | ||
authors = ["Ethan Frey <[email protected]>"] | ||
edition = "2018" | ||
description = "CosmWasm-3 Interface: On-Chain MultiSig/Voting contracts" | ||
license = "Apache-2.0" | ||
repository = "https://github.com/CosmWasm/cosmwasm-plus" | ||
homepage = "https://cosmwasm.com" | ||
documentation = "https://docs.cosmwasm.com" | ||
|
||
[dependencies] | ||
cw0 = { path = "../../packages/cw0", version = "0.2.1" } | ||
cosmwasm-std = { version = "0.10.1" } | ||
schemars = "0.7" | ||
serde = { version = "1.0.103", default-features = false, features = ["derive"] } | ||
|
||
[dev-dependencies] | ||
cosmwasm-schema = { version = "0.10.1" } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
CW3: A CosmWasm spec for on-chain multiSig/voting contracts | ||
Copyright (C) 2020 Confio OÜ | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
# CW3 Spec: MultiSig/Voting Contracts | ||
|
||
CW3 is a specification for voting contracts based on CosmWasm. | ||
It is an extension of CW1 (which served as an immediate 1 of N multisig). | ||
In this case, no key can immediately execute, but only propose | ||
a set of messages for execution. The proposal, subsequent | ||
approvals, and signature aggregation all happen on chain. | ||
|
||
There are at least 3 different cases we want to cover in this spec: | ||
|
||
- K of N immutible multisig. One key proposes a set of messages, | ||
after K-1 others approve it, it can be executed with the | ||
multisig address. | ||
- K of N flexible, mutable multisig. Like above, but with | ||
multiple contracts. One contract stores the group, which is | ||
referenced from multiple multisig contracts (which in turn | ||
implement cw3). One cw3 contracts is able to update the | ||
group content (maybe needing 67% vote). Other cw3 contracts | ||
may hold tokens, staking rights, etc with various execution | ||
thresholds, all controlled by one group. (Group interface | ||
and updating them will be defined in a future spec, likely cw4). | ||
|
||
This should fit in this interface (possibly with some | ||
extensions for pieces, but the usage should look the | ||
same externally): | ||
|
||
- Token weighted voting. People lock tokens in a contract | ||
for voting rights. There is a vote threshold to execute | ||
messages. The voting set is dynamic. This has a similar | ||
"propose, approve, execute" flow, but we will need to | ||
support clear YES/NO votes and quora not just absolute | ||
thresholds. | ||
|
||
The common denominator is that they allow you to propose | ||
arbitrary `CosmosMsg` to a contract, and allow a series | ||
of votes/approvals to determine if it can be executed, | ||
as well as a final step to execute any approved proposal once. | ||
|
||
## Base | ||
|
||
The following interfaces must be implemented for all cw3 | ||
contracts. Note that updating the members of the voting | ||
contract is not contained here (one approach is defined in cw4). | ||
Also, how to change the threshold rules (if at all) is not | ||
standardized. Those are considered admin tasks, and the common | ||
API is designed for standard usage, as that is where we can | ||
standardize the most tooling without limiting more complex | ||
governance controls. | ||
|
||
### Messages | ||
|
||
`Propose{title, description, msgs, earliest, latest}` - This accepts | ||
`Vec<CosmosMsg>` and creates a new proposal. This will return | ||
an auto-generated ID in the `Data` field (and the logs) that | ||
can be used to reference the proposal later. | ||
|
||
If the Proposer is a valid voter on the proposal, this will imply a Yes vote by | ||
the Proposer for a faster workflow, especially useful in eg. 2 of 3 | ||
or 3 of 5 multisig, we don't need to propose in one block, get result, | ||
and vote in another block. | ||
|
||
Earliest and latest are optional and can request the first | ||
and last height/time that we can try `Execute`. For a vote, | ||
we may require at least 2 days to pass, but no more than 7. | ||
This is optional and even if set, may be modified by the contract | ||
(overriding or just enforcing min/max/default values). | ||
|
||
Many implementations will want to restrict who can propose. | ||
Maybe only people in the voting set. Maybe there is some | ||
deposit to be made along with the proposal. This is not | ||
in the spec but left open to the implementation. | ||
|
||
`Vote{proposal_id, vote}` - Given a proposal_id, you can | ||
vote yes, no, abstain or veto. Each signed may have a | ||
different "weight" in the voting and they apply their | ||
entire weight on the vote. | ||
|
||
Many contracts (like typical | ||
multisig with absolute threshold) may consider veto and | ||
abstain as no and just count yes votes. Contracts with quora | ||
may count abstain towards quora but not yes or no for threshold. | ||
Some contracts may give extra power to veto rather than a | ||
simple no, but this may just act like a normal no vote. | ||
|
||
`Execute{proposal_id}` - This will check if the voting | ||
conditions have passed for the given proposal. If it has | ||
succeeded, the proposal is marked as `Executed` and the | ||
messages are dispatched. If the messages fail (eg out of gas), | ||
this is all reverted and can be tried again later with | ||
more gas. | ||
|
||
`Close{proposal_id}` - This will check if the voting conditions | ||
have failed for the given proposal. If so (eg. time expired | ||
and insufficient votes), then the proposal is marked `Failed`. | ||
This is not strictly necessary, as it will only act when | ||
it is impossible the contract would ever be executed, | ||
but can be triggered to provide some better UI. | ||
|
||
### Queries | ||
|
||
`Threshold{}` - This returns information on the rules needed | ||
to declare a contract a success. What percentage of the votes | ||
and how they are tallied. | ||
|
||
`Proposal{proposal_id}` - Returns the information set when | ||
creating the proposal, along with the current status. | ||
|
||
`ListProposals{start_after, limit}` - Returns the same info | ||
as `Proposal`, but for all proposals along with pagination. | ||
Starts at proposal_id 1 and accending. | ||
|
||
`ReverseProposals{start_before, limit}` - Returns the same info | ||
as `Proposal`, but for all proposals along with pagination. | ||
Starts at latest proposal_id and descending. (Often this | ||
is what you will want for a UI) | ||
|
||
`Vote{proposal_id, voter}` - Returns how the given | ||
voter (HumanAddr) voted on the proposal. (May be null) | ||
|
||
`ListVotes{proposal_id, start_after, limit}` - Returns the same info | ||
as `Vote`, but for all votes along with pagination. | ||
Returns the voters sorted by the voters' address in | ||
lexographically ascending order. | ||
|
||
## Voter Info | ||
|
||
Information on who can vote is contract dependent. But | ||
we will work on a common API to display some of this. | ||
|
||
**TODO** |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
use std::env::current_dir; | ||
use std::fs::create_dir_all; | ||
|
||
use cosmwasm_schema::{export_schema, export_schema_with_title, remove_schemas, schema_for}; | ||
|
||
use cw3::{ | ||
Cw3HandleMsg, Cw3QueryMsg, ProposalListResponse, ProposalResponse, ThresholdResponse, | ||
VoteListResponse, VoteResponse, | ||
}; | ||
|
||
fn main() { | ||
let mut out_dir = current_dir().unwrap(); | ||
out_dir.push("schema"); | ||
create_dir_all(&out_dir).unwrap(); | ||
remove_schemas(&out_dir).unwrap(); | ||
|
||
export_schema_with_title(&mut schema_for!(Cw3HandleMsg), &out_dir, "HandleMsg"); | ||
export_schema_with_title(&mut schema_for!(Cw3QueryMsg), &out_dir, "QueryMsg"); | ||
export_schema(&schema_for!(ProposalResponse), &out_dir); | ||
export_schema(&schema_for!(ProposalListResponse), &out_dir); | ||
export_schema(&schema_for!(VoteResponse), &out_dir); | ||
export_schema(&schema_for!(VoteListResponse), &out_dir); | ||
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. All those schemas are only generated for (the same is true for the schemas in cosmwasm-std (packages/std/schema), which are kind of pointless) 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. These work for generic queriers that don't support custom messages, and are actually the basis of most generic clients. I would expect some custom contracts to add more and then we have custom clients that know that, but those would be chain-specific naturally, and this is the only set of schemas that would work over all contracts and all chains. |
||
export_schema(&schema_for!(ThresholdResponse), &out_dir); | ||
} |
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.
Above in
you assume that the Propose is the first approval. But I'd say it can be a valid case that the composer/proposer is not one of the signers but some type of moderator.
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.
Should I specify that Propose does not include a yes vote from the sender if applicable?
Specify that it does only if the proposer is in the valid voter set?
Or leave it unspecified?
I'd like to specify this, as then wallets know if they need to propose and vote, or just propose.
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 it is clean to make propose and vote two messages. It would be nice if they could be sent in one tranaction, but then we can't rely on execution data. However, this would work with client-side generated IDs.
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 defined it as the first in the README