Skip to content
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

Merged
merged 10 commits into from
Sep 15, 2020
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ workflows:
- package_cw0
- package_cw1
- package_cw2
- package_cw3
- package_cw20
- package_cw721
- lint
Expand Down Expand Up @@ -327,6 +328,43 @@ jobs:
- target
key: cargocache-v2-cw2:1.44.1-{{ checksum "~/project/Cargo.lock" }}

package_cw3:
docker:
- image: rust:1.44.1
working_directory: ~/project/packages/cw3
steps:
- checkout:
path: ~/project
- run:
name: Version information
command: rustc --version; cargo --version; rustup --version; rustup target list --installed
- restore_cache:
keys:
- cargocache-v2-cw3:1.44.1-{{ checksum "~/project/Cargo.lock" }}
- run:
name: Build library for native target
command: cargo build --locked
- run:
name: Run unit tests
command: cargo test --locked
- run:
name: Build and run schema generator
command: cargo schema --locked
- run:
name: Ensure schemas are up-to-date
command: |
CHANGES_IN_REPO=$(git status --porcelain)
if [[ -n "$CHANGES_IN_REPO" ]]; then
echo "Repository is dirty. Showing 'git status' and 'git --no-pager diff' for debugging now:"
git status && git --no-pager diff
exit 1
fi
- save_cache:
paths:
- /usr/local/cargo/registry
- target
key: cargocache-v2-cw3:1.44.1-{{ checksum "~/project/Cargo.lock" }}

package_cw20:
docker:
- image: rust:1.44.1
Expand Down
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions packages/cw3/.cargo/config
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"
19 changes: 19 additions & 0 deletions packages/cw3/Cargo.toml
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" }
14 changes: 14 additions & 0 deletions packages/cw3/NOTICE
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.
107 changes: 107 additions & 0 deletions packages/cw3/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# 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

### Messages

`Propose{title, description, msgs, expires}` - 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. You can specify
an expiration time/height in Propose, but this may be set
automatically 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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Above in

  • 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.

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.

Copy link
Member Author

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.

Copy link
Member

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.

Copy link
Member Author

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


`Vote{proposal_id, vote}` - Given a proposal_id, you can
vote yes, no, abstain or veto. 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 contracts is marked as `Executed` and the
ethanfrey marked this conversation as resolved.
Show resolved Hide resolved
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

`Proposal{proposal_id}` - Returns the information set when
creating the contract, along with the current status.
ethanfrey marked this conversation as resolved.
Show resolved Hide resolved

`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 `Proposal`, but for all proposals along with pagination.
ethanfrey marked this conversation as resolved.
Show resolved Hide resolved
Starts at proposal_id 1 and accending.

## Voter Info

Information on who can vote is contract dependent. But
we will work on a common API to display some of this.

**TODO**
23 changes: 23 additions & 0 deletions packages/cw3/examples/schema.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
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, 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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All those schemas are only generated for T = Empty, so T cannot be used together with the schema files. If we want to stick with the custom T in CosmosMsg, I think we should remove the schemas here. Then only the implementations generate schemas, which either set T or actually use Empty.

(the same is true for the schemas in cosmwasm-std (packages/std/schema), which are kind of pointless)

Copy link
Member Author

Choose a reason for hiding this comment

The 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.

}
Loading