Skip to content

Commit

Permalink
created contract scaffold
Browse files Browse the repository at this point in the history
  • Loading branch information
NoahSaso committed Oct 7, 2024
1 parent b0c7ef1 commit 9ad11b4
Show file tree
Hide file tree
Showing 10 changed files with 314 additions and 4 deletions.
31 changes: 31 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ exclude = ["ci/configs/", "wasmvm/libwasmvm"]
members = [
"contracts/dao-dao-core",
"contracts/distribution/*",
"contracts/delegation/*",
"contracts/external/*",
"contracts/proposal/*",
"contracts/pre-propose/*",
Expand Down Expand Up @@ -117,6 +118,7 @@ dao-proposal-sudo = { path = "./contracts/test/dao-proposal-sudo", version = "2.
dao-rewards-distributor = { path = "./contracts/distribution/dao-rewards-distributor", version = "2.5.0" }
dao-test-custom-factory = { path = "./contracts/test/dao-test-custom-factory", version = "2.5.0" }
dao-testing = { path = "./packages/dao-testing", version = "2.5.0" }
dao-vote-delegation = { path = "./contracts/delegation/dao-vote-delegation", version = "2.5.0" }
dao-voting = { path = "./packages/dao-voting", version = "2.5.0" }
dao-voting-cw20-balance = { path = "./contracts/test/dao-voting-cw20-balance", version = "2.5.0" }
dao-voting-cw20-staked = { path = "./contracts/voting/dao-voting-cw20-staked", version = "2.5.0" }
Expand Down
8 changes: 4 additions & 4 deletions contracts/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# DAO Contracts

- `dao-dao-core` - the core module for DAOs.
- `external` - contracts used by DAOs that are not part of a DAO
module.
- `delegation` - delegation modules.
- `distribution` - token distribution modules.
- `external` - contracts used by DAOs that are not part of a DAO module.
- `pre-propose` - pre-propose modules.
- `proposal` - proposal modules.
- `staking` - cw20 staking functionality and a staking rewards system.
- `voting` - voting modules.
- `staking` - cw20 staking functionality and a staking rewards
system. These contracts are used by [Wasmswap](https://github.com/Wasmswap) as well as DAO DAO.

For a description of each module type, see [our wiki](https://github.com/DA0-DA0/dao-contracts/wiki/DAO-DAO-Contracts-Design).
45 changes: 45 additions & 0 deletions contracts/delegation/dao-vote-delegation/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
[package]
name = "dao-vote-delegation"
authors = ["Noah <[email protected]>"]
description = "Manages delegation of voting power for DAOs."
edition = { workspace = true }
license = { workspace = true }
repository = { workspace = true }
version = { workspace = true }

[lib]
crate-type = ["cdylib", "rlib"]

[features]
backtraces = ["cosmwasm-std/backtraces"]
# use library feature to disable all instantiate/execute/query exports
library = []

[dependencies]
cosmwasm-std = { workspace = true }
cosmwasm-schema = { workspace = true }
cw2 = { workspace = true }
cw4 = { workspace = true }
cw20 = { workspace = true }
cw20-base = { workspace = true, features = ["library"] }
cw-controllers = { workspace = true }
cw-ownable = { workspace = true }
cw-storage-plus = { workspace = true }
cw-utils = { workspace = true }
dao-hooks = { workspace = true }
dao-interface = { workspace = true }
dao-voting = { workspace = true }
semver = { workspace = true }
thiserror = { workspace = true }

[dev-dependencies]
cw-multi-test = { workspace = true }
anyhow = { workspace = true }
cw20-stake = { workspace = true, features = ["library"] }
cw4-group = { workspace = true, features = ["library"] }
cw721-base = { workspace = true, features = ["library"] }
dao-voting-cw20-staked = { workspace = true, features = ["library"] }
dao-voting-cw4 = { workspace = true, features = ["library"] }
dao-voting-token-staked = { workspace = true, features = ["library"] }
dao-voting-cw721-staked = { workspace = true, features = ["library"] }
dao-testing = { workspace = true }
54 changes: 54 additions & 0 deletions contracts/delegation/dao-vote-delegation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# DAO Vote Delegation

[![dao-vote-delegation on
crates.io](https://img.shields.io/crates/v/dao-vote-delegation.svg?logo=rust)](https://crates.io/crates/dao-vote-delegation)
[![docs.rs](https://img.shields.io/docsrs/dao-vote-delegation?logo=docsdotrs)](https://docs.rs/dao-vote-delegation/latest/dao_vote_delegation/)

The `dao-vote-delegation` contract allows members of a DAO to delegate their
voting power to other members of the DAO who have registered as delegates. It
works in conjunction with voting and proposal modules, as well as the rewards
distributor, to offer a comprehensive delegation system for DAOs that supports
the following features:

- Fractional delegation of voting power on a per-proposal-module basis.
- Overridable delegate votes that can be overridden on a per-proposal basis by
the delegator
- Delegate reward commission.

## Instantiation and Setup

This contract must be instantiated by the DAO.

### Hooks

After instantiating the contract, it is VITAL to set up the required hooks for
it to work. To compute delegate voting power correctly, this contract needs to
know about both voting power changes and votes cast on proposals as soon as they
happen.

This can be achieved using the `add_hook` method on voting/staking contracts
that support voting power changes, such as:

- `cw4-group`
- `dao-voting-cw721-staked`
- `dao-voting-token-staked`
- `cw20-stake`

For proposal modules, the corresponding hook is `add_vote_hook`:

- `dao-proposal-single`
- `dao-proposal-multiple`
- `dao-proposal-condorcet`

## Design Decisions

### Fractional Delegation via Percentages

In order to support fractional delegation, users assign a percentage of voting
power to each delegate. Percentages are used instead of choosing an absolute
amount of voting power (e.g. staked tokens) since voting power can change
independently of delegation. If an absolute amount were used, and a user who had
delegated all of their voting power to a few different delegates then unstaked
half of their tokens, there is no clear way to resolve what their new
delegations are. Using percentages instead allows voting power and delegation to
be decided independently.
11 changes: 11 additions & 0 deletions contracts/delegation/dao-vote-delegation/examples/schema.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use cosmwasm_schema::write_api;
use dao_vote_delegation::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};

fn main() {
write_api! {
instantiate: InstantiateMsg,
query: QueryMsg,
execute: ExecuteMsg,
migrate: MigrateMsg,
}
}
30 changes: 30 additions & 0 deletions contracts/delegation/dao-vote-delegation/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use cosmwasm_std::{DivideByZeroError, OverflowError, StdError};
use cw_utils::PaymentError;
use thiserror::Error;

#[derive(Error, Debug, PartialEq)]
pub enum ContractError {
#[error(transparent)]
Std(#[from] StdError),

#[error(transparent)]
Ownable(#[from] cw_ownable::OwnershipError),

#[error(transparent)]
Overflow(#[from] OverflowError),

#[error(transparent)]
DivideByZero(#[from] DivideByZeroError),

#[error(transparent)]
Payment(#[from] PaymentError),

#[error("semver parsing error: {0}")]
SemVer(String),
}

impl From<semver::Error> for ContractError {
fn from(err: semver::Error) -> Self {
Self::SemVer(err.to_string())
}
}
11 changes: 11 additions & 0 deletions contracts/delegation/dao-vote-delegation/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))]

pub mod contract;

Check failure on line 3 in contracts/delegation/dao-vote-delegation/src/lib.rs

View workflow job for this annotation

GitHub Actions / Test Suite

file not found for module `contract`
mod error;
pub mod msg;
pub mod state;

#[cfg(test)]
mod testing;

pub use crate::error::ContractError;
79 changes: 79 additions & 0 deletions contracts/delegation/dao-vote-delegation/src/msg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use cosmwasm_schema::{cw_serde, QueryResponses};
use cosmwasm_std::{Addr, Decimal};
use cw4::MemberChangedHookMsg;
use cw_ownable::cw_ownable_execute;
use cw_utils::Duration;
use dao_hooks::{nft_stake::NftStakeChangedHookMsg, stake::StakeChangedHookMsg};
use dao_interface::voting::InfoResponse;

pub use cw_ownable::Ownership;

use crate::state::Delegation;

#[cw_serde]
pub struct InstantiateMsg {
/// The DAO. If not provided, the instantiator is used.
pub dao: Option<String>,
/// the maximum percent of voting power that a single delegate can wield.
/// they can be delegated any amount of voting power—this cap is only
/// applied when casting votes.
pub vp_cap_percent: Option<Decimal>,
/// the duration a delegation is valid for, after which it must be renewed
/// by the delegator.
pub delegation_validity: Option<Duration>,
}

#[cw_ownable_execute]
#[cw_serde]
pub enum ExecuteMsg {
/// Called when a member is added or removed
/// to a cw4-groups or cw721-roles contract.
MemberChangedHook(MemberChangedHookMsg),
/// Called when NFTs are staked or unstaked.
NftStakeChangeHook(NftStakeChangedHookMsg),
/// Called when tokens are staked or unstaked.
StakeChangeHook(StakeChangedHookMsg),
/// updates the configuration of the delegation system
UpdateConfig {
/// the maximum percent of voting power that a single delegate can
/// wield. they can be delegated any amount of voting power—this cap is
/// only applied when casting votes.
vp_cap_percent: Option<Decimal>,
/// the duration a delegation is valid for, after which it must be
/// renewed by the delegator.
delegation_validity: Option<Duration>,
},
}

#[cw_serde]
#[derive(QueryResponses)]
pub enum QueryMsg {
/// Returns contract version info
#[returns(InfoResponse)]
Info {},
/// Returns information about the ownership of this contract.
#[returns(Ownership<Addr>)]
Ownership {},
/// Returns the delegations by a delegator.
#[returns(DelegationsResponse)]
DelegatorDelegations {
delegator: String,
start_after: Option<u64>,
limit: Option<u32>,
},
/// Returns the delegations to a delegate.
#[returns(DelegationsResponse)]
DelegateDelegations {
delegate: String,
start_after: Option<u64>,
limit: Option<u32>,
},
}

#[cw_serde]
pub struct DelegationsResponse {
pub delegations: Vec<Delegation>,
}

#[cw_serde]
pub struct MigrateMsg {}
47 changes: 47 additions & 0 deletions contracts/delegation/dao-vote-delegation/src/state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Addr, Decimal, Uint128};
use cw20::Expiration;
use cw_storage_plus::{Item, Map, SnapshotMap, Strategy};
use cw_utils::Duration;

/// the configuration of the delegation system.
pub const CONFIG: Item<Config> = Item::new("config");

/// the DAO this delegation system is connected to.
pub const DAO: Item<Addr> = Item::new("dao");

/// the VP delegated to a delegate that has not yet been used in votes cast by
/// delegators in a specific proposal.
pub const UNVOTED_DELEGATED_VP: Map<(&Addr, u64), Uint128> = Map::new("udvp");

/// the VP delegated to a delegate by height.
pub const DELEGATED_VP: SnapshotMap<&Addr, Uint128> = SnapshotMap::new(
"dvp",
"dvp__checkpoints",
"dvp__changelog",
Strategy::EveryBlock,
);

#[cw_serde]
pub struct Config {
/// the maximum percent of voting power that a single delegate can wield.
/// they can be delegated any amount of voting power—this cap is only
/// applied when casting votes.
pub vp_cap_percent: Option<Decimal>,
/// the duration a delegation is valid for, after which it must be renewed
/// by the delegator.
pub delegation_validity: Option<Duration>,
}

#[cw_serde]
pub struct Delegation {
/// the delegator.
pub delegator: Addr,
/// the delegate that can vote on behalf of the delegator.
pub delegate: Addr,
/// the percent of the delegator's voting power that is delegated to the
/// delegate.
pub percent: Decimal,
/// when the delegation expires.
pub expiration: Expiration,
}

0 comments on commit 9ad11b4

Please sign in to comment.