Skip to content

Commit

Permalink
feat(em. controller): add blacklisting logic (#118)
Browse files Browse the repository at this point in the history
* feat(em. controller): add blacklisting logic

* adjust tests

* fix comment
  • Loading branch information
epanchee authored Nov 6, 2024
1 parent 4c05ad5 commit 0795721
Show file tree
Hide file tree
Showing 14 changed files with 412 additions and 25 deletions.
12 changes: 6 additions & 6 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions contracts/emissions_controller/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "astroport-emissions-controller"
version = "1.1.2"
version = "1.2.0"
authors = ["Astroport"]
edition = "2021"
description = "Astroport vxASTRO Emissions Voting Contract"
Expand All @@ -23,7 +23,7 @@ cw-storage-plus.workspace = true
cosmwasm-schema.workspace = true
thiserror.workspace = true
itertools.workspace = true
astroport-governance = { path = "../../packages/astroport-governance", version = "4.2" }
astroport-governance = { path = "../../packages/astroport-governance", version = "4.3" }
astroport.workspace = true
neutron-sdk = "0.10.0"
serde_json = "1"
Expand Down
3 changes: 3 additions & 0 deletions contracts/emissions_controller/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,7 @@ pub enum ContractError {

#[error("Outpost {prefix} is jailed. Only vxASTRO unlocks are available")]
JailedOutpost { prefix: String },

#[error("Pool {0} is blacklisted")]
PoolIsBlacklisted(String),
}
76 changes: 71 additions & 5 deletions contracts/emissions_controller/src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ use astroport::incentives;
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{
attr, ensure, to_json_binary, wasm_execute, BankMsg, Coin, CosmosMsg, Decimal, DepsMut, Env,
Fraction, IbcMsg, IbcTimeout, MessageInfo, Order, Response, StdError, StdResult, Storage,
Uint128,
attr, ensure, ensure_eq, to_json_binary, wasm_execute, BankMsg, Coin, CosmosMsg, Decimal,
DepsMut, Env, Fraction, IbcMsg, IbcTimeout, MessageInfo, Order, Response, StdError, StdResult,
Storage, Uint128,
};
use cw_utils::{must_pay, nonpayable};
use itertools::Itertools;
Expand All @@ -29,8 +29,8 @@ use astroport_governance::{assembly, voting_escrow};

use crate::error::ContractError;
use crate::state::{
get_active_outposts, CONFIG, OUTPOSTS, OWNERSHIP_PROPOSAL, POOLS_WHITELIST, TUNE_INFO,
USER_INFO, VOTED_POOLS,
get_active_outposts, CONFIG, OUTPOSTS, OWNERSHIP_PROPOSAL, POOLS_BLACKLIST, POOLS_WHITELIST,
TUNE_INFO, USER_INFO, VOTED_POOLS,
};
use crate::utils::{
build_emission_ibc_msg, get_epoch_start, get_outpost_prefix, jail_outpost, min_ntrn_ibc_fee,
Expand Down Expand Up @@ -136,6 +136,9 @@ pub fn execute(
}
ExecuteMsg::Custom(hub_msg) => match hub_msg {
HubMsg::WhitelistPool { lp_token: pool } => whitelist_pool(deps, env, info, pool),
HubMsg::UpdateBlacklist { add, remove } => {
update_blacklist(deps, info, env, add, remove)
}
HubMsg::UpdateOutpost {
prefix,
astro_denom,
Expand Down Expand Up @@ -191,6 +194,12 @@ pub fn whitelist_pool(
ContractError::IncorrectWhitelistFee(config.whitelisting_fee)
);

// Ensure that LP token is not blacklisted
ensure!(
!POOLS_BLACKLIST.has(deps.storage, &pool),
ContractError::PoolIsBlacklisted(pool.clone())
);

// Perform basic LP token validation. Ensure the outpost exists.
let outposts = get_active_outposts(deps.storage)?;
if let Some(prefix) = get_outpost_prefix(&pool, &outposts) {
Expand Down Expand Up @@ -244,6 +253,63 @@ pub fn whitelist_pool(
.add_attributes([attr("action", "whitelist_pool"), attr("pool", &pool)]))
}

pub fn update_blacklist(
deps: DepsMut<NeutronQuery>,
info: MessageInfo,
env: Env,
add: Vec<String>,
remove: Vec<String>,
) -> Result<Response<NeutronMsg>, ContractError> {
let config = CONFIG.load(deps.storage)?;

ensure_eq!(info.sender, config.owner, ContractError::Unauthorized {});

// Checking for duplicates
ensure!(
remove.iter().chain(add.iter()).all_unique(),
StdError::generic_err("Duplicated LP tokens found")
);

// Remove pools from blacklist
for lp_token in &remove {
ensure!(
POOLS_BLACKLIST.has(deps.storage, lp_token),
StdError::generic_err(format!("LP token {lp_token} wasn't found in the blacklist"))
);

POOLS_BLACKLIST.remove(deps.storage, lp_token);
}

// Add pools to blacklist
for lp_token in &add {
ensure!(
!POOLS_BLACKLIST.has(deps.storage, lp_token),
StdError::generic_err(format!("LP token {lp_token} is already blacklisted"))
);

// If key doesn't exist .remove() doesn't throw an error
VOTED_POOLS.remove(deps.storage, lp_token, env.block.time.seconds())?;
POOLS_BLACKLIST.save(deps.storage, lp_token, &())?;
}

// And remove pools from the whitelist if they are there
POOLS_WHITELIST.update::<_, StdError>(deps.storage, |mut whitelist| {
whitelist.retain(|pool| !add.contains(pool));
Ok(whitelist)
})?;

let mut attrs = vec![attr("action", "update_blacklist")];

if !add.is_empty() {
attrs.push(attr("add", add.into_iter().join(",")));
}
if !remove.is_empty() {
attrs.push(attr("remove", remove.into_iter().join(",")));
}

Ok(Response::default().add_attributes(attrs))
}

/// Permissioned endpoint to add or update outpost.
/// Performs several simple checks to cut off possible human errors.
pub fn update_outpost(
Expand Down
14 changes: 12 additions & 2 deletions contracts/emissions_controller/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use astroport_governance::emissions_controller::hub::{

use crate::error::ContractError;
use crate::state::{
get_active_outposts, get_all_outposts, CONFIG, POOLS_WHITELIST, TUNE_INFO, USER_INFO,
VOTED_POOLS,
get_active_outposts, get_all_outposts, CONFIG, POOLS_BLACKLIST, POOLS_WHITELIST, TUNE_INFO,
USER_INFO, VOTED_POOLS,
};
use crate::utils::simulate_tune;

Expand Down Expand Up @@ -122,6 +122,16 @@ pub fn query(deps: Deps<NeutronQuery>, env: Env, msg: QueryMsg) -> Result<Binary

Ok(to_json_binary(pools_whitelist)?)
}
QueryMsg::QueryBlacklist { limit, start_after } => {
let limit = limit.unwrap_or(MAX_PAGE_LIMIT) as usize;
let start_after = start_after.as_ref().map(|s| Bound::exclusive(s.as_str()));
let pools_blacklist = POOLS_BLACKLIST
.keys(deps.storage, start_after, None, Order::Ascending)
.take(limit)
.collect::<StdResult<Vec<_>>>()?;

Ok(to_json_binary(&pools_blacklist)?)
}
QueryMsg::CheckWhitelist { lp_tokens } => {
let whitelist = POOLS_WHITELIST.load(deps.storage)?;
let is_whitelisted = lp_tokens
Expand Down
1 change: 1 addition & 0 deletions contracts/emissions_controller/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub const CONFIG: Item<Config> = Item::new("config");
pub const OWNERSHIP_PROPOSAL: Item<OwnershipProposal> = Item::new("ownership_proposal");
/// Array of pools eligible for voting.
pub const POOLS_WHITELIST: Item<Vec<String>> = Item::new("pools_whitelist");
pub const POOLS_BLACKLIST: Map<&str, ()> = Map::new("pools_blacklist");
/// Registered Astroport outposts with respective parameters.
pub const OUTPOSTS: Map<&str, OutpostInfo> = Map::new("outposts");
/// Historical user's voting information.
Expand Down
24 changes: 24 additions & 0 deletions contracts/emissions_controller/tests/common/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,20 @@ impl ControllerHelper {
)
}

pub fn update_blacklist(
&mut self,
user: &Addr,
add: Vec<String>,
remove: Vec<String>,
) -> AnyResult<AppResponse> {
self.app.execute_contract(
user.clone(),
self.emission_controller.clone(),
&emissions_controller::msg::ExecuteMsg::Custom(HubMsg::UpdateBlacklist { add, remove }),
&[],
)
}

pub fn add_outpost(&mut self, prefix: &str, outpost: OutpostInfo) -> AnyResult<AppResponse> {
self.app.execute_contract(
self.owner.clone(),
Expand Down Expand Up @@ -573,6 +587,16 @@ impl ControllerHelper {
)
}

pub fn query_blacklist(&self) -> StdResult<Vec<String>> {
self.app.wrap().query_wasm_smart(
&self.emission_controller,
&emissions_controller::hub::QueryMsg::QueryBlacklist {
limit: Some(100),
start_after: None,
},
)
}

pub fn check_whitelist(&self, lp_tokens: Vec<String>) -> StdResult<Vec<(String, bool)>> {
self.app.wrap().query_wasm_smart(
&self.emission_controller,
Expand Down
Loading

0 comments on commit 0795721

Please sign in to comment.