Skip to content

Commit

Permalink
feat: Enforce min_out locally for withdrawals
Browse files Browse the repository at this point in the history
  • Loading branch information
apollo-sturdy committed Sep 25, 2023
1 parent 2a27c85 commit 5ee3998
Show file tree
Hide file tree
Showing 6 changed files with 324 additions and 157 deletions.
24 changes: 4 additions & 20 deletions src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,19 +142,11 @@ pub fn execute(
deposit_asset_info,
),
CallbackMsg::EnforceMinOut {
asset,
recipient,
balance_before,
min_out,
} => callback_enforce_min_out(
deps,
env,
info,
asset,
assets,
recipient,
balance_before,
balances_before,
min_out,
),
} => callback_enforce_min_out(deps, assets, recipient, balances_before, min_out),
CallbackMsg::AfterRedeem {
receive_choice,
vault_base_token,
Expand All @@ -172,15 +164,7 @@ pub fn execute(
assets,
receive_choice,
recipient,
min_out,
} => callback_after_withdraw_liq(
deps,
env,
assets,
receive_choice,
recipient,
min_out,
),
} => callback_after_withdraw_liq(deps, env, assets, receive_choice, recipient),
}
}
}
Expand Down
78 changes: 52 additions & 26 deletions src/deposit.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use apollo_cw_asset::{AssetInfo, AssetList};
use apollo_cw_asset::{Asset, AssetInfo, AssetList};
use apollo_utils::assets::receive_assets;
use cosmwasm_std::{
to_binary, Addr, Binary, Coin, DepsMut, Empty, Env, MessageInfo, Response, Uint128,
to_binary, Addr, Binary, Coin, DepsMut, Empty, Env, Event, MessageInfo, Response, Uint128,
};
use cw_dex::traits::Pool as PoolTrait;
use cw_dex::Pool;
Expand All @@ -16,15 +16,15 @@ pub fn execute_deposit(
deps: DepsMut,
env: Env,
info: MessageInfo,
caller_funds: AssetList,
assets: AssetList,
vault_address: Addr,
recipient: Option<String>,
min_out: Uint128,
) -> Result<Response, ContractError> {
// Unwrap recipient or use sender
let recipient = recipient.map_or(Ok(info.sender.clone()), |x| deps.api.addr_validate(&x))?;

let receive_assets_res = receive_assets(&info, &env, &caller_funds)?;
let receive_assets_res = receive_assets(&info, &env, &assets)?;

// Query the vault info to get the deposit asset
let vault: VaultContract<Empty, Empty> = VaultContract::new(&deps.querier, &vault_address)?;
Expand All @@ -37,25 +37,33 @@ pub fn execute_deposit(
let vault_token = AssetInfo::native(&vault.vault_token);
let balance_before = vault_token.query_balance(&deps.querier, recipient.clone())?;
let enforce_min_out_msg = CallbackMsg::EnforceMinOut {
asset: vault_token,
assets: vec![vault_token.clone()],
recipient: recipient.clone(),
balance_before,
min_out,
balances_before: vec![Asset::new(vault_token.clone(), balance_before)].into(),
min_out: vec![Asset::new(vault_token.clone(), min_out)].into(),
}
.into_cosmos_msg(&env)?;

let event = Event::new("apollo/vault-zapper/execute_deposit")
.add_attribute("assets", assets.to_string())
.add_attribute("vault_address", &vault_address)
.add_attribute("recipient", &recipient)
.add_attribute("min_out", min_out);

// Check if coins sent are already same as the depositable assets
// If yes, then just deposit the coins
if caller_funds.len() == 1 && caller_funds.to_vec()[0].info == deposit_asset_info {
let amount = caller_funds.to_vec()[0].amount;
if assets.len() == 1 && assets.to_vec()[0].info == deposit_asset_info {
let amount = assets.to_vec()[0].amount;
let msgs = vault.increase_allowance_and_deposit(
amount,
&deposit_asset_info,
Some(recipient.to_string()),
)?;

return Ok(receive_assets_res
.add_messages(msgs)
.add_message(enforce_min_out_msg));
.add_message(enforce_min_out_msg)
.add_event(event));
}

//Check if the depositable asset is an LP token
Expand All @@ -80,7 +88,7 @@ pub fn execute_deposit(

// Basket Liquidate deposited coins
// We only liquidate the coins that are not already the target asset
let liquidate_coins = caller_funds
let liquidate_coins = assets
.into_iter()
.filter_map(|a| {
if !receive_asset_infos.contains(&a.info) {
Expand Down Expand Up @@ -125,7 +133,8 @@ pub fn execute_deposit(

Ok(receive_assets_res
.add_messages(msgs)
.add_message(enforce_min_out_msg))
.add_message(enforce_min_out_msg)
.add_event(event))
}

pub fn callback_provide_liquidity(
Expand Down Expand Up @@ -198,22 +207,39 @@ pub fn callback_deposit(

pub fn callback_enforce_min_out(
deps: DepsMut,
_env: Env,
_info: MessageInfo,
asset: AssetInfo,
assets: Vec<AssetInfo>,
recipient: Addr,
balance_before: Uint128,
min_out: Uint128,
balances_before: AssetList,
min_out: AssetList,
) -> Result<Response, ContractError> {
let new_balance = asset.query_balance(&deps.querier, recipient)?;
let diff = new_balance.saturating_sub(balance_before);

if diff < min_out {
return Err(ContractError::MinOutNotMet {
min_out,
actual: diff,
});
let mut new_balances =
AssetList::query_asset_info_balances(assets.clone(), &deps.querier, &recipient)?;
let assets_received = new_balances.deduct_many(&balances_before)?;

for asset in min_out.iter() {
let received = assets_received
.find(&asset.info)
.map(|x| x.amount)
.unwrap_or_default();
if received < asset.amount {
return Err(ContractError::MinOutNotMet {
min_out: asset.amount,
actual: received,
});
}
}

let mut event = Event::new("apollo/vault-zapper/callback_enforce_min_out")
.add_attribute("recipient", recipient);
if !assets.is_empty() {
event = event.add_attribute("assets", format!("{:?}", assets));
}
if min_out.len() > 0 {
event = event.add_attribute("min_out", format!("{:?}", min_out));
}
if assets_received.len() > 0 {
event = event.add_attribute("assets_received", format!("{:?}", assets_received));
}

Ok(Response::new())
Ok(Response::new().add_event(event))
}
19 changes: 10 additions & 9 deletions src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,19 @@ pub enum CallbackMsg {
recipient: Addr,
deposit_asset_info: AssetInfo,
},
/// Enforce that the minimum amount of vault tokens are received
/// Enforce that the minimum amount of the specified assets are sent to the
/// recipient after the transaction
EnforceMinOut {
/// The asset to check the balance of
asset: AssetInfo,
/// The assets to check the balance of
assets: Vec<AssetInfo>,
/// The address to check the balance of
recipient: Addr,
/// The recipient's balance of `asset` before the transaction
balance_before: Uint128,
/// The minimum amount of `asset` to receive. If the amount of
/// `asset` received is less than this, the transaction will fail.
min_out: Uint128,
/// The recipient's balance of each of the assets before the transaction
balances_before: AssetList,
/// The minimum amount of each asset to receive. If the amount received
/// of any of the assets is less than this, the transaction will
/// fail.
min_out: AssetList,
},
/// Called after redeeming vault tokens
AfterRedeem {
Expand All @@ -105,7 +107,6 @@ pub enum CallbackMsg {
assets: Vec<AssetInfo>,
receive_choice: ReceiveChoice,
recipient: Addr,
min_out: AssetList,
},
}

Expand Down
1 change: 0 additions & 1 deletion src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,6 @@ mod tests {
.unwrap()
.map(|x| x.unwrap().0)
.collect();
println!("{:?}", res);
assert_eq!(res.len(), 3);
assert_eq!(
res,
Expand Down
Loading

0 comments on commit 5ee3998

Please sign in to comment.