Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Closed pools to be opened #695

Merged
merged 11 commits into from
Jul 18, 2022
4 changes: 3 additions & 1 deletion misc/types.json
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,9 @@
"_enum": [
"Active",
"CollectingSubsidy",
"Stale"
"Closed",
"Clean",
"Initialized"
]
},
"RegistrationInfo": {
Expand Down
2 changes: 2 additions & 0 deletions primitives/src/pool_status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@ pub enum PoolStatus {
Closed,
/// The pool has been cleaned up, usually after the corresponding market has been resolved.
Clean,
/// The pool has just been created.
Initialized,
}
2 changes: 2 additions & 0 deletions primitives/src/traits/swaps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ pub trait Swaps<AccountId> {
/// * `pool_id`: Unique pool identifier associated with the pool to be destroyed.
fn destroy_pool_in_subsidy_phase(pool_id: PoolId) -> Result<Weight, DispatchError>;

fn open_pool(pool_id: PoolId) -> Result<Weight, DispatchError>;

/// Pool - Exit with exact pool amount
///
/// Takes an asset from `pool_id` and transfers to `origin`. Differently from `pool_exit`,
Expand Down
1 change: 1 addition & 0 deletions zrml/prediction-markets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,7 @@ mod pallet {
Some(amount),
Some(weights),
)?;
T::Swaps::open_pool(pool_id)?;
Chralt98 marked this conversation as resolved.
Show resolved Hide resolved

// This errors if a pool already exists!
T::MarketCommons::insert_market_pool(market_id, pool_id)?;
Expand Down
4 changes: 4 additions & 0 deletions zrml/swaps/src/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ fn bench_create_pool<T: Config>(
.unwrap();
let pool_id = <NextPoolId<T>>::get() - 1;

if scoring_rule == ScoringRule::CPMM {
let _ = Pallet::<T>::open_pool(pool_id);
}

if subsidize {
let min_subsidy = T::MinSubsidy::get();
T::Shares::deposit(base_asset, &caller, min_subsidy).unwrap();
Expand Down
19 changes: 17 additions & 2 deletions zrml/swaps/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,6 @@ mod pallet {
let pool = Self::pool_by_id(pool_id)?;
let pool_account_id = Pallet::<T>::pool_account_id(pool_id);

Self::check_if_pool_is_active(&pool)?;
let params = PoolParams {
asset_bounds: max_assets_in,
event: |evt| Self::deposit_event(Event::PoolJoin(evt)),
Expand Down Expand Up @@ -846,6 +845,8 @@ mod pallet {
PoolClosed(PoolId),
/// A pool was cleaned up. \[pool_id\]
PoolCleanedUp(PoolId),
/// A pool was opened. \[pool_id\]
PoolActive(PoolId),
maltekliemann marked this conversation as resolved.
Show resolved Hide resolved
/// Someone has exited a pool. \[PoolAssetsEvent\]
PoolExit(
PoolAssetsEvent<
Expand Down Expand Up @@ -1412,7 +1413,7 @@ mod pallet {
);
T::Shares::deposit(pool_shares_id, &who, amount_unwrapped)?;

let pool_status = PoolStatus::Active;
let pool_status = PoolStatus::Initialized;
let total_subsidy = None;
let total_weight = Some(total_weight);
let weights = Some(map);
Expand Down Expand Up @@ -1667,6 +1668,20 @@ mod pallet {
})
}

fn open_pool(pool_id: PoolId) -> Result<Weight, DispatchError> {
Self::mutate_pool(pool_id, |pool| {
ensure!(
pool.pool_status == PoolStatus::Initialized,
Error::<T>::InvalidStateTransition
);
pool.pool_status = PoolStatus::Active;
Ok(())
})?;
Self::deposit_event(Event::PoolActive(pool_id));
// TODO(#603): Fix weight calculation!
Ok(T::DbWeight::get().reads_writes(1, 1))
}

/// Pool - Exit with exact pool amount
///
/// Takes an asset from `pool_id` and transfers to `origin`. Differently from `pool_exit`,
Expand Down
116 changes: 95 additions & 21 deletions zrml/swaps/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,30 +272,47 @@ fn create_pool_generates_a_new_pool_with_correct_parameters_for_cpmm() {
let next_pool_before = Swaps::next_pool_id();
assert_eq!(next_pool_before, 0);

create_initial_pool(ScoringRule::CPMM, Some(0), true);
let amount = <Runtime as crate::Config>::MinLiquidity::get();
let base_asset = ASSETS.last().unwrap();
ASSETS.iter().cloned().for_each(|asset| {
assert_ok!(Currencies::deposit(asset, &BOB, amount));
});
assert_ok!(Swaps::create_pool(
BOB,
ASSETS.iter().cloned().collect(),
*base_asset,
0,
ScoringRule::CPMM,
Some(1),
Some(amount),
Some(vec!(_4, _3, _2, _1)),
));

let next_pool_after = Swaps::next_pool_id();
assert_eq!(next_pool_after, 1);

let pool = Swaps::pools(0).unwrap();

assert_eq!(pool.assets, ASSETS.iter().cloned().collect::<Vec<_>>());
assert_eq!(pool.assets, ASSETS);
assert_eq!(pool.base_asset, *base_asset);
assert_eq!(pool.market_id, 0);
assert_eq!(pool.pool_status, PoolStatus::Initialized);
assert_eq!(pool.scoring_rule, ScoringRule::CPMM);
assert_eq!(pool.swap_fee.unwrap(), 0);
assert_eq!(pool.swap_fee, Some(1));
assert_eq!(pool.total_subsidy, None);
assert_eq!(pool.total_weight.unwrap(), _8);
assert_eq!(pool.total_weight.unwrap(), _10);

assert_eq!(*pool.weights.as_ref().unwrap().get(&ASSET_A).unwrap(), _2);
assert_eq!(*pool.weights.as_ref().unwrap().get(&ASSET_B).unwrap(), _2);
assert_eq!(*pool.weights.as_ref().unwrap().get(&ASSET_A).unwrap(), _4);
assert_eq!(*pool.weights.as_ref().unwrap().get(&ASSET_B).unwrap(), _3);
assert_eq!(*pool.weights.as_ref().unwrap().get(&ASSET_C).unwrap(), _2);
assert_eq!(*pool.weights.as_ref().unwrap().get(&ASSET_D).unwrap(), _2);
assert_eq!(*pool.weights.as_ref().unwrap().get(&ASSET_D).unwrap(), _1);
Chralt98 marked this conversation as resolved.
Show resolved Hide resolved

let pool_account = Swaps::pool_account_id(0);
System::assert_last_event(
Event::PoolCreate(
CommonPoolEventParams { pool_id: next_pool_before, who: BOB },
pool,
<Runtime as Config>::MinLiquidity::get(),
amount,
pool_account,
)
.into(),
Expand Down Expand Up @@ -499,7 +516,7 @@ fn end_subsidy_phase_distributes_shares_and_outcome_assets() {
}

#[test]
fn nothing_except_exit_pool_is_allowed_in_closed_cpmm_pools() {
fn single_asset_operations_and_swaps_fail_on_closed_cpmm_pools() {
ExtBuilder::default().build().execute_with(|| {
use zeitgeist_primitives::traits::Swaps as _;
create_initial_pool_with_funds_for_alice(ScoringRule::CPMM, Some(0), true);
Expand Down Expand Up @@ -530,10 +547,6 @@ fn nothing_except_exit_pool_is_allowed_in_closed_cpmm_pools() {
Swaps::pool_exit_with_exact_pool_amount(alice_signed(), 0, ASSET_A, _1, _1_2),
crate::Error::<Runtime>::PoolIsNotActive
);
assert_noop!(
Swaps::pool_join(alice_signed(), 0, 0, vec!(_1, _1, _1, _1)),
crate::Error::<Runtime>::PoolIsNotActive
);
assert_noop!(
Swaps::pool_join_with_exact_asset_amount(alice_signed(), 0, ASSET_E, 1, 1),
crate::Error::<Runtime>::PoolIsNotActive
Expand Down Expand Up @@ -703,15 +716,17 @@ fn pool_join_amount_satisfies_max_in_ratio_constraints() {
ScoringRule::CPMM,
Some(0),
Some(<Runtime as crate::Config>::MinLiquidity::get()),
Some(vec!(_2, _2, _2, _5)) // Asset weights don't divide total weight.
Some(vec!(_2, _2, _2, _5)), // Asset weights don't divide total weight.
));
let pool_id = 0;
assert_ok!(Swaps::open_pool(pool_id));

assert_ok!(Currencies::deposit(ASSET_D, &ALICE, u64::MAX.into()));

assert_noop!(
Swaps::pool_join_with_exact_pool_amount(
alice_signed(),
0,
pool_id,
ASSET_A,
_100,
_10000 // Don't care how much we have to pay!
Expand Down Expand Up @@ -1492,6 +1507,7 @@ fn clean_up_pool_handles_rikiddo_pools_properly() {
#[test_case(PoolStatus::Active; "active")]
#[test_case(PoolStatus::Clean; "clean")]
#[test_case(PoolStatus::CollectingSubsidy; "collecting_subsidy")]
#[test_case(PoolStatus::Initialized; "initialized")]
fn clean_up_pool_fails_if_pool_is_not_closed(pool_status: PoolStatus) {
ExtBuilder::default().build().execute_with(|| {
create_initial_pool(ScoringRule::RikiddoSigmoidFeeMarketEma, None, false);
Expand Down Expand Up @@ -1587,6 +1603,8 @@ fn swap_exact_amount_in_exchanges_correct_values_with_cpmm_with_fees() {
Some(<Runtime as crate::Config>::MinLiquidity::get()),
Some(vec!(_2, _2, _2, _2)),
));
let pool_id = 0;
assert_ok!(Swaps::open_pool(pool_id));

let asset_bound = Some(_1 / 2);
let max_price = Some(_2);
Expand All @@ -1596,7 +1614,7 @@ fn swap_exact_amount_in_exchanges_correct_values_with_cpmm_with_fees() {
let asset_amount_out = 9_900_990_100;
assert_ok!(Swaps::swap_exact_amount_in(
alice_signed(),
0,
pool_id,
ASSET_A,
asset_amount_in,
ASSET_B,
Expand All @@ -1610,7 +1628,7 @@ fn swap_exact_amount_in_exchanges_correct_values_with_cpmm_with_fees() {
asset_bound,
asset_in: ASSET_A,
asset_out: ASSET_B,
cpep: CommonPoolEventParams { pool_id: 0, who: 0 },
cpep: CommonPoolEventParams { pool_id, who: 0 },
max_price,
})
.into(),
Expand Down Expand Up @@ -1787,14 +1805,16 @@ fn swap_exact_amount_out_exchanges_correct_values_with_cpmm_with_fees() {
Some(<Runtime as crate::Config>::MinLiquidity::get()),
Some(vec!(_2, _2, _2, _2)),
));
let pool_id = 0;
assert_ok!(Swaps::open_pool(pool_id));

let asset_amount_out = _1;
let asset_amount_in = 11223344556; // 10101010100 / 0.9
let asset_bound = Some(_2);
let max_price = Some(_3);
assert_ok!(Swaps::swap_exact_amount_out(
alice_signed(),
0,
pool_id,
ASSET_A,
asset_bound,
ASSET_B,
Expand All @@ -1808,7 +1828,7 @@ fn swap_exact_amount_out_exchanges_correct_values_with_cpmm_with_fees() {
asset_bound,
asset_in: ASSET_A,
asset_out: ASSET_B,
cpep: CommonPoolEventParams { pool_id: 0, who: 0 },
cpep: CommonPoolEventParams { pool_id, who: 0 },
max_price,
})
.into(),
Expand Down Expand Up @@ -2088,7 +2108,7 @@ fn create_pool_fails_on_weight_below_minimum_weight() {
ScoringRule::CPMM,
Some(0),
Some(<Runtime as crate::Config>::MinLiquidity::get()),
Some(vec!(_2, <Runtime as crate::Config>::MinWeight::get() - 1, _2, _2))
Some(vec!(_2, <Runtime as crate::Config>::MinWeight::get() - 1, _2, _2)),
),
crate::Error::<Runtime>::BelowMinimumWeight,
);
Expand All @@ -2110,7 +2130,7 @@ fn create_pool_fails_on_weight_above_maximum_weight() {
ScoringRule::CPMM,
Some(0),
Some(<Runtime as crate::Config>::MinLiquidity::get()),
Some(vec!(_2, <Runtime as crate::Config>::MaxWeight::get() + 1, _2, _2))
Some(vec!(_2, <Runtime as crate::Config>::MaxWeight::get() + 1, _2, _2)),
),
crate::Error::<Runtime>::AboveMaximumWeight,
);
Expand Down Expand Up @@ -2204,6 +2224,7 @@ fn close_pool_fails_if_pool_does_not_exist() {
#[test_case(PoolStatus::Closed; "closed")]
#[test_case(PoolStatus::Clean; "clean")]
#[test_case(PoolStatus::CollectingSubsidy; "collecting_subsidy")]
#[test_case(PoolStatus::Initialized; "initialized")]
fn close_pool_fails_if_pool_is_not_active(pool_status: PoolStatus) {
ExtBuilder::default().build().execute_with(|| {
create_initial_pool(ScoringRule::CPMM, Some(0), true);
Expand All @@ -2229,6 +2250,55 @@ fn close_pool_succeeds_and_emits_correct_event_if_pool_exists() {
});
}

#[test]
fn open_pool_fails_if_pool_does_not_exist() {
ExtBuilder::default().build().execute_with(|| {
assert_noop!(Swaps::open_pool(0), crate::Error::<Runtime>::PoolDoesNotExist);
});
}

#[test_case(PoolStatus::Active; "active")]
#[test_case(PoolStatus::Clean; "clean")]
#[test_case(PoolStatus::CollectingSubsidy; "collecting_subsidy")]
#[test_case(PoolStatus::Closed; "closed")]
fn open_pool_fails_if_pool_is_not_closed(pool_status: PoolStatus) {
ExtBuilder::default().build().execute_with(|| {
create_initial_pool(ScoringRule::CPMM, Some(1), true);
let pool_id = 0;
assert_ok!(Swaps::mutate_pool(pool_id, |pool| {
pool.pool_status = pool_status;
Ok(())
}));
assert_noop!(Swaps::open_pool(pool_id), crate::Error::<Runtime>::InvalidStateTransition);
});
}

#[test]
fn open_pool_succeeds_and_emits_correct_event_if_pool_exists() {
ExtBuilder::default().build().execute_with(|| {
frame_system::Pallet::<Runtime>::set_block_number(1);
let amount = <Runtime as crate::Config>::MinLiquidity::get();
ASSETS.iter().cloned().for_each(|asset| {
assert_ok!(Currencies::deposit(asset, &BOB, amount));
});
assert_ok!(Swaps::create_pool(
BOB,
vec![ASSET_D, ASSET_B, ASSET_C, ASSET_A],
ASSET_A,
0,
ScoringRule::CPMM,
Some(0),
Some(amount),
Some(vec!(_1, _2, _3, _4)),
));
let pool_id = 0;
assert_ok!(Swaps::open_pool(pool_id));
let pool = Swaps::pool(pool_id).unwrap();
assert_eq!(pool.pool_status, PoolStatus::Active);
System::assert_last_event(Event::PoolActive(pool_id).into());
});
}

#[test]
fn pool_join_fails_if_max_assets_in_is_violated() {
ExtBuilder::default().build().execute_with(|| {
Expand Down Expand Up @@ -2461,6 +2531,7 @@ fn create_initial_pool(
});
}

let pool_id = Swaps::next_pool_id();
assert_ok!(Swaps::create_pool(
BOB,
ASSETS.iter().cloned().collect(),
Expand All @@ -2475,6 +2546,9 @@ fn create_initial_pool(
},
if scoring_rule == ScoringRule::CPMM { Some(vec!(_2, _2, _2, _2)) } else { None },
));
if scoring_rule == ScoringRule::CPMM {
assert_ok!(Swaps::open_pool(pool_id));
Chralt98 marked this conversation as resolved.
Show resolved Hide resolved
}
}

fn create_initial_pool_with_funds_for_alice(
Expand Down