|
3 | 3 |
|
4 | 4 | use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency};
|
5 | 5 | use frame_system::RawOrigin;
|
| 6 | +use safe_math::SafeDiv; |
| 7 | +use substrate_fixed::traits::FromFixed; |
6 | 8 |
|
7 | 9 | use super::mock::*;
|
8 | 10 | use crate::*;
|
9 | 11 | use approx::assert_abs_diff_eq;
|
10 | 12 | use frame_support::dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays};
|
11 | 13 | use frame_support::sp_runtime::DispatchError;
|
12 | 14 | use sp_core::{Get, H256, U256};
|
13 |
| -use substrate_fixed::types::{I96F32, U64F64, U96F32}; |
| 15 | +use substrate_fixed::types::{I96F32, I110F18, U64F64, U96F32}; |
14 | 16 |
|
15 | 17 | /***********************************************************
|
16 | 18 | staking::add_stake() tests
|
@@ -4240,3 +4242,192 @@ fn test_move_stake_limit_partial() {
|
4240 | 4242 | assert_abs_diff_eq!(new_alpha, 149_000_000_000, epsilon = 100_000_000,);
|
4241 | 4243 | });
|
4242 | 4244 | }
|
| 4245 | + |
| 4246 | +#[test] |
| 4247 | +fn test_unstake_all_hits_liquidity_min() { |
| 4248 | + new_test_ext(1).execute_with(|| { |
| 4249 | + let subnet_owner_coldkey = U256::from(1001); |
| 4250 | + let subnet_owner_hotkey = U256::from(1002); |
| 4251 | + let coldkey = U256::from(1); |
| 4252 | + let hotkey = U256::from(2); |
| 4253 | + |
| 4254 | + let stake_amount = 190_000_000_000; // 190 Alpha |
| 4255 | + |
| 4256 | + let netuid: u16 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey); |
| 4257 | + register_ok_neuron(netuid, hotkey, coldkey, 192213123); |
| 4258 | + // Give the neuron some stake to remove |
| 4259 | + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( |
| 4260 | + &hotkey, |
| 4261 | + &coldkey, |
| 4262 | + netuid, |
| 4263 | + stake_amount, |
| 4264 | + ); |
| 4265 | + |
| 4266 | + // Setup the Alpha pool so that removing all the Alpha will bring liqudity below the minimum |
| 4267 | + let remaining_tao: I96F32 = |
| 4268 | + DefaultMinimumPoolLiquidity::<Test>::get().saturating_sub(I96F32::from(1)); |
| 4269 | + let alpha_reserves: I110F18 = I110F18::from(stake_amount + 10_000_000); |
| 4270 | + let alpha = stake_amount; |
| 4271 | + |
| 4272 | + let k: I110F18 = I110F18::from_fixed(remaining_tao) |
| 4273 | + .saturating_mul(alpha_reserves.saturating_add(I110F18::from(alpha))); |
| 4274 | + let tao_reserves: I110F18 = k.safe_div(alpha_reserves); |
| 4275 | + |
| 4276 | + SubnetTAO::<Test>::insert(netuid, tao_reserves.to_num::<u64>()); |
| 4277 | + SubnetAlphaIn::<Test>::insert(netuid, alpha_reserves.to_num::<u64>()); |
| 4278 | + |
| 4279 | + // Try to unstake, but we reduce liquidity too far |
| 4280 | + |
| 4281 | + assert_ok!(SubtensorModule::unstake_all( |
| 4282 | + RuntimeOrigin::signed(coldkey), |
| 4283 | + hotkey, |
| 4284 | + )); |
| 4285 | + |
| 4286 | + // Expect nothing to be unstaked |
| 4287 | + let new_alpha = |
| 4288 | + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid); |
| 4289 | + assert_abs_diff_eq!(new_alpha, stake_amount, epsilon = 0,); |
| 4290 | + }); |
| 4291 | +} |
| 4292 | + |
| 4293 | +#[test] |
| 4294 | +fn test_unstake_all_alpha_hits_liquidity_min() { |
| 4295 | + new_test_ext(1).execute_with(|| { |
| 4296 | + let subnet_owner_coldkey = U256::from(1001); |
| 4297 | + let subnet_owner_hotkey = U256::from(1002); |
| 4298 | + let coldkey = U256::from(1); |
| 4299 | + let hotkey = U256::from(2); |
| 4300 | + |
| 4301 | + let stake_amount = 190_000_000_000; // 190 Alpha |
| 4302 | + |
| 4303 | + let netuid: u16 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey); |
| 4304 | + register_ok_neuron(netuid, hotkey, coldkey, 192213123); |
| 4305 | + // Give the neuron some stake to remove |
| 4306 | + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( |
| 4307 | + &hotkey, |
| 4308 | + &coldkey, |
| 4309 | + netuid, |
| 4310 | + stake_amount, |
| 4311 | + ); |
| 4312 | + |
| 4313 | + // Setup the Alpha pool so that removing all the Alpha will bring liqudity below the minimum |
| 4314 | + let remaining_tao: I96F32 = |
| 4315 | + DefaultMinimumPoolLiquidity::<Test>::get().saturating_sub(I96F32::from(1)); |
| 4316 | + let alpha_reserves: I110F18 = I110F18::from(stake_amount + 10_000_000); |
| 4317 | + let alpha = stake_amount; |
| 4318 | + |
| 4319 | + let k: I110F18 = I110F18::from_fixed(remaining_tao) |
| 4320 | + .saturating_mul(alpha_reserves.saturating_add(I110F18::from(alpha))); |
| 4321 | + let tao_reserves: I110F18 = k.safe_div(alpha_reserves); |
| 4322 | + |
| 4323 | + SubnetTAO::<Test>::insert(netuid, tao_reserves.to_num::<u64>()); |
| 4324 | + SubnetAlphaIn::<Test>::insert(netuid, alpha_reserves.to_num::<u64>()); |
| 4325 | + |
| 4326 | + // Try to unstake, but we reduce liquidity too far |
| 4327 | + |
| 4328 | + assert_ok!(SubtensorModule::unstake_all_alpha( |
| 4329 | + RuntimeOrigin::signed(coldkey), |
| 4330 | + hotkey, |
| 4331 | + )); |
| 4332 | + |
| 4333 | + // Expect nothing to be unstaked |
| 4334 | + let new_alpha = |
| 4335 | + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid); |
| 4336 | + assert_abs_diff_eq!(new_alpha, stake_amount, epsilon = 0,); |
| 4337 | + }); |
| 4338 | +} |
| 4339 | + |
| 4340 | +#[test] |
| 4341 | +fn test_unstake_all_alpha_works() { |
| 4342 | + new_test_ext(1).execute_with(|| { |
| 4343 | + let subnet_owner_coldkey = U256::from(1001); |
| 4344 | + let subnet_owner_hotkey = U256::from(1002); |
| 4345 | + let coldkey = U256::from(1); |
| 4346 | + let hotkey = U256::from(2); |
| 4347 | + |
| 4348 | + let stake_amount = 190_000_000_000; // 190 Alpha |
| 4349 | + |
| 4350 | + let netuid: u16 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey); |
| 4351 | + register_ok_neuron(netuid, hotkey, coldkey, 192213123); |
| 4352 | + // Give the neuron some stake to remove |
| 4353 | + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( |
| 4354 | + &hotkey, |
| 4355 | + &coldkey, |
| 4356 | + netuid, |
| 4357 | + stake_amount, |
| 4358 | + ); |
| 4359 | + |
| 4360 | + // Setup the Alpha pool so that removing all the Alpha will keep liq above min |
| 4361 | + let remaining_tao: I96F32 = |
| 4362 | + DefaultMinimumPoolLiquidity::<Test>::get().saturating_add(I96F32::from(10_000_000)); |
| 4363 | + let alpha_reserves: I110F18 = I110F18::from(stake_amount + 10_000_000); |
| 4364 | + let alpha = stake_amount; |
| 4365 | + |
| 4366 | + let k: I110F18 = I110F18::from_fixed(remaining_tao) |
| 4367 | + .saturating_mul(alpha_reserves.saturating_add(I110F18::from(alpha))); |
| 4368 | + let tao_reserves: I110F18 = k.safe_div(alpha_reserves); |
| 4369 | + |
| 4370 | + SubnetTAO::<Test>::insert(netuid, tao_reserves.to_num::<u64>()); |
| 4371 | + SubnetAlphaIn::<Test>::insert(netuid, alpha_reserves.to_num::<u64>()); |
| 4372 | + |
| 4373 | + // Unstake all alpha to root |
| 4374 | + assert_ok!(SubtensorModule::unstake_all_alpha( |
| 4375 | + RuntimeOrigin::signed(coldkey), |
| 4376 | + hotkey, |
| 4377 | + )); |
| 4378 | + |
| 4379 | + let new_alpha = |
| 4380 | + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid); |
| 4381 | + assert_abs_diff_eq!(new_alpha, 0, epsilon = 1_000,); |
| 4382 | + let new_root = |
| 4383 | + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, 0); |
| 4384 | + assert!(new_root > 100_000); |
| 4385 | + }); |
| 4386 | +} |
| 4387 | + |
| 4388 | +#[test] |
| 4389 | +fn test_unstake_all_works() { |
| 4390 | + new_test_ext(1).execute_with(|| { |
| 4391 | + let subnet_owner_coldkey = U256::from(1001); |
| 4392 | + let subnet_owner_hotkey = U256::from(1002); |
| 4393 | + let coldkey = U256::from(1); |
| 4394 | + let hotkey = U256::from(2); |
| 4395 | + |
| 4396 | + let stake_amount = 190_000_000_000; // 190 Alpha |
| 4397 | + |
| 4398 | + let netuid: u16 = add_dynamic_network(&subnet_owner_hotkey, &subnet_owner_coldkey); |
| 4399 | + register_ok_neuron(netuid, hotkey, coldkey, 192213123); |
| 4400 | + // Give the neuron some stake to remove |
| 4401 | + SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet( |
| 4402 | + &hotkey, |
| 4403 | + &coldkey, |
| 4404 | + netuid, |
| 4405 | + stake_amount, |
| 4406 | + ); |
| 4407 | + |
| 4408 | + // Setup the Alpha pool so that removing all the Alpha will keep liq above min |
| 4409 | + let remaining_tao: I96F32 = |
| 4410 | + DefaultMinimumPoolLiquidity::<Test>::get().saturating_add(I96F32::from(10_000_000)); |
| 4411 | + let alpha_reserves: I110F18 = I110F18::from(stake_amount + 10_000_000); |
| 4412 | + let alpha = stake_amount; |
| 4413 | + |
| 4414 | + let k: I110F18 = I110F18::from_fixed(remaining_tao) |
| 4415 | + .saturating_mul(alpha_reserves.saturating_add(I110F18::from(alpha))); |
| 4416 | + let tao_reserves: I110F18 = k.safe_div(alpha_reserves); |
| 4417 | + |
| 4418 | + SubnetTAO::<Test>::insert(netuid, tao_reserves.to_num::<u64>()); |
| 4419 | + SubnetAlphaIn::<Test>::insert(netuid, alpha_reserves.to_num::<u64>()); |
| 4420 | + |
| 4421 | + // Unstake all alpha to root |
| 4422 | + assert_ok!(SubtensorModule::unstake_all( |
| 4423 | + RuntimeOrigin::signed(coldkey), |
| 4424 | + hotkey, |
| 4425 | + )); |
| 4426 | + |
| 4427 | + let new_alpha = |
| 4428 | + SubtensorModule::get_stake_for_hotkey_and_coldkey_on_subnet(&hotkey, &coldkey, netuid); |
| 4429 | + assert_abs_diff_eq!(new_alpha, 0, epsilon = 1_000,); |
| 4430 | + let new_balance = SubtensorModule::get_coldkey_balance(&coldkey); |
| 4431 | + assert!(new_balance > 100_000); |
| 4432 | + }); |
| 4433 | +} |
0 commit comments