Skip to content

Commit

Permalink
Start outlining factory pattern work
Browse files Browse the repository at this point in the history
  • Loading branch information
JakeHartnell committed Sep 13, 2023
1 parent 67e8b83 commit 1eb197a
Show file tree
Hide file tree
Showing 28 changed files with 919 additions and 23 deletions.
15 changes: 15 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ dao-proposal-multiple = { path = "./contracts/proposal/dao-proposal-multiple", v
dao-proposal-single = { path = "./contracts/proposal/dao-proposal-single", version = "2.2.0" }
dao-proposal-sudo = { path = "./test-contracts/dao-proposal-sudo", version = "2.2.0" }
dao-proposal-hook-counter = { path = "./test-contracts/dao-proposal-hook-counter", version = "2.2.0" }
dao-test-custom-factory = { path = "./test-contracts/dao-test-custom-factory", version = "*" }
dao-testing = { path = "./packages/dao-testing", version = "2.2.0" }
dao-voting = { path = "./packages/dao-voting", version = "2.2.0" }
dao-voting-cw20-balance = { path = "./test-contracts/dao-voting-cw20-balance", version = "2.2.0" }
Expand Down
3 changes: 3 additions & 0 deletions ci/bootstrap-env/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ fn main() -> Result<()> {
},
active_threshold: None,
})?,
funds: vec![],
admin: Some(Admin::CoreModule {}),
label: "DAO DAO Voting Module".to_string(),
},
Expand Down Expand Up @@ -101,12 +102,14 @@ fn main() -> Result<()> {
})
.unwrap(),
admin: Some(Admin::CoreModule {}),
funds: vec![],
label: "DAO DAO Pre-Propose Module".to_string(),
},
},
close_proposal_on_execution_failure: false,
})?,
admin: Some(Admin::CoreModule {}),
funds: vec![],
label: "DAO DAO Proposal Module".to_string(),
}],
initial_items: None,
Expand Down
3 changes: 3 additions & 0 deletions ci/integration-tests/src/helpers/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ pub fn create_dao(
})?,
admin: Some(Admin::CoreModule {}),
label: "DAO DAO Voting Module".to_string(),
funds: vec![],
},
proposal_modules_instantiate_info: vec![ModuleInstantiateInfo {
code_id: chain.orc.contract_map.code_id("dao_proposal_single")?,
Expand Down Expand Up @@ -86,11 +87,13 @@ pub fn create_dao(
})
.unwrap(),
admin: Some(Admin::CoreModule {}),
funds: vec![],
label: "DAO DAO Pre-Propose Module".to_string(),
},
},
})?,
admin: Some(Admin::CoreModule {}),
funds: vec![],
label: "DAO DAO Proposal Module".to_string(),
}],
initial_items: None,
Expand Down
1 change: 1 addition & 0 deletions contracts/dao-dao-core/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,7 @@ pub fn migrate(deps: DepsMut, env: Env, msg: MigrateMsg) -> Result<Response, Con
msg: to_binary(&migrate_params.params).unwrap(),
admin: Some(Admin::CoreModule {}),
label: "migrator".to_string(),
funds: vec![],
}],
to_disable: vec![],
})
Expand Down
37 changes: 36 additions & 1 deletion contracts/voting/dao-voting-cw721-staked/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use cosmwasm_std::{
use cw2::{get_contract_version, set_contract_version, ContractVersion};
use cw721::{Cw721QueryMsg, Cw721ReceiveMsg, NumTokensResponse};
use cw_storage_plus::Bound;
use cw_utils::{parse_reply_instantiate_data, Duration};
use cw_utils::{parse_reply_execute_data, parse_reply_instantiate_data, Duration};
use dao_hooks::nft_stake::{stake_nft_hook_msgs, unstake_nft_hook_msgs};
use dao_interface::voting::IsActiveResponse;
use dao_voting::threshold::{ActiveThreshold, ActiveThresholdResponse};
Expand All @@ -25,6 +25,7 @@ pub(crate) const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");

const INSTANTIATE_NFT_CONTRACT_REPLY_ID: u64 = 0;
const VALIDATE_ABSOLUTE_COUNT_FOR_NEW_NFT_CONTRACTS: u64 = 1;
const FACTORY_EXECUTE_REPLY_ID: u64 = 2;

// We multiply by this when calculating needed power for being active
// when using active threshold with percent
Expand Down Expand Up @@ -176,6 +177,25 @@ pub fn instantiate(
.add_attribute("method", "instantiate")
.add_submessage(instantiate_msg))
}
NftContract::Factory(binary) => match from_binary(&binary)? {
WasmMsg::Execute {
msg,
contract_addr,
funds,
} => Ok(Response::new()
.add_attribute("action", "intantiate")
.add_submessage(SubMsg::reply_on_success(
WasmMsg::Execute {
contract_addr,
msg,
// TODO what to do with funds for fair burn?
// Need to pass them along to the factory
funds,
},
FACTORY_EXECUTE_REPLY_ID,
))),
_ => return Err(ContractError::UnsupportedFactoryMsg {}),

Check failure on line 197 in contracts/voting/dao-voting-cw721-staked/src/contract.rs

View workflow job for this annotation

GitHub Actions / Lints

unneeded `return` statement
},
}
}

Expand Down Expand Up @@ -713,6 +733,21 @@ pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> Result<Response, ContractE
}
Ok(Response::new())
}
FACTORY_EXECUTE_REPLY_ID => {
let res = parse_reply_execute_data(msg)?;

// TODO validate active threshold is set. Some contracts such as a minter,
// contract may not have any supply until tokens are minted.

match res.data {
Some(data) => {

Check failure on line 743 in contracts/voting/dao-voting-cw721-staked/src/contract.rs

View workflow job for this annotation

GitHub Actions / Lints

unused variable: `data`
// TODO parse data and save token contract address / denom
unimplemented!()
}
// TODO better error
None => return Err(ContractError::Unauthorized {}),

Check failure on line 748 in contracts/voting/dao-voting-cw721-staked/src/contract.rs

View workflow job for this annotation

GitHub Actions / Lints

unneeded `return` statement
}
}
_ => Err(ContractError::UnknownReplyId { id: msg.id }),
}
}
7 changes: 7 additions & 0 deletions contracts/voting/dao-voting-cw721-staked/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
use cosmwasm_std::{Addr, StdError};
use cw_utils::ParseReplyError;
use thiserror::Error;

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

#[error(transparent)]
ParseReplyError(#[from] ParseReplyError),

#[error("Can not stake that which has already been staked")]
AlreadyStaked {},

Expand Down Expand Up @@ -45,6 +49,9 @@ pub enum ContractError {
#[error("Got a submessage reply with unknown id: {id}")]
UnknownReplyId { id: u64 },

#[error("Factory message must serialize to WasmMsg::Execute")]
UnsupportedFactoryMsg {},

#[error("Active threshold count must be greater than zero")]
ZeroActiveCount {},

Expand Down
35 changes: 19 additions & 16 deletions contracts/voting/dao-voting-cw721-staked/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ use dao_voting::threshold::{ActiveThreshold, ActiveThresholdResponse};
#[cw_serde]
#[allow(clippy::large_enum_variant)]
pub enum NftContract {
/// Uses an existing cw721 or sg721 token contract.
Existing {
/// Address of an already instantiated cw721 token contract.
/// Address of an already instantiated cw721 or sg721 token contract.
address: String,
},
/// Creates a new NFT collection used for staking and governance.
New {
/// Code ID for cw721 token contract.
code_id: u64,
Expand All @@ -23,6 +25,9 @@ pub enum NftContract {
/// valid mint message for the corresponding cw721 contract.
initial_nfts: Vec<Binary>,
},
/// Uses a factory pattern that must return the denom, optionally a Token Contract address,
/// and any setup messages. The binary must serialize to a `WasmMsg::Execute` message.
Factory(Binary),
}

#[cw_serde]
Expand All @@ -46,22 +51,20 @@ pub enum ExecuteMsg {
/// Unstakes the specified token_ids on behalf of the
/// sender. token_ids must have unique values and have non-zero
/// length.
Unstake {
token_ids: Vec<String>,
},
Unstake { token_ids: Vec<String> },
/// Claim NFTs that have been unstaked for the specified duration.
ClaimNfts {},
UpdateConfig {
duration: Option<Duration>,
},
AddHook {
addr: String,
},
RemoveHook {
addr: String,
},
/// Sets the active threshold to a new value. Only the
/// instantiator this contract (a DAO most likely) may call this
/// method.
/// Updates the contract configuration, namely unstaking duration.
/// Only callable by the DAO that initialized this voting contract.
UpdateConfig { duration: Option<Duration> },
/// Adds a hook which is called on staking / unstaking events.
/// Only callable by the DAO that initialized this voting contract.
AddHook { addr: String },
/// Removes a hook which is called on staking / unstaking events.
/// Only callable by the DAO that initialized this voting contract.
RemoveHook { addr: String },
/// Sets the active threshold to a new value.
/// Only callable by the DAO that initialized this voting contract.
UpdateActiveThreshold {
new_threshold: Option<ActiveThreshold>,
},
Expand Down
41 changes: 38 additions & 3 deletions contracts/voting/dao-voting-token-staked/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@
use cosmwasm_std::entry_point;

use cosmwasm_std::{
coins, to_binary, BankMsg, BankQuery, Binary, Coin, CosmosMsg, Deps, DepsMut, Env, MessageInfo,
Order, Reply, Response, StdResult, SubMsg, Uint128, Uint256, WasmMsg,
coins, from_binary, to_binary, BankMsg, BankQuery, Binary, Coin, CosmosMsg, Deps, DepsMut, Env,
MessageInfo, Order, Reply, Response, StdResult, SubMsg, Uint128, Uint256, WasmMsg,
};
use cw2::{get_contract_version, set_contract_version, ContractVersion};
use cw_controllers::ClaimsResponse;
use cw_storage_plus::Bound;
use cw_tokenfactory_issuer::msg::{
DenomUnit, ExecuteMsg as IssuerExecuteMsg, InstantiateMsg as IssuerInstantiateMsg, Metadata,
};
use cw_utils::{maybe_addr, must_pay, parse_reply_instantiate_data, Duration};
use cw_utils::{
maybe_addr, must_pay, parse_reply_execute_data, parse_reply_instantiate_data, Duration,
};
use dao_hooks::stake::{stake_hook_msgs, unstake_hook_msgs};
use dao_interface::state::ModuleInstantiateCallback;
use dao_interface::voting::{
Expand Down Expand Up @@ -43,6 +45,7 @@ const MAX_LIMIT: u32 = 30;
const DEFAULT_LIMIT: u32 = 10;

const INSTANTIATE_TOKEN_FACTORY_ISSUER_REPLY_ID: u64 = 0;
const FACTORY_EXECUTE_REPLY_ID: u64 = 2;

// We multiply by this when calculating needed power for being active
// when using active threshold with percent
Expand Down Expand Up @@ -122,6 +125,23 @@ pub fn instantiate(
.add_attribute("token", "new_token")
.add_submessage(issuer_instantiate_msg))
}
TokenInfo::Factory(binary) => match from_binary(&binary)? {
WasmMsg::Execute {
msg, contract_addr, ..
} => Ok(Response::new()
.add_attribute("action", "intantiate")
.add_submessage(SubMsg::reply_on_success(
WasmMsg::Execute {
contract_addr,
msg,
// TODO what to do with funds for fair burn?
// Need to pass them along to the factory
funds: vec![],
},
FACTORY_EXECUTE_REPLY_ID,
))),
_ => return Err(ContractError::UnsupportedFactoryMsg {}),
},
}
}

Expand Down Expand Up @@ -695,6 +715,21 @@ pub fn reply(deps: DepsMut, env: Env, msg: Reply) -> Result<Response, ContractEr
_ => unreachable!(),
}
}
FACTORY_EXECUTE_REPLY_ID => {
let res = parse_reply_execute_data(msg)?;

// TODO validate active threshold is set. Some contracts such as a minter,
// contract may not have any supply until tokens are minted.

match res.data {
Some(data) => {
// TODO parse data and save token contract address / denom
unimplemented!()
}
// TODO better error
None => return Err(ContractError::Unauthorized {}),
}
}
_ => Err(ContractError::UnknownReplyId { id: msg.id }),
}
}
3 changes: 3 additions & 0 deletions contracts/voting/dao-voting-token-staked/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ pub enum ContractError {
#[error("Got a submessage reply with unknown id: {id}")]
UnknownReplyId { id: u64 },

#[error("Factory message must serialize to WasmMsg::Execute")]
UnsupportedFactoryMsg {},

#[error("Amount being unstaked must be non-zero")]
ZeroUnstake {},
}
5 changes: 4 additions & 1 deletion contracts/voting/dao-voting-token-staked/src/msg.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use cosmwasm_schema::{cw_serde, QueryResponses};
use cosmwasm_std::Uint128;
use cosmwasm_std::{Binary, Uint128};
use cw_tokenfactory_issuer::msg::DenomUnit;
use cw_utils::Duration;
use dao_dao_macros::{active_query, token_query, voting_module_query};
Expand Down Expand Up @@ -54,6 +54,9 @@ pub enum TokenInfo {
/// Creates a new Token Factory token via the issue contract with the DAO automatically
/// setup as admin and owner.
New(NewTokenInfo),
/// Uses a factory pattern that must return the denom, optionally a Token Contract address.
/// The binary must serialize to a `WasmMsg::Execute` message.
Factory(Binary),
}

#[cw_serde]
Expand Down
9 changes: 7 additions & 2 deletions packages/dao-interface/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{Addr, Binary, CosmosMsg, WasmMsg};
use cosmwasm_std::{Addr, Binary, Coin, CosmosMsg, WasmMsg};

/// Top level config type for core module.
#[cw_serde]
Expand Down Expand Up @@ -60,6 +60,8 @@ pub struct ModuleInstantiateInfo {
/// CosmWasm level admin of the instantiated contract. See:
/// <https://docs.cosmwasm.com/docs/1.0/smart-contracts/migration>
pub admin: Option<Admin>,
/// Funds to be sent to the instantiated contract.
pub funds: Vec<Coin>,
/// Label for the instantiated contract.
pub label: String,
}
Expand All @@ -73,7 +75,7 @@ impl ModuleInstantiateInfo {
}),
code_id: self.code_id,
msg: self.msg,
funds: vec![],
funds: self.funds,
label: self.label,
}
}
Expand All @@ -98,6 +100,7 @@ mod tests {
msg: to_binary("foo").unwrap(),
admin: None,
label: "bar".to_string(),
funds: vec![],
};
assert_eq!(
no_admin.into_wasm_msg(Addr::unchecked("ekez")),
Expand All @@ -120,6 +123,7 @@ mod tests {
addr: "core".to_string(),
}),
label: "bar".to_string(),
funds: vec![],
};
assert_eq!(
no_admin.into_wasm_msg(Addr::unchecked("ekez")),
Expand All @@ -140,6 +144,7 @@ mod tests {
msg: to_binary("foo").unwrap(),
admin: Some(Admin::CoreModule {}),
label: "bar".to_string(),
funds: vec![],
};
assert_eq!(
no_admin.into_wasm_msg(Addr::unchecked("ekez")),
Expand Down
Loading

0 comments on commit 1eb197a

Please sign in to comment.