1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
use std::marker::PhantomData;

use cosmwasm_schema::cw_serde;
use cosmwasm_std::Addr;
use cw_hooks::Hooks;
use cw_storage_plus::{Item, Map};

use dao_voting::deposit::CheckedDepositInfo;

#[cw_serde]
pub struct Config {
    /// Information about the deposit required to create a
    /// proposal. If `None`, no deposit is required.
    pub deposit_info: Option<CheckedDepositInfo>,
    /// If false, only members (addresses with voting power) may create
    /// proposals in the DAO. Otherwise, any address may create a
    /// proposal so long as they pay the deposit.
    pub open_proposal_submission: bool,
}

pub struct PreProposeContract<InstantiateExt, ExecuteExt, QueryExt, ProposalMessage> {
    /// The proposal module that this module is associated with.
    pub proposal_module: Item<'static, Addr>,
    /// The DAO (dao-dao module) that this module is associated
    /// with.
    pub dao: Item<'static, Addr>,
    /// The configuration for this module.
    pub config: Item<'static, Config>,
    /// Map between proposal IDs and (deposit, proposer) pairs.
    pub deposits: Map<'static, u64, (Option<CheckedDepositInfo>, Addr)>,
    /// Consumers of proposal submitted hooks.
    pub proposal_submitted_hooks: Hooks<'static>,

    // These types are used in associated functions, but not
    // assocaited data. To stop the compiler complaining about unused
    // generics, we build this phantom data.
    instantiate_type: PhantomData<InstantiateExt>,
    execute_type: PhantomData<ExecuteExt>,
    query_type: PhantomData<QueryExt>,
    proposal_type: PhantomData<ProposalMessage>,
}

impl<InstantiateExt, ExecuteExt, QueryExt, ProposalMessage>
    PreProposeContract<InstantiateExt, ExecuteExt, QueryExt, ProposalMessage>
{
    const fn new(
        proposal_key: &'static str,
        dao_key: &'static str,
        config_key: &'static str,
        deposits_key: &'static str,
        proposal_submitted_hooks_key: &'static str,
    ) -> Self {
        Self {
            proposal_module: Item::new(proposal_key),
            dao: Item::new(dao_key),
            config: Item::new(config_key),
            deposits: Map::new(deposits_key),
            proposal_submitted_hooks: Hooks::new(proposal_submitted_hooks_key),
            execute_type: PhantomData,
            instantiate_type: PhantomData,
            query_type: PhantomData,
            proposal_type: PhantomData,
        }
    }
}

impl<InstantiateExt, ExecuteExt, QueryExt, ProposalMessage> Default
    for PreProposeContract<InstantiateExt, ExecuteExt, QueryExt, ProposalMessage>
{
    fn default() -> Self {
        // Call into constant function here. Presumably, the compiler
        // is clever enough to inline this. This gives us
        // "more-or-less" constant evaluation for our default method.
        Self::new(
            "proposal_module",
            "dao",
            "config",
            "deposits",
            "proposal_submitted_hooks",
        )
    }
}