astroport_emissions_controller/
query.rs1use std::collections::HashSet;
2
3#[cfg(not(feature = "library"))]
4use cosmwasm_std::entry_point;
5use cosmwasm_std::{to_json_binary, Binary, Deps, Env, Order, StdError, StdResult};
6use cw_storage_plus::Bound;
7use itertools::Itertools;
8use neutron_sdk::bindings::query::NeutronQuery;
9
10use astroport_governance::emissions_controller::consts::MAX_PAGE_LIMIT;
11use astroport_governance::emissions_controller::hub::{
12 QueryMsg, SimulateTuneResponse, UserInfoResponse,
13};
14
15use crate::error::ContractError;
16use crate::state::{
17 get_active_outposts, get_all_outposts, CONFIG, POOLS_BLACKLIST, POOLS_WHITELIST, TUNE_INFO,
18 USER_INFO, VOTED_POOLS,
19};
20use crate::utils::simulate_tune;
21
22#[cfg_attr(not(feature = "library"), entry_point)]
24pub fn query(deps: Deps<NeutronQuery>, env: Env, msg: QueryMsg) -> Result<Binary, ContractError> {
25 match msg {
26 QueryMsg::UserInfo { user, timestamp } => {
27 let block_time = env.block.time.seconds();
28 let timestamp = timestamp.unwrap_or(block_time);
29 let user_info = match timestamp {
30 timestamp if timestamp == block_time => USER_INFO.may_load(deps.storage, &user),
31 timestamp => USER_INFO.may_load_at_height(deps.storage, &user, timestamp),
32 }?
33 .unwrap_or_default();
34
35 let applied_votes = user_info
36 .votes
37 .iter()
38 .filter_map(|(pool, weight)| {
39 let data = if timestamp == block_time {
40 VOTED_POOLS.may_load(deps.storage, pool)
41 } else {
42 VOTED_POOLS.may_load_at_height(deps.storage, pool, timestamp)
43 };
44
45 match data {
46 Ok(Some(pool_info)) if pool_info.init_ts <= user_info.vote_ts => {
47 Some(Ok((pool.clone(), *weight)))
48 }
49 Err(err) => Some(Err(err)),
50 _ => None,
51 }
52 })
53 .try_collect()?;
54
55 let response = UserInfoResponse {
56 vote_ts: user_info.vote_ts,
57 voting_power: user_info.voting_power,
58 votes: user_info.votes,
59 applied_votes,
60 };
61
62 Ok(to_json_binary(&response)?)
63 }
64 QueryMsg::TuneInfo { timestamp } => {
65 let block_time = env.block.time.seconds();
66 let timestamp = timestamp.unwrap_or(block_time);
67 let tune_info = match timestamp {
68 timestamp if timestamp == block_time => TUNE_INFO.may_load(deps.storage),
69 timestamp => TUNE_INFO.may_load_at_height(deps.storage, timestamp),
70 }?
71 .ok_or_else(|| StdError::generic_err(format!("Tune info not found at {timestamp}")))?;
72 Ok(to_json_binary(&tune_info)?)
73 }
74 QueryMsg::Config {} => Ok(to_json_binary(&CONFIG.load(deps.storage)?)?),
75 QueryMsg::VotedPool { pool, timestamp } => {
76 let block_time = env.block.time.seconds();
77 let timestamp = timestamp.unwrap_or(block_time);
78 let voted_pool = match timestamp {
79 timestamp if timestamp == block_time => VOTED_POOLS.may_load(deps.storage, &pool),
80 timestamp => VOTED_POOLS.may_load_at_height(deps.storage, &pool, timestamp),
81 }?
82 .ok_or_else(|| StdError::generic_err(format!("Voted pool not found at {timestamp}")))?;
83 Ok(to_json_binary(&voted_pool)?)
84 }
85 QueryMsg::VotedPools { limit, start_after } => {
86 let limit = limit.unwrap_or(MAX_PAGE_LIMIT) as usize;
87 let voted_pools = VOTED_POOLS
88 .range(
89 deps.storage,
90 start_after.as_ref().map(|s| Bound::exclusive(s.as_str())),
91 None,
92 Order::Ascending,
93 )
94 .take(limit)
95 .collect::<StdResult<Vec<_>>>()?;
96 Ok(to_json_binary(&voted_pools)?)
97 }
98 QueryMsg::ListOutposts {} => {
99 let outposts = get_all_outposts(deps.storage)?.into_iter().collect_vec();
100 Ok(to_json_binary(&outposts)?)
101 }
102 QueryMsg::QueryWhitelist { limit, start_after } => {
103 let limit = limit.unwrap_or(MAX_PAGE_LIMIT) as usize;
104 let pools_whitelist = POOLS_WHITELIST
105 .load(deps.storage)?
106 .into_iter()
107 .skip_while(|pool| {
108 if let Some(start_after) = &start_after {
109 pool != start_after
110 } else {
111 false
112 }
113 })
114 .take(limit)
115 .collect_vec();
116
117 let pools_whitelist = if start_after.is_some() {
118 &pools_whitelist[1..]
119 } else {
120 &pools_whitelist
121 };
122
123 Ok(to_json_binary(pools_whitelist)?)
124 }
125 QueryMsg::QueryBlacklist { limit, start_after } => {
126 let limit = limit.unwrap_or(MAX_PAGE_LIMIT) as usize;
127 let start_after = start_after.as_ref().map(|s| Bound::exclusive(s.as_str()));
128 let pools_blacklist = POOLS_BLACKLIST
129 .keys(deps.storage, start_after, None, Order::Ascending)
130 .take(limit)
131 .collect::<StdResult<Vec<_>>>()?;
132
133 Ok(to_json_binary(&pools_blacklist)?)
134 }
135 QueryMsg::CheckWhitelist { lp_tokens } => {
136 let whitelist = POOLS_WHITELIST.load(deps.storage)?;
137 let is_whitelisted = lp_tokens
138 .into_iter()
139 .map(|lp_token| {
140 let is_whitelisted = whitelist.contains(&lp_token);
141 (lp_token, is_whitelisted)
142 })
143 .collect_vec();
144 Ok(to_json_binary(&is_whitelisted)?)
145 }
146 QueryMsg::SimulateTune {} => {
147 let deps = deps.into_empty();
148
149 let voted_pools = VOTED_POOLS
150 .keys(deps.storage, None, None, Order::Ascending)
151 .collect::<StdResult<HashSet<_>>>()?;
152 let outposts = get_active_outposts(deps.storage)?;
153 let config = CONFIG.load(deps.storage)?;
154
155 let tune_result = simulate_tune(
156 deps,
157 &voted_pools,
158 &outposts,
159 env.block.time.seconds(),
160 &config,
161 )?;
162 Ok(to_json_binary(&SimulateTuneResponse {
163 new_emissions_state: tune_result.new_emissions_state,
164 next_pools_grouped: tune_result.next_pools_grouped,
165 })?)
166 }
167 }
168}