Skip to content

Commit 2e36f11

Browse files
Merge pull request #1443 from galacticcouncil/fix/stableswap-asset-tradability
2 parents 43a6c5d + 422353a commit 2e36f11

4 files changed

Lines changed: 183 additions & 5 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pallets/stableswap/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pallet-stableswap"
3-
version = "7.4.0"
3+
version = "7.4.1"
44
description = "AMM for correlated assets"
55
authors = ["GalacticCouncil"]
66
edition = "2021"

pallets/stableswap/src/lib.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -945,9 +945,12 @@ pub mod pallet {
945945
let pool = Pools::<T>::get(pool_id).ok_or(Error::<T>::PoolNotFound)?;
946946
let _ = pool.find_asset(asset_id).ok_or(Error::<T>::AssetNotInPool)?;
947947

948-
AssetTradability::<T>::mutate(pool_id, asset_id, |current_state| {
949-
*current_state = state;
950-
});
948+
// If the state is the default, we remove the entry to save storage.
949+
if state == Tradability::default() {
950+
AssetTradability::<T>::remove(pool_id, asset_id);
951+
} else {
952+
AssetTradability::<T>::insert(pool_id, asset_id, state);
953+
}
951954

952955
Self::deposit_event(Event::TradableStateUpdated {
953956
pool_id,

pallets/stableswap/src/tests/update_pool.rs

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,178 @@ fn set_tradable_state_should_fail_when_pool_does_not_exist() {
180180
);
181181
});
182182
}
183+
184+
#[test]
185+
fn set_tradable_state_should_remove_storage_when_state_is_default() {
186+
let asset_a: AssetId = 1;
187+
let asset_b: AssetId = 2;
188+
let pool_id: AssetId = 100;
189+
190+
ExtBuilder::default()
191+
.with_endowed_accounts(vec![(ALICE, asset_a, 200 * ONE), (ALICE, asset_b, 200 * ONE)])
192+
.with_registered_asset("pool".as_bytes().to_vec(), pool_id, 12)
193+
.with_registered_asset("one".as_bytes().to_vec(), asset_a, 12)
194+
.with_registered_asset("two".as_bytes().to_vec(), asset_b, 12)
195+
.build()
196+
.execute_with(|| {
197+
assert_ok!(Stableswap::create_pool(
198+
RuntimeOrigin::root(),
199+
pool_id,
200+
to_bounded_asset_vec(vec![asset_a, asset_b]),
201+
100,
202+
Permill::from_percent(0),
203+
));
204+
205+
assert_ok!(Stableswap::set_asset_tradable_state(
206+
RuntimeOrigin::root(),
207+
pool_id,
208+
asset_a,
209+
Tradability::FROZEN,
210+
));
211+
assert!(<AssetTradability<Test>>::contains_key(pool_id, asset_a));
212+
213+
assert_ok!(Stableswap::set_asset_tradable_state(
214+
RuntimeOrigin::root(),
215+
pool_id,
216+
asset_a,
217+
Tradability::default(),
218+
));
219+
220+
assert!(!<AssetTradability<Test>>::contains_key(pool_id, asset_a));
221+
});
222+
}
223+
224+
#[test]
225+
fn set_tradable_state_should_allow_all_operations_when_reset_to_default() {
226+
let asset_a: AssetId = 1;
227+
let asset_b: AssetId = 2;
228+
let pool_id: AssetId = 100;
229+
230+
ExtBuilder::default()
231+
.with_endowed_accounts(vec![(ALICE, asset_a, 200 * ONE), (ALICE, asset_b, 200 * ONE)])
232+
.with_registered_asset("pool".as_bytes().to_vec(), pool_id, 12)
233+
.with_registered_asset("one".as_bytes().to_vec(), asset_a, 12)
234+
.with_registered_asset("two".as_bytes().to_vec(), asset_b, 12)
235+
.build()
236+
.execute_with(|| {
237+
assert_ok!(Stableswap::create_pool(
238+
RuntimeOrigin::root(),
239+
pool_id,
240+
to_bounded_asset_vec(vec![asset_a, asset_b]),
241+
100,
242+
Permill::from_percent(0),
243+
));
244+
245+
assert_ok!(Stableswap::set_asset_tradable_state(
246+
RuntimeOrigin::root(),
247+
pool_id,
248+
asset_a,
249+
Tradability::FROZEN,
250+
));
251+
252+
assert_ok!(Stableswap::set_asset_tradable_state(
253+
RuntimeOrigin::root(),
254+
pool_id,
255+
asset_a,
256+
Tradability::default(),
257+
));
258+
259+
let stored = <AssetTradability<Test>>::get(pool_id, asset_a);
260+
assert_eq!(stored, Tradability::default());
261+
assert!(stored.contains(Tradability::SELL));
262+
assert!(stored.contains(Tradability::BUY));
263+
assert!(stored.contains(Tradability::ADD_LIQUIDITY));
264+
assert!(stored.contains(Tradability::REMOVE_LIQUIDITY));
265+
});
266+
}
267+
268+
#[test]
269+
fn set_tradable_state_should_handle_full_toggle_through_default_and_partial_flags() {
270+
let asset_a: AssetId = 1;
271+
let asset_b: AssetId = 2;
272+
let pool_id: AssetId = 100;
273+
274+
ExtBuilder::default()
275+
.with_endowed_accounts(vec![(ALICE, asset_a, 200 * ONE), (ALICE, asset_b, 200 * ONE)])
276+
.with_registered_asset("pool".as_bytes().to_vec(), pool_id, 12)
277+
.with_registered_asset("one".as_bytes().to_vec(), asset_a, 12)
278+
.with_registered_asset("two".as_bytes().to_vec(), asset_b, 12)
279+
.build()
280+
.execute_with(|| {
281+
assert_ok!(Stableswap::create_pool(
282+
RuntimeOrigin::root(),
283+
pool_id,
284+
to_bounded_asset_vec(vec![asset_a, asset_b]),
285+
100,
286+
Permill::from_percent(0),
287+
));
288+
289+
assert_ok!(Stableswap::set_asset_tradable_state(
290+
RuntimeOrigin::root(),
291+
pool_id,
292+
asset_a,
293+
Tradability::FROZEN,
294+
));
295+
assert_eq!(<AssetTradability<Test>>::get(pool_id, asset_a), Tradability::FROZEN);
296+
297+
assert_ok!(Stableswap::set_asset_tradable_state(
298+
RuntimeOrigin::root(),
299+
pool_id,
300+
asset_a,
301+
Tradability::default(),
302+
));
303+
assert!(!<AssetTradability<Test>>::contains_key(pool_id, asset_a));
304+
305+
let partial = Tradability::SELL | Tradability::BUY;
306+
assert_ok!(Stableswap::set_asset_tradable_state(
307+
RuntimeOrigin::root(),
308+
pool_id,
309+
asset_a,
310+
partial,
311+
));
312+
assert!(<AssetTradability<Test>>::contains_key(pool_id, asset_a));
313+
assert_eq!(<AssetTradability<Test>>::get(pool_id, asset_a), partial);
314+
315+
assert_ok!(Stableswap::set_asset_tradable_state(
316+
RuntimeOrigin::root(),
317+
pool_id,
318+
asset_a,
319+
Tradability::default(),
320+
));
321+
assert!(!<AssetTradability<Test>>::contains_key(pool_id, asset_a));
322+
});
323+
}
324+
325+
#[test]
326+
fn set_tradable_state_should_not_create_storage_entry_when_initial_state_is_default() {
327+
let asset_a: AssetId = 1;
328+
let asset_b: AssetId = 2;
329+
let pool_id: AssetId = 100;
330+
331+
ExtBuilder::default()
332+
.with_endowed_accounts(vec![(ALICE, asset_a, 200 * ONE), (ALICE, asset_b, 200 * ONE)])
333+
.with_registered_asset("pool".as_bytes().to_vec(), pool_id, 12)
334+
.with_registered_asset("one".as_bytes().to_vec(), asset_a, 12)
335+
.with_registered_asset("two".as_bytes().to_vec(), asset_b, 12)
336+
.build()
337+
.execute_with(|| {
338+
assert_ok!(Stableswap::create_pool(
339+
RuntimeOrigin::root(),
340+
pool_id,
341+
to_bounded_asset_vec(vec![asset_a, asset_b]),
342+
100,
343+
Permill::from_percent(0),
344+
));
345+
346+
assert!(!<AssetTradability<Test>>::contains_key(pool_id, asset_a));
347+
348+
assert_ok!(Stableswap::set_asset_tradable_state(
349+
RuntimeOrigin::root(),
350+
pool_id,
351+
asset_a,
352+
Tradability::default(),
353+
));
354+
355+
assert!(!<AssetTradability<Test>>::contains_key(pool_id, asset_a));
356+
});
357+
}

0 commit comments

Comments
 (0)