use std::cmp::min;
use std::collections::{HashMap, HashSet};
use std::str::FromStr;
use cosmwasm_std::{
attr, ensure, ensure_eq, entry_point, to_json_binary, to_json_string, Addr, Attribute, Binary,
Decimal, Deps, DepsMut, Env, MessageInfo, Order, ReplyOn, Response, StdError, StdResult,
SubMsg, Uint128, Uint64,
};
use cw2::{get_contract_version, set_contract_version};
use astroport::asset::{addr_opt_validate, Asset, AssetInfo, AssetInfoExt};
use astroport::common::{claim_ownership, drop_ownership_proposal, propose_new_owner};
use astroport::factory::UpdateAddr;
use astroport::maker::{
AssetWithLimit, BalancesResponse, Config, ConfigResponse, ExecuteMsg, InstantiateMsg,
MigrateMsg, QueryMsg, SecondReceiverConfig, SecondReceiverParams, SeizeConfig,
UpdateDevFundConfig,
};
use astroport::pair::MAX_ALLOWED_SLIPPAGE;
use crate::error::ContractError;
use crate::migration::migrate_from_v120_plus;
use crate::reply::PROCESS_DEV_FUND_REPLY_ID;
use crate::state::{BRIDGES, CONFIG, LAST_COLLECT_TS, OWNERSHIP_PROPOSAL, SEIZE_CONFIG};
use crate::utils::{
build_distribute_msg, build_send_msg, build_swap_msg, get_pool, try_build_swap_msg,
update_second_receiver_cfg, validate_bridge, validate_cooldown, BRIDGES_EXECUTION_MAX_DEPTH,
BRIDGES_INITIAL_DEPTH,
};
const CONTRACT_NAME: &str = "astroport-maker";
const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
const DEFAULT_MAX_SPREAD: u64 = 5;
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn instantiate(
deps: DepsMut,
env: Env,
_info: MessageInfo,
msg: InstantiateMsg,
) -> Result<Response, ContractError> {
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
let governance_contract = addr_opt_validate(deps.api, &msg.governance_contract)?;
let governance_percent = if let Some(governance_percent) = msg.governance_percent {
if governance_percent > Uint64::new(100) {
return Err(ContractError::IncorrectGovernancePercent {});
};
governance_percent
} else {
Uint64::zero()
};
if msg.staking_contract.is_none() && governance_percent != Uint64::new(100) {
return Err(ContractError::GovernancePercentMustBe100 {});
}
let max_spread = if let Some(max_spread) = msg.max_spread {
if max_spread.is_zero() || max_spread.gt(&Decimal::from_str(MAX_ALLOWED_SLIPPAGE)?) {
return Err(ContractError::IncorrectMaxSpread {});
};
max_spread
} else {
Decimal::percent(DEFAULT_MAX_SPREAD)
};
msg.astro_token.check(deps.api)?;
if let Some(default_bridge) = &msg.default_bridge {
default_bridge.check(deps.api)?
}
validate_cooldown(msg.collect_cooldown)?;
LAST_COLLECT_TS.save(deps.storage, &env.block.time.seconds())?;
let mut cfg = Config {
owner: deps.api.addr_validate(&msg.owner)?,
default_bridge: msg.default_bridge,
astro_token: msg.astro_token,
factory_contract: deps.api.addr_validate(&msg.factory_contract)?,
staking_contract: addr_opt_validate(deps.api, &msg.staking_contract)?,
rewards_enabled: false,
pre_upgrade_blocks: 0,
last_distribution_block: 0,
remainder_reward: Uint128::zero(),
pre_upgrade_astro_amount: Uint128::zero(),
governance_contract,
governance_percent,
max_spread,
second_receiver_cfg: None,
collect_cooldown: msg.collect_cooldown,
dev_fund_conf: None,
};
update_second_receiver_cfg(deps.as_ref(), &mut cfg, &msg.second_receiver_params)?;
if cfg.staking_contract.is_none() && cfg.governance_contract.is_none() {
return Err(
StdError::generic_err("Either staking or governance contract must be set").into(),
);
}
CONFIG.save(deps.storage, &cfg)?;
let (second_fee_receiver, second_receiver_cut) = if let Some(SecondReceiverConfig {
second_fee_receiver,
second_receiver_cut,
}) = cfg.second_receiver_cfg
{
(
second_fee_receiver.to_string(),
second_receiver_cut.to_string(),
)
} else {
(String::from("none"), String::from("0"))
};
SEIZE_CONFIG.save(
deps.storage,
&SeizeConfig {
receiver: Addr::unchecked(""),
seizable_assets: vec![],
},
)?;
Ok(Response::default().add_attributes([
attr("owner", msg.owner),
attr(
"default_bridge",
cfg.default_bridge
.map(|v| v.to_string())
.unwrap_or_else(|| String::from("none")),
),
attr("astro_token", cfg.astro_token.to_string()),
attr("factory_contract", msg.factory_contract),
attr(
"staking_contract",
msg.staking_contract.unwrap_or_else(|| String::from("none")),
),
attr(
"governance_contract",
msg.governance_contract
.unwrap_or_else(|| String::from("none")),
),
attr("governance_percent", governance_percent),
attr("max_spread", max_spread.to_string()),
attr("second_fee_receiver", second_fee_receiver),
attr("second_receiver_cut", second_receiver_cut),
]))
}
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
match msg {
ExecuteMsg::Collect { assets } => collect(deps, env, assets),
ExecuteMsg::UpdateConfig {
factory_contract,
staking_contract,
governance_contract,
governance_percent,
basic_asset,
max_spread,
second_receiver_params,
collect_cooldown,
astro_token,
dev_fund_config,
} => update_config(
deps,
info,
factory_contract,
staking_contract,
governance_contract,
governance_percent,
basic_asset,
max_spread,
second_receiver_params,
collect_cooldown,
astro_token,
dev_fund_config,
),
ExecuteMsg::UpdateBridges { add, remove } => update_bridges(deps, info, add, remove),
ExecuteMsg::SwapBridgeAssets { assets, depth } => {
swap_bridge_assets(deps, env, info, assets, depth)
}
ExecuteMsg::DistributeAstro {} => distribute_astro(deps, env, info),
ExecuteMsg::ProposeNewOwner { owner, expires_in } => {
let config: Config = CONFIG.load(deps.storage)?;
propose_new_owner(
deps,
info,
env,
owner,
expires_in,
config.owner,
OWNERSHIP_PROPOSAL,
)
.map_err(Into::into)
}
ExecuteMsg::DropOwnershipProposal {} => {
let config: Config = CONFIG.load(deps.storage)?;
drop_ownership_proposal(deps, info, config.owner, OWNERSHIP_PROPOSAL)
.map_err(Into::into)
}
ExecuteMsg::ClaimOwnership {} => {
claim_ownership(deps, info, env, OWNERSHIP_PROPOSAL, |deps, new_owner| {
CONFIG.update::<_, StdError>(deps.storage, |mut v| {
v.owner = new_owner;
Ok(v)
})?;
Ok(())
})
.map_err(Into::into)
}
ExecuteMsg::EnableRewards { blocks } => {
let mut config: Config = CONFIG.load(deps.storage)?;
if info.sender != config.owner {
return Err(ContractError::Unauthorized {});
}
if config.rewards_enabled {
return Err(ContractError::RewardsAlreadyEnabled {});
}
if blocks == 0 {
return Err(ContractError::Std(StdError::generic_err(
"Number of blocks should be > 0",
)));
}
config.rewards_enabled = true;
config.pre_upgrade_blocks = blocks;
config.last_distribution_block = env.block.height;
CONFIG.save(deps.storage, &config)?;
Ok(Response::default().add_attribute("action", "enable_rewards"))
}
ExecuteMsg::Seize { assets } => seize(deps, env, assets),
ExecuteMsg::UpdateSeizeConfig {
receiver,
seizable_assets,
} => {
let config = CONFIG.load(deps.storage)?;
ensure_eq!(info.sender, config.owner, ContractError::Unauthorized {});
SEIZE_CONFIG.update::<_, StdError>(deps.storage, |mut seize_config| {
if let Some(receiver) = receiver {
seize_config.receiver = deps.api.addr_validate(&receiver)?;
}
seize_config.seizable_assets = seizable_assets;
Ok(seize_config)
})?;
Ok(Response::new().add_attribute("action", "update_seize_config"))
}
}
}
fn collect(
deps: DepsMut,
env: Env,
assets: Vec<AssetWithLimit>,
) -> Result<Response, ContractError> {
let mut cfg = CONFIG.load(deps.storage)?;
LAST_COLLECT_TS.update(deps.storage, |last_ts| match cfg.collect_cooldown {
Some(cd_period) if env.block.time.seconds() < last_ts + cd_period => {
Err(ContractError::Cooldown {
next_collect_ts: last_ts + cd_period,
})
}
_ => Ok(env.block.time.seconds()),
})?;
let astro = cfg.astro_token.clone();
let mut uniq = HashSet::new();
if !assets
.clone()
.into_iter()
.all(|a| uniq.insert(a.info.to_string()))
{
return Err(ContractError::DuplicatedAsset {});
}
let (mut response, bridge_assets) = swap_assets(
deps.as_ref(),
&env.contract.address,
&cfg,
assets.into_iter().filter(|a| a.info.ne(&astro)).collect(),
)?;
if response.messages.is_empty() {
let (mut distribute_msg, attributes) = distribute(deps, env, &mut cfg)?;
if !distribute_msg.is_empty() {
response.messages.append(&mut distribute_msg);
response = response.add_attributes(attributes);
}
} else {
response.messages.push(build_distribute_msg(
env,
bridge_assets,
BRIDGES_INITIAL_DEPTH,
)?);
}
Ok(response.add_attribute("action", "collect"))
}
enum SwapTarget {
Astro(SubMsg),
Bridge { asset: AssetInfo, msg: SubMsg },
}
fn swap_assets(
deps: Deps,
contract_addr: &Addr,
cfg: &Config,
assets: Vec<AssetWithLimit>,
) -> Result<(Response, Vec<AssetInfo>), ContractError> {
let mut response = Response::default();
let mut bridge_assets = HashMap::new();
for a in assets {
let mut balance = a.info.query_pool(&deps.querier, contract_addr)?;
if let Some(limit) = a.limit {
if limit < balance && limit > Uint128::zero() {
balance = limit;
}
}
if !balance.is_zero() {
match swap(deps, cfg, a.info, balance)? {
SwapTarget::Astro(msg) => {
response.messages.push(msg);
}
SwapTarget::Bridge { asset, msg } => {
response.messages.push(msg);
bridge_assets.insert(asset.to_string(), asset);
}
}
}
}
Ok((response, bridge_assets.into_values().collect()))
}
fn swap(
deps: Deps,
cfg: &Config,
from_token: AssetInfo,
amount_in: Uint128,
) -> Result<SwapTarget, ContractError> {
let bridge_token = BRIDGES.load(deps.storage, from_token.to_string());
if let Ok(bridge_token) = bridge_token {
let bridge_pool = validate_bridge(
deps,
&cfg.factory_contract,
&from_token,
&bridge_token,
&cfg.astro_token,
BRIDGES_INITIAL_DEPTH,
)?;
let msg = build_swap_msg(
cfg.max_spread,
&bridge_pool,
&from_token,
Some(&bridge_token),
amount_in,
)?;
let swap_msg = if bridge_token == cfg.astro_token {
SwapTarget::Astro(msg)
} else {
SwapTarget::Bridge {
asset: bridge_token,
msg,
}
};
return Ok(swap_msg);
}
if let Some(default_bridge) = &cfg.default_bridge {
if from_token.ne(default_bridge) {
let swap_to_default =
try_build_swap_msg(&deps.querier, cfg, &from_token, default_bridge, amount_in);
if let Ok(msg) = swap_to_default {
return Ok(SwapTarget::Bridge {
asset: default_bridge.clone(),
msg,
});
}
}
}
let swap_to_astro =
try_build_swap_msg(&deps.querier, cfg, &from_token, &cfg.astro_token, amount_in);
if let Ok(msg) = swap_to_astro {
return Ok(SwapTarget::Astro(msg));
}
Err(ContractError::CannotSwap(from_token))
}
fn swap_bridge_assets(
deps: DepsMut,
env: Env,
info: MessageInfo,
assets: Vec<AssetInfo>,
depth: u64,
) -> Result<Response, ContractError> {
if info.sender != env.contract.address {
return Err(ContractError::Unauthorized {});
}
if assets.is_empty() {
return Ok(Response::default());
}
if depth >= BRIDGES_EXECUTION_MAX_DEPTH {
return Err(ContractError::MaxBridgeDepth(depth));
}
let cfg = CONFIG.load(deps.storage)?;
let bridges = assets
.into_iter()
.map(|a| AssetWithLimit {
info: a,
limit: None,
})
.collect();
let (response, bridge_assets) =
swap_assets(deps.as_ref(), &env.contract.address, &cfg, bridges)?;
if response.messages.is_empty() {
return Err(ContractError::Std(StdError::generic_err(
"Empty swap messages",
)));
}
Ok(response
.add_submessage(build_distribute_msg(env, bridge_assets, depth + 1)?)
.add_attribute("action", "swap_bridge_assets"))
}
fn distribute_astro(deps: DepsMut, env: Env, info: MessageInfo) -> Result<Response, ContractError> {
if info.sender != env.contract.address {
return Err(ContractError::Unauthorized {});
}
let mut cfg = CONFIG.load(deps.storage)?;
let (distribute_msg, attributes) = distribute(deps, env, &mut cfg)?;
if distribute_msg.is_empty() {
return Ok(Response::default());
}
Ok(Response::default()
.add_submessages(distribute_msg)
.add_attributes(attributes))
}
type DistributeMsgParts = (Vec<SubMsg>, Vec<Attribute>);
fn distribute(
deps: DepsMut,
env: Env,
cfg: &mut Config,
) -> Result<DistributeMsgParts, ContractError> {
let mut result = vec![];
let mut attributes = vec![];
let mut amount = cfg
.astro_token
.query_pool(&deps.querier, &env.contract.address)?;
if amount.is_zero() {
return Ok((result, attributes));
}
let mut pure_astro_reward = amount;
let mut current_preupgrade_distribution = Uint128::zero();
if !cfg.rewards_enabled {
cfg.pre_upgrade_astro_amount = amount;
cfg.remainder_reward = amount;
CONFIG.save(deps.storage, cfg)?;
return Ok((result, attributes));
} else if !cfg.remainder_reward.is_zero() {
let blocks_passed = env.block.height - cfg.last_distribution_block;
if blocks_passed == 0 {
return Ok((result, attributes));
}
let mut remainder_reward = cfg.remainder_reward;
let astro_distribution_portion = cfg
.pre_upgrade_astro_amount
.checked_div(Uint128::from(cfg.pre_upgrade_blocks))?;
current_preupgrade_distribution = min(
Uint128::from(blocks_passed).checked_mul(astro_distribution_portion)?,
remainder_reward,
);
amount = amount.checked_sub(remainder_reward)?;
pure_astro_reward = amount;
amount = amount.checked_add(current_preupgrade_distribution)?;
remainder_reward = remainder_reward.checked_sub(current_preupgrade_distribution)?;
cfg.remainder_reward = remainder_reward;
cfg.last_distribution_block = env.block.height;
CONFIG.save(deps.storage, cfg)?;
}
let second_receiver_amount = if let Some(second_receiver_cfg) = &cfg.second_receiver_cfg {
let amount = amount.multiply_ratio(
Uint128::from(second_receiver_cfg.second_receiver_cut),
Uint128::new(100),
);
if !amount.is_zero() {
let asset = Asset {
info: cfg.astro_token.clone(),
amount,
};
result.push(SubMsg::new(
asset.into_msg(second_receiver_cfg.second_fee_receiver.to_string())?,
))
}
amount
} else {
Uint128::zero()
};
let governance_amount = if let Some(governance_contract) = &cfg.governance_contract {
let amount = amount
.checked_sub(second_receiver_amount)?
.multiply_ratio(Uint128::from(cfg.governance_percent), Uint128::new(100));
if !amount.is_zero() {
result.push(SubMsg::new(build_send_msg(
&Asset {
info: cfg.astro_token.clone(),
amount,
},
governance_contract.to_string(),
None,
)?))
}
amount
} else {
Uint128::zero()
};
let dev_amount = if let Some(dev_fund_conf) = &cfg.dev_fund_conf {
let dev_share = amount * dev_fund_conf.share;
if !dev_share.is_zero() {
let pool = get_pool(
&deps.querier,
&cfg.factory_contract,
&cfg.astro_token,
&dev_fund_conf.asset_info,
)?;
let mut swap_msg = build_swap_msg(
cfg.max_spread,
&pool,
&cfg.astro_token,
Some(&dev_fund_conf.asset_info),
dev_share,
)?;
swap_msg.reply_on = ReplyOn::Success;
swap_msg.id = PROCESS_DEV_FUND_REPLY_ID;
result.push(swap_msg);
}
dev_share
} else {
Uint128::zero()
};
if let Some(staking_contract) = &cfg.staking_contract {
let amount = amount.checked_sub(governance_amount + second_receiver_amount + dev_amount)?;
if !amount.is_zero() {
let to_staking_asset = cfg.astro_token.with_balance(amount);
result.push(SubMsg::new(to_staking_asset.into_msg(staking_contract)?));
}
}
attributes = vec![
attr("action", "distribute_astro"),
attr("astro_distribution", pure_astro_reward),
];
if !current_preupgrade_distribution.is_zero() {
attributes.push(attr(
"preupgrade_astro_distribution",
current_preupgrade_distribution,
));
}
Ok((result, attributes))
}
#[allow(clippy::too_many_arguments)]
fn update_config(
deps: DepsMut,
info: MessageInfo,
factory_contract: Option<String>,
staking_contract: Option<String>,
governance_contract: Option<UpdateAddr>,
governance_percent: Option<Uint64>,
default_bridge_opt: Option<AssetInfo>,
max_spread: Option<Decimal>,
second_receiver_params: Option<SecondReceiverParams>,
collect_cooldown: Option<u64>,
astro_token: Option<AssetInfo>,
dev_fund_conf: Option<Box<UpdateDevFundConfig>>,
) -> Result<Response, ContractError> {
let mut attributes = vec![attr("action", "set_config")];
let mut config = CONFIG.load(deps.storage)?;
if info.sender != config.owner {
return Err(ContractError::Unauthorized {});
}
if let Some(factory_contract) = factory_contract {
config.factory_contract = deps.api.addr_validate(&factory_contract)?;
attributes.push(attr("factory_contract", &factory_contract));
};
if let Some(staking_contract) = staking_contract {
config.staking_contract = Some(deps.api.addr_validate(&staking_contract)?);
attributes.push(attr("staking_contract", &staking_contract));
};
if let Some(action) = governance_contract {
match action {
UpdateAddr::Set(gov) => {
config.governance_contract = Some(deps.api.addr_validate(&gov)?);
attributes.push(attr("governance_contract", &gov));
}
UpdateAddr::Remove {} => {
if config.staking_contract.is_none() {
return Err(StdError::generic_err(
"Cannot remove governance contract if staking contract is not set",
)
.into());
}
attributes.push(attr("governance_contract", "removed"));
config.governance_contract = None;
}
}
}
if let Some(governance_percent) = governance_percent {
if governance_percent > Uint64::new(100) {
return Err(ContractError::IncorrectGovernancePercent {});
};
if config.staking_contract.is_none() && governance_percent != Uint64::new(100) {
return Err(ContractError::GovernancePercentMustBe100 {});
}
config.governance_percent = governance_percent;
attributes.push(attr("governance_percent", governance_percent));
};
if let Some(default_bridge) = &default_bridge_opt {
default_bridge.check(deps.api)?;
attributes.push(attr("default_bridge", default_bridge.to_string()));
config.default_bridge = default_bridge_opt;
}
if let Some(max_spread) = max_spread {
if max_spread.is_zero() || max_spread > Decimal::from_str(MAX_ALLOWED_SLIPPAGE)? {
return Err(ContractError::IncorrectMaxSpread {});
};
config.max_spread = max_spread;
attributes.push(attr("max_spread", max_spread.to_string()));
};
update_second_receiver_cfg(deps.as_ref(), &mut config, &second_receiver_params)?;
if let Some(second_receiver_params) = second_receiver_params {
attributes.push(attr(
"second_fee_receiver",
second_receiver_params.second_fee_receiver,
));
attributes.push(attr(
"second_receiver_cut",
second_receiver_params.second_receiver_cut,
));
}
if let Some(collect_cooldown) = collect_cooldown {
validate_cooldown(Some(collect_cooldown))?;
config.collect_cooldown = Some(collect_cooldown);
attributes.push(attr("collect_cooldown", collect_cooldown.to_string()));
}
if let Some(astro_token) = astro_token {
astro_token.check(deps.api)?;
attributes.push(attr("new_astro_token", astro_token.to_string()));
config.astro_token = astro_token;
}
if let Some(dev_fund_config) = dev_fund_conf {
config.dev_fund_conf = dev_fund_config.set;
if let Some(dev_fund_conf) = config.dev_fund_conf.as_ref() {
deps.api.addr_validate(&dev_fund_conf.address)?;
ensure!(
dev_fund_conf.share > Decimal::zero() && dev_fund_conf.share <= Decimal::one(),
StdError::generic_err("Dev fund share must be > 0 and <= 1")
);
get_pool(
&deps.querier,
&config.factory_contract,
&config.astro_token,
&dev_fund_conf.asset_info,
)?;
attributes.push(attr(
"new_dev_fund_settings",
to_json_string(dev_fund_conf)?,
));
}
}
CONFIG.save(deps.storage, &config)?;
Ok(Response::new().add_attributes(attributes))
}
fn update_bridges(
deps: DepsMut,
info: MessageInfo,
add: Option<Vec<(AssetInfo, AssetInfo)>>,
remove: Option<Vec<AssetInfo>>,
) -> Result<Response, ContractError> {
let cfg = CONFIG.load(deps.storage)?;
if info.sender != cfg.owner {
return Err(ContractError::Unauthorized {});
}
if let Some(remove_bridges) = remove {
for asset in remove_bridges {
BRIDGES.remove(deps.storage, asset.to_string());
}
}
let astro = cfg.astro_token.clone();
if let Some(add_bridges) = add {
for (asset, bridge) in add_bridges {
if asset.equal(&bridge) {
return Err(ContractError::InvalidBridge(asset, bridge));
}
validate_bridge(
deps.as_ref(),
&cfg.factory_contract,
&asset,
&bridge,
&astro,
BRIDGES_INITIAL_DEPTH,
)?;
BRIDGES.save(deps.storage, asset.to_string(), &bridge)?;
}
}
Ok(Response::default().add_attribute("action", "update_bridges"))
}
fn seize(deps: DepsMut, env: Env, assets: Vec<AssetWithLimit>) -> Result<Response, ContractError> {
ensure!(
!assets.is_empty(),
StdError::generic_err("assets vector is empty")
);
let conf = SEIZE_CONFIG.load(deps.storage)?;
ensure!(
!conf.seizable_assets.is_empty(),
StdError::generic_err("No seizable assets found")
);
let input_set = assets
.iter()
.map(|a| a.info.to_string())
.collect::<HashSet<_>>();
let seizable_set = conf
.seizable_assets
.iter()
.map(|a| a.to_string())
.collect::<HashSet<_>>();
ensure!(
input_set.is_subset(&seizable_set),
StdError::generic_err("Input vector contains assets that are not seizable")
);
let send_msgs = assets
.into_iter()
.filter_map(|asset| {
let balance = asset
.info
.query_pool(&deps.querier, &env.contract.address)
.ok()?;
let limit = asset
.limit
.map(|limit| limit.min(balance))
.unwrap_or(balance);
if limit.is_zero() {
None
} else {
Some(asset.info.with_balance(limit).into_msg(&conf.receiver))
}
})
.collect::<StdResult<Vec<_>>>()?;
Ok(Response::new()
.add_messages(send_msgs)
.add_attribute("action", "seize"))
}
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult<Binary> {
match msg {
QueryMsg::Config {} => to_json_binary(&query_get_config(deps)?),
QueryMsg::Balances { assets } => to_json_binary(&query_get_balances(deps, env, assets)?),
QueryMsg::Bridges {} => to_json_binary(&query_bridges(deps)?),
QueryMsg::QuerySeizeConfig {} => to_json_binary(&SEIZE_CONFIG.load(deps.storage)?),
}
}
fn query_get_config(deps: Deps) -> StdResult<ConfigResponse> {
let config = CONFIG.load(deps.storage)?;
Ok(ConfigResponse {
owner: config.owner,
factory_contract: config.factory_contract,
staking_contract: config.staking_contract,
dev_fund_conf: config.dev_fund_conf,
governance_contract: config.governance_contract,
governance_percent: config.governance_percent,
astro_token: config.astro_token,
max_spread: config.max_spread,
remainder_reward: config.remainder_reward,
pre_upgrade_astro_amount: config.pre_upgrade_astro_amount,
default_bridge: config.default_bridge,
second_receiver_cfg: config.second_receiver_cfg,
})
}
fn query_get_balances(deps: Deps, env: Env, assets: Vec<AssetInfo>) -> StdResult<BalancesResponse> {
let mut resp = BalancesResponse { balances: vec![] };
for a in assets {
let balance = a.query_pool(&deps.querier, &env.contract.address)?;
if !balance.is_zero() {
resp.balances.push(Asset {
info: a,
amount: balance,
})
}
}
Ok(resp)
}
fn query_bridges(deps: Deps) -> StdResult<Vec<(String, String)>> {
BRIDGES
.range(deps.storage, None, None, Order::Ascending)
.map(|bridge| {
let (bridge, asset) = bridge?;
Ok((bridge, asset.to_string()))
})
.collect()
}
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn migrate(mut deps: DepsMut, env: Env, msg: MigrateMsg) -> Result<Response, ContractError> {
let contract_version = get_contract_version(deps.storage)?;
match contract_version.contract.as_ref() {
"astroport-maker" => match contract_version.version.as_ref() {
"1.2.0" => {
migrate_from_v120_plus(deps.branch(), msg)?;
LAST_COLLECT_TS.save(deps.storage, &env.block.time.seconds())?;
SEIZE_CONFIG.save(
deps.storage,
&SeizeConfig {
receiver: Addr::unchecked(""),
seizable_assets: vec![],
},
)?;
}
"1.4.0" | "1.5.0" => {
let config = CONFIG.load(deps.storage)?;
CONFIG.save(deps.storage, &config)?;
SEIZE_CONFIG.save(
deps.storage,
&SeizeConfig {
receiver: Addr::unchecked(""),
seizable_assets: vec![],
},
)?;
}
"1.6.0" => {
SEIZE_CONFIG.save(
deps.storage,
&SeizeConfig {
receiver: Addr::unchecked(""),
seizable_assets: vec![],
},
)?;
}
_ => return Err(ContractError::MigrationError {}),
},
_ => return Err(ContractError::MigrationError {}),
};
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
Ok(Response::new()
.add_attribute("previous_contract_name", &contract_version.contract)
.add_attribute("previous_contract_version", &contract_version.version)
.add_attribute("new_contract_name", CONTRACT_NAME)
.add_attribute("new_contract_version", CONTRACT_VERSION))
}