Skip to content

Commit

Permalink
Implement force_pool_exit and disable other zrml-swaps functions (z…
Browse files Browse the repository at this point in the history
…eitgeistpm#1235)

* Abstract `pool_exit` business logic into `do_*` function

* Add `force_pool_exit` and test

* Install call filters for zrml-swaps
  • Loading branch information
maltekliemann authored Jan 18, 2024
1 parent b5e0d4e commit ca684ac
Show file tree
Hide file tree
Showing 4 changed files with 349 additions and 34 deletions.
11 changes: 7 additions & 4 deletions runtime/battery-station/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ use zrml_prediction_markets::Call::{
};
use zrml_rikiddo::types::{EmaMarketVolume, FeeSigmoid, RikiddoSigmoidMV};
use zrml_swaps::Call::{
pool_exit, pool_exit_with_exact_asset_amount, pool_exit_with_exact_pool_amount, pool_join,
pool_join_with_exact_asset_amount, pool_join_with_exact_pool_amount, swap_exact_amount_in,
swap_exact_amount_out,
force_pool_exit, pool_exit, pool_exit_with_exact_asset_amount,
pool_exit_with_exact_pool_amount, pool_join, pool_join_with_exact_asset_amount,
pool_join_with_exact_pool_amount, swap_exact_amount_in, swap_exact_amount_out,
};
#[cfg(feature = "parachain")]
use {
Expand Down Expand Up @@ -164,7 +164,6 @@ impl Contains<RuntimeCall> for ContractsCallfilter {
#[derive(scale_info::TypeInfo)]
pub struct IsCallable;

// Currently disables Rikiddo.
impl Contains<RuntimeCall> for IsCallable {
fn contains(call: &RuntimeCall) -> bool {
#[allow(clippy::match_like_matches_macro)]
Expand All @@ -182,6 +181,10 @@ impl Contains<RuntimeCall> for IsCallable {
} => false,
_ => true,
},
RuntimeCall::Swaps(inner_call) => match inner_call {
force_pool_exit { .. } => true,
_ => false,
},
_ => true,
}
}
Expand Down
5 changes: 5 additions & 0 deletions runtime/zeitgeist/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ impl Contains<RuntimeCall> for IsCallable {
use zrml_prediction_markets::Call::{
admin_move_market_to_closed, admin_move_market_to_resolved, create_market, edit_market,
};
use zrml_swaps::Call::force_pool_exit;

#[allow(clippy::match_like_matches_macro)]
match runtime_call {
Expand Down Expand Up @@ -170,6 +171,10 @@ impl Contains<RuntimeCall> for IsCallable {
}
}
RuntimeCall::SimpleDisputes(_) => false,
RuntimeCall::Swaps(inner_call) => match inner_call {
force_pool_exit { .. } => true,
_ => false,
},
RuntimeCall::System(inner_call) => {
match inner_call {
// Some "waste" storage will never impact proper operation.
Expand Down
85 changes: 55 additions & 30 deletions zrml/swaps/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,36 +129,7 @@ mod pallet {
min_assets_out: Vec<BalanceOf<T>>,
) -> DispatchResult {
let who = ensure_signed(origin)?;
ensure!(pool_amount != Zero::zero(), Error::<T>::ZeroAmount);
let who_clone = who.clone();
let pool = Self::pool_by_id(pool_id)?;
// If the pool is still in use, prevent a pool drain.
Self::ensure_minimum_liquidity_shares(pool_id, &pool, pool_amount)?;
let pool_account_id = Pallet::<T>::pool_account_id(&pool_id);
let params = PoolParams {
asset_bounds: min_assets_out,
event: |evt| Self::deposit_event(Event::PoolExit(evt)),
pool_account_id: &pool_account_id,
pool_amount,
pool_id,
pool: &pool,
transfer_asset: |amount, amount_bound, asset| {
Self::ensure_minimum_balance(pool_id, &pool, asset, amount)?;
ensure!(amount >= amount_bound, Error::<T>::LimitOut);
T::AssetManager::transfer(asset, &pool_account_id, &who, amount)?;
Ok(())
},
transfer_pool: || {
Self::burn_pool_shares(pool_id, &who, pool_amount)?;
Ok(())
},
fee: |amount: BalanceOf<T>| {
let exit_fee_amount = amount.bmul(Self::calc_exit_fee(&pool))?;
Ok(exit_fee_amount)
},
who: who_clone,
};
crate::utils::pool::<_, _, _, _, T>(params)
Self::do_pool_exit(who, pool_id, pool_amount, min_assets_out)
}

/// Pool - Exit with exact pool amount
Expand Down Expand Up @@ -512,6 +483,22 @@ mod pallet {
)?;
Ok(Some(weight).into())
}

#[pallet::call_index(11)]
#[pallet::weight(T::WeightInfo::pool_exit(
min_assets_out.len().min(T::MaxAssets::get().into()) as u32
))]
#[transactional]
pub fn force_pool_exit(
origin: OriginFor<T>,
who: T::AccountId,
#[pallet::compact] pool_id: PoolId,
#[pallet::compact] pool_amount: BalanceOf<T>,
min_assets_out: Vec<BalanceOf<T>>,
) -> DispatchResult {
let _ = ensure_signed(origin)?;
Self::do_pool_exit(who, pool_id, pool_amount, min_assets_out)
}
}

#[pallet::config]
Expand Down Expand Up @@ -747,6 +734,44 @@ mod pallet {
pub(crate) type NextPoolId<T> = StorageValue<_, PoolId, ValueQuery>;

impl<T: Config> Pallet<T> {
fn do_pool_exit(
who: T::AccountId,
pool_id: PoolId,
pool_amount: BalanceOf<T>,
min_assets_out: Vec<BalanceOf<T>>,
) -> DispatchResult {
ensure!(pool_amount != Zero::zero(), Error::<T>::ZeroAmount);
let who_clone = who.clone();
let pool = Self::pool_by_id(pool_id)?;
// If the pool is still in use, prevent a pool drain.
Self::ensure_minimum_liquidity_shares(pool_id, &pool, pool_amount)?;
let pool_account_id = Pallet::<T>::pool_account_id(&pool_id);
let params = PoolParams {
asset_bounds: min_assets_out,
event: |evt| Self::deposit_event(Event::PoolExit(evt)),
pool_account_id: &pool_account_id,
pool_amount,
pool_id,
pool: &pool,
transfer_asset: |amount, amount_bound, asset| {
Self::ensure_minimum_balance(pool_id, &pool, asset, amount)?;
ensure!(amount >= amount_bound, Error::<T>::LimitOut);
T::AssetManager::transfer(asset, &pool_account_id, &who, amount)?;
Ok(())
},
transfer_pool: || {
Self::burn_pool_shares(pool_id, &who, pool_amount)?;
Ok(())
},
fee: |amount: BalanceOf<T>| {
let exit_fee_amount = amount.bmul(Self::calc_exit_fee(&pool))?;
Ok(exit_fee_amount)
},
who: who_clone,
};
crate::utils::pool::<_, _, _, _, T>(params)
}

pub fn get_spot_price(
pool_id: &PoolId,
asset_in: &AssetOf<T>,
Expand Down
Loading

0 comments on commit ca684ac

Please sign in to comment.