Skip to content

Commit

Permalink
feat!: Use named type for update whitelist and query (#255)
Browse files Browse the repository at this point in the history
* feat: Use named type for update whitelist and query

* feat: Add migrate entrypoint to incentives contract
  • Loading branch information
apollo-sturdy authored and pacmanifold committed Jul 19, 2023
1 parent 4d63e64 commit 74b56cc
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 86 deletions.
35 changes: 27 additions & 8 deletions contracts/incentives/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use mars_red_bank_types::{
error::MarsError,
incentives::{
Config, ConfigResponse, EmissionResponse, ExecuteMsg, IncentiveState,
IncentiveStateResponse, InstantiateMsg, QueryMsg,
IncentiveStateResponse, InstantiateMsg, MigrateMsg, QueryMsg, WhitelistEntry,
},
};
use mars_utils::helpers::{option_string_to_addr, validate_native_denom};
Expand Down Expand Up @@ -140,15 +140,15 @@ pub fn execute_update_whitelist(
mut deps: DepsMut,
env: Env,
info: MessageInfo,
add_denoms: Vec<(String, Uint128)>,
add_denoms: Vec<WhitelistEntry>,
remove_denoms: Vec<String>,
) -> Result<Response, ContractError> {
OWNER.assert_owner(deps.storage, &info.sender)?;

let config = CONFIG.load(deps.storage)?;

// Add add_denoms and remove_denoms to a set to check for duplicates
let denoms = add_denoms.iter().map(|(denom, _)| denom).chain(remove_denoms.iter());
let denoms = add_denoms.iter().map(|entry| &entry.denom).chain(remove_denoms.iter());
let mut denoms_set = std::collections::HashSet::new();
for denom in denoms {
if !denoms_set.insert(denom) {
Expand Down Expand Up @@ -212,7 +212,11 @@ pub fn execute_update_whitelist(
WHITELIST.remove(deps.storage, denom);
}

for (denom, min_emission) in add_denoms.iter() {
for entry in add_denoms.iter() {
let WhitelistEntry {
denom,
min_emission_rate,
} = entry;
// If the denom is not already whitelisted, increase the counter and check that we are not
// exceeding the max whitelist limit. If the denom is already whitelisted, we don't need
// to change the counter and instead just update the min_emission.
Expand All @@ -226,7 +230,7 @@ pub fn execute_update_whitelist(
}

validate_native_denom(denom)?;
WHITELIST.save(deps.storage, denom, min_emission)?;
WHITELIST.save(deps.storage, denom, min_emission_rate)?;
}

// Set the new whitelist count, if it has changed
Expand Down Expand Up @@ -681,9 +685,17 @@ fn query_red_bank_address(deps: Deps) -> StdResult<Addr> {
)
}

fn query_whitelist(deps: Deps) -> StdResult<Vec<(String, Uint128)>> {
let whitelist: Vec<(String, Uint128)> =
WHITELIST.range(deps.storage, None, None, Order::Ascending).collect::<StdResult<_>>()?;
fn query_whitelist(deps: Deps) -> StdResult<Vec<WhitelistEntry>> {
let whitelist: Vec<WhitelistEntry> = WHITELIST
.range(deps.storage, None, None, Order::Ascending)
.map(|res| {
let (denom, min_emission_rate) = res?;
Ok(WhitelistEntry {
denom,
min_emission_rate,
})
})
.collect::<StdResult<_>>()?;
Ok(whitelist)
}

Expand Down Expand Up @@ -727,3 +739,10 @@ pub fn query_emissions(

Ok(emissions.into_iter().map(|x| x.into()).collect())
}

/// MIGRATION
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
Ok(Response::default())
}
2 changes: 1 addition & 1 deletion contracts/incentives/tests/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub fn th_query_with_env<T: serde::de::DeserializeOwned>(deps: Deps, env: Env, m
pub fn th_whitelist_denom(deps: DepsMut, denom: &str) {
let owner = "owner";
let msg = ExecuteMsg::UpdateWhitelist {
add_denoms: vec![(denom.to_string(), Uint128::new(3))],
add_denoms: vec![(denom.to_string(), Uint128::new(3)).into()],
remove_denoms: vec![],
};
let info = mock_info(owner, &[]);
Expand Down
2 changes: 1 addition & 1 deletion contracts/incentives/tests/test_set_asset_incentive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ fn can_only_set_new_incentive_with_start_time_multiple_of_epoch_duration_from_cu

// Whitelist umars as incentive denom
let msg = ExecuteMsg::UpdateWhitelist {
add_denoms: vec![("umars".to_string(), Uint128::new(3))],
add_denoms: vec![("umars".to_string(), Uint128::new(3)).into()],
remove_denoms: vec![],
};
execute(deps.as_mut(), env.clone(), mock_info("owner", &[]), msg).unwrap();
Expand Down
76 changes: 38 additions & 38 deletions contracts/incentives/tests/test_whitelist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use mars_incentives::{
};
use mars_owner::OwnerError::NotOwner;
use mars_red_bank_types::{
incentives::{ExecuteMsg, QueryMsg},
incentives::{ExecuteMsg, QueryMsg, WhitelistEntry},
red_bank::{Market, UserCollateralResponse},
};
use mars_testing::MockEnvParams;
Expand Down Expand Up @@ -41,7 +41,7 @@ fn update_whitelist_only_callable_by_admin() {
mock_env(),
mock_info(bad_guy, &[]),
ExecuteMsg::UpdateWhitelist {
add_denoms: vec![("umars".to_string(), Uint128::new(3))],
add_denoms: vec![("umars".to_string(), Uint128::new(3)).into()],
remove_denoms: vec![],
},
)
Expand All @@ -56,14 +56,14 @@ fn update_whitelist_add_denom_works() {
// only owner can update whitelist
let owner = "owner";
let msg = ExecuteMsg::UpdateWhitelist {
add_denoms: vec![("umars".to_string(), Uint128::new(3))],
add_denoms: vec![("umars".to_string(), Uint128::new(3)).into()],
remove_denoms: vec![],
};
let info = mock_info(owner, &[]);
execute(deps.as_mut(), mock_env(), info, msg).unwrap();

let whitelist: Vec<(String, Uint128)> = th_query(deps.as_ref(), QueryMsg::Whitelist {});
assert_eq!(whitelist, vec![("umars".to_string(), Uint128::new(3))]);
let whitelist: Vec<WhitelistEntry> = th_query(deps.as_ref(), QueryMsg::Whitelist {});
assert_eq!(whitelist, vec![("umars".to_string(), Uint128::new(3)).into()]);
}

#[test]
Expand All @@ -73,14 +73,14 @@ fn update_whitelist_remove_denom_works() {
// only owner can update whitelist
let owner = "owner";
let msg = ExecuteMsg::UpdateWhitelist {
add_denoms: vec![("umars".to_string(), Uint128::new(3))],
add_denoms: vec![("umars".to_string(), Uint128::new(3)).into()],
remove_denoms: vec![],
};
let info = mock_info(owner, &[]);
execute(deps.as_mut(), mock_env(), info, msg).unwrap();

let whitelist: Vec<(String, Uint128)> = th_query(deps.as_ref(), QueryMsg::Whitelist {});
assert_eq!(whitelist, vec![("umars".to_string(), Uint128::new(3))]);
let whitelist: Vec<WhitelistEntry> = th_query(deps.as_ref(), QueryMsg::Whitelist {});
assert_eq!(whitelist, vec![("umars".to_string(), Uint128::new(3)).into()]);

// remove denom
let msg = ExecuteMsg::UpdateWhitelist {
Expand All @@ -90,7 +90,7 @@ fn update_whitelist_remove_denom_works() {
let info = mock_info(owner, &[]);
execute(deps.as_mut(), mock_env(), info, msg).unwrap();

let whitelist: Vec<(String, Uint128)> = th_query(deps.as_ref(), QueryMsg::Whitelist {});
let whitelist: Vec<WhitelistEntry> = th_query(deps.as_ref(), QueryMsg::Whitelist {});
assert!(whitelist.is_empty());
}

Expand All @@ -101,7 +101,7 @@ fn cannot_add_invalid_denom_to_whitelist() {
// only owner can update whitelist
let owner = "owner";
let msg = ExecuteMsg::UpdateWhitelist {
add_denoms: vec![("//invalid-denom//".to_string(), Uint128::new(3))],
add_denoms: vec![("//invalid-denom//".to_string(), Uint128::new(3)).into()],
remove_denoms: vec![],
};
let info = mock_info(owner, &[]);
Expand Down Expand Up @@ -145,7 +145,7 @@ fn incentive_can_only_be_added_if_denom_whitelisted() {

// add denom to whitelist
let add_whitelist_msg: ExecuteMsg = ExecuteMsg::UpdateWhitelist {
add_denoms: vec![("umars".to_string(), Uint128::new(3))],
add_denoms: vec![("umars".to_string(), Uint128::new(3)).into()],
remove_denoms: vec![],
};
execute(deps.as_mut(), mock_env(), mock_info(owner, &[]), add_whitelist_msg).unwrap();
Expand All @@ -171,7 +171,7 @@ fn incentives_updated_and_removed_when_removing_from_whitelist() {

// add denom to whitelist
let add_whitelist_msg = ExecuteMsg::UpdateWhitelist {
add_denoms: vec![("umars".to_string(), Uint128::new(3))],
add_denoms: vec![("umars".to_string(), Uint128::new(3)).into()],
remove_denoms: vec![],
};
execute(deps.as_mut(), mock_env(), mock_info(owner, &[]), add_whitelist_msg).unwrap();
Expand Down Expand Up @@ -275,29 +275,29 @@ fn whitelisting_already_whitelisted_denom_updates_min_emission() {

// add denom to whitelist
let add_whitelist_msg: ExecuteMsg = ExecuteMsg::UpdateWhitelist {
add_denoms: vec![("umars".to_string(), Uint128::new(3))],
add_denoms: vec![("umars".to_string(), Uint128::new(3)).into()],
remove_denoms: vec![],
};
execute(deps.as_mut(), mock_env(), mock_info(owner, &[]), add_whitelist_msg).unwrap();

// Query whitelist
let whitelist: Vec<(String, Uint128)> = th_query(deps.as_ref(), QueryMsg::Whitelist {});
assert_eq!(whitelist, vec![("umars".to_string(), Uint128::new(3))]);
let whitelist: Vec<WhitelistEntry> = th_query(deps.as_ref(), QueryMsg::Whitelist {});
assert_eq!(whitelist, vec![("umars".to_string(), Uint128::new(3)).into()]);

// Query whitelist count
let whitelist_count = WHITELIST_COUNT.load(&deps.storage).unwrap();
assert_eq!(whitelist_count, 1);

// add denom to whitelist again, with a higher min emission
let add_whitelist_msg: ExecuteMsg = ExecuteMsg::UpdateWhitelist {
add_denoms: vec![("umars".to_string(), Uint128::new(5))],
add_denoms: vec![("umars".to_string(), Uint128::new(5)).into()],
remove_denoms: vec![],
};
execute(deps.as_mut(), mock_env(), mock_info(owner, &[]), add_whitelist_msg).unwrap();

// Query whitelist
let whitelist: Vec<(String, Uint128)> = th_query(deps.as_ref(), QueryMsg::Whitelist {});
assert_eq!(whitelist, vec![("umars".to_string(), Uint128::new(5))]);
let whitelist: Vec<WhitelistEntry> = th_query(deps.as_ref(), QueryMsg::Whitelist {});
assert_eq!(whitelist, vec![("umars".to_string(), Uint128::new(5)).into()]);

// Query whitelist count, should not have changed.
let whitelist_count = WHITELIST_COUNT.load(&deps.storage).unwrap();
Expand All @@ -314,16 +314,16 @@ fn cannot_whitelist_more_than_max_limit() {
// add 10 denoms to whitelist
let add_whitelist_msg: ExecuteMsg = ExecuteMsg::UpdateWhitelist {
add_denoms: vec![
("umars".to_string(), Uint128::new(3)),
("denom1".to_string(), Uint128::new(3)),
("denom2".to_string(), Uint128::new(3)),
("denom3".to_string(), Uint128::new(3)),
("denom4".to_string(), Uint128::new(3)),
("denom5".to_string(), Uint128::new(3)),
("denom6".to_string(), Uint128::new(3)),
("denom7".to_string(), Uint128::new(3)),
("denom8".to_string(), Uint128::new(3)),
("denom9".to_string(), Uint128::new(3)),
("umars".to_string(), Uint128::new(3)).into(),
("denom1".to_string(), Uint128::new(3)).into(),
("denom2".to_string(), Uint128::new(3)).into(),
("denom3".to_string(), Uint128::new(3)).into(),
("denom4".to_string(), Uint128::new(3)).into(),
("denom5".to_string(), Uint128::new(3)).into(),
("denom6".to_string(), Uint128::new(3)).into(),
("denom7".to_string(), Uint128::new(3)).into(),
("denom8".to_string(), Uint128::new(3)).into(),
("denom9".to_string(), Uint128::new(3)).into(),
],
remove_denoms: vec![],
};
Expand All @@ -335,7 +335,7 @@ fn cannot_whitelist_more_than_max_limit() {

// add denom to whitelist again, should fail
let add_whitelist_msg: ExecuteMsg = ExecuteMsg::UpdateWhitelist {
add_denoms: vec![("denom10".to_string(), Uint128::new(5))],
add_denoms: vec![("denom10".to_string(), Uint128::new(5)).into()],
remove_denoms: vec![],
};
let res =
Expand All @@ -349,7 +349,7 @@ fn cannot_whitelist_more_than_max_limit() {

// Remove one denom from whitelist, and add a new one, should work
let add_whitelist_msg: ExecuteMsg = ExecuteMsg::UpdateWhitelist {
add_denoms: vec![("denom10".to_string(), Uint128::new(5))],
add_denoms: vec![("denom10".to_string(), Uint128::new(5)).into()],
remove_denoms: vec![("umars".to_string())],
};
execute(deps.as_mut(), mock_env(), mock_info(owner, &[]), add_whitelist_msg).unwrap();
Expand All @@ -369,8 +369,8 @@ fn update_whitelist_args_cannot_contain_duplicate_denoms() {
// add 1 denoms to whitelist twice
let whitelist_msg: ExecuteMsg = ExecuteMsg::UpdateWhitelist {
add_denoms: vec![
("umars".to_string(), Uint128::new(3)),
("umars".to_string(), Uint128::new(5)),
("umars".to_string(), Uint128::new(3)).into(),
("umars".to_string(), Uint128::new(5)).into(),
],
remove_denoms: vec![],
};
Expand All @@ -397,7 +397,7 @@ fn update_whitelist_args_cannot_contain_duplicate_denoms() {

// Try to add and remove the same denom
let whitelist_msg: ExecuteMsg = ExecuteMsg::UpdateWhitelist {
add_denoms: vec![("umars".to_string(), Uint128::new(3))],
add_denoms: vec![("umars".to_string(), Uint128::new(3)).into()],
remove_denoms: vec![("umars".to_string())],
};
let err = execute(deps.as_mut(), mock_env(), mock_info(owner, &[]), whitelist_msg).unwrap_err();
Expand All @@ -418,14 +418,14 @@ fn cannot_remove_denom_from_whitelist_that_is_not_there() {

// add 1 denoms to whitelist
let add_whitelist_msg: ExecuteMsg = ExecuteMsg::UpdateWhitelist {
add_denoms: vec![("umars".to_string(), Uint128::new(3))],
add_denoms: vec![("umars".to_string(), Uint128::new(3)).into()],
remove_denoms: vec![],
};
execute(deps.as_mut(), mock_env(), mock_info(owner, &[]), add_whitelist_msg).unwrap();

// Query whitelist
let whitelist: Vec<(String, Uint128)> = th_query(deps.as_ref(), QueryMsg::Whitelist {});
assert_eq!(whitelist, vec![("umars".to_string(), Uint128::new(3))]);
let whitelist: Vec<WhitelistEntry> = th_query(deps.as_ref(), QueryMsg::Whitelist {});
assert_eq!(whitelist, vec![("umars".to_string(), Uint128::new(3)).into()]);

// Check whitelist count
let whitelist_count = WHITELIST_COUNT.load(&deps.storage).unwrap();
Expand All @@ -446,8 +446,8 @@ fn cannot_remove_denom_from_whitelist_that_is_not_there() {
);

// Query whitelist, should still be the same
let whitelist: Vec<(String, Uint128)> = th_query(deps.as_ref(), QueryMsg::Whitelist {});
assert_eq!(whitelist, vec![("umars".to_string(), Uint128::new(3))]);
let whitelist: Vec<WhitelistEntry> = th_query(deps.as_ref(), QueryMsg::Whitelist {});
assert_eq!(whitelist, vec![("umars".to_string(), Uint128::new(3)).into()]);

// Check whitelist count. Should still be 1.
let whitelist_count = WHITELIST_COUNT.load(&deps.storage).unwrap();
Expand Down
5 changes: 1 addition & 4 deletions packages/testing/src/integration/mock_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,7 @@ impl Incentives {
env.owner.clone(),
self.contract_addr.clone(),
&incentives::ExecuteMsg::UpdateWhitelist {
add_denoms: incentive_denoms
.iter()
.map(|(denom, min_emission)| (denom.to_string(), (*min_emission).into()))
.collect(),
add_denoms: incentive_denoms.iter().map(|x| x.into()).collect(),
remove_denoms: vec![],
},
&[],
Expand Down
33 changes: 31 additions & 2 deletions packages/types/src/incentives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,32 @@ impl IncentiveStateResponse {
}
}

#[cw_serde]
pub struct WhitelistEntry {
/// The incentive token denom that is whitelisted
pub denom: String,
/// The minimum emission rate per second for this incentive token
pub min_emission_rate: Uint128,
}

impl From<&(&str, u128)> for WhitelistEntry {
fn from((denom, min_emission_rate): &(&str, u128)) -> Self {
Self {
denom: denom.to_string(),
min_emission_rate: Uint128::from(*min_emission_rate),
}
}
}

impl From<(String, Uint128)> for WhitelistEntry {
fn from((denom, min_emission_rate): (String, Uint128)) -> Self {
Self {
denom,
min_emission_rate,
}
}
}

#[cw_serde]
pub struct InstantiateMsg {
/// Contract owner
Expand All @@ -69,7 +95,7 @@ pub enum ExecuteMsg {
UpdateWhitelist {
/// The denoms to add to the whitelist as well as a minimum emission rate per second for
/// each. If the denom is already in the whitelist, the minimum emission rate will be updated.
add_denoms: Vec<(String, Uint128)>,
add_denoms: Vec<WhitelistEntry>,
/// The denoms to remove from the whitelist. This will update the index of the incentive
/// state and then remove any active incentive schedules.
///
Expand Down Expand Up @@ -215,10 +241,13 @@ pub enum QueryMsg {

/// Queries the incentive denom whitelist. Returns a Vec<(String, Uint128)> containing the
/// denoms of all whitelisted incentive denoms, as well as the minimum emission rate for each.
#[returns(Vec<(String,Uint128)>)]
#[returns(Vec<WhitelistEntry>)]
Whitelist {},
}

#[cw_serde]
pub struct MigrateMsg {}

#[cw_serde]
pub struct EmissionResponse {
/// The unix timestamp in seconds at which the emission epoch starts
Expand Down
Loading

0 comments on commit 74b56cc

Please sign in to comment.