astroport_emissions_controller/
instantiate.rs

1use astroport::asset::validate_native_denom;
2#[cfg(not(feature = "library"))]
3use cosmwasm_std::entry_point;
4use cosmwasm_std::{
5    ensure, to_json_binary, Addr, DepsMut, Env, MessageInfo, Reply, Response, StdError, SubMsg,
6    SubMsgResponse, SubMsgResult, Uint128, WasmMsg,
7};
8use cw2::set_contract_version;
9use cw_utils::parse_instantiate_response_data;
10use neutron_sdk::bindings::msg::NeutronMsg;
11use neutron_sdk::bindings::query::NeutronQuery;
12
13use astroport_governance::emissions_controller::hub::{Config, TuneInfo};
14use astroport_governance::emissions_controller::hub::{EmissionsState, HubInstantiateMsg};
15use astroport_governance::emissions_controller::utils::query_incentives_addr;
16use astroport_governance::voting_escrow;
17
18use crate::error::ContractError;
19use crate::state::{CONFIG, POOLS_WHITELIST, TUNE_INFO};
20use crate::utils::{get_epoch_start, get_xastro_rate_and_share};
21
22/// Contract name that is used for migration.
23pub const CONTRACT_NAME: &str = env!("CARGO_PKG_NAME");
24/// Contract version that is used for migration.
25pub const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
26/// ID for the vxastro contract instantiate reply
27pub const INSTANTIATE_VXASTRO_REPLY_ID: u64 = 1;
28
29/// Creates a new contract with the specified parameters in the [`InstantiateMsg`].
30#[cfg_attr(not(feature = "library"), entry_point)]
31pub fn instantiate(
32    deps: DepsMut<NeutronQuery>,
33    env: Env,
34    _info: MessageInfo,
35    msg: HubInstantiateMsg,
36) -> Result<Response<NeutronMsg>, ContractError> {
37    let deps = deps.into_empty();
38
39    set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
40
41    validate_native_denom(&msg.astro_denom)?;
42
43    let factory = deps.api.addr_validate(&msg.factory)?;
44
45    let staking =
46        if msg.xastro_denom.starts_with("factory/") && msg.xastro_denom.ends_with("/xASTRO") {
47            deps.api
48                .addr_validate(msg.xastro_denom.split('/').nth(1).unwrap())
49        } else {
50            Err(StdError::generic_err(format!(
51                "Invalid xASTRO denom {}",
52                msg.xastro_denom
53            )))
54        }?;
55
56    let config = Config {
57        owner: deps.api.addr_validate(&msg.owner)?,
58        assembly: deps.api.addr_validate(&msg.assembly)?,
59        vxastro: Addr::unchecked(""),
60        incentives_addr: query_incentives_addr(deps.querier, &factory)?,
61        factory,
62        astro_denom: msg.astro_denom.to_string(),
63        pools_per_outpost: msg.pools_per_outpost,
64        whitelisting_fee: msg.whitelisting_fee,
65        fee_receiver: deps.api.addr_validate(&msg.fee_receiver)?,
66        whitelist_threshold: msg.whitelist_threshold,
67        emissions_multiple: msg.emissions_multiple,
68        max_astro: msg.max_astro,
69        staking,
70        xastro_denom: msg.xastro_denom.clone(),
71    };
72    config.validate()?;
73
74    CONFIG.save(deps.storage, &config)?;
75
76    // Query dynamic emissions curve state
77    let (xastro_rate, _) = get_xastro_rate_and_share(deps.querier, &config)?;
78
79    // Set tune_ts so the first tuning happens in 2 weeks
80    TUNE_INFO.save(
81        deps.storage,
82        &TuneInfo {
83            tune_ts: get_epoch_start(env.block.time.seconds()),
84            pools_grouped: Default::default(),
85            outpost_emissions_statuses: Default::default(),
86            emissions_state: EmissionsState {
87                xastro_rate,
88                collected_astro: msg.collected_astro,
89                ema: msg.ema,
90                emissions_amount: Uint128::zero(),
91            },
92        },
93        env.block.time.seconds(),
94    )?;
95
96    // Instantiate vxASTRO contract
97    let init_vxastro_msg = WasmMsg::Instantiate {
98        admin: Some(msg.assembly),
99        code_id: msg.vxastro_code_id,
100        msg: to_json_binary(&voting_escrow::InstantiateMsg {
101            deposit_denom: msg.xastro_denom.to_string(),
102            emissions_controller: env.contract.address.to_string(),
103            marketing: msg.vxastro_marketing_info,
104        })?,
105        funds: vec![],
106        label: "Vote Escrowed xASTRO".to_string(),
107    };
108
109    POOLS_WHITELIST.save(deps.storage, &vec![])?;
110
111    Ok(Response::default()
112        .add_attribute("action", "instantiate_emissions_controller")
113        .add_submessage(SubMsg::reply_on_success(
114            init_vxastro_msg,
115            INSTANTIATE_VXASTRO_REPLY_ID,
116        )))
117}
118
119#[cfg_attr(not(feature = "library"), entry_point)]
120pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> Result<Response, ContractError> {
121    match msg {
122        Reply {
123            id: INSTANTIATE_VXASTRO_REPLY_ID,
124            result:
125                SubMsgResult::Ok(SubMsgResponse {
126                    data: Some(data), ..
127                }),
128        } => {
129            let vxastro_contract = parse_instantiate_response_data(&data)?.contract_address;
130
131            CONFIG.update::<_, StdError>(deps.storage, |mut config| {
132                ensure!(
133                    config.vxastro == Addr::unchecked(""),
134                    StdError::generic_err("vxASTRO contract is already set")
135                );
136
137                config.vxastro = Addr::unchecked(&vxastro_contract);
138                Ok(config)
139            })?;
140
141            Ok(Response::new().add_attribute("vxastro", vxastro_contract))
142        }
143        _ => Err(ContractError::FailedToParseReply {}),
144    }
145}